import 'package:flutter/material.dart'; import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/models/exposure_pair.dart'; import 'package:lightmeter/models/iso_value.dart'; import 'package:lightmeter/models/nd_value.dart'; import 'package:lightmeter/models/photography_value.dart'; import 'package:lightmeter/res/dimens.dart'; import 'components/shared/animated_dialog.dart'; import 'components/dialog_picker.dart'; import 'components/reading_container.dart'; import 'models/reading_value.dart'; class MeteringTopBar extends StatelessWidget { static const _columnsCount = 3; final ExposurePair? fastest; final ExposurePair? slowest; final double ev; final IsoValue iso; final NdValue nd; final ValueChanged onIsoChanged; final ValueChanged onNdChanged; const MeteringTopBar({ required this.fastest, required this.slowest, required this.ev, required this.iso, required this.nd, required this.onIsoChanged, required this.onNdChanged, super.key, }); @override Widget build(BuildContext context) { final columnWidth = (MediaQuery.of(context).size.width - Dimens.paddingM * 2 - Dimens.grid16 * (_columnsCount - 1)) / 3; return ClipRRect( borderRadius: const BorderRadius.only( bottomLeft: Radius.circular(Dimens.borderRadiusL), bottomRight: Radius.circular(Dimens.borderRadiusL), ), child: ColoredBox( color: Theme.of(context).colorScheme.surface, child: Padding( padding: const EdgeInsets.all(Dimens.paddingM), child: SafeArea( bottom: false, child: MediaQuery( data: MediaQuery.of(context), child: Row( mainAxisSize: MainAxisSize.min, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox( height: columnWidth / 3 * 4, child: ReadingContainer( values: [ ReadingValue( label: S.of(context).fastestExposurePair, value: fastest != null ? '${fastest!.aperture.toString()} - ${fastest!.shutterSpeed.toString()}' : 'N/A', ), ReadingValue( label: S.of(context).slowestExposurePair, value: fastest != null ? '${slowest!.aperture.toString()} - ${slowest!.shutterSpeed.toString()}' : 'N/A', ), ], ), ), const _InnerPadding(), Row( children: [ SizedBox( width: columnWidth, child: ReadingContainer.singleValue( value: ReadingValue( label: 'EV', value: ev.toStringAsFixed(1), ), ), ), const _InnerPadding(), SizedBox( width: columnWidth, child: _AnimatedDialogPicker( title: S.of(context).iso, subtitle: S.of(context).filmSpeed, selectedValue: iso, values: isoValues, itemTitleBuilder: (_, value) => Text(value.value.toString()), // using ascending order, because increase in film speed rises EV evDifferenceBuilder: (selected, other) => selected.toStringDifference(other), onChanged: onIsoChanged, ), ), ], ) ], ), ), const _InnerPadding(), SizedBox( width: columnWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ AnimatedDialog( openedSize: Size( MediaQuery.of(context).size.width - Dimens.paddingM * 2, (MediaQuery.of(context).size.width - Dimens.paddingM * 2) / 3 * 4, ), child: const AspectRatio( aspectRatio: 3 / 4, child: ColoredBox(color: Colors.black), ), ), const _InnerPadding(), _AnimatedDialogPicker( title: S.of(context).nd, subtitle: S.of(context).ndFilterFactor, selectedValue: nd, values: ndValues, itemTitleBuilder: (_, value) => Text( value.value == 0 ? S.of(context).none : value.value.toString(), ), // using descending order, because ND filter darkens image & lowers EV evDifferenceBuilder: (selected, other) => other.toStringDifference(selected), onChanged: onNdChanged, ), ], ), ), ], ), ), ), ), ), ); } } class _InnerPadding extends SizedBox { const _InnerPadding() : super(height: Dimens.grid16, width: Dimens.grid16); } class _AnimatedDialogPicker extends StatelessWidget { final _key = GlobalKey(); final String title; final String subtitle; final T selectedValue; final List values; final DialogPickerItemBuilder itemTitleBuilder; final DialogPickerEvDifferenceBuilder evDifferenceBuilder; final ValueChanged onChanged; _AnimatedDialogPicker({ required this.title, required this.subtitle, required this.selectedValue, required this.values, required this.itemTitleBuilder, required this.evDifferenceBuilder, required this.onChanged, }) : super(); @override Widget build(BuildContext context) { return AnimatedDialog( key: _key, closedChild: ReadingContainer.singleValue( value: ReadingValue( label: title, value: selectedValue.value.toString(), ), ), openedChild: MeteringScreenDialogPicker( title: title, subtitle: subtitle, initialValue: selectedValue, values: values, itemTitleBuilder: itemTitleBuilder, evDifferenceBuilder: evDifferenceBuilder, onCancel: () { _key.currentState?.close(); }, onSelect: (value) { _key.currentState?.close().then((_) => onChanged(value)); }, ), ); } }