mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2025-08-17 10:36:41 +00:00
reworked DialogSwitchListItem
This commit is contained in:
parent
709d19bb73
commit
e4bb7588ef
4 changed files with 101 additions and 43 deletions
|
@ -4,7 +4,6 @@ import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/providers/services_provider.dart';
|
import 'package:lightmeter/providers/services_provider.dart';
|
||||||
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
import 'package:lightmeter/providers/user_preferences_provider.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart';
|
import 'package:lightmeter/screens/settings/components/shared/dialog_switch/widget_dialog_switch.dart';
|
||||||
import 'package:lightmeter/screens/settings/components/shared/iap_list_tile/widget_list_tile_iap.dart';
|
|
||||||
|
|
||||||
class CameraFeaturesListTile extends StatelessWidget {
|
class CameraFeaturesListTile extends StatelessWidget {
|
||||||
const CameraFeaturesListTile({super.key});
|
const CameraFeaturesListTile({super.key});
|
||||||
|
@ -15,28 +14,43 @@ class CameraFeaturesListTile extends StatelessWidget {
|
||||||
leading: const Icon(Icons.camera_alt_outlined),
|
leading: const Icon(Icons.camera_alt_outlined),
|
||||||
title: Text(S.of(context).cameraFeatures),
|
title: Text(S.of(context).cameraFeatures),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
UserPreferencesProvider.cameraConfigOf(context).entries.map(
|
||||||
|
(entry) => DialogSwitchListItem(
|
||||||
|
value: CameraFeature.spotMetering,
|
||||||
|
title: S.of(context).cameraFeatureSpotMetering,
|
||||||
|
subtitle: S.of(context).cameraFeatureSpotMeteringHint,
|
||||||
|
initialValue: UserPreferencesProvider.cameraFeatureOf(context, CameraFeature.spotMetering),
|
||||||
|
isProRequired: true,
|
||||||
|
),
|
||||||
|
);
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => DialogSwitch<CameraFeature>(
|
builder: (_) => DialogSwitch<CameraFeature>(
|
||||||
icon: Icons.camera_alt_outlined,
|
icon: Icons.camera_alt_outlined,
|
||||||
title: S.of(context).cameraFeatures,
|
title: S.of(context).cameraFeatures,
|
||||||
values: UserPreferencesProvider.cameraConfigOf(context),
|
items: [
|
||||||
enabledAdapter: (feature) => switch (feature) {
|
DialogSwitchListItem(
|
||||||
CameraFeature.spotMetering => true,
|
value: CameraFeature.showFocalLength,
|
||||||
CameraFeature.histogram => true,
|
title: S.of(context).cameraFeaturesShowFocalLength,
|
||||||
CameraFeature.showFocalLength =>
|
subtitle: S.of(context).cameraFeaturesShowFocalLengthHint,
|
||||||
ServicesProvider.of(context).userPreferencesService.cameraFocalLength != null,
|
initialValue: UserPreferencesProvider.cameraFeatureOf(context, CameraFeature.showFocalLength),
|
||||||
},
|
isEnabled: ServicesProvider.of(context).userPreferencesService.cameraFocalLength != null,
|
||||||
titleAdapter: (context, feature) => switch (feature) {
|
),
|
||||||
CameraFeature.spotMetering => S.of(context).cameraFeatureSpotMetering,
|
DialogSwitchListItem(
|
||||||
CameraFeature.histogram => S.of(context).cameraFeatureHistogram,
|
value: CameraFeature.spotMetering,
|
||||||
CameraFeature.showFocalLength => S.of(context).cameraFeaturesShowFocalLength,
|
title: S.of(context).cameraFeatureSpotMetering,
|
||||||
},
|
subtitle: S.of(context).cameraFeatureSpotMeteringHint,
|
||||||
subtitleAdapter: (context, feature) => switch (feature) {
|
initialValue: UserPreferencesProvider.cameraFeatureOf(context, CameraFeature.spotMetering),
|
||||||
CameraFeature.spotMetering => S.of(context).cameraFeatureSpotMeteringHint,
|
isProRequired: true,
|
||||||
CameraFeature.histogram => S.of(context).cameraFeatureHistogramHint,
|
),
|
||||||
CameraFeature.showFocalLength => S.of(context).cameraFeaturesShowFocalLengthHint,
|
DialogSwitchListItem(
|
||||||
},
|
value: CameraFeature.histogram,
|
||||||
|
title: S.of(context).cameraFeatureHistogram,
|
||||||
|
subtitle: S.of(context).cameraFeatureHistogramHint,
|
||||||
|
initialValue: UserPreferencesProvider.cameraFeatureOf(context, CameraFeature.histogram),
|
||||||
|
isProRequired: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
onSave: UserPreferencesProvider.of(context).setCameraFeature,
|
onSave: UserPreferencesProvider.of(context).setCameraFeature,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -22,8 +22,16 @@ class MeteringScreenLayoutListTile extends StatelessWidget {
|
||||||
icon: Icons.layers_outlined,
|
icon: Icons.layers_outlined,
|
||||||
title: S.of(context).meteringScreenLayout,
|
title: S.of(context).meteringScreenLayout,
|
||||||
description: S.of(context).meteringScreenLayoutHint,
|
description: S.of(context).meteringScreenLayoutHint,
|
||||||
values: UserPreferencesProvider.meteringScreenConfigOf(context),
|
items: UserPreferencesProvider.meteringScreenConfigOf(context)
|
||||||
titleAdapter: _toStringLocalized,
|
.entries
|
||||||
|
.map(
|
||||||
|
(entry) => DialogSwitchListItem(
|
||||||
|
value: entry.key,
|
||||||
|
title: _toStringLocalized(context, entry.key),
|
||||||
|
initialValue: UserPreferencesProvider.meteringScreenFeatureOf(context, entry.key),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.toList(growable: false),
|
||||||
onSave: (value) {
|
onSave: (value) {
|
||||||
if (!value[MeteringScreenLayoutFeature.equipmentProfiles]!) {
|
if (!value[MeteringScreenLayoutFeature.equipmentProfiles]!) {
|
||||||
EquipmentProfilesProvider.of(context).selectProfile(EquipmentProfiles.of(context).first);
|
EquipmentProfilesProvider.of(context).selectProfile(EquipmentProfiles.of(context).first);
|
||||||
|
|
|
@ -1,27 +1,41 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:lightmeter/generated/l10n.dart';
|
import 'package:lightmeter/generated/l10n.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
|
import 'package:lightmeter/utils/context_utils.dart';
|
||||||
|
import 'package:lightmeter/utils/guard_pro_tap.dart';
|
||||||
|
|
||||||
typedef StringAdapter<T> = String Function(BuildContext context, T value);
|
typedef StringAdapter<T> = String Function(BuildContext context, T value);
|
||||||
|
|
||||||
|
class DialogSwitchListItem<T> {
|
||||||
|
final T value;
|
||||||
|
final String title;
|
||||||
|
final String? subtitle;
|
||||||
|
final bool initialValue;
|
||||||
|
final bool isEnabled;
|
||||||
|
final bool isProRequired;
|
||||||
|
|
||||||
|
const DialogSwitchListItem({
|
||||||
|
required this.value,
|
||||||
|
required this.title,
|
||||||
|
this.subtitle,
|
||||||
|
required this.initialValue,
|
||||||
|
this.isEnabled = true,
|
||||||
|
this.isProRequired = false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
class DialogSwitch<T> extends StatefulWidget {
|
class DialogSwitch<T> extends StatefulWidget {
|
||||||
final IconData icon;
|
final IconData icon;
|
||||||
final String title;
|
final String title;
|
||||||
final String? description;
|
final String? description;
|
||||||
final Map<T, bool> values;
|
final List<DialogSwitchListItem<T>> items;
|
||||||
final StringAdapter<T> titleAdapter;
|
|
||||||
final StringAdapter<T>? subtitleAdapter;
|
|
||||||
final bool Function(T value)? enabledAdapter;
|
|
||||||
final ValueChanged<Map<T, bool>> onSave;
|
final ValueChanged<Map<T, bool>> onSave;
|
||||||
|
|
||||||
const DialogSwitch({
|
const DialogSwitch({
|
||||||
required this.icon,
|
required this.icon,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.description,
|
this.description,
|
||||||
required this.values,
|
required this.items,
|
||||||
required this.titleAdapter,
|
|
||||||
this.subtitleAdapter,
|
|
||||||
this.enabledAdapter,
|
|
||||||
required this.onSave,
|
required this.onSave,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
|
@ -31,7 +45,11 @@ class DialogSwitch<T> extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _DialogSwitchState<T> extends State<DialogSwitch<T>> {
|
class _DialogSwitchState<T> extends State<DialogSwitch<T>> {
|
||||||
late final Map<T, bool> _features = Map.from(widget.values);
|
late final Map<T, bool> _features = Map.fromEntries(
|
||||||
|
widget.items.map(
|
||||||
|
(item) => MapEntry(item.value, item.initialValue),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -54,22 +72,15 @@ class _DialogSwitchState<T> extends State<DialogSwitch<T>> {
|
||||||
],
|
],
|
||||||
ListView(
|
ListView(
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
children: _features.entries.map(
|
children: widget.items.map(
|
||||||
(entry) {
|
(item) {
|
||||||
final isEnabled = widget.enabledAdapter?.call(entry.key) ?? true;
|
final value = _features[item.value]!;
|
||||||
return SwitchListTile(
|
return SwitchListTile(
|
||||||
contentPadding: EdgeInsets.symmetric(horizontal: Dimens.dialogTitlePadding.left),
|
contentPadding: EdgeInsets.symmetric(horizontal: Dimens.dialogTitlePadding.left),
|
||||||
title: Text(widget.titleAdapter(context, entry.key)),
|
title: Text(item.title),
|
||||||
subtitle:
|
subtitle: item.subtitle != null ? Text(item.subtitle!) : null,
|
||||||
widget.subtitleAdapter != null ? Text(widget.subtitleAdapter!.call(context, entry.key)) : null,
|
value: item.isProRequired ? context.isPro && value : value,
|
||||||
value: _features[entry.key]!,
|
onChanged: item.isEnabled ? (value) => _setItem(item, value) : null,
|
||||||
onChanged: isEnabled
|
|
||||||
? (value) {
|
|
||||||
setState(() {
|
|
||||||
_features.update(entry.key, (_) => value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
).toList(),
|
).toList(),
|
||||||
|
@ -93,4 +104,18 @@ class _DialogSwitchState<T> extends State<DialogSwitch<T>> {
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _setItem(DialogSwitchListItem<T> item, bool value) {
|
||||||
|
void setItemState() {
|
||||||
|
setState(() {
|
||||||
|
_features.update(item.value, (_) => value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.isProRequired) {
|
||||||
|
guardProTap(context, setItemState);
|
||||||
|
} else {
|
||||||
|
setItemState();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
11
lib/utils/guard_pro_tap.dart
Normal file
11
lib/utils/guard_pro_tap.dart
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lightmeter/navigation/routes.dart';
|
||||||
|
import 'package:lightmeter/utils/context_utils.dart';
|
||||||
|
|
||||||
|
void guardProTap(BuildContext context, VoidCallback callback) {
|
||||||
|
if (context.isPro) {
|
||||||
|
callback();
|
||||||
|
} else {
|
||||||
|
Navigator.of(context).pushNamed(NavigationRoutes.proFeaturesScreen.name);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue