From 82c63803bbda610a7d501db093ef6aed24e57710 Mon Sep 17 00:00:00 2001 From: Vadim Date: Sun, 19 Mar 2023 22:08:29 +0300 Subject: [PATCH] moved equipment profiles screen from iap --- .../dialog_filter/widget_dialog_filter.dart | 139 +++++++++++++++++ .../widget_list_tile_equipment.dart | 46 ++++++ .../widget_section_equipment_profile.dart | 141 ++++++++++++++++++ .../screen_equipment_profile.dart | 36 +++++ .../widget_list_tile_equipment_profiles.dart | 23 +-- 5 files changed, 367 insertions(+), 18 deletions(-) create mode 100644 lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/dialog_filter/widget_dialog_filter.dart create mode 100644 lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/equipment_list_tile/widget_list_tile_equipment.dart create mode 100644 lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/widget_section_equipment_profile.dart create mode 100644 lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/dialog_filter/widget_dialog_filter.dart b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/dialog_filter/widget_dialog_filter.dart new file mode 100644 index 0000000..228808a --- /dev/null +++ b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/dialog_filter/widget_dialog_filter.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; + +class DialogFilter extends StatefulWidget { + final Icon icon; + final String title; + final String description; + final List values; + final String Function(BuildContext context, T value) titleAdapter; + final bool rangeSelect; + + const DialogFilter({ + required this.icon, + required this.title, + required this.description, + required this.values, + required this.titleAdapter, + this.rangeSelect = false, + super.key, + }); + + @override + State> createState() => _DialogFilterState(); +} + +class _DialogFilterState extends State> { + late final List _selectedValues = List.generate( + widget.values.length, + (_) => true, + growable: false, + ); + + bool get _hasAnySelected => _selectedValues.contains(true); + bool get _hasAnyUnselected => _selectedValues.contains(false); + + @override + Widget build(BuildContext context) { + return AlertDialog( + icon: widget.icon, + titlePadding: Dimens.dialogIconTitlePadding, + title: Text(widget.title), + contentPadding: EdgeInsets.zero, + content: Column( + children: [ + Padding( + padding: Dimens.dialogIconTitlePadding, + child: Text(widget.description), + ), + const Divider(), + // TODO: try to find lazy-building solution + Expanded( + child: SingleChildScrollView( + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.min, + children: List.generate( + widget.values.length, + (index) => CheckboxListTile( + value: _selectedValues[index], + controlAffinity: ListTileControlAffinity.leading, + title: Text( + widget.titleAdapter(context, widget.values[index]), + style: Theme.of(context).textTheme.bodyLarge!, + ), + onChanged: (value) { + if (value != null) { + setState(() { + if (widget.rangeSelect) { + if (value) { + final indexOfChecked = _selectedValues.indexOf(value); + if (indexOfChecked == -1) { + _selectedValues[index] = value; + } else if (indexOfChecked < index) { + _selectedValues.fillRange(indexOfChecked, index + 1, value); + } else { + _selectedValues.fillRange(index, indexOfChecked, value); + } + } else { + if (index > _selectedValues.length / 2) { + _selectedValues.fillRange(index, _selectedValues.length, false); + _selectedValues[index] = value; + } else { + _selectedValues.fillRange(0, index, false); + _selectedValues[index] = value; + } + } + } else { + _selectedValues[index] = value; + } + }); + } + }, + ), + ), + ), + ), + ), + const Divider(), + Padding( + padding: Dimens.dialogActionsPadding, + child: Row( + children: [ + SizedBox( + width: 40, + child: IconButton( + padding: EdgeInsets.zero, + icon: Icon(_hasAnyUnselected ? Icons.select_all : Icons.deselect), + onPressed: _toggleAll, + ), + ), + const Spacer(), + TextButton( + onPressed: Navigator.of(context).pop, + child: Text(S.of(context).cancel), + ), + TextButton( + onPressed: + _hasAnySelected ? () => Navigator.of(context).pop(_selectedValues) : null, + child: Text(S.of(context).save), + ), + ], + ), + ) + ], + ), + ); + } + + void _toggleAll() { + setState(() { + if (_hasAnyUnselected) { + _selectedValues.fillRange(0, _selectedValues.length, true); + } else { + _selectedValues.fillRange(0, _selectedValues.length, false); + } + }); + } +} diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/equipment_list_tile/widget_list_tile_equipment.dart b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/equipment_list_tile/widget_list_tile_equipment.dart new file mode 100644 index 0000000..356c4aa --- /dev/null +++ b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/components/equipment_list_tile/widget_list_tile_equipment.dart @@ -0,0 +1,46 @@ +import 'package:flutter/material.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; + +import '../dialog_filter/widget_dialog_filter.dart'; + +class EquipmentListTile extends StatelessWidget { + final IconData icon; + final String title; + final String description; + final List selectedValues; + final List values; + final ValueChanged> onChanged; + final bool rangeSelect; + + const EquipmentListTile({ + required this.icon, + required this.title, + required this.description, + required this.selectedValues, + required this.values, + required this.onChanged, + required this.rangeSelect, + super.key, + }); + + @override + Widget build(BuildContext context) { + return ListTile( + leading: Icon(icon), + title: Text(title), + onTap: () { + showDialog( + context: context, + builder: (_) => DialogFilter( + icon: Icon(icon), + title: title, + description: description, + values: values, + titleAdapter: (_, value) => value.toString(), + rangeSelect: rangeSelect, + ), + ); + }, + ); + } +} diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/widget_section_equipment_profile.dart b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/widget_section_equipment_profile.dart new file mode 100644 index 0000000..d553ed7 --- /dev/null +++ b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_section/widget_section_equipment_profile.dart @@ -0,0 +1,141 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; + +import 'components/equipment_list_tile/widget_list_tile_equipment.dart'; + +class EquipmentListTilesSection extends StatefulWidget { + final EquipmentProfileData data; + + const EquipmentListTilesSection({required this.data, super.key}); + + @override + State createState() => _EquipmentListTilesSectionState(); +} + +class _EquipmentListTilesSectionState extends State { + final TextEditingController _nameController = TextEditingController(text: 'Default'); + final FocusNode _fieldFocusNode = FocusNode(); + bool _expanded = false; + + @override + void dispose() { + _nameController.dispose(); + _fieldFocusNode.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Card( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: Dimens.paddingM), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.fromLTRB( + Dimens.paddingM, + 0, + Dimens.paddingM, + 0, + ), + child: IgnorePointer( + ignoring: !_expanded, + child: TextFormField( + focusNode: _fieldFocusNode, + controller: _nameController, + onChanged: (value) {}, + decoration: const InputDecoration( + hintText: 'Profile name', + border: InputBorder.none, + ), + ), + ), + ), + ), + Row( + children: [ + _collapseButton(), + IconButton( + onPressed: () {}, + icon: const Icon(Icons.delete), + ), + ], + ), + ], + ), + if (_expanded) const _DialogsListTiles() + ], + ), + ), + ); + } + + Widget _collapseButton() { + return IconButton( + onPressed: () { + setState(() { + _expanded = !_expanded; + }); + if (!_expanded) { + _fieldFocusNode.unfocus(); + } + }, + icon: Icon(_expanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down), + ); + } +} + +class _DialogsListTiles extends StatelessWidget { + const _DialogsListTiles(); + + @override + Widget build(BuildContext context) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + EquipmentListTile( + icon: Icons.iso, + title: S.of(context).isoValues, + description: S.of(context).isoValuesFilterDescription, + values: isoValues, + selectedValues: const [], + rangeSelect: false, + onChanged: (value) {}, + ), + EquipmentListTile( + icon: Icons.filter_b_and_w, + title: S.of(context).ndFilters, + description: S.of(context).ndFiltersFilterDescription, + values: ndValues, + selectedValues: const [], + rangeSelect: false, + onChanged: (value) {}, + ), + EquipmentListTile( + icon: Icons.camera, + title: S.of(context).apertureValues, + description: S.of(context).apertureValuesFilterDescription, + values: apertureValues, + selectedValues: const [], + rangeSelect: true, + onChanged: (value) {}, + ), + EquipmentListTile( + icon: Icons.shutter_speed, + title: S.of(context).shutterSpeedValues, + description: S.of(context).shutterSpeedValuesFilterDescription, + values: shutterSpeedValues, + selectedValues: const [], + rangeSelect: true, + onChanged: (value) {}, + ), + ], + ); + } +} diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart new file mode 100644 index 0000000..400d3a9 --- /dev/null +++ b/lib/screens/settings/components/metering/components/equipment_profiles/components/equipment_profile_screen/screen_equipment_profile.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lightmeter/generated/l10n.dart'; +import 'package:lightmeter/providers/equipment_profile_provider.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; + +import 'components/equipment_profile_section/widget_section_equipment_profile.dart'; + +class EquipmentProfileScreen extends StatefulWidget { + const EquipmentProfileScreen({super.key}); + + @override + State createState() => _EquipmentProfileScreenState(); +} + +class _EquipmentProfileScreenState extends State { + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + elevation: 0, + title: Text(S.of(context).equipmentProfiles), + ), + body: SafeArea( + bottom: false, + child: ListView.builder( + padding: const EdgeInsets.all(Dimens.paddingM), + itemCount: EquipmentProfiles.of(context)?.length ?? 0, + itemBuilder: (_, index) => EquipmentListTilesSection( + data: EquipmentProfiles.of(context)![index], + ), + ), + ), + ); + } +} diff --git a/lib/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart b/lib/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart index 912ca9a..4745a1d 100644 --- a/lib/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart +++ b/lib/screens/settings/components/metering/components/equipment_profiles/widget_list_tile_equipment_profiles.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; -import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart'; +import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart'; + +import 'components/equipment_profile_screen/screen_equipment_profile.dart'; class EquipmentProfilesListTile extends StatelessWidget { const EquipmentProfilesListTile({super.key}); @@ -11,23 +13,8 @@ class EquipmentProfilesListTile extends StatelessWidget { leading: const Icon(Icons.camera), title: Text(S.of(context).equipmentProfiles), onTap: () { - showEquipmentProfilesDialog( - context, - EquipmentProfileSectionLocalizationData( - isoValues: S.of(context).isoValues, - isoValuesFilterDescription: S.of(context).isoValuesFilterDescription, - ndValues: S.of(context).ndFilters, - ndValuesFilterDescription: S.of(context).ndFiltersFilterDescription, - apertureValues: S.of(context).apertureValues, - apertureValuesFilterDescription: S.of(context).apertureValuesFilterDescription, - shutterSpeedValues: S.of(context).shutterSpeedValues, - shutterSpeedValuesFilterDescription: S.of(context).shutterSpeedValuesFilterDescription, - dialogFilterLocalizationData: DialogFilterLocalizationData( - cancel: S.of(context).cancel, - save: S.of(context).save, - ), - ), - ); + Navigator.of(context).push( + MaterialPageRoute(builder: (_) => const EquipmentProfileScreen())); }, ); }