Filters & Calendars

This commit is contained in:
reinjens 2024-11-09 22:03:03 +01:00
parent 798941af12
commit b96919c118
18 changed files with 1064 additions and 172 deletions

View file

@ -7,6 +7,7 @@ import 'package:ambito/src/pages/actions/actions_page.dart';
import 'package:ambito/src/pages/actions/actions_pre_page.dart';
import 'package:ambito/src/pages/calendar/calendar_page.dart';
import 'package:ambito/src/pages/calendar/calendar_page_year.dart';
import 'package:ambito/src/pages/dashboard/dashboard_page.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
@ -48,6 +49,8 @@ void main() async {
await MeasureRepository().buildMeasureFilters();
await MeasureRepository().downloadImages();
runApp(const Ambito());
}
@ -103,6 +106,41 @@ class Ambito extends StatelessWidget {
name: '/massnahmendatenbank',
page: () => const ActionsPage(),
),
GetPage(
name: '/dashboard',
page: () => DashboardPage(
businessId: prefs.getInt('currentUser') ?? 22,
userId: 0,
),
),
GetPage(
name: '/dashboard/meine-massnahmen',
page: () => DashboardPage(
businessId: prefs.getInt('currentUser') ?? 22,
userId: 0,
),
),
GetPage(
name: '/dashboard/urkunde',
page: () => DashboardPage(
businessId: prefs.getInt('currentUser') ?? 22,
userId: 0,
),
),
GetPage(
name: '/dashboard/flaechen',
page: () => DashboardPage(
businessId: prefs.getInt('currentUser') ?? 22,
userId: 0,
),
),
GetPage(
name: '/dashboard/stammdaten',
page: () => DashboardPage(
businessId: prefs.getInt('currentUser') ?? 22,
userId: 0,
),
),
GetPage(name: '/massnahme/:id', page: () => const ActionDetailPage())
],
);

View file

@ -0,0 +1,14 @@
const List<String> months = [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
];

View file

@ -25,7 +25,22 @@ class ItemFilterRepository extends BaseDB {
.toList();
}
List<dynamic>? getIdsByTypeAndName(String type, String name) {
return isar.itemFilters
.where()
.typeEqualTo(type)
.and()
.nameEqualTo(name)
.idsProperty()
.findAll()
.expand((list) => list ?? [])
.toSet()
.toList();
}
FieldDropdown getDropDown(String type, String label) {
if (type == 'month') {}
List<ItemFilter> filterItems = getByType(type)!;
return FieldDropdown(

View file

@ -51,7 +51,7 @@ class MeasureRepository extends BaseDB {
..name = entry.key
..type = 'areaType'
..description =
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy.'
..image =
'images/actions/areatype/${entry.key.toLowerCase().replaceUmlauts()}.jpg'
..color = colors[entry.key]
@ -63,8 +63,7 @@ class MeasureRepository extends BaseDB {
..id = autoIncrement()
..name = entry.key
..type = 'group'
..description =
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt.'
..description = 'Lorem ipsum dolor sit amet, consetetur sadipscing.'
..image =
'images/actions/areatype/${entry.key.toLowerCase().replaceUmlauts()}.jpg'
..color = colors[entry.key]
@ -101,4 +100,18 @@ class MeasureRepository extends BaseDB {
List<Measure> getAllOrdered() {
return isar.measures.where().sortByName().findAll();
}
Future<bool> downloadImages() async {
List<Measure> measures = isar.measures.where().findAll();
List<String> files = [];
for (Measure measure in measures) {
if (measure.files != null) {
for (FilePart file in measure.files!) {
files.add(file.url!);
}
}
}
logger.d(files);
return true;
}
}

View file

@ -27,7 +27,7 @@ class BaseApi {
var json = _jsonDecoded(response.body);
//if (table == 'measure') {
//logger.d(json);
// logger.d(json);
//}
var results = json['results'];

View file

@ -0,0 +1,22 @@
import '../../../main.dart';
class AmbitoDownloader {
static Future<bool> downloadImage(
String type,
String id,
String downloadUrl,
) async {
logger.d(downloadUrl);
//await WebImageDownloader.downloadImageFromWeb(downloadUrl);
/*var documentDirectory = await getApplicationDocumentsDirectory();
var yourPath = "${documentDirectory.path}/$type";
var filePathAndName = '$yourPath/%id.jpg';
await Directory(yourPath).create(recursive: true);
File yourFile = File(filePathAndName);
yourFile.writeAsBytesSync(response.bodyBytes);*/
return true;
}
}

View file

@ -17,7 +17,7 @@ class AmbitoFilterNotifier extends ChangeNotifier {
void setFilter(String type, String value) {
prefs.setString('filter_$type', value).then((_) {
activeFilters[type] = value;
activeIds[type] = ItemFilterRepository().getIdsByType(type);
activeIds[type] = ItemFilterRepository().getIdsByTypeAndName(type, value);
notifyListeners();
});
}

View file

@ -1,6 +1,27 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
final orangeColors = {
'primary': const Color(0xffeebb4b),
'secondary': const Color(0xfff8e0aa),
'tertiary': const Color(0xfff3b25c),
'quarternary': const Color(0xffec863a),
};
final redColors = {
'primary': const Color(0xff96172f),
'secondary': const Color(0xffca414c),
'tertiary': const Color(0xffa83745),
'quarternary': const Color(0xff883443),
};
final greenColors = {
'primary': const Color(0xff88a44e),
'secondary': const Color(0xffd5d808),
'tertiary': const Color(0xffacc11e),
'quarternary': const Color(0xff3d693f),
};
final actionGroupColors = {
'Bauelemente': const Color(0xffFFD269).withOpacity(.4),
'Begrünung': const Color(0xff40DD74).withOpacity(.4),
@ -11,9 +32,9 @@ final actionGroupColors = {
};
final actionAreaColors = {
'Landschaft': const Color(0xfff8e0aa).withOpacity(.6),
'Weinberg': const Color(0xffacc11e).withOpacity(.6),
'Betriebsfläche': const Color(0xffca414c).withOpacity(.6),
'Landschaft': const Color(0xffeebb4b).withOpacity(.3),
'Weinberg': const Color(0xff88a44e).withOpacity(.3),
'Betriebsfläche': const Color(0xff96172f).withOpacity(.3),
'Betriebsstätte': const Color(0xffCCCDCC).withOpacity(.6),
};
@ -46,7 +67,7 @@ class AmbitoTheme {
onError: Color(0xFFFFFFFF),
onErrorContainer: Color(0xFF410002),
surface: Color(0xFFffffff),
onSurface: Color(0xFF656565),
onSurface: Color(0xFF666666),
surfaceContainerHighest: Color(0xFFDDE3EA),
onSurfaceVariant: Color(0xFF41484D),
outline: Color(0xFF71787E),
@ -200,22 +221,25 @@ class AmbitoTheme {
),
);
EdgeInsets get padding => const EdgeInsets.all(16);
EdgeInsets get paddingSmall => const EdgeInsets.all(8);
EdgeInsets get padding => const EdgeInsets.all(20);
EdgeInsets get paddingSmall => const EdgeInsets.all(10);
Widget get horizontalSpacer => const SizedBox(
width: 16,
width: 20,
);
Widget get horizontalSpacerMax => const SizedBox(
width: 40,
);
Widget get horizontalSpacerSmall => const SizedBox(
width: 8,
width: 10,
);
Widget get verticalSpacer => const SizedBox(
height: 16,
height: 20,
);
Widget get verticalSpacerSmall => const SizedBox(
height: 8,
height: 10,
);
Widget get verticalSpacerMax => const SizedBox(
height: 48,
height: 40,
);
ThemeData get darkThemeData => ThemeData(

View file

@ -37,6 +37,9 @@ class ActionDetailPageState extends State<ActionDetailPage> {
Widget content = const SizedBox();
Measure? massnahme;
List<Widget> contentItems = [];
List<Widget> sidebarItems = [];
@override
void initState() {
id = Get.parameters['id'] ?? '';
@ -44,11 +47,60 @@ class ActionDetailPageState extends State<ActionDetailPage> {
massnahme = MeasureRepository().get(int.parse(id)) as Measure;
setState(() {
if (massnahme != null) {
contentItems = [
DescriptionCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
BackgroundCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
PresetsCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
BiodiverisityCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
CreationCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
MaintenanceCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
FundingCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
];
sidebarItems = [
AdvisorCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
MaterialCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
FactsheetCard(
massnahme: massnahme!,
),
baseTheme.verticalSpacer,
ReviewCard(
massnahme: massnahme!,
),
];
content = _buildInfoPage(massnahme!);
}
});
}
logger.d(id);
super.initState();
}
@ -58,9 +110,7 @@ class ActionDetailPageState extends State<ActionDetailPage> {
appBar: AmbitoAppbar(
links: const ['dashboard', 'massnahmen'],
),
body: SingleChildScrollView(
child: content,
),
body: content,
);
}
@ -102,9 +152,8 @@ class ActionDetailPageState extends State<ActionDetailPage> {
color: baseTheme.currentColorScheme.primary,
child: massnahme.getImage(),
),
SizedBox(
width: 1140,
child: Expanded(
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
baseTheme.verticalSpacer,
@ -119,37 +168,13 @@ class ActionDetailPageState extends State<ActionDetailPage> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Column(
children: [
DescriptionCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
BackgroundCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
PresetsCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
BiodiverisityCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
CreationCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
MaintenanceCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
FundingCard(
massnahme: massnahme,
),
baseTheme.verticalSpacer,
],
child: SingleChildScrollView(
child: ListView.builder(
shrinkWrap: true,
itemCount: contentItems.length,
itemBuilder: (BuildContext context, int index) {
return contentItems[index];
}),
),
),
baseTheme.horizontalSpacer,

View file

@ -64,8 +64,9 @@ class ActionsPageState extends State<ActionsPage> {
setState(() {
filterAreaType = ambitoFilterNotifier.getFilter('areaType');
filterType = ambitoFilterNotifier.getFilter('group');
filterSupport = ambitoFilterNotifier.getFilter('fundingProgram');
filterMonths = ambitoFilterNotifier.getFilter('month');
});
logger.d(ambitoFilterNotifier.activeIds);
}
@override
@ -75,7 +76,7 @@ class ActionsPageState extends State<ActionsPage> {
}
void _initializeData() {
massnahmen = MeasureRepository().getAll();
massnahmen = MeasureRepository().getAllOrdered();
_updateFilterSets();
}

View file

@ -45,10 +45,11 @@ class ActionsPrePageState extends State<ActionsPrePage> {
},
onHover: (value) {},
child: SizedBox(
width: 300,
height: 400,
width: 262,
height: 350,
child: Card(
color: actionAreaColors[filter.name!],
elevation: 4,
surfaceTintColor: actionAreaColors[filter.name!],
child: Column(
children: [
ClipRRect(
@ -112,41 +113,44 @@ class ActionsPrePageState extends State<ActionsPrePage> {
links: const ['dashboard', 'massnahmen'],
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
baseTheme.verticalSpacerMax,
Text(
'Maßnahmenkategorien',
textAlign: TextAlign.start,
style:
baseTheme.currentThemeData.textTheme.headlineLarge?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
child: SizedBox(
width: 1152,
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
baseTheme.verticalSpacerMax,
Text(
'Maßnahmenkategorien',
textAlign: TextAlign.start,
style: baseTheme.currentThemeData.textTheme.headlineLarge
?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
),
),
),
baseTheme.verticalSpacerMax,
Wrap(
alignment: WrapAlignment.center,
spacing: 16,
children: cards,
),
baseTheme.verticalSpacerMax,
TextButton(
onPressed: () async {
await prefs.setString('selected_areaType', '');
await Get.toNamed('/massnahmendatenbank');
},
child: Text(
'Zeig mir alle $counterComplete Maßnahmen...',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
))
],
baseTheme.verticalSpacerMax,
Wrap(
alignment: WrapAlignment.center,
spacing: 32,
children: cards,
),
baseTheme.verticalSpacerMax,
TextButton(
onPressed: () async {
await prefs.setString('selected_areaType', '');
await Get.toNamed('/massnahmendatenbank');
},
child: Text(
'Zeig mir alle $counterComplete Maßnahmen...',
style: const TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold,
color: Colors.blueAccent,
),
))
],
),
),
),
);

View file

@ -8,6 +8,7 @@ import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
import '../../consts/consts.dart';
import '../../widgets/appbar/ambito_appbar.dart';
class CalendarPage extends StatefulWidget {
@ -20,20 +21,6 @@ class CalendarPage extends StatefulWidget {
class CalendarPageState extends State<CalendarPage> {
List<Appointment> appointments = <Appointment>[];
List<String> months = [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
];
List<ItemFilter>? monthFilter = [];
@override

View file

@ -3,6 +3,7 @@ import 'package:ambito/src/entity/_general/filter/item_filter.dart';
import 'package:ambito/src/entity/measure/measure_repository.dart';
import 'package:flutter/material.dart';
import '../../consts/consts.dart';
import '../../widgets/appbar/ambito_appbar.dart';
class CalendarPageYear extends StatefulWidget {
@ -13,22 +14,12 @@ class CalendarPageYear extends StatefulWidget {
}
class CalendarPageYearState extends State<CalendarPageYear> {
List<TableRow> rows = <TableRow>[];
List<TableRow> rowsBody = <TableRow>[];
List<TableRow> rowsHeader = <TableRow>[];
List<String> months = [
'Januar',
'Februar',
'März',
'April',
'Mai',
'Juni',
'Juli',
'August',
'September',
'Oktober',
'November',
'Dezember',
];
Set<String> displayFilterSet = {'creation', 'maintenance'};
List<FilterChip> displayFilters = [];
List<ItemFilter>? monthFilter = [];
@override
@ -44,9 +35,8 @@ class CalendarPageYearState extends State<CalendarPageYear> {
padding: const EdgeInsets.all(8),
child: Text(
'Maßnahme',
style: baseTheme.currentThemeData.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
style: baseTheme.currentThemeData.textTheme.titleMedium
?.copyWith(fontWeight: FontWeight.bold, color: Colors.white),
),
),
),
@ -58,14 +48,15 @@ class CalendarPageYearState extends State<CalendarPageYear> {
child: Text(
textAlign: TextAlign.center,
month,
style: baseTheme.currentThemeData.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.bold,
),
style: baseTheme.currentThemeData.textTheme.titleMedium
?.copyWith(fontWeight: FontWeight.bold, color: Colors.white),
),
),
);
}
rows.add(TableRow(children: cells));
rowsHeader.add(TableRow(
decoration: const BoxDecoration(color: Color(0xFF60845E)),
children: cells));
var massnahmen = MeasureRepository().getAllOrdered();
for (var massnahme in massnahmen) {
if (massnahme.name != null && massnahme.name!.isNotEmpty) {
@ -104,7 +95,7 @@ class CalendarPageYearState extends State<CalendarPageYear> {
);
}
}
rows.add(
rowsBody.add(
TableRow(
children: cells,
),
@ -120,52 +111,145 @@ class CalendarPageYearState extends State<CalendarPageYear> {
appBar: AmbitoAppbar(
links: const ['dashboard', 'massnahmen'],
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(32),
child: Table(
border: TableBorder(
top: const BorderSide(
width: 2,
color: Colors.black,
),
left: const BorderSide(
width: 2,
color: Colors.black,
),
right: const BorderSide(
width: 2,
color: Colors.black,
),
bottom: const BorderSide(
width: 2,
color: Colors.black,
),
horizontalInside: BorderSide(
width: 1,
color: Colors.black.withOpacity(.6),
body: Card(
child: Column(
children: [
/*Padding(
padding: const EdgeInsets.only(top: 32, left: 32, right: 32),
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FilterChip(
label: const Text('Zeitraum der Anlage'),
selected: displayFilterSet.contains('creation'),
selectedColor: baseTheme.currentColorScheme.primary,
onSelected: (bool selected) {
setState(() {
if (selected) {
displayFilterSet.add('creation');
} else {
displayFilterSet.remove('creation');
}
});
},
),
baseTheme.horizontalSpacerSmall,
FilterChip(
label: const Text('Zeitraum der Pflege'),
selected: displayFilterSet.contains('maintenance'),
selectedColor: baseTheme.currentColorScheme.inversePrimary,
onSelected: (bool selected) {
setState(() {
if (selected) {
displayFilterSet.add('maintenance');
} else {
displayFilterSet.remove('maintenance');
}
});
},
),
],
),
),*/
Padding(
padding: const EdgeInsets.only(top: 32, left: 32, right: 32),
child: _buildTableHeader(fixedWidth),
),
Expanded(
child: SingleChildScrollView(
child: Padding(
padding:
const EdgeInsets.only(bottom: 32, left: 32, right: 32),
child: _buildTableBody(fixedWidth),
),
),
),
columnWidths: <int, TableColumnWidth>{
0: FlexColumnWidth(300),
1: FlexColumnWidth(fixedWidth),
2: FlexColumnWidth(fixedWidth),
3: FlexColumnWidth(fixedWidth),
4: FlexColumnWidth(fixedWidth),
5: FlexColumnWidth(fixedWidth),
6: FlexColumnWidth(fixedWidth),
7: FlexColumnWidth(fixedWidth),
8: FlexColumnWidth(fixedWidth),
9: FlexColumnWidth(fixedWidth),
10: FlexColumnWidth(fixedWidth),
11: FlexColumnWidth(fixedWidth),
12: FlexColumnWidth(fixedWidth),
13: FlexColumnWidth(fixedWidth),
},
children: rows,
),
],
),
),
);
}
Table _buildTableHeader(double fixedWidth) {
TableBorder tableBorder = TableBorder(
top: const BorderSide(
width: 2,
color: Colors.black,
),
left: const BorderSide(
width: 2,
color: Colors.black,
),
right: const BorderSide(
width: 2,
color: Colors.black,
),
bottom: const BorderSide(
width: 2,
color: Colors.black,
),
horizontalInside: BorderSide(
width: 1,
color: Colors.black.withOpacity(.6),
),
verticalInside: const BorderSide(
width: 0,
color: Colors.transparent,
),
);
return _getTable(fixedWidth, tableBorder, rowsHeader);
}
Table _buildTableBody(double fixedWidth) {
TableBorder tableBorder = TableBorder(
top: const BorderSide(
width: 0,
color: Colors.black,
),
left: const BorderSide(
width: 2,
color: Colors.black,
),
right: const BorderSide(
width: 2,
color: Colors.black,
),
bottom: const BorderSide(
width: 2,
color: Colors.black,
),
horizontalInside: BorderSide(
width: 1,
color: Colors.black.withOpacity(.6),
),
verticalInside: const BorderSide(
width: 0,
),
);
return _getTable(fixedWidth, tableBorder, rowsBody);
}
Table _getTable(
double fixedWidth, TableBorder tableBorder, List<TableRow> rows) {
return Table(
border: tableBorder,
columnWidths: <int, TableColumnWidth>{
0: const FlexColumnWidth(300),
1: FlexColumnWidth(fixedWidth),
2: FlexColumnWidth(fixedWidth),
3: FlexColumnWidth(fixedWidth),
4: FlexColumnWidth(fixedWidth),
5: FlexColumnWidth(fixedWidth),
6: FlexColumnWidth(fixedWidth),
7: FlexColumnWidth(fixedWidth),
8: FlexColumnWidth(fixedWidth),
9: FlexColumnWidth(fixedWidth),
10: FlexColumnWidth(fixedWidth),
11: FlexColumnWidth(fixedWidth),
12: FlexColumnWidth(fixedWidth),
13: FlexColumnWidth(fixedWidth),
},
children: rows,
);
}
}

View file

@ -0,0 +1,162 @@
import 'package:ambito/src/entity/_general/filter/item_filter.dart';
import 'package:ambito/src/entity/_general/filter/item_filter_repository.dart';
import 'package:ambito/src/entity/measure/measure.dart';
import 'package:ambito/src/entity/measure/measure_repository.dart';
import 'package:ambito/src/extensions/extensions.dart';
import 'package:ambito/src/packages/ambito_theme/ambito_theme.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_calendar/calendar.dart';
import '../../consts/consts.dart';
import '../../widgets/appbar/ambito_appbar.dart';
class CalendarPage extends StatefulWidget {
const CalendarPage({super.key});
@override
State<StatefulWidget> createState() => CalendarPageState();
}
class CalendarPageState extends State<CalendarPage> {
List<Appointment> appointments = <Appointment>[];
List<ItemFilter>? monthFilter = [];
@override
void initState() {
initDataSource();
super.initState();
}
initDataSource() {
monthFilter = ItemFilterRepository().getByType('month');
for (String month in months) {
DateTime now = DateTime.now();
int monthInt = months.indexOf(month) + 1;
DateTime startDate = DateTime(now.year, monthInt, 1, 0, 0, 0);
DateTime endDate = DateTime(
now.year, monthInt, startDate.lastDayOfMonth.day, 23, 59, 59);
ItemFilter? itemFilter =
monthFilter?.firstWhereOrNull((item) => item.name == month);
if (itemFilter != null) {
List<Measure?> currentMeasures =
MeasureRepository().getByIds(itemFilter.ids!);
for (var measure in currentMeasures) {
appointments.add(
Appointment(
startTime: startDate,
endTime: endDate,
isAllDay: true,
subject: measure!.name ?? '',
color: actionGroupColors[measure.actionGroup!.value!]!,
),
);
}
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AmbitoAppbar(
links: const ['dashboard', 'massnahmen'],
),
body: Center(
child: Padding(
padding: const EdgeInsets.all(32),
child: SfCalendar(
firstDayOfWeek: 1,
showNavigationArrow: true,
view: CalendarView.month,
dataSource: _AppointmentDataSource(appointments),
monthViewSettings: const MonthViewSettings(
appointmentDisplayMode: MonthAppointmentDisplayMode.appointment,
appointmentDisplayCount: 64,
),
),
),
),
);
}
_AppointmentDataSource _getCalendarDataSource() {
List<Appointment> appointments = <Appointment>[];
appointments.add(Appointment(
startTime: DateTime.now(),
endTime: DateTime.now().add(Duration(minutes: 10)),
subject: 'Meeting',
isAllDay: true,
color: Colors.blue,
startTimeZone: '',
endTimeZone: '',
));
return _AppointmentDataSource(appointments);
}
}
class _AppointmentDataSource extends CalendarDataSource {
_AppointmentDataSource(List<Appointment> source) {
appointments = source;
}
}
/*class ActionDataSource extends CalendarDataSource {
ActionDataSource(List<Action> source) {
appointments = source;
}
@override
DateTime getStartTime(int index) {
return appointments![index].from;
}
@override
DateTime getEndTime(int index) {
return appointments![index].to;
}
@override
bool isAllDay(int index) {
return appointments![index].isAllDay;
}
@override
String getSubject(int index) {
return appointments![index].eventName;
}
@override
String getStartTimeZone(int index) {
return appointments![index].startTimeZone;
}
@override
String getEndTimeZone(int index) {
return appointments![index].endTimeZone;
}
@override
Color getColor(int index) {
return appointments![index].background;
}
}
class Action {
Action(
{this.eventName = '',
required this.from,
required this.to,
required this.background,
this.isAllDay = false});
String eventName;
DateTime from;
DateTime to;
Color background;
bool isAllDay;
}*/

View file

@ -0,0 +1,444 @@
import 'package:ambito/src/packages/ambito_theme/ambito_theme.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:percent_indicator/linear_percent_indicator.dart';
import '../../../main.dart';
import '../../widgets/appbar/ambito_appbar.dart';
class DashboardPage extends StatefulWidget {
const DashboardPage(
{super.key, required this.businessId, required this.userId});
final int businessId;
final int userId;
@override
State<StatefulWidget> createState() => DashboardPageState();
}
class DashboardPageState extends State<DashboardPage> {
List<Widget> cards = [];
@override
void initState() {
cards.add(
_buildCard(
Colors.green,
'images/actions/nist_brut_unterschlupforte.jpg',
'Meine\nMaßnahmen',
'/dashboard/meine-massnahmen',
),
);
cards.add(
_buildCard(
Colors.green,
'images/actions/steinhaufen.jpg',
'Urkunde',
'/dashboard/urkunde',
),
);
cards.add(
_buildCard(
Colors.green,
'images/actions/staudenbeete.jpg',
'Flächen',
'/dashboard/flaechen',
),
);
cards.add(
_buildCard(
Colors.green,
'images/actions/pflanzgefaesse.jpg',
'Stammdaten',
'/dashboard/stammdaten',
),
);
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AmbitoAppbar(
links: const ['dashboard', 'massnahmen'],
),
body: SingleChildScrollView(
child: Align(
alignment: Alignment.topCenter,
child: SizedBox(
width: 1152,
child: Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
baseTheme.verticalSpacerMax,
Text(
'Willkommen, Max Mustermann!',
textAlign: TextAlign.start,
style: baseTheme.currentThemeData.textTheme.headlineLarge
?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
),
),
baseTheme.verticalSpacerMax,
Wrap(
alignment: WrapAlignment.center,
spacing: 32,
children: cards,
),
baseTheme.verticalSpacerMax,
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 532,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Biodiversitätsbewertung',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.headlineMedium
?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
),
),
baseTheme.verticalSpacer,
SizedBox(
width: 532,
child: Card(
elevation: 4,
surfaceTintColor:
orangeColors['primary']?.withOpacity(0.3),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Fragebögen',
textAlign: TextAlign.left,
style: baseTheme.currentThemeData
.textTheme.headlineSmall
?.copyWith(
color: orangeColors['primary'],
fontWeight: FontWeight.bold,
),
),
baseTheme.verticalSpacerSmall,
Row(
children: [
LinearPercentIndicator(
width: 440,
lineHeight: 20.0,
animation: true,
percent: 0.8,
padding: EdgeInsets.zero,
backgroundColor: baseTheme
.currentColorScheme.surface,
progressColor:
orangeColors['primary'],
barRadius: const Radius.circular(8),
),
const Spacer(),
IconButton(
iconSize: 24,
onPressed: () {},
icon: const Icon(
Icons.arrow_forward_ios,
),
color: Colors.white,
style: IconButton.styleFrom(
fixedSize: const Size(20, 20),
padding: const EdgeInsets.all(2),
backgroundColor:
orangeColors['primary'],
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(8),
),
),
),
],
),
baseTheme.verticalSpacerSmall,
Text(
'4 / 5 abgeschlossen',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.bodyLarge
?.copyWith(
color: baseTheme
.currentColorScheme.onSurface,
),
),
],
),
),
),
),
baseTheme.verticalSpacer,
SizedBox(
width: 532,
child: Card(
elevation: 4,
surfaceTintColor:
greenColors['primary']?.withOpacity(0.3),
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Ergebnisse',
textAlign: TextAlign.left,
style: baseTheme.currentThemeData
.textTheme.headlineSmall
?.copyWith(
color: greenColors['primary'],
fontWeight: FontWeight.bold,
),
),
baseTheme.verticalSpacerSmall,
Row(
children: [
LinearPercentIndicator(
width: 480,
lineHeight: 20.0,
animation: true,
percent: 0.8,
padding: EdgeInsets.zero,
backgroundColor: baseTheme
.currentColorScheme.surface,
progressColor: greenColors['primary'],
barRadius: const Radius.circular(8),
),
],
),
baseTheme.verticalSpacerSmall,
Text(
'Weinberg: 80%',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.bodyLarge
?.copyWith(
color: baseTheme
.currentColorScheme.onSurface,
),
),
baseTheme.verticalSpacerSmall,
Row(
children: [
LinearPercentIndicator(
width: 480,
lineHeight: 20.0,
animation: true,
percent: 0.52,
padding: EdgeInsets.zero,
backgroundColor: baseTheme
.currentColorScheme.surface,
progressColor: greenColors['primary'],
barRadius: const Radius.circular(8),
),
],
),
baseTheme.verticalSpacerSmall,
Text(
'Landschaft: 52%',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.bodyLarge
?.copyWith(
color: baseTheme
.currentColorScheme.onSurface,
),
),
baseTheme.verticalSpacerSmall,
Row(
children: [
LinearPercentIndicator(
width: 480,
lineHeight: 20.0,
animation: true,
percent: 0.27,
padding: EdgeInsets.zero,
backgroundColor: baseTheme
.currentColorScheme.surface,
progressColor: greenColors['primary'],
barRadius: const Radius.circular(8),
),
],
),
baseTheme.verticalSpacerSmall,
Text(
'Betriebsstätte: 27%',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.bodyLarge
?.copyWith(
color: baseTheme
.currentColorScheme.onSurface,
),
),
],
),
),
),
),
],
),
),
const Spacer(),
SizedBox(
width: 532,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'Förderungen',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.headlineMedium
?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
),
),
baseTheme.verticalSpacer,
Text(
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.',
textAlign: TextAlign.start,
style: baseTheme
.currentThemeData.textTheme.bodyLarge
?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
),
),
baseTheme.verticalSpacer,
_buildProjectCard(
'Projekt A',
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.',
),
baseTheme.verticalSpacer,
_buildProjectCard(
'Projekt B',
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.',
),
],
),
),
],
),
],
),
),
),
),
);
}
Widget _buildCard(Color background, String image, String title, String link) {
return GestureDetector(
onTap: () {
Get.toNamed(link);
},
child: SizedBox(
width: 262,
height: 250,
child: Card(
elevation: 4,
surfaceTintColor: Colors.white,
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset(
image,
),
),
Expanded(
child: Center(
child: Text(
title,
textAlign: TextAlign.center,
style: baseTheme.currentThemeData.textTheme.headlineSmall
?.copyWith(
color: const Color(0xFF666666),
fontWeight: FontWeight.bold,
),
),
),
),
],
),
),
),
);
}
Widget _buildProjectCard(String title, String text) {
return SizedBox(
width: 532,
child: Card(
elevation: 4,
surfaceTintColor: Colors.white,
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
textAlign: TextAlign.center,
style: baseTheme.currentThemeData.textTheme.headlineSmall
?.copyWith(
color: greenColors['primary'],
fontWeight: FontWeight.bold,
),
),
baseTheme.verticalSpacer,
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(
text,
softWrap: true,
overflow: TextOverflow.ellipsis,
maxLines: 3,
textAlign: TextAlign.start,
style: baseTheme.currentThemeData.textTheme.bodyLarge
?.copyWith(
color: baseTheme.currentColorScheme.onSurface,
),
),
),
IconButton(
iconSize: 24,
onPressed: () {},
icon: const Icon(
Icons.arrow_forward_ios,
),
color: Colors.white,
style: IconButton.styleFrom(
fixedSize: const Size(20, 20),
padding: const EdgeInsets.all(2),
backgroundColor: greenColors['primary'],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
),
],
),
],
),
),
),
);
}
}

View file

@ -22,6 +22,7 @@ class AmbitoAppbar extends AppBar {
),
),
leadingWidth: 80,
scrolledUnderElevation: 0,
centerTitle: true,
title: Builder(
builder: (context) => _links(context, links),

View file

@ -150,6 +150,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.3.0"
charcode:
dependency: transitive
description:
name: charcode
sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
url: "https://pub.dev"
source: hosted
version: "1.3.1"
checked_yaml:
dependency: transitive
description:
@ -206,6 +214,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.6"
csslib:
dependency: transitive
description:
name: csslib
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
cupertino_icons:
dependency: "direct main"
description:
@ -506,6 +522,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.8.0"
html:
dependency: transitive
description:
name: html
sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec"
url: "https://pub.dev"
source: hosted
version: "0.15.5"
http:
dependency: "direct main"
description:
@ -530,6 +554,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "4.0.2"
image_downloader_web:
dependency: "direct main"
description:
name: image_downloader_web
sha256: "11290f6ef5bd5afcb3c623c5a10c16da53a2f41a9bf238d9e20f7ff77407e39e"
url: "https://pub.dev"
source: hosted
version: "2.0.6"
intl:
dependency: "direct main"
description:
@ -802,6 +834,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.11.1"
percent_indicator:
dependency: "direct main"
description:
name: percent_indicator
sha256: c37099ad833a883c9d71782321cb65c3a848c21b6939b6185f0ff6640d05814c
url: "https://pub.dev"
source: hosted
version: "4.2.3"
permission_handler:
dependency: "direct main"
description:
@ -1207,6 +1247,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.3.1"
universal_html:
dependency: transitive
description:
name: universal_html
sha256: "56536254004e24d9d8cfdb7dbbf09b74cf8df96729f38a2f5c238163e3d58971"
url: "https://pub.dev"
source: hosted
version: "2.2.4"
universal_io:
dependency: transitive
description:
name: universal_io
sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad"
url: "https://pub.dev"
source: hosted
version: "2.2.2"
uuid:
dependency: transitive
description:

View file

@ -51,6 +51,8 @@ dependencies:
flutter_rating_stars: ^1.1.0
syncfusion_flutter_calendar: ^27.1.58
timezone: ^0.9.4
percent_indicator: ^4.2.3
image_downloader_web: ^2.0.6
dev_dependencies: