Detail Page -> responsive, collapsible, dynamic TOC, only display filled properties
This commit is contained in:
parent
886d9dcc0e
commit
c0608d9cff
27 changed files with 1066 additions and 368 deletions
41
i18n/de.json
41
i18n/de.json
|
@ -24,6 +24,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"actionDetailPage": {
|
"actionDetailPage": {
|
||||||
|
"tabs": {
|
||||||
|
"info": "Informationen",
|
||||||
|
"misc": "Beratung & Materialien"
|
||||||
|
},
|
||||||
|
"expanded": {
|
||||||
|
"collapse_all": "Alle einklappen",
|
||||||
|
"expand_all": "Alle ausklappen"
|
||||||
|
},
|
||||||
"description": {
|
"description": {
|
||||||
"title": "Beschreibung"
|
"title": "Beschreibung"
|
||||||
},
|
},
|
||||||
|
@ -41,10 +49,22 @@
|
||||||
},
|
},
|
||||||
"creation":{
|
"creation":{
|
||||||
"title": "Anlage",
|
"title": "Anlage",
|
||||||
"timeFrame": "Zeitrahmen"
|
"timeFrame": "Zeitrahmen",
|
||||||
|
"additional": "Zusatzinformationen",
|
||||||
|
"reminders": "Beachtenswert",
|
||||||
|
"tools": "Arbeitsmittel",
|
||||||
|
"steps": "Arbeitsschritte",
|
||||||
|
"tips": "Tipps"
|
||||||
},
|
},
|
||||||
"maintenance": {
|
"maintenance": {
|
||||||
"title": "Pflege"
|
"title": "Pflege",
|
||||||
|
"time": "Zeitrahmen",
|
||||||
|
"additional_time": "Zusatzinformationen",
|
||||||
|
"frequency": "Frequenz",
|
||||||
|
"additional_frequency": "Zusatzinformationen",
|
||||||
|
"tools": "Arbeitsmittel",
|
||||||
|
"steps": "Arbeitsschritte",
|
||||||
|
"tips": "Tipps"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"title": "Förderungen"
|
"title": "Förderungen"
|
||||||
|
@ -59,6 +79,23 @@
|
||||||
"review": {
|
"review": {
|
||||||
"title": "Rezensionen"
|
"title": "Rezensionen"
|
||||||
},
|
},
|
||||||
|
"size": {
|
||||||
|
"title": "Größe / Fläche"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"title": "Standort"
|
||||||
|
},
|
||||||
|
"sources": {
|
||||||
|
"title": "Quellen"
|
||||||
|
},
|
||||||
|
"toc": {
|
||||||
|
"title": "Inhalt"
|
||||||
|
},
|
||||||
|
"implementation": {
|
||||||
|
"title": "Fachgerechte Umsetzung",
|
||||||
|
"costs": "Kosten",
|
||||||
|
"time": "Zeit"
|
||||||
|
},
|
||||||
"material": {
|
"material": {
|
||||||
"title": "Material",
|
"title": "Material",
|
||||||
"suggested_price": "Preis ca. ",
|
"suggested_price": "Preis ca. ",
|
||||||
|
|
|
@ -41,7 +41,7 @@ const BreakpointConfiguration myBreakpoints = BreakpointConfiguration(
|
||||||
breakpoint: 320,
|
breakpoint: 320,
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
margin: 32,
|
margin: 32,
|
||||||
padding: 0,
|
padding: 10,
|
||||||
columns: 8,
|
columns: 8,
|
||||||
),
|
),
|
||||||
md: Breakpoint(
|
md: Breakpoint(
|
||||||
|
@ -179,6 +179,14 @@ class Ambito extends StatelessWidget {
|
||||||
name: '/massnahmendatenbank',
|
name: '/massnahmendatenbank',
|
||||||
page: () => const ActionsPage(),
|
page: () => const ActionsPage(),
|
||||||
),
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/massnahmendatenbank/:kategorie',
|
||||||
|
page: () => const ActionsPage(),
|
||||||
|
),
|
||||||
|
GetPage(
|
||||||
|
name: '/massnahmendatenbank/:kategorie/:typ',
|
||||||
|
page: () => const ActionsPage(),
|
||||||
|
),
|
||||||
GetPage(
|
GetPage(
|
||||||
name: '/dashboard',
|
name: '/dashboard',
|
||||||
page: () => DashboardPage(
|
page: () => DashboardPage(
|
||||||
|
|
|
@ -72,7 +72,7 @@ abstract class AmbitoTheme {
|
||||||
onPrimary: Color(0xFFFFFFFF),
|
onPrimary: Color(0xFFFFFFFF),
|
||||||
primaryContainer: Color(0xFFDCE3C9),
|
primaryContainer: Color(0xFFDCE3C9),
|
||||||
onPrimaryContainer: Color(0xFF001E2D),
|
onPrimaryContainer: Color(0xFF001E2D),
|
||||||
secondary: Color(0xFFF5F5F5),
|
secondary: Color(0xff87A34E),
|
||||||
onSecondary: Color(0xFFFFFFFF),
|
onSecondary: Color(0xFFFFFFFF),
|
||||||
secondaryContainer: Color(0xFFD2E5F4),
|
secondaryContainer: Color(0xFFD2E5F4),
|
||||||
onSecondaryContainer: Color(0xFF0A1D28),
|
onSecondaryContainer: Color(0xFF0A1D28),
|
||||||
|
|
|
@ -58,7 +58,7 @@ class AmbitoThemeLarge extends AmbitoTheme {
|
||||||
letterSpacing: 0.1,
|
letterSpacing: 0.1,
|
||||||
),
|
),
|
||||||
labelLarge: GoogleFonts.openSans(
|
labelLarge: GoogleFonts.openSans(
|
||||||
fontSize: 32,
|
fontSize: 28,
|
||||||
height: 1.42,
|
height: 1.42,
|
||||||
fontWeight: FontWeight.w500,
|
fontWeight: FontWeight.w500,
|
||||||
letterSpacing: 0.1,
|
letterSpacing: 0.1,
|
||||||
|
|
|
@ -13,7 +13,6 @@ import 'package:get/get.dart';
|
||||||
import 'package:highlight_text/highlight_text.dart';
|
import 'package:highlight_text/highlight_text.dart';
|
||||||
import 'package:screen_breakpoints/screen_breakpoints.dart';
|
import 'package:screen_breakpoints/screen_breakpoints.dart';
|
||||||
|
|
||||||
import '../../../main.dart';
|
|
||||||
import '../../entity/entities.dart';
|
import '../../entity/entities.dart';
|
||||||
import '../../packages/ambito_theme/ambito_theme.dart';
|
import '../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
|
||||||
|
@ -41,8 +40,8 @@ class ActionsPageState extends State<ActionsPage> {
|
||||||
List<String>? selectedMonths;
|
List<String>? selectedMonths;
|
||||||
List massnahmen = [];
|
List massnahmen = [];
|
||||||
Map<String, HighlightedWord> words = {};
|
Map<String, HighlightedWord> words = {};
|
||||||
String? preselectAreaType;
|
String preselectAreaType = '';
|
||||||
String? preselectMeasureType;
|
String preselectMeasureType = '';
|
||||||
|
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
final FocusNode _searchFocusNode = FocusNode();
|
final FocusNode _searchFocusNode = FocusNode();
|
||||||
|
@ -51,13 +50,22 @@ class ActionsPageState extends State<ActionsPage> {
|
||||||
void initState() {
|
void initState() {
|
||||||
ambitoFilterNotifier.addListener(_changeListener);
|
ambitoFilterNotifier.addListener(_changeListener);
|
||||||
|
|
||||||
setState(() {
|
preselectAreaType = Get.parameters['kategorie'] ?? '';
|
||||||
preselectAreaType = prefs.getString('selected_areaType');
|
if (preselectAreaType != '') {
|
||||||
if (preselectAreaType != null && preselectAreaType!.isNotEmpty) {
|
setState(() {
|
||||||
filterAreaType = preselectAreaType;
|
filterAreaType = preselectAreaType;
|
||||||
ambitoFilterNotifier.setFilter('areaType', preselectAreaType!);
|
ambitoFilterNotifier.setFilter('areaType', preselectAreaType);
|
||||||
}
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
|
preselectMeasureType = Get.parameters['typ'] ?? '';
|
||||||
|
if (preselectMeasureType != '') {
|
||||||
|
setState(() {
|
||||||
|
filterType = preselectMeasureType;
|
||||||
|
ambitoFilterNotifier.setFilter('actionType', preselectMeasureType);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_initializeData();
|
_initializeData();
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ class ActionsPrePageState extends State<ActionsPrePage> {
|
||||||
InkWell(
|
InkWell(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
prefs.setString('selected_areaType', filter.name!).then((value) {
|
prefs.setString('selected_areaType', filter.name!).then((value) {
|
||||||
Get.toNamed('/massnahmendatenbank');
|
Get.toNamed('/massnahmendatenbank/${filter.name}');
|
||||||
setState(() {});
|
setState(() {});
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
|
import 'package:ambito/main.dart';
|
||||||
import 'package:ambito/src/entity/entities.dart';
|
import 'package:ambito/src/entity/entities.dart';
|
||||||
import 'package:ambito/src/entity/measure/measure_repository.dart';
|
import 'package:ambito/src/entity/measure/measure_repository.dart';
|
||||||
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
|
import 'package:animated_segmented_tab_control/animated_segmented_tab_control.dart';
|
||||||
|
import 'package:expansion_tile_card/expansion_tile_card.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_breadcrumb/flutter_breadcrumb.dart';
|
import 'package:flutter_breadcrumb/flutter_breadcrumb.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
@ -10,6 +14,8 @@ import '../../../widgets/appbar/ambito_appbar.dart';
|
||||||
import '../../ambito_page.dart';
|
import '../../ambito_page.dart';
|
||||||
import 'cards/_cards.dart';
|
import 'cards/_cards.dart';
|
||||||
|
|
||||||
|
final Map<String, GlobalKey<ExpansionTileCardState>> globalKeys = {};
|
||||||
|
|
||||||
class ActionDetailPage extends AmbitoPage {
|
class ActionDetailPage extends AmbitoPage {
|
||||||
const ActionDetailPage({super.key});
|
const ActionDetailPage({super.key});
|
||||||
|
|
||||||
|
@ -23,34 +29,128 @@ class ActionDetailPage extends AmbitoPage {
|
||||||
}
|
}
|
||||||
|
|
||||||
class ActionDetailPageState extends State<ActionDetailPage> {
|
class ActionDetailPageState extends State<ActionDetailPage> {
|
||||||
late String id;
|
late final String id;
|
||||||
|
final ScrollController scrollController = ScrollController();
|
||||||
Widget content = const SizedBox();
|
bool showBackToTopButton = false;
|
||||||
|
final Map<String, GlobalKey<ExpansionTileCardState>> expansionKeys = {};
|
||||||
Measure? massnahme;
|
Measure? massnahme;
|
||||||
|
|
||||||
List<Widget> contentItems = [];
|
List<Widget> contentItems = [];
|
||||||
List<Widget> sidebarItems = [];
|
final Set<String> visibleItems = {};
|
||||||
|
bool collapsed = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
|
||||||
id = Get.parameters['id'] ?? '';
|
id = Get.parameters['id'] ?? '';
|
||||||
if (id != '') {
|
if (id.isNotEmpty) {
|
||||||
setState(() {
|
massnahme = MeasureRepository().get(int.parse(id)) as Measure;
|
||||||
massnahme = MeasureRepository().get(int.parse(id)) as Measure;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
super.initState();
|
scrollController.addListener(() {
|
||||||
|
const showOffset = 10.0;
|
||||||
|
setState(
|
||||||
|
() => showBackToTopButton = scrollController.offset > showOffset);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AmbitoAppbar(
|
appBar: AmbitoAppbar(
|
||||||
links: const ['dashboard', 'massnahmen'],
|
links: const ['dashboard', 'massnahmen'],
|
||||||
breakpoint: Breakpoint.fromContext(context),
|
breakpoint: Breakpoint.fromContext(context),
|
||||||
),
|
),
|
||||||
body: _buildInfoPage(context, massnahme),
|
body: (context.breakpoint != myBreakpoints.sm)
|
||||||
|
? _buildInfoPage(context, massnahme)
|
||||||
|
: _tabbedInfoPage(context, massnahme),
|
||||||
|
floatingActionButton: (context.breakpoint != myBreakpoints.sm)
|
||||||
|
? AnimatedOpacity(
|
||||||
|
duration: const Duration(milliseconds: 1000),
|
||||||
|
opacity: showBackToTopButton ? 1.0 : 0.0,
|
||||||
|
child: FloatingActionButton(
|
||||||
|
shape: const CircleBorder(),
|
||||||
|
elevation: 0,
|
||||||
|
onPressed: () => scrollController.animateTo(
|
||||||
|
0,
|
||||||
|
duration: const Duration(milliseconds: 500),
|
||||||
|
curve: Curves.fastOutSlowIn,
|
||||||
|
),
|
||||||
|
backgroundColor: theme.currentColorScheme.primary,
|
||||||
|
child: Icon(Icons.arrow_upward,
|
||||||
|
color: theme.currentColorScheme.onPrimary),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _tabbedInfoPage(BuildContext context, Measure? massnahme) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
if (massnahme == null) {
|
||||||
|
return const Center(child: CircularProgressIndicator());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Padding(
|
||||||
|
padding: context.breakpoint.padding,
|
||||||
|
child: DefaultTabController(
|
||||||
|
length: 2,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: Text(
|
||||||
|
massnahme.name!,
|
||||||
|
style: theme.currentThemeData.textTheme.headlineMedium,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
theme.verticalSpacerSmall,
|
||||||
|
SegmentedTabControl(
|
||||||
|
tabTextColor: theme.currentColorScheme.secondary,
|
||||||
|
selectedTabTextColor: theme.currentColorScheme.onSecondary,
|
||||||
|
barDecoration: BoxDecoration(
|
||||||
|
color: theme.currentColorScheme.onSecondary,
|
||||||
|
border: Border.all(
|
||||||
|
width: 1.0,
|
||||||
|
color: theme.currentColorScheme.secondary,
|
||||||
|
),
|
||||||
|
borderRadius: const BorderRadius.all(
|
||||||
|
Radius.circular(
|
||||||
|
8.0,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
indicatorDecoration:
|
||||||
|
BoxDecoration(color: theme.currentColorScheme.secondary),
|
||||||
|
tabs: [
|
||||||
|
SegmentTab(
|
||||||
|
label:
|
||||||
|
context.translate('page.actionDetailPage.tabs.info')),
|
||||||
|
SegmentTab(
|
||||||
|
label:
|
||||||
|
context.translate('page.actionDetailPage.tabs.misc')),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
theme.verticalSpacerSmall,
|
||||||
|
Expanded(
|
||||||
|
child: TabBarView(
|
||||||
|
children: [
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Column(children: _buildContentItems(massnahme)),
|
||||||
|
),
|
||||||
|
SingleChildScrollView(
|
||||||
|
child: Column(
|
||||||
|
children: _buildSidebarItems(context, theme, massnahme),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,54 +158,21 @@ class ActionDetailPageState extends State<ActionDetailPage> {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
if (massnahme == null) {
|
if (massnahme == null) {
|
||||||
return const Center(
|
return const Center(child: CircularProgressIndicator());
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contentItems = _buildContentItems(massnahme);
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
Align(
|
_buildBreadcrumb(context, theme, massnahme),
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: BreadCrumb(
|
|
||||||
items: <BreadCrumbItem>[
|
|
||||||
BreadCrumbItem(
|
|
||||||
content: TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.offAndToNamed('/');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Start',
|
|
||||||
style: theme.bodyMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
BreadCrumbItem(
|
|
||||||
content: TextButton(
|
|
||||||
onPressed: () {
|
|
||||||
Get.offAndToNamed('/massnahmendatenbank');
|
|
||||||
},
|
|
||||||
child: Text(
|
|
||||||
'Massnahmen',
|
|
||||||
style: theme.bodyMedium,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
BreadCrumbItem(
|
|
||||||
content: Text(
|
|
||||||
massnahme.name ?? '',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
divider: const Icon(Icons.chevron_right),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 300,
|
height: 300,
|
||||||
child: massnahme.getFullImage(),
|
child: massnahme.getFullImage()),
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
|
controller: scrollController,
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 1152,
|
width: 1152,
|
||||||
child: Column(
|
child: Column(
|
||||||
|
@ -123,59 +190,14 @@ class ActionDetailPageState extends State<ActionDetailPage> {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Column(children: [
|
child: Column(children: contentItems),
|
||||||
DescriptionCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
BackgroundCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
PresetsCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
BiodiverisityCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
CreationCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
MaintenanceCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
FundingCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
]),
|
|
||||||
),
|
),
|
||||||
theme.horizontalSpacer,
|
theme.horizontalSpacer,
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 300,
|
width: 300,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
children:
|
||||||
children: [
|
_buildSidebarItems(context, theme, massnahme),
|
||||||
AdvisorCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
MaterialCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
FactsheetCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
ReviewCard(
|
|
||||||
massnahme: massnahme,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -188,4 +210,155 @@ class ActionDetailPageState extends State<ActionDetailPage> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _buildBreadcrumb(
|
||||||
|
BuildContext context, AmbitoTheme theme, Measure massnahme) {
|
||||||
|
return Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: BreadCrumb(
|
||||||
|
items: [
|
||||||
|
BreadCrumbItem(
|
||||||
|
content: TextButton(
|
||||||
|
onPressed: () => Get.offAndToNamed('/'),
|
||||||
|
child: Text('Massnahmenkategorien', style: theme.bodyMedium),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BreadCrumbItem(
|
||||||
|
content: TextButton(
|
||||||
|
onPressed: () => Get.offAndToNamed('/massnahmendatenbank'),
|
||||||
|
child: Text('Maßnamentypen', style: theme.bodyMedium),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BreadCrumbItem(
|
||||||
|
content: TextButton(
|
||||||
|
onPressed: () => Get.offAndToNamed('/massnahmendatenbank'),
|
||||||
|
child:
|
||||||
|
Text(massnahme.actionGroup!.value!, style: theme.bodyMedium),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
BreadCrumbItem(content: Text(massnahme.name ?? '')),
|
||||||
|
],
|
||||||
|
divider: const Icon(Icons.chevron_right),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _buildContentItems(Measure massnahme) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
List<Widget> elements = [];
|
||||||
|
|
||||||
|
void addCard(
|
||||||
|
{required Widget card,
|
||||||
|
required String titleKey,
|
||||||
|
required bool condition}) {
|
||||||
|
if (condition) {
|
||||||
|
visibleItems.add(context.translate(titleKey));
|
||||||
|
elements.addAll([card, theme.verticalSpacer]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: DescriptionCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.description.title',
|
||||||
|
condition: massnahme.factsheetDefinition?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: BackgroundCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.background.target',
|
||||||
|
condition: massnahme.factsheetTarget?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: PresetsCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.presets.title',
|
||||||
|
condition: massnahme.remarkablePresets?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: SizeCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.size.title',
|
||||||
|
condition: massnahme.factsheetSizeArea?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: LocationCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.location.title',
|
||||||
|
condition: massnahme.factsheetLocation?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: ImplementationCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.implementation.title',
|
||||||
|
condition: (massnahme.moneyAction?.isNotEmpty ?? false) &&
|
||||||
|
(massnahme.timeAction?.isNotEmpty ?? false),
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: CreationCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.creation.title',
|
||||||
|
condition: massnahme.timeFrame?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: MaintenanceCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.maintenance.title',
|
||||||
|
condition: massnahme.timeMaintenance?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
addCard(
|
||||||
|
card: SourcesCard(massnahme: massnahme),
|
||||||
|
titleKey: 'page.actionDetailPage.sources.title',
|
||||||
|
condition: massnahme.sources?.isNotEmpty ?? false,
|
||||||
|
);
|
||||||
|
|
||||||
|
return [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: TextButton(
|
||||||
|
onPressed: () {
|
||||||
|
globalKeys.forEach((key, value) {
|
||||||
|
if (collapsed == false) {
|
||||||
|
value.currentState?.collapse();
|
||||||
|
} else {
|
||||||
|
value.currentState?.expand();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setState(() {
|
||||||
|
collapsed = !collapsed;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Text(
|
||||||
|
context.translate((collapsed == false)
|
||||||
|
? 'page.actionDetailPage.expanded.collapse_all'
|
||||||
|
: 'page.actionDetailPage.expanded.expand_all'),
|
||||||
|
style: theme.bodyLarge.copyWith(
|
||||||
|
color: theme.currentColorScheme.onSurface,
|
||||||
|
decoration: TextDecoration.underline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
theme.verticalSpacer,
|
||||||
|
...elements,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Widget> _buildSidebarItems(
|
||||||
|
BuildContext context, AmbitoTheme theme, Measure massnahme) {
|
||||||
|
return [
|
||||||
|
if (visibleItems.isNotEmpty && context.breakpoint != myBreakpoints.sm)
|
||||||
|
TocCard(massnahme: massnahme, items: visibleItems.toList()),
|
||||||
|
if (visibleItems.isNotEmpty && context.breakpoint != myBreakpoints.sm)
|
||||||
|
theme.verticalSpacer,
|
||||||
|
AdvisorCard(massnahme: massnahme),
|
||||||
|
theme.verticalSpacer,
|
||||||
|
MaterialCard(massnahme: massnahme),
|
||||||
|
theme.verticalSpacer,
|
||||||
|
FactsheetCard(massnahme: massnahme),
|
||||||
|
theme.verticalSpacer,
|
||||||
|
ReviewCard(massnahme: massnahme),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,12 @@ export 'creation_card.dart';
|
||||||
export 'description_card.dart';
|
export 'description_card.dart';
|
||||||
export 'factsheet_card.dart';
|
export 'factsheet_card.dart';
|
||||||
export 'funding_card.dart';
|
export 'funding_card.dart';
|
||||||
|
export 'implementation_card.dart';
|
||||||
|
export 'location_card.dart';
|
||||||
export 'maintenance_card.dart';
|
export 'maintenance_card.dart';
|
||||||
export 'material_card.dart';
|
export 'material_card.dart';
|
||||||
export 'presets_card.dart';
|
export 'presets_card.dart';
|
||||||
export 'review_card.dart';
|
export 'review_card.dart';
|
||||||
|
export 'size_card.dart';
|
||||||
|
export 'sources_card.dart';
|
||||||
|
export 'toc_card.dart';
|
||||||
|
|
50
lib/src/pages/actions/detail/cards/_main_card.dart
Normal file
50
lib/src/pages/actions/detail/cards/_main_card.dart
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
|
import 'package:ambito/src/pages/actions/detail/action_detail_page.dart';
|
||||||
|
import 'package:expansion_tile_card/expansion_tile_card.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
|
||||||
|
class MainCard extends StatelessWidget {
|
||||||
|
const MainCard(
|
||||||
|
{super.key,
|
||||||
|
required this.massnahme,
|
||||||
|
required this.title,
|
||||||
|
required this.content});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
final String title;
|
||||||
|
final Widget content;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
globalKeys.putIfAbsent(title, () => GlobalKey<ExpansionTileCardState>());
|
||||||
|
|
||||||
|
return ExpansionTileCard(
|
||||||
|
key: globalKeys[title],
|
||||||
|
initiallyExpanded: true,
|
||||||
|
contentPadding: const EdgeInsets.only(left: 16),
|
||||||
|
elevation: 0,
|
||||||
|
expandedTextColor: theme.currentColorScheme.outline,
|
||||||
|
baseColor: theme.currentColorScheme.outline.withOpacity(.1),
|
||||||
|
expandedColor: theme.currentColorScheme.outline.withOpacity(.1),
|
||||||
|
title: Text(
|
||||||
|
context.translate(title),
|
||||||
|
style: theme.currentThemeData.textTheme.labelMedium
|
||||||
|
?.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.topLeft,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 20, right: 20, bottom: 20),
|
||||||
|
child: content,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
48
lib/src/pages/actions/detail/cards/_sidebar_card.dart
Normal file
48
lib/src/pages/actions/detail/cards/_sidebar_card.dart
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
|
||||||
|
class SideBarCard extends StatelessWidget {
|
||||||
|
const SideBarCard(
|
||||||
|
{super.key,
|
||||||
|
required this.massnahme,
|
||||||
|
required this.title,
|
||||||
|
required this.content});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
final String title;
|
||||||
|
final List<Widget> content;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
child: Card(
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
),
|
||||||
|
elevation: 0,
|
||||||
|
color: greenColors['primary']!.withOpacity(.1),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
context.translate(title),
|
||||||
|
style: theme.currentThemeData.textTheme.labelMedium
|
||||||
|
?.copyWith(color: theme.currentColorScheme.primary),
|
||||||
|
),
|
||||||
|
theme.verticalSpacerSmall,
|
||||||
|
...content
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
import 'package:ambito/src/pages/actions/detail/cards/_sidebar_card.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_linkify/flutter_linkify.dart';
|
import 'package:flutter_linkify/flutter_linkify.dart';
|
||||||
import 'package:linkify/linkify.dart';
|
import 'package:linkify/linkify.dart';
|
||||||
|
@ -15,48 +15,30 @@ class AdvisorCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
return SideBarCard(
|
||||||
width: double.infinity,
|
massnahme: massnahme,
|
||||||
child: Card(
|
title: 'page.actionDetailPage.advisor.title',
|
||||||
shape: RoundedRectangleBorder(
|
content: [
|
||||||
borderRadius: BorderRadius.circular(8),
|
Text(
|
||||||
|
'Max Mustermann',
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge
|
||||||
|
?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
elevation: 0,
|
Linkify(
|
||||||
color: greenColors['primary']!.withOpacity(.1),
|
text: 'EMail: max@mustermann.de',
|
||||||
child: Padding(
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
padding: const EdgeInsets.all(16),
|
linkifiers: const [
|
||||||
child: Column(
|
EmailLinkifier(),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
],
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
context.translate('page.actionDetailPage.advisor.title'),
|
|
||||||
style: theme.currentThemeData.textTheme.labelMedium
|
|
||||||
?.copyWith(color: theme.currentColorScheme.primary),
|
|
||||||
),
|
|
||||||
theme.verticalSpacerSmall,
|
|
||||||
Text(
|
|
||||||
'Max Mustermann',
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium
|
|
||||||
?.copyWith(fontWeight: FontWeight.bold),
|
|
||||||
),
|
|
||||||
Linkify(
|
|
||||||
text: 'EMail: max@mustermann.de',
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
linkifiers: const [
|
|
||||||
EmailLinkifier(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
Linkify(
|
|
||||||
text: 'Tel: +4917666554433',
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
linkifiers: const [
|
|
||||||
PhoneNumberLinkifier(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
Linkify(
|
||||||
|
text: 'Tel: +4917666554433',
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
linkifiers: const [
|
||||||
|
PhoneNumberLinkifier(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
|
||||||
import 'package:expansion_tile_card/expansion_tile_card.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
class BackgroundCard extends StatelessWidget {
|
class BackgroundCard extends StatelessWidget {
|
||||||
const BackgroundCard({super.key, required this.massnahme});
|
const BackgroundCard({super.key, required this.massnahme});
|
||||||
|
@ -14,50 +13,15 @@ class BackgroundCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
return MainCard(
|
||||||
width: double.infinity,
|
massnahme: massnahme,
|
||||||
child: ExpansionTileCard(
|
title: 'page.actionDetailPage.background.target',
|
||||||
initiallyExpanded: true,
|
content: Column(
|
||||||
elevation: 0,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
expandedTextColor: theme.currentColorScheme.outline,
|
|
||||||
baseColor: theme.currentColorScheme.secondary,
|
|
||||||
expandedColor: theme.currentColorScheme.secondary,
|
|
||||||
title: Text(
|
|
||||||
context.translate('page.actionDetailPage.background.title'),
|
|
||||||
style: theme.currentThemeData.textTheme.labelMedium,
|
|
||||||
),
|
|
||||||
children: [
|
children: [
|
||||||
Align(
|
Text(
|
||||||
alignment: Alignment.topLeft,
|
massnahme.factsheetTarget.toString(),
|
||||||
child: Padding(
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
context
|
|
||||||
.translate('page.actionDetailPage.background.areaType'),
|
|
||||||
style: theme.currentThemeData.textTheme.labelSmall,
|
|
||||||
),
|
|
||||||
theme.verticalSpacerSmall,
|
|
||||||
Text(
|
|
||||||
massnahme.factsheetLocation.toString(),
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
Text(
|
|
||||||
context
|
|
||||||
.translate('page.actionDetailPage.background.target'),
|
|
||||||
style: theme.currentThemeData.textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
theme.verticalSpacerSmall,
|
|
||||||
Text(
|
|
||||||
massnahme.factsheetTarget.toString(),
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
class CreationCard extends StatelessWidget {
|
class CreationCard extends StatelessWidget {
|
||||||
const CreationCard({super.key, required this.massnahme});
|
const CreationCard({super.key, required this.massnahme});
|
||||||
|
@ -13,40 +14,117 @@ class CreationCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
Chip buildChip(String label) {
|
||||||
width: double.infinity,
|
return Chip(
|
||||||
child: Card(
|
labelPadding: EdgeInsets.zero,
|
||||||
shape: RoundedRectangleBorder(
|
backgroundColor: theme.currentColorScheme.secondary,
|
||||||
borderRadius: BorderRadius.circular(0),
|
label: Text(
|
||||||
|
label,
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge
|
||||||
|
?.copyWith(color: theme.currentColorScheme.onSecondary),
|
||||||
),
|
),
|
||||||
elevation: 0,
|
);
|
||||||
color: theme.currentColorScheme.secondary,
|
}
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
List<Chip> buildChips(List<String?>? items) =>
|
||||||
child: Column(
|
items
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
?.where((item) => item?.isNotEmpty ?? false)
|
||||||
|
.map((item) => buildChip(item!))
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
List<Widget> buildTools(List<String?>? tools) =>
|
||||||
|
tools?.where((item) => item?.isNotEmpty ?? false).map((item) {
|
||||||
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
const Icon(Icons.fiber_manual_record, size: 8),
|
||||||
context.translate('page.actionDetailPage.creation.title'),
|
theme.horizontalSpacerSmall,
|
||||||
style: theme.currentThemeData.textTheme.titleMedium,
|
Expanded(
|
||||||
),
|
child: Text(
|
||||||
theme.verticalSpacer,
|
item!,
|
||||||
Text(
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
context.translate('page.actionDetailPage.creation.timeFrame'),
|
),
|
||||||
style: theme.currentThemeData.textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
Text(
|
|
||||||
massnahme.timeFrame
|
|
||||||
?.map((item) => item.value)
|
|
||||||
.toList()
|
|
||||||
.join(', ') ??
|
|
||||||
'',
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
}).toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
Widget buildSection({
|
||||||
|
required String titleKey,
|
||||||
|
required List<Widget> children,
|
||||||
|
}) {
|
||||||
|
if (children.isEmpty) return const SizedBox.shrink();
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Divider(),
|
||||||
|
Text(
|
||||||
|
context.translate(titleKey),
|
||||||
|
style: theme.currentThemeData.textTheme.labelMedium,
|
||||||
),
|
),
|
||||||
),
|
...children,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTextSection(String? text, String titleKey) {
|
||||||
|
if (text == null || text.isEmpty) return const SizedBox.shrink();
|
||||||
|
return buildSection(
|
||||||
|
titleKey: titleKey,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final tfChips =
|
||||||
|
buildChips(massnahme.timeFrame?.map((e) => e.value).toList());
|
||||||
|
final creationTools =
|
||||||
|
buildTools(massnahme.attachmentMaterial?.map((e) => e.value).toList());
|
||||||
|
|
||||||
|
return MainCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.creation.title',
|
||||||
|
content: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (tfChips.isNotEmpty)
|
||||||
|
buildSection(
|
||||||
|
titleKey: 'page.actionDetailPage.creation.timeFrame',
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 8,
|
||||||
|
spacing: 8,
|
||||||
|
children: tfChips,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.timeframeActionAdditional,
|
||||||
|
'page.actionDetailPage.creation.additional',
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.attachmentReminder,
|
||||||
|
'page.actionDetailPage.creation.reminders',
|
||||||
|
),
|
||||||
|
if (creationTools.isNotEmpty)
|
||||||
|
buildSection(
|
||||||
|
titleKey: 'page.actionDetailPage.creation.tools',
|
||||||
|
children: creationTools,
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.attachmentWorkSteps,
|
||||||
|
'page.actionDetailPage.creation.steps',
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.attachmentTip,
|
||||||
|
'page.actionDetailPage.creation.tips',
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
import 'package:ambito/src/pages/actions/detail/cards/_main_card.dart';
|
||||||
import 'package:expansion_tile_card/expansion_tile_card.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
|
@ -14,31 +13,13 @@ class DescriptionCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
return MainCard(
|
||||||
width: double.infinity,
|
massnahme: massnahme,
|
||||||
child: ExpansionTileCard(
|
title: 'page.actionDetailPage.description.title',
|
||||||
initiallyExpanded: true,
|
content: Text(
|
||||||
elevation: 0,
|
massnahme.factsheetDefinition ?? '',
|
||||||
expandedTextColor: theme.currentColorScheme.outline,
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
baseColor: theme.currentColorScheme.secondary,
|
textAlign: TextAlign.left,
|
||||||
expandedColor: theme.currentColorScheme.secondary,
|
|
||||||
title: Text(
|
|
||||||
context.translate('page.actionDetailPage.description.title'),
|
|
||||||
style: theme.currentThemeData.textTheme.labelMedium,
|
|
||||||
),
|
|
||||||
children: [
|
|
||||||
Align(
|
|
||||||
alignment: Alignment.topLeft,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.only(left: 16, right: 16, bottom: 16),
|
|
||||||
child: Text(
|
|
||||||
massnahme.factsheetDefinition ?? '',
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
textAlign: TextAlign.left,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
import 'package:ambito/src/widgets/buttons/text_button.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_sidebar_card.dart';
|
||||||
|
|
||||||
class FactsheetCard extends StatelessWidget {
|
class FactsheetCard extends StatelessWidget {
|
||||||
const FactsheetCard({super.key, required this.massnahme});
|
const FactsheetCard({super.key, required this.massnahme});
|
||||||
|
@ -13,28 +14,23 @@ class FactsheetCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
return SideBarCard(
|
||||||
width: double.infinity,
|
massnahme: massnahme,
|
||||||
child: Card(
|
title: 'page.actionDetailPage.factsheet.title',
|
||||||
shape: RoundedRectangleBorder(
|
content: [
|
||||||
borderRadius: BorderRadius.circular(0),
|
Text(
|
||||||
|
'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam',
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge
|
||||||
|
?.copyWith(fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
elevation: 0,
|
theme.verticalSpacer,
|
||||||
color: theme.currentColorScheme.tertiary,
|
Align(
|
||||||
child: Padding(
|
alignment: Alignment.center,
|
||||||
padding: const EdgeInsets.all(16),
|
child: TextButtonElement(
|
||||||
child: Column(
|
title: 'page.actionDetailPage.factsheet.download',
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
onPressed: () {}),
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
context.translate('page.actionDetailPage.factsheet.title'),
|
|
||||||
style: theme.currentThemeData.textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
52
lib/src/pages/actions/detail/cards/implementation_card.dart
Normal file
52
lib/src/pages/actions/detail/cards/implementation_card.dart
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
|
class ImplementationCard extends StatelessWidget {
|
||||||
|
const ImplementationCard({super.key, required this.massnahme});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return MainCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.implementation.title',
|
||||||
|
content: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (massnahme.moneyAction != null && massnahme.moneyAction != '')
|
||||||
|
Text(
|
||||||
|
context.translate('page.actionDetailPage.implementation.costs'),
|
||||||
|
style: theme.currentThemeData.textTheme.labelMedium,
|
||||||
|
),
|
||||||
|
if (massnahme.moneyAction != null && massnahme.moneyAction != '')
|
||||||
|
Text(
|
||||||
|
massnahme.moneyAction.toString(),
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
if (massnahme.moneyAction != null &&
|
||||||
|
massnahme.moneyAction != '' &&
|
||||||
|
massnahme.timeAction != null &&
|
||||||
|
massnahme.timeAction != '')
|
||||||
|
const Divider(),
|
||||||
|
if (massnahme.timeAction != null && massnahme.timeAction != '')
|
||||||
|
Text(
|
||||||
|
context.translate('page.actionDetailPage.implementation.time'),
|
||||||
|
style: theme.currentThemeData.textTheme.labelMedium,
|
||||||
|
),
|
||||||
|
if (massnahme.timeAction != null && massnahme.timeAction != '')
|
||||||
|
Text(
|
||||||
|
massnahme.timeAction.toString(),
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
25
lib/src/pages/actions/detail/cards/location_card.dart
Normal file
25
lib/src/pages/actions/detail/cards/location_card.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
|
class LocationCard extends StatelessWidget {
|
||||||
|
const LocationCard({super.key, required this.massnahme});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return MainCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.location.title',
|
||||||
|
content: Text(
|
||||||
|
massnahme.factsheetLocation.toString(),
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
class MaintenanceCard extends StatelessWidget {
|
class MaintenanceCard extends StatelessWidget {
|
||||||
const MaintenanceCard({super.key, required this.massnahme});
|
const MaintenanceCard({super.key, required this.massnahme});
|
||||||
|
@ -13,27 +14,130 @@ class MaintenanceCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
Chip buildChip(String label) {
|
||||||
width: double.infinity,
|
return Chip(
|
||||||
child: Card(
|
labelPadding: EdgeInsets.zero,
|
||||||
shape: RoundedRectangleBorder(
|
backgroundColor: theme.currentColorScheme.secondary,
|
||||||
borderRadius: BorderRadius.circular(0),
|
label: Text(
|
||||||
|
label,
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge
|
||||||
|
?.copyWith(color: theme.currentColorScheme.onSecondary),
|
||||||
),
|
),
|
||||||
elevation: 0,
|
);
|
||||||
color: theme.currentColorScheme.secondary,
|
}
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
List<Chip> buildChips(List<String?>? items) =>
|
||||||
child: Column(
|
items
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
?.where((item) => item?.isNotEmpty ?? false)
|
||||||
|
.map((item) => buildChip(item!))
|
||||||
|
.toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
List<Widget> buildTools(List<String?>? tools) =>
|
||||||
|
tools?.where((item) => item?.isNotEmpty ?? false).map((item) {
|
||||||
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Text(
|
const Icon(Icons.fiber_manual_record, size: 8),
|
||||||
context.translate('page.actionDetailPage.maintenance.title'),
|
theme.horizontalSpacerSmall,
|
||||||
style: theme.currentThemeData.textTheme.titleMedium,
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
item!,
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
theme.verticalSpacer,
|
|
||||||
],
|
],
|
||||||
|
);
|
||||||
|
}).toList() ??
|
||||||
|
[];
|
||||||
|
|
||||||
|
Widget buildSection({
|
||||||
|
required String titleKey,
|
||||||
|
required List<Widget> children,
|
||||||
|
}) {
|
||||||
|
if (children.isEmpty) return const SizedBox.shrink();
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
const Divider(),
|
||||||
|
Text(
|
||||||
|
context.translate(titleKey),
|
||||||
|
style: theme.currentThemeData.textTheme.labelMedium,
|
||||||
),
|
),
|
||||||
),
|
...children,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget buildTextSection(String? text, String titleKey) {
|
||||||
|
if (text == null || text.isEmpty) return const SizedBox.shrink();
|
||||||
|
return buildSection(
|
||||||
|
titleKey: titleKey,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
text,
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
final tfChips =
|
||||||
|
buildChips(massnahme.timeMaintenance?.map((e) => e.value).toList());
|
||||||
|
final tfMaintenance = buildChips(
|
||||||
|
massnahme.frequencyMaintenance?.map((e) => e.value).toList());
|
||||||
|
final creationTools =
|
||||||
|
buildTools(massnahme.maintenanceMaterial?.map((e) => e.value).toList());
|
||||||
|
|
||||||
|
return MainCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.maintenance.title',
|
||||||
|
content: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
if (tfChips.isNotEmpty)
|
||||||
|
buildSection(
|
||||||
|
titleKey: 'page.actionDetailPage.maintenance.time',
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 8,
|
||||||
|
spacing: 8,
|
||||||
|
children: tfChips,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.timeMaintenanceAdditional,
|
||||||
|
'page.actionDetailPage.maintenance.additional_time',
|
||||||
|
),
|
||||||
|
if (tfMaintenance.isNotEmpty)
|
||||||
|
buildSection(
|
||||||
|
titleKey: 'page.actionDetailPage.maintenance.frequency',
|
||||||
|
children: [
|
||||||
|
Wrap(
|
||||||
|
runSpacing: 8,
|
||||||
|
spacing: 8,
|
||||||
|
children: tfMaintenance,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.frequencyMaintenanceAdditional,
|
||||||
|
'page.actionDetailPage.maintenance.additional_frequency',
|
||||||
|
),
|
||||||
|
if (creationTools.isNotEmpty)
|
||||||
|
buildSection(
|
||||||
|
titleKey: 'page.actionDetailPage.maintenance.tools',
|
||||||
|
children: creationTools,
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.workMaintenance,
|
||||||
|
'page.actionDetailPage.maintenance.steps',
|
||||||
|
),
|
||||||
|
buildTextSection(
|
||||||
|
massnahme.tipsMaintenance,
|
||||||
|
'page.actionDetailPage.maintenance.tips',
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
|
import 'package:ambito/src/widgets/buttons/text_button.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_sidebar_card.dart';
|
||||||
|
|
||||||
class MaterialCard extends StatelessWidget {
|
class MaterialCard extends StatelessWidget {
|
||||||
const MaterialCard({super.key, required this.massnahme});
|
const MaterialCard({super.key, required this.massnahme});
|
||||||
|
@ -13,37 +15,26 @@ class MaterialCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
return SideBarCard(
|
||||||
width: double.infinity,
|
massnahme: massnahme,
|
||||||
child: Card(
|
title: 'page.actionDetailPage.material.title',
|
||||||
shape: RoundedRectangleBorder(
|
content: [
|
||||||
borderRadius: BorderRadius.circular(8),
|
_getSortedMaterials(context),
|
||||||
),
|
theme.verticalSpacer,
|
||||||
elevation: 0,
|
if (massnahme.costsMaterial != null)
|
||||||
color: greenColors['primary']!.withOpacity(.1),
|
Text(context
|
||||||
child: Padding(
|
.translate('page.actionDetailPage.material.suggested_price') +
|
||||||
padding: const EdgeInsets.all(16),
|
massnahme.costsMaterial +
|
||||||
child: Column(
|
' €'),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
theme.verticalSpacerSmall,
|
||||||
children: [
|
Align(
|
||||||
Text(
|
alignment: Alignment.center,
|
||||||
context.translate('page.actionDetailPage.material.title'),
|
child: TextButtonElement(
|
||||||
style: theme.currentThemeData.textTheme.labelMedium
|
title: 'page.actionDetailPage.material.add_to_basket',
|
||||||
?.copyWith(color: theme.currentColorScheme.primary),
|
onPressed: () {},
|
||||||
),
|
|
||||||
theme.verticalSpacerSmall,
|
|
||||||
_getSortedMaterials(context),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
if (massnahme.costsMaterial != null)
|
|
||||||
Text(context.translate(
|
|
||||||
'page.actionDetailPage.material.suggested_price') +
|
|
||||||
massnahme.costsMaterial +
|
|
||||||
' €'),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
),
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +61,7 @@ class MaterialCard extends StatelessWidget {
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
item,
|
item,
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
class PresetsCard extends StatelessWidget {
|
class PresetsCard extends StatelessWidget {
|
||||||
const PresetsCard({super.key, required this.massnahme});
|
const PresetsCard({super.key, required this.massnahme});
|
||||||
|
@ -13,41 +13,12 @@ class PresetsCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
return SizedBox(
|
return MainCard(
|
||||||
width: double.infinity,
|
massnahme: massnahme,
|
||||||
child: Card(
|
title: 'page.actionDetailPage.presets.title',
|
||||||
shape: RoundedRectangleBorder(
|
content: Text(
|
||||||
borderRadius: BorderRadius.circular(0),
|
massnahme.remarkablePresets.toString(),
|
||||||
),
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
elevation: 0,
|
|
||||||
color: theme.currentColorScheme.secondary,
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(16),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
context.translate('page.actionDetailPage.presets.title'),
|
|
||||||
style: theme.currentThemeData.textTheme.titleMedium,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
Text(
|
|
||||||
massnahme.remarkablePresets.toString(),
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
theme.verticalSpacer,
|
|
||||||
Text(
|
|
||||||
context.translate('page.actionDetailPage.presets.tips'),
|
|
||||||
style: theme.currentThemeData.textTheme.titleSmall,
|
|
||||||
),
|
|
||||||
theme.verticalSpacerSmall,
|
|
||||||
Text(
|
|
||||||
massnahme.tipsPresets.toString(),
|
|
||||||
style: theme.currentThemeData.textTheme.bodyMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
import 'package:ambito/src/extensions/extensions.dart';
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_rating/flutter_rating.dart';
|
||||||
import 'package:flutter_rating_stars/flutter_rating_stars.dart';
|
import 'package:flutter_rating_stars/flutter_rating_stars.dart';
|
||||||
|
|
||||||
import '../../../../entity/entities.dart';
|
import '../../../../entity/entities.dart';
|
||||||
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_sidebar_card.dart';
|
||||||
|
|
||||||
class ReviewCard extends StatelessWidget {
|
class ReviewCard extends StatelessWidget {
|
||||||
const ReviewCard({super.key, required this.massnahme});
|
const ReviewCard({super.key, required this.massnahme});
|
||||||
|
@ -14,6 +16,49 @@ class ReviewCard extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final AmbitoTheme theme = getTheme(context);
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return SideBarCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.review.title',
|
||||||
|
content: [
|
||||||
|
StarRating(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
size: 24,
|
||||||
|
allowHalfRating: true,
|
||||||
|
rating: 3.5,
|
||||||
|
filledIcon: Icons.star,
|
||||||
|
halfFilledIcon: Icons.star_half,
|
||||||
|
emptyIcon: Icons.star_border_outlined,
|
||||||
|
color:
|
||||||
|
Colors.yellow.shade800, // Color for filled and half-filled icons
|
||||||
|
borderColor: Colors.yellow.shade800, // Color for empty icons
|
||||||
|
onRatingChanged: null,
|
||||||
|
),
|
||||||
|
theme.verticalSpacerSmall,
|
||||||
|
Text(
|
||||||
|
'21 Bewertungen',
|
||||||
|
style: theme.bodySmall,
|
||||||
|
),
|
||||||
|
theme.verticalSpacer,
|
||||||
|
Text(
|
||||||
|
'"Sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam"',
|
||||||
|
style: theme.bodyLarge.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Maxi Mustermann',
|
||||||
|
style: theme.bodyLarge.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
theme.verticalSpacer,
|
||||||
|
Text(
|
||||||
|
'"Lorem ipsum dolor sit amet, consetetur sadipscing elitr"',
|
||||||
|
style: theme.bodyLarge.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
'Peter Parker',
|
||||||
|
style: theme.bodyLarge.copyWith(fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: Card(
|
child: Card(
|
||||||
|
@ -56,8 +101,8 @@ class ReviewCard extends StatelessWidget {
|
||||||
valueLabelPadding:
|
valueLabelPadding:
|
||||||
const EdgeInsets.symmetric(vertical: 1, horizontal: 8),
|
const EdgeInsets.symmetric(vertical: 1, horizontal: 8),
|
||||||
valueLabelMargin: const EdgeInsets.only(right: 8),
|
valueLabelMargin: const EdgeInsets.only(right: 8),
|
||||||
starOffColor: const Color(0xffe7e8ea),
|
starOffColor: Colors.yellow.withOpacity(.3),
|
||||||
starColor: Colors.grey.shade600,
|
starColor: Colors.yellow,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
25
lib/src/pages/actions/detail/cards/size_card.dart
Normal file
25
lib/src/pages/actions/detail/cards/size_card.dart
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
import '_main_card.dart';
|
||||||
|
|
||||||
|
class SizeCard extends StatelessWidget {
|
||||||
|
const SizeCard({super.key, required this.massnahme});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return MainCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.size.title',
|
||||||
|
content: Text(
|
||||||
|
massnahme.factsheetSizeArea.toString(),
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
26
lib/src/pages/actions/detail/cards/sources_card.dart
Normal file
26
lib/src/pages/actions/detail/cards/sources_card.dart
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import 'package:ambito/src/pages/actions/detail/cards/_main_card.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
|
||||||
|
class SourcesCard extends StatelessWidget {
|
||||||
|
const SourcesCard({super.key, required this.massnahme});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return MainCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.sources.title',
|
||||||
|
content: Text(
|
||||||
|
massnahme.sources ?? '',
|
||||||
|
style: theme.currentThemeData.textTheme.bodyLarge,
|
||||||
|
textAlign: TextAlign.left,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
37
lib/src/pages/actions/detail/cards/toc_card.dart
Normal file
37
lib/src/pages/actions/detail/cards/toc_card.dart
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import 'package:ambito/src/pages/actions/detail/cards/_sidebar_card.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:super_bullet_list/bullet_list.dart';
|
||||||
|
|
||||||
|
import '../../../../entity/entities.dart';
|
||||||
|
import '../../../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
|
||||||
|
class TocCard extends StatelessWidget {
|
||||||
|
const TocCard({super.key, required this.massnahme, required this.items});
|
||||||
|
|
||||||
|
final Measure massnahme;
|
||||||
|
final List<String> items;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return SideBarCard(
|
||||||
|
massnahme: massnahme,
|
||||||
|
title: 'page.actionDetailPage.toc.title',
|
||||||
|
content: [
|
||||||
|
SuperBulletList(
|
||||||
|
gap: 2,
|
||||||
|
crossAxisMargin: 2,
|
||||||
|
iconSize: 24,
|
||||||
|
isOrdered: true,
|
||||||
|
items: items
|
||||||
|
.map((item) => Text(
|
||||||
|
item,
|
||||||
|
style: theme.bodyLarge,
|
||||||
|
))
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
40
lib/src/widgets/buttons/text_button.dart
Normal file
40
lib/src/widgets/buttons/text_button.dart
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import 'package:ambito/src/extensions/extensions.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
import '../../packages/ambito_theme/ambito_theme.dart';
|
||||||
|
|
||||||
|
class TextButtonElement extends StatelessWidget {
|
||||||
|
const TextButtonElement(
|
||||||
|
{super.key, required this.title, required this.onPressed});
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final VoidCallback onPressed;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final AmbitoTheme theme = getTheme(context);
|
||||||
|
|
||||||
|
return TextButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
backgroundColor:
|
||||||
|
WidgetStateProperty.all(theme.currentColorScheme.secondary),
|
||||||
|
padding: WidgetStateProperty.all<EdgeInsets>(
|
||||||
|
const EdgeInsets.all(16),
|
||||||
|
),
|
||||||
|
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
|
||||||
|
RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
8.0,
|
||||||
|
),
|
||||||
|
))),
|
||||||
|
onPressed: onPressed,
|
||||||
|
child: Text(
|
||||||
|
context.translate(title),
|
||||||
|
style: theme.bodyLarge.copyWith(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
color: theme.currentColorScheme.onPrimary,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
56
pubspec.lock
56
pubspec.lock
|
@ -22,6 +22,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "6.7.0"
|
version: "6.7.0"
|
||||||
|
animated_segmented_tab_control:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: animated_segmented_tab_control
|
||||||
|
sha256: "4c04f5510037b1c30dbed00efae77559cc4e11f0fe2207c2358252d1870e4ab1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
args:
|
args:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -118,6 +126,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.9.2"
|
version: "8.9.2"
|
||||||
|
bulleted_list:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: bulleted_list
|
||||||
|
sha256: "35ddc56b7fd9977ae3932264f5b722e702748a044aa16f0a7109bf7e4886fedb"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.1+0.1a"
|
||||||
cached_network_image:
|
cached_network_image:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -154,10 +170,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: charcode
|
name: charcode
|
||||||
sha256: fb98c0f6d12c920a02ee2d998da788bca066ca5f148492b7085ee23372b12306
|
sha256: fb0f1107cac15a5ea6ef0a6ef71a807b9e4267c713bb93e00e92d737cc8dbd8a
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.1"
|
version: "1.4.0"
|
||||||
checked_yaml:
|
checked_yaml:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -334,6 +350,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.1"
|
version: "1.1.1"
|
||||||
|
flextras:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flextras
|
||||||
|
sha256: e73b5c86dd9419569d2a48db470059b41b496012513e4e1bdc56ba2c661048d9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
flutter:
|
flutter:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description: flutter
|
description: flutter
|
||||||
|
@ -432,6 +456,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "9.1.1"
|
version: "9.1.1"
|
||||||
|
flutter_rating:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: flutter_rating
|
||||||
|
sha256: "207bcd4a276585b8a0771a5ac03c0f3cdb27490e79a609f9a483d9794fe630b7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.2"
|
||||||
flutter_rating_stars:
|
flutter_rating_stars:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -458,6 +490,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.0"
|
version: "4.0.0"
|
||||||
|
gap:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: gap
|
||||||
|
sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
geolocator:
|
geolocator:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -910,10 +950,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: permission_handler_html
|
name: permission_handler_html
|
||||||
sha256: af26edbbb1f2674af65a8f4b56e1a6f526156bc273d0e65dd8075fab51c78851
|
sha256: "6b9cb54b7135073841a35513fba39e598b421702d5f4d92319992fd6eb5532a9"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.1.3+2"
|
version: "0.1.3+4"
|
||||||
permission_handler_platform_interface:
|
permission_handler_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -1207,6 +1247,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.0"
|
version: "1.2.0"
|
||||||
|
super_bullet_list:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: super_bullet_list
|
||||||
|
sha256: ffe4514582c4e5a0d58b16e2131b35c25f159629488670b655255c03960e0ee5
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.0.3"
|
||||||
syncfusion_flutter_calendar:
|
syncfusion_flutter_calendar:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
@ -58,6 +58,10 @@ dependencies:
|
||||||
expansion_tile_card: ^3.0.0
|
expansion_tile_card: ^3.0.0
|
||||||
flutter_linkify: ^6.0.0
|
flutter_linkify: ^6.0.0
|
||||||
linkify: ^5.0.0
|
linkify: ^5.0.0
|
||||||
|
flutter_rating: ^2.0.2
|
||||||
|
bulleted_list: ^0.0.1+0.1a
|
||||||
|
super_bullet_list: ^0.0.3
|
||||||
|
animated_segmented_tab_control: ^2.0.0
|
||||||
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
|
|
Loading…
Reference in a new issue