634 lines
34 KiB
Dart
634 lines
34 KiB
Dart
import 'package:ambito/src/entity/_general/id_value/id_value.dart';
|
|
import 'package:ambito/src/entity/area/area_datasource.dart';
|
|
import 'package:ambito/src/entity/area/area_repository.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:google_geocoding_api/google_geocoding_api.dart';
|
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|
import 'package:screen_breakpoints/screen_breakpoints.dart';
|
|
import 'package:syncfusion_flutter_core/theme.dart';
|
|
import 'package:syncfusion_flutter_datagrid/datagrid.dart';
|
|
import 'package:toggle_switch/toggle_switch.dart';
|
|
|
|
import '../../../config/config.dart';
|
|
import '../../../consts/consts.dart';
|
|
import '../../../entity/area/area.dart';
|
|
import '../../../entity/business/business.dart';
|
|
import '../../../packages/ambito_api/base_api.dart';
|
|
import '../../../packages/ambito_theme/ambito_theme.dart';
|
|
import '../../../widgets/appbar/ambito_appbar.dart';
|
|
import '../../../widgets/map/map_widget.dart';
|
|
import '../../../widgets/map/marker_generator.dart';
|
|
import '../../../widgets/page/base_page.dart';
|
|
|
|
class DashboardAreasPage extends StatefulWidget {
|
|
const DashboardAreasPage(
|
|
{super.key, required this.businessId, required this.userId});
|
|
|
|
final int businessId;
|
|
final int userId;
|
|
|
|
@override
|
|
State<StatefulWidget> createState() => DashboardAreasPageState();
|
|
}
|
|
|
|
class DashboardAreasPageState extends State<DashboardAreasPage> {
|
|
Widget mapWidget = const SizedBox();
|
|
final api = GoogleGeocodingApi(googleApiKey, isLogged: false);
|
|
Set<Marker> markers = {};
|
|
Set<Polygon> polygons = {};
|
|
List<Area> areas = [];
|
|
Business? business;
|
|
|
|
int display = 0;
|
|
|
|
@override
|
|
void initState() {
|
|
BaseApi().getContent('business').then((_) {
|
|
business = isar.business.get(widget.businessId);
|
|
|
|
display = int.tryParse(Get.parameters['index'] ?? '0') ?? 0;
|
|
|
|
api
|
|
.search(business!.addressComplete!, language: 'de')
|
|
.then((GoogleGeocodingResponse response) {
|
|
MarkerGenerator(64)
|
|
.createBitmapDescriptorFromIconData(
|
|
Icons.home,
|
|
Colors.white,
|
|
const Color(0xFF60845E),
|
|
const Color(0xff87A34E),
|
|
)
|
|
.then((
|
|
BitmapDescriptor bitMapDescriptor,
|
|
) {
|
|
final prettyAddress = response.results.firstOrNull?.mapToPretty();
|
|
areas = AreaRepository().getAreasForBusiness(widget.businessId);
|
|
|
|
for (Area area in areas) {
|
|
final polygon = area.toPolygon();
|
|
if (polygon != null) {
|
|
setState(() {
|
|
polygons.add(polygon);
|
|
});
|
|
}
|
|
}
|
|
setState(() {
|
|
markers.add(
|
|
Marker(
|
|
markerId: MarkerId(business!.name!),
|
|
position: LatLng(
|
|
prettyAddress?.latitude ?? 0,
|
|
prettyAddress?.longitude ?? 0,
|
|
),
|
|
icon: bitMapDescriptor,
|
|
),
|
|
);
|
|
mapWidget = MapWidget(
|
|
markers: markers,
|
|
polygons: polygons,
|
|
);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
super.initState();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final AmbitoTheme theme = getTheme(context);
|
|
|
|
setState(() {});
|
|
areas = AreaRepository().getAreasForBusiness(widget.businessId);
|
|
|
|
return BasePage().getPage(
|
|
context,
|
|
SingleChildScrollView(
|
|
child: Align(
|
|
alignment: Alignment.topCenter,
|
|
child: Padding(
|
|
padding: context.breakpoint.padding,
|
|
child: SizedBox(
|
|
width: 1152,
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
theme.verticalSpacer,
|
|
Text(
|
|
'Flächen',
|
|
style: theme.titleMedium,
|
|
),
|
|
theme.verticalSpacer,
|
|
Row(
|
|
children: [
|
|
ToggleSwitch(
|
|
initialLabelIndex: display,
|
|
totalSwitches: 2,
|
|
minWidth: 200,
|
|
borderWidth: 1,
|
|
labels: const ['Karte', 'Liste'],
|
|
activeBgColor: [theme.currentColorScheme.secondary],
|
|
borderColor: [theme.currentColorScheme.secondary],
|
|
inactiveBgColor: Colors.white,
|
|
activeFgColor: theme.currentColorScheme.onSecondary,
|
|
customTextStyles: [theme.bodyMedium],
|
|
onToggle: (index) {
|
|
setState(() {
|
|
display = index ?? 0;
|
|
});
|
|
},
|
|
),
|
|
const Spacer(),
|
|
OutlinedButton(
|
|
style: OutlinedButton.styleFrom(
|
|
minimumSize: const Size(200, 50),
|
|
shape: RoundedRectangleBorder(
|
|
side: const BorderSide(
|
|
color: Colors.blue,
|
|
width: 1,
|
|
style: BorderStyle.solid),
|
|
borderRadius: BorderRadius.circular(
|
|
10,
|
|
),
|
|
),
|
|
backgroundColor: theme.currentColorScheme.secondary,
|
|
foregroundColor:
|
|
theme.currentColorScheme.onSecondary,
|
|
side: BorderSide(
|
|
width: 1,
|
|
color: theme.currentColorScheme.secondary),
|
|
),
|
|
onPressed: () async {
|
|
final TextEditingController _controllerName =
|
|
TextEditingController();
|
|
final TextEditingController _controllerSize =
|
|
TextEditingController();
|
|
final TextEditingController _controllerDescription =
|
|
TextEditingController();
|
|
await showDialog<String>(
|
|
context: context,
|
|
builder: (BuildContext context) =>
|
|
Dialog.fullscreen(
|
|
child: Scaffold(
|
|
appBar: AmbitoAppbar(
|
|
links: const ['dashboard', 'massnahmen'],
|
|
breakpoint:
|
|
Breakpoint.fromContext(context),
|
|
theme: theme),
|
|
body: BreakpointBuilder(
|
|
builder: (
|
|
context,
|
|
breakpoint,
|
|
configuration,
|
|
) {
|
|
return SingleChildScrollView(
|
|
child: Center(
|
|
child: SizedBox(
|
|
width:
|
|
Breakpoint.fromContext(context)
|
|
.width,
|
|
child: Padding(
|
|
padding:
|
|
const EdgeInsets.all(8.0),
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.center,
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment.start,
|
|
children: <Widget>[
|
|
theme.verticalSpacer,
|
|
Text(
|
|
'Fläche bearbeiten',
|
|
style: theme.headlineMedium
|
|
.copyWith(
|
|
color: theme
|
|
.currentColorScheme
|
|
.onSurface,
|
|
),
|
|
),
|
|
theme.verticalSpacer,
|
|
Align(
|
|
alignment:
|
|
Alignment.centerRight,
|
|
child: Row(
|
|
mainAxisAlignment:
|
|
MainAxisAlignment.end,
|
|
children: [
|
|
OutlinedButton(
|
|
style: OutlinedButton
|
|
.styleFrom(
|
|
minimumSize:
|
|
const Size(
|
|
200, 50),
|
|
shape:
|
|
RoundedRectangleBorder(
|
|
side: BorderSide(
|
|
color: redColors[
|
|
'primary']!,
|
|
width: 1,
|
|
style:
|
|
BorderStyle
|
|
.solid,
|
|
),
|
|
borderRadius:
|
|
BorderRadius
|
|
.circular(
|
|
10,
|
|
),
|
|
),
|
|
backgroundColor: theme
|
|
.currentColorScheme
|
|
.surface
|
|
.withOpacity(
|
|
.1),
|
|
foregroundColor: theme
|
|
.currentColorScheme
|
|
.primary,
|
|
side: BorderSide(
|
|
width: 1,
|
|
color: theme
|
|
.currentColorScheme
|
|
.primary,
|
|
),
|
|
),
|
|
onPressed: () {
|
|
Navigator.pop(
|
|
context);
|
|
},
|
|
child: Text(
|
|
'Abbrechen',
|
|
style: theme
|
|
.bodyMedium,
|
|
),
|
|
),
|
|
theme.horizontalSpacer,
|
|
OutlinedButton(
|
|
onHover: (hover) {},
|
|
style: OutlinedButton
|
|
.styleFrom(
|
|
minimumSize:
|
|
const Size(
|
|
200, 50),
|
|
shape:
|
|
RoundedRectangleBorder(
|
|
side: BorderSide(
|
|
color: redColors[
|
|
'primary']!,
|
|
width: 1,
|
|
style:
|
|
BorderStyle
|
|
.solid,
|
|
),
|
|
borderRadius:
|
|
BorderRadius
|
|
.circular(
|
|
10,
|
|
),
|
|
),
|
|
backgroundColor: theme
|
|
.currentColorScheme
|
|
.secondary,
|
|
foregroundColor: theme
|
|
.currentColorScheme
|
|
.onPrimary,
|
|
side: BorderSide(
|
|
width: 1,
|
|
color: theme
|
|
.currentColorScheme
|
|
.secondary,
|
|
),
|
|
),
|
|
onPressed: () async {
|
|
Area area = Area()
|
|
..id = isar.areas
|
|
.autoIncrement()
|
|
..description =
|
|
_controllerDescription
|
|
.value
|
|
.text
|
|
..business = [
|
|
IdValue()
|
|
..id = widget
|
|
.businessId
|
|
..value =
|
|
business!
|
|
.name!
|
|
]
|
|
..name =
|
|
_controllerName
|
|
.value
|
|
.text
|
|
..size =
|
|
_controllerSize
|
|
.value
|
|
.text;
|
|
await BaseApi()
|
|
.postContent(
|
|
'area',
|
|
area.toJson());
|
|
|
|
await BaseApi()
|
|
.getContent(
|
|
'business');
|
|
setState(() {
|
|
areas = AreaRepository()
|
|
.getAreasForBusiness(
|
|
widget
|
|
.businessId);
|
|
logger.d(
|
|
areas.length);
|
|
});
|
|
Navigator.pop(
|
|
context);
|
|
},
|
|
child: Text(
|
|
'Speichern',
|
|
style: theme
|
|
.bodyMedium,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
theme.verticalSpacer,
|
|
Card(
|
|
elevation: 0,
|
|
color: theme
|
|
.currentColorScheme
|
|
.tertiary,
|
|
child: Padding(
|
|
padding:
|
|
EdgeInsets.all(20),
|
|
child: Column(
|
|
crossAxisAlignment:
|
|
CrossAxisAlignment
|
|
.start,
|
|
children: [
|
|
Text(
|
|
'Allgemein',
|
|
style: theme
|
|
.headlineSmall,
|
|
),
|
|
theme.verticalSpacer,
|
|
Row(
|
|
children: [
|
|
Expanded(
|
|
child:
|
|
TextField(
|
|
controller:
|
|
_controllerName,
|
|
maxLines: 1,
|
|
decoration:
|
|
InputDecoration(
|
|
labelText:
|
|
'Bezeichnung',
|
|
isDense:
|
|
true,
|
|
hintText:
|
|
'Bezeichnung',
|
|
filled:
|
|
true,
|
|
fillColor:
|
|
Colors
|
|
.white,
|
|
hoverColor:
|
|
Colors
|
|
.white,
|
|
border:
|
|
OutlineInputBorder(
|
|
borderSide:
|
|
BorderSide(
|
|
color: redColors[
|
|
'primary']!,
|
|
width:
|
|
1,
|
|
style: BorderStyle
|
|
.solid,
|
|
),
|
|
borderRadius:
|
|
BorderRadius.circular(
|
|
8),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
theme
|
|
.horizontalSpacer,
|
|
Expanded(
|
|
child:
|
|
TextField(
|
|
controller:
|
|
_controllerSize,
|
|
maxLines: 1,
|
|
decoration:
|
|
InputDecoration(
|
|
suffixText:
|
|
'm²',
|
|
labelText:
|
|
'Größe',
|
|
isDense:
|
|
true,
|
|
hintText:
|
|
'Größe',
|
|
filled:
|
|
true,
|
|
fillColor:
|
|
Colors
|
|
.white,
|
|
hoverColor:
|
|
Colors
|
|
.white,
|
|
border:
|
|
OutlineInputBorder(
|
|
borderSide:
|
|
BorderSide(
|
|
color: redColors[
|
|
'primary']!,
|
|
width:
|
|
1,
|
|
style: BorderStyle
|
|
.solid,
|
|
),
|
|
borderRadius:
|
|
BorderRadius.circular(
|
|
8),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
theme.verticalSpacer,
|
|
TextField(
|
|
controller:
|
|
_controllerDescription,
|
|
maxLines: 5,
|
|
decoration:
|
|
InputDecoration(
|
|
labelText:
|
|
'Notizen',
|
|
isDense: true,
|
|
hintText:
|
|
'Notizen',
|
|
filled: true,
|
|
fillColor:
|
|
Colors.white,
|
|
hoverColor:
|
|
Colors.white,
|
|
border:
|
|
OutlineInputBorder(
|
|
borderSide:
|
|
BorderSide(
|
|
color: redColors[
|
|
'primary']!,
|
|
width: 1,
|
|
style:
|
|
BorderStyle
|
|
.solid,
|
|
),
|
|
borderRadius:
|
|
BorderRadius
|
|
.circular(
|
|
8),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
theme.verticalSpacer,
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
),
|
|
),
|
|
),
|
|
);
|
|
Get.offAndToNamed('/dashboard/flaechen/1');
|
|
},
|
|
child: Text(
|
|
'Neue Fläche',
|
|
style: theme.bodyMedium,
|
|
))
|
|
],
|
|
),
|
|
theme.verticalSpacer,
|
|
(display == 0) ? mapWidget : gridWidget(areas),
|
|
theme.verticalSpacer,
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Widget gridWidget(List<Area> areas) {
|
|
final AmbitoTheme theme = getTheme(context);
|
|
|
|
return SizedBox(
|
|
width: 1152,
|
|
child: SfDataGridTheme(
|
|
data: SfDataGridThemeData(
|
|
headerColor: theme.currentColorScheme.primaryContainer,
|
|
sortIcon: Icon(
|
|
Icons.keyboard_arrow_down,
|
|
color: theme.currentColorScheme.primary,
|
|
),
|
|
),
|
|
child: SfDataGrid(
|
|
allowSorting: true,
|
|
source: AreaDataSource(areas: areas, context: context),
|
|
columnWidthMode: ColumnWidthMode.fill,
|
|
columns: [
|
|
GridColumn(
|
|
visible: false,
|
|
columnName: 'id',
|
|
label: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
alignment: Alignment.centerRight,
|
|
child: Text(
|
|
'ID',
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.bodyMedium.copyWith(
|
|
color: theme.currentColorScheme.primary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
GridColumn(
|
|
columnName: 'name',
|
|
label: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'Bezeichnung',
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.bodyMedium.copyWith(
|
|
color: theme.currentColorScheme.primary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
GridColumn(
|
|
columnName: 'size',
|
|
maximumWidth: 200,
|
|
label: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'Größe',
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.bodyMedium.copyWith(
|
|
color: theme.currentColorScheme.primary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
GridColumn(
|
|
columnName: 'description',
|
|
maximumWidth: 100,
|
|
allowSorting: false,
|
|
label: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'Notiz',
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.bodyMedium.copyWith(
|
|
color: theme.currentColorScheme.primary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
GridColumn(
|
|
columnName: 'action',
|
|
allowSorting: false,
|
|
maximumWidth: 150,
|
|
label: Container(
|
|
padding: const EdgeInsets.symmetric(horizontal: 10.0),
|
|
alignment: Alignment.centerLeft,
|
|
child: Text(
|
|
'Aktion',
|
|
overflow: TextOverflow.ellipsis,
|
|
style: theme.bodyMedium.copyWith(
|
|
color: theme.currentColorScheme.primary,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|