mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-22 23:40:41 +00:00
added LightmeterProSettingsSection
This commit is contained in:
parent
db86b001aa
commit
a1e6214671
7 changed files with 293 additions and 70 deletions
|
@ -93,8 +93,10 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"lightmeterPro": "Lightmeter PRO",
|
||||
"buyLightmeterPro": "Buy Lightmeter PRO",
|
||||
"lightmeterProDescription": "TBD",
|
||||
"buyLightmeterPro": "Buy Lightmeter Pro",
|
||||
"lightmeterPro": "Lightmeter Pro",
|
||||
"lightmeterProDescription": "Unlocks extra features, such as equipment profiles containing aperture, shutter speed, ISO and ND values filters and films.\n\nThe source code of Lightmeter is available on GitHub. You are welcome to compile it yourself. However, if you want to support the development and receive new features and updates, consider purchasing Lightmeter Pro.",
|
||||
"equipmentProfilesFeatureDescription": "Each equipment profile allows you to select:\n- Aperture values and shutter speeds, that your lens and camera have\n- ND filters, that fit the chosen lens\n- ISO values, that your camera supports\nCreating multiple profiles for different cameras and lenses allows you to easily switch between them and always have the relevant readings!",
|
||||
"filmsInUseFeatureDescription": "Select the films that you usually use. Selecting one will apply a correction to shutter speeds greater than 1\" to compensate for the reciprocity failure.",
|
||||
"buy": "Buy"
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
|
||||
import 'package:lightmeter/screens/shared/sliver_screen/screen_sliver.dart';
|
||||
|
||||
class BuyProScreen extends StatelessWidget {
|
||||
const BuyProScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SliverScreen(
|
||||
title: S.of(context).lightmeterPro,
|
||||
appBarActions: [
|
||||
IconButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
icon: const Icon(Icons.close),
|
||||
),
|
||||
],
|
||||
slivers: [
|
||||
SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
[
|
||||
Text(S.of(context).lightmeterProDescription),
|
||||
Row(
|
||||
children: [
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
child: Text(S.of(context).buy),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(child: SizedBox(height: MediaQuery.paddingOf(context).bottom)),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/settings/components/buy_pro/components/equipment_profiles/components/equipment_profile_screen/screen_buy_pro.dart';
|
||||
|
||||
class BuyProListTile extends StatelessWidget {
|
||||
const BuyProListTile({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.camera),
|
||||
title: Text(S.of(context).buyLightmeterPro),
|
||||
onTap: () {
|
||||
Navigator.of(context).push<bool>(
|
||||
MaterialPageRoute(builder: (_) => const BuyProScreen()),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
|
||||
class BuyProListTile extends StatelessWidget {
|
||||
const BuyProListTile({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListTile(
|
||||
leading: const Icon(Icons.star),
|
||||
title: Text(S.of(context).buyLightmeterPro),
|
||||
onTap: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (_) => AlertDialog(
|
||||
icon: const Icon(Icons.star),
|
||||
titlePadding: Dimens.dialogIconTitlePadding,
|
||||
title: Text(S.of(context).lightmeterPro),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
|
||||
content: SingleChildScrollView(child: Text(S.of(context).lightmeterProDescription)),
|
||||
actionsPadding: Dimens.dialogActionsPadding,
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Navigator.of(context).pop,
|
||||
child: Text(S.of(context).cancel),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: Text(S.of(context).buy),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/settings/components/buy_pro/components/equipment_profiles/widget_list_tile_buy_pro.dart';
|
||||
import 'package:lightmeter/screens/settings/components/lightmeter_pro/components/buy_pro/widget_list_tile_buy_pro.dart';
|
||||
import 'package:lightmeter/screens/settings/components/shared/settings_section/widget_settings_section.dart';
|
||||
|
||||
class BuyProSettingsSection extends StatelessWidget {
|
||||
const BuyProSettingsSection({super.key});
|
||||
class LightmeterProSettingsSection extends StatelessWidget {
|
||||
const LightmeterProSettingsSection({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
|
@ -0,0 +1,242 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:lightmeter/res/dimens.dart';
|
||||
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_container/components/equipment_list_tiles/widget_list_tiles_equipments.dart';
|
||||
import 'package:lightmeter/screens/settings/components/equipment/components/equipment_profiles/components/equipment_profile_screen/components/equipment_profile_name_dialog/widget_dialog_equipment_profile_name.dart';
|
||||
import 'package:m3_lightmeter_resources/m3_lightmeter_resources.dart';
|
||||
|
||||
class ExpandableSection extends StatefulWidget {
|
||||
final EquipmentProfile data;
|
||||
final ValueChanged<EquipmentProfile> onUpdate;
|
||||
final VoidCallback onDelete;
|
||||
final VoidCallback onExpand;
|
||||
|
||||
const ExpandableSection({
|
||||
required this.data,
|
||||
required this.onUpdate,
|
||||
required this.onDelete,
|
||||
required this.onExpand,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ExpandableSection> createState() => ExpandableSectionState();
|
||||
}
|
||||
|
||||
class ExpandableSectionState extends State<ExpandableSection>
|
||||
with TickerProviderStateMixin {
|
||||
late EquipmentProfile _equipmentData = EquipmentProfile(
|
||||
id: widget.data.id,
|
||||
name: widget.data.name,
|
||||
apertureValues: widget.data.apertureValues,
|
||||
ndValues: widget.data.ndValues,
|
||||
shutterSpeedValues: widget.data.shutterSpeedValues,
|
||||
isoValues: widget.data.isoValues,
|
||||
);
|
||||
|
||||
late final AnimationController _controller = AnimationController(
|
||||
duration: Dimens.durationM,
|
||||
vsync: this,
|
||||
);
|
||||
bool get _expanded => _controller.isCompleted;
|
||||
|
||||
@override
|
||||
void didUpdateWidget(ExpandableSection oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
_equipmentData = EquipmentProfile(
|
||||
id: widget.data.id,
|
||||
name: widget.data.name,
|
||||
apertureValues: widget.data.apertureValues,
|
||||
ndValues: widget.data.ndValues,
|
||||
shutterSpeedValues: widget.data.shutterSpeedValues,
|
||||
isoValues: widget.data.isoValues,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_controller.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: [
|
||||
ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: Dimens.paddingM),
|
||||
title: Row(
|
||||
children: [
|
||||
_AnimatedNameLeading(controller: _controller),
|
||||
const SizedBox(width: Dimens.grid8),
|
||||
Flexible(
|
||||
child: Text(
|
||||
_equipmentData.name,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
trailing: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_AnimatedArrowButton(
|
||||
controller: _controller,
|
||||
onPressed: () => _expanded ? collapse() : expand(),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: widget.onDelete,
|
||||
icon: const Icon(Icons.delete),
|
||||
),
|
||||
],
|
||||
),
|
||||
onTap: () => _expanded ? _showNameDialog() : expand(),
|
||||
),
|
||||
_AnimatedEquipmentListTiles(
|
||||
controller: _controller,
|
||||
equipmentData: _equipmentData,
|
||||
onApertureValuesSelected: (value) {
|
||||
_equipmentData = _equipmentData.copyWith(apertureValues: value);
|
||||
widget.onUpdate(_equipmentData);
|
||||
},
|
||||
onIsoValuesSelecred: (value) {
|
||||
_equipmentData = _equipmentData.copyWith(isoValues: value);
|
||||
widget.onUpdate(_equipmentData);
|
||||
},
|
||||
onNdValuesSelected: (value) {
|
||||
_equipmentData = _equipmentData.copyWith(ndValues: value);
|
||||
widget.onUpdate(_equipmentData);
|
||||
},
|
||||
onShutterSpeedValuesSelected: (value) {
|
||||
_equipmentData = _equipmentData.copyWith(shutterSpeedValues: value);
|
||||
widget.onUpdate(_equipmentData);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showNameDialog() {
|
||||
showDialog<String>(
|
||||
context: context,
|
||||
builder: (_) => EquipmentProfileNameDialog(initialValue: _equipmentData.name),
|
||||
).then((value) {
|
||||
if (value != null) {
|
||||
_equipmentData = _equipmentData.copyWith(name: value);
|
||||
widget.onUpdate(_equipmentData);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void expand() {
|
||||
widget.onExpand();
|
||||
_controller.forward();
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
Future.delayed(_controller.duration!).then((_) {
|
||||
Scrollable.ensureVisible(
|
||||
context,
|
||||
alignmentPolicy: ScrollPositionAlignmentPolicy.keepVisibleAtEnd,
|
||||
duration: _controller.duration!,
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void collapse() {
|
||||
_controller.reverse();
|
||||
}
|
||||
}
|
||||
|
||||
class _AnimatedNameLeading extends AnimatedWidget {
|
||||
const _AnimatedNameLeading({required AnimationController controller})
|
||||
: super(listenable: controller);
|
||||
|
||||
Animation<double> get _progress => listenable as Animation<double>;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(right: _progress.value * Dimens.grid8),
|
||||
child: Icon(
|
||||
Icons.edit,
|
||||
size: _progress.value * Dimens.grid24,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AnimatedArrowButton extends AnimatedWidget {
|
||||
final VoidCallback onPressed;
|
||||
|
||||
const _AnimatedArrowButton({
|
||||
required AnimationController controller,
|
||||
required this.onPressed,
|
||||
}) : super(listenable: controller);
|
||||
|
||||
Animation<double> get _progress => listenable as Animation<double>;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
onPressed: onPressed,
|
||||
icon: Transform.rotate(
|
||||
angle: _progress.value * pi,
|
||||
child: const Icon(Icons.keyboard_arrow_down),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _AnimatedEquipmentListTiles extends AnimatedWidget {
|
||||
final EquipmentProfile equipmentData;
|
||||
final ValueChanged<List<ApertureValue>> onApertureValuesSelected;
|
||||
final ValueChanged<List<IsoValue>> onIsoValuesSelecred;
|
||||
final ValueChanged<List<NdValue>> onNdValuesSelected;
|
||||
final ValueChanged<List<ShutterSpeedValue>> onShutterSpeedValuesSelected;
|
||||
|
||||
const _AnimatedEquipmentListTiles({
|
||||
required AnimationController controller,
|
||||
required this.equipmentData,
|
||||
required this.onApertureValuesSelected,
|
||||
required this.onIsoValuesSelecred,
|
||||
required this.onNdValuesSelected,
|
||||
required this.onShutterSpeedValuesSelected,
|
||||
}) : super(listenable: controller);
|
||||
|
||||
Animation<double> get _progress => listenable as Animation<double>;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SizedOverflowBox(
|
||||
alignment: Alignment.topCenter,
|
||||
size: Size(
|
||||
double.maxFinite,
|
||||
_progress.value * Dimens.grid56 * 4,
|
||||
),
|
||||
child: Opacity(
|
||||
opacity: _progress.value,
|
||||
child: EquipmentListTiles(
|
||||
selectedApertureValues: equipmentData.apertureValues,
|
||||
selectedIsoValues: equipmentData.isoValues,
|
||||
selectedNdValues: equipmentData.ndValues,
|
||||
selectedShutterSpeedValues: equipmentData.shutterSpeedValues,
|
||||
onApertureValuesSelected: onApertureValuesSelected,
|
||||
onIsoValuesSelecred: onIsoValuesSelecred,
|
||||
onNdValuesSelected: onNdValuesSelected,
|
||||
onShutterSpeedValuesSelected: onShutterSpeedValuesSelected,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:lightmeter/generated/l10n.dart';
|
||||
import 'package:lightmeter/screens/settings/components/about/widget_settings_section_about.dart';
|
||||
import 'package:lightmeter/screens/settings/components/buy_pro/widget_settings_section_pro.dart';
|
||||
import 'package:lightmeter/screens/settings/components/lightmeter_pro/widget_settings_section_lightmeter_pro.dart';
|
||||
import 'package:lightmeter/screens/settings/components/equipment/widget_settings_section_equipment.dart';
|
||||
import 'package:lightmeter/screens/settings/components/general/widget_settings_section_general.dart';
|
||||
import 'package:lightmeter/screens/settings/components/metering/widget_settings_section_metering.dart';
|
||||
|
@ -44,7 +44,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
|||
SliverList(
|
||||
delegate: SliverChildListDelegate(
|
||||
<Widget>[
|
||||
const BuyProSettingsSection(),
|
||||
const LightmeterProSettingsSection(),
|
||||
const MeteringSettingsSection(),
|
||||
const EquipmentSettingsSection(),
|
||||
const GeneralSettingsSection(),
|
||||
|
|
Loading…
Reference in a new issue