Compare commits

..

No commits in common. "1be7c3be48df5c91c4fce41df9f258e3e9224fd2" and "4201d36abb202787691121ea48b3dbb38cde2e09" have entirely different histories.

10 changed files with 118 additions and 122 deletions

View file

@ -36,7 +36,6 @@
"lightSensor": "Light sensor", "lightSensor": "Light sensor",
"meteringScreenLayout": "Metering screen layout", "meteringScreenLayout": "Metering screen layout",
"meteringScreenLayoutHint": "Hide elements on the metering screen that you don't need so that they don't waste exposure pairs list space.", "meteringScreenLayoutHint": "Hide elements on the metering screen that you don't need so that they don't waste exposure pairs list space.",
"meteringScreenLayoutHintEquipmentProfiles": "Equipment profile picker",
"meteringScreenFeatureExtremeExposurePairs": "Fastest & shortest exposure pairs", "meteringScreenFeatureExtremeExposurePairs": "Fastest & shortest exposure pairs",
"meteringScreenFeatureFilmPicker": "Film picker", "meteringScreenFeatureFilmPicker": "Film picker",
"meteringScreenFeatureHistogram": "Histogram", "meteringScreenFeatureHistogram": "Histogram",

View file

@ -36,7 +36,6 @@
"lightSensor": "Capteur de lumière", "lightSensor": "Capteur de lumière",
"meteringScreenLayout": "Disposition de l'écran de mesure", "meteringScreenLayout": "Disposition de l'écran de mesure",
"meteringScreenLayoutHint": "Masquer les éléments sur l'écran de mesure dont vous n'avez pas besoin pour qu'ils ne gaspillent pas de l'espace dans les paires d'exposition.", "meteringScreenLayoutHint": "Masquer les éléments sur l'écran de mesure dont vous n'avez pas besoin pour qu'ils ne gaspillent pas de l'espace dans les paires d'exposition.",
"meteringScreenLayoutHintEquipmentProfiles": "Sélecteur de profil de l'équipement",
"meteringScreenFeatureExtremeExposurePairs": "Paires d'exposition les plus rapides et les plus courtes", "meteringScreenFeatureExtremeExposurePairs": "Paires d'exposition les plus rapides et les plus courtes",
"meteringScreenFeatureFilmPicker": "Sélecteur de film", "meteringScreenFeatureFilmPicker": "Sélecteur de film",
"meteringScreenFeatureHistogram": "Histogramme", "meteringScreenFeatureHistogram": "Histogramme",

View file

@ -36,7 +36,6 @@
"lightSensor": "Датчик освещённости", "lightSensor": "Датчик освещённости",
"meteringScreenLayout": "Элементы главного экрана", "meteringScreenLayout": "Элементы главного экрана",
"meteringScreenLayoutHint": "Здесь вы можете скрыть некоторые ненужные или неиспользуемые элементы с главного экрана.", "meteringScreenLayoutHint": "Здесь вы можете скрыть некоторые ненужные или неиспользуемые элементы с главного экрана.",
"meteringScreenLayoutHintEquipmentProfiles": "Выбор профиля оборудования",
"meteringScreenFeatureExtremeExposurePairs": "Длинная и короткая выдержки", "meteringScreenFeatureExtremeExposurePairs": "Длинная и короткая выдержки",
"meteringScreenFeatureFilmPicker": "Выбор пленки", "meteringScreenFeatureFilmPicker": "Выбор пленки",
"meteringScreenFeatureHistogram": "Гистограмма", "meteringScreenFeatureHistogram": "Гистограмма",

View file

@ -36,7 +36,6 @@
"lightSensor": "光传感器", "lightSensor": "光传感器",
"meteringScreenLayout": "布局", "meteringScreenLayout": "布局",
"meteringScreenLayoutHint": "隐藏不需要的元素,以免浪费曝光列表空间", "meteringScreenLayoutHint": "隐藏不需要的元素,以免浪费曝光列表空间",
"meteringScreenLayoutHintEquipmentProfiles": "设备配置选择",
"meteringScreenFeatureExtremeExposurePairs": "最快 & 最慢曝光组合", "meteringScreenFeatureExtremeExposurePairs": "最快 & 最慢曝光组合",
"meteringScreenFeatureFilmPicker": "胶片选择", "meteringScreenFeatureFilmPicker": "胶片选择",
"meteringScreenFeatureHistogram": "直方图", "meteringScreenFeatureHistogram": "直方图",

View file

@ -31,23 +31,10 @@ class MeteringTopBarShape extends CustomPainter {
@override @override
void paint(Canvas canvas, Size size) { void paint(Canvas canvas, Size size) {
final paint = Paint()..color = color; final paint = Paint()..color = color;
late final Path path; final path = Path();
const circularRadius = Radius.circular(Dimens.borderRadiusL);
if (appendixHeight == 0 || appendixWidth == 0) { if (appendixHeight == 0 || appendixWidth == 0) {
path = _drawNoAppendix(size, Dimens.borderRadiusL); path.addRRect(
} else if (appendixHeight < 0) {
path = _drawAppendixOnLeft(size, Dimens.borderRadiusL);
canvas.scale(-1, 1);
canvas.translate(-size.width, 0);
} else {
path = _drawAppendixOnLeft(size, Dimens.borderRadiusL);
}
canvas.drawPath(path, paint);
}
Path _drawNoAppendix(Size size, double bottomRadius) {
final circularRadius = Radius.circular(bottomRadius);
return Path()
..addRRect(
RRect.fromLTRBAndCorners( RRect.fromLTRBAndCorners(
0, 0,
0, 0,
@ -56,51 +43,73 @@ class MeteringTopBarShape extends CustomPainter {
bottomLeft: circularRadius, bottomLeft: circularRadius,
bottomRight: circularRadius, bottomRight: circularRadius,
), ),
) );
..close(); } else if (appendixHeight < 0) {
} // Left side with bottom corner
path.lineTo(0, size.height + appendixHeight - Dimens.borderRadiusL);
path.arcToPoint(
Offset(Dimens.borderRadiusL, size.height + appendixHeight),
radius: circularRadius,
clockwise: false,
);
Path _drawAppendixOnLeft(Size size, double bottomRadius) { // Bottom side with step
final path = Path(); final allowedRadius = min(appendixHeight.abs() / 2, Dimens.borderRadiusL);
final circularRadius = Radius.circular(bottomRadius); path.lineTo(appendixWidth - allowedRadius, size.height + appendixHeight);
final appendixHeight = this.appendixHeight.abs(); path.arcToPoint(
Offset(appendixWidth, size.height + appendixHeight + allowedRadius),
radius: circularRadius,
);
path.lineTo(appendixWidth, size.height - allowedRadius);
path.arcToPoint(
Offset(appendixWidth + allowedRadius, size.height),
radius: circularRadius,
clockwise: false,
);
// Left side with bottom corner // Right side with bottom corner
path.lineTo(0, size.height - bottomRadius); path.lineTo(size.width - Dimens.borderRadiusL, size.height);
path.arcToPoint( path.arcToPoint(
Offset(bottomRadius, size.height), Offset(size.width, size.height - Dimens.borderRadiusL),
radius: circularRadius, radius: circularRadius,
clockwise: false, clockwise: false,
); );
} else {
// Left side with bottom corner
path.lineTo(0, size.height - Dimens.borderRadiusL);
path.arcToPoint(
Offset(Dimens.borderRadiusL, size.height),
radius: circularRadius,
clockwise: false,
);
// Bottom side with step // Bottom side with step
final allowedRadius = min(appendixHeight.abs() / 2, bottomRadius); final allowedRadius = min(appendixHeight.abs() / 2, Dimens.borderRadiusL);
path.lineTo(appendixWidth - allowedRadius, size.height); path.relativeLineTo(appendixWidth - allowedRadius * 2, 0);
path.arcToPoint( path.relativeArcToPoint(
Offset(appendixWidth, size.height - allowedRadius), Offset(allowedRadius, -allowedRadius),
radius: Radius.circular(allowedRadius), radius: Radius.circular(allowedRadius),
rotation: 90, rotation: 90,
clockwise: false, clockwise: false,
); );
path.lineTo(appendixWidth, size.height - appendixHeight + allowedRadius); path.relativeLineTo(0, -appendixHeight + allowedRadius * 2);
path.arcToPoint( path.relativeArcToPoint(
Offset(appendixWidth + allowedRadius, size.height - appendixHeight), Offset(allowedRadius, -allowedRadius),
radius: Radius.circular(allowedRadius), radius: Radius.circular(allowedRadius),
rotation: 90, rotation: 90,
); );
// Right side with bottom corner
path.lineTo(size.width - bottomRadius, size.height - appendixHeight);
path.arcToPoint(
Offset(size.width, size.height - appendixHeight - bottomRadius),
radius: circularRadius,
clockwise: false,
);
// Right side with bottom corner
path.lineTo(size.width - Dimens.borderRadiusL, size.height - appendixHeight);
path.arcToPoint(
Offset(size.width, size.height - appendixHeight - Dimens.borderRadiusL),
radius: circularRadius,
clockwise: false,
);
}
path.lineTo(size.width, 0); path.lineTo(size.width, 0);
path.close(); path.close();
canvas.drawPath(path, paint);
return path;
} }
@override @override

View file

@ -20,7 +20,9 @@ class MeteringTopBar extends StatelessWidget {
return CustomPaint( return CustomPaint(
painter: MeteringTopBarShape( painter: MeteringTopBarShape(
color: Theme.of(context).colorScheme.surface, color: Theme.of(context).colorScheme.surface,
appendixWidth: MediaQuery.of(context).size.width / 2 - Dimens.grid8 / 2 + Dimens.paddingM, appendixWidth: appendixHeight > 0
? MediaQuery.of(context).size.width / 2 - Dimens.grid8 + Dimens.paddingM
: MediaQuery.of(context).size.width / 2 + Dimens.grid8 - Dimens.paddingM,
appendixHeight: appendixHeight, appendixHeight: appendixHeight,
), ),
child: Padding( child: Padding(

View file

@ -22,15 +22,15 @@ class AnimatedDialog extends StatefulWidget {
class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProviderStateMixin { class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProviderStateMixin {
final GlobalKey _key = GlobalKey(); final GlobalKey _key = GlobalKey();
late Size _closedSize; late final Size _closedSize;
late Offset _closedOffset; late final Offset _closedOffset;
late final AnimationController _animationController; late final AnimationController _animationController;
late final CurvedAnimation _defaultCurvedAnimation; late final CurvedAnimation _defaultCurvedAnimation;
late final Animation<Color?> _barrierColorAnimation; late final Animation<Color?> _barrierColorAnimation;
late SizeTween _sizeTween; late final SizeTween _sizeTween;
late Animation<Size?> _sizeAnimation; late final Animation<Size?> _sizeAnimation;
late Animation<Size?> _offsetAnimation; late final Animation<Size?> _offsetAnimation;
late final Animation<double> _borderRadiusAnimation; late final Animation<double> _borderRadiusAnimation;
late final Animation<double> _closedOpacityAnimation; late final Animation<double> _closedOpacityAnimation;
late final Animation<double> _openedOpacityAnimation; late final Animation<double> _openedOpacityAnimation;
@ -88,7 +88,35 @@ class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProvide
), ),
); );
_setClosedOffset(); WidgetsBinding.instance.addPostFrameCallback((_) {
final mediaQuery = MediaQuery.of(context);
_closedSize = _key.currentContext!.size!;
_sizeTween = SizeTween(
begin: _closedSize,
end: widget.openedSize ??
Size(
mediaQuery.size.width -
mediaQuery.padding.horizontal -
Dimens.dialogMargin.horizontal,
mediaQuery.size.height - mediaQuery.padding.vertical - Dimens.dialogMargin.vertical,
),
);
_sizeAnimation = _sizeTween.animate(_defaultCurvedAnimation);
final renderBox = _key.currentContext!.findRenderObject()! as RenderBox;
_closedOffset = renderBox.localToGlobal(Offset.zero);
_offsetAnimation = SizeTween(
begin: Size(
_closedOffset.dx + _closedSize.width / 2,
_closedOffset.dy + _closedSize.height / 2,
),
end: Size(
mediaQuery.size.width / 2,
mediaQuery.size.height / 2 + mediaQuery.padding.top / 2 - mediaQuery.padding.bottom / 2,
),
).animate(_defaultCurvedAnimation);
});
} }
@override @override
@ -105,12 +133,6 @@ class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProvide
).animate(_defaultCurvedAnimation); ).animate(_defaultCurvedAnimation);
} }
@override
void didUpdateWidget(covariant AnimatedDialog oldWidget) {
super.didUpdateWidget(oldWidget);
_setClosedOffset();
}
@override @override
void dispose() { void dispose() {
_animationController.dispose(); _animationController.dispose();
@ -129,38 +151,6 @@ class AnimatedDialogState extends State<AnimatedDialog> with SingleTickerProvide
); );
} }
void _setClosedOffset() {
WidgetsBinding.instance.addPostFrameCallback((_) {
final renderBox = _key.currentContext?.findRenderObject()! as RenderBox?;
if (renderBox != null) {
final size = MediaQuery.sizeOf(context);
final padding = MediaQuery.paddingOf(context);
_closedSize = _key.currentContext!.size!;
_sizeTween = SizeTween(
begin: _closedSize,
end: widget.openedSize ??
Size(
size.width - padding.horizontal - Dimens.dialogMargin.horizontal,
size.height - padding.vertical - Dimens.dialogMargin.vertical,
),
);
_sizeAnimation = _sizeTween.animate(_defaultCurvedAnimation);
_closedOffset = renderBox.localToGlobal(Offset.zero);
_offsetAnimation = SizeTween(
begin: Size(
_closedOffset.dx + _closedSize.width / 2,
_closedOffset.dy + _closedSize.height / 2,
),
end: Size(
size.width / 2,
size.height / 2 + padding.top / 2 - padding.bottom / 2,
),
).animate(_defaultCurvedAnimation);
}
});
}
void _openDialog() { void _openDialog() {
Navigator.of(context).push( Navigator.of(context).push(
PageRouteBuilder( PageRouteBuilder(

View file

@ -84,7 +84,15 @@ class _InheritedListeners extends StatelessWidget {
context.read<MeteringBloc>().add(const FilmChangedEvent(Film.other())); context.read<MeteringBloc>().add(const FilmChangedEvent(Film.other()));
} }
}, },
child: child, child: MeteringScreenLayoutFeatureListener(
feature: MeteringScreenLayoutFeature.equipmentProfiles,
onDidChangeDependencies: (value) {
if (!value) {
EquipmentProfileProvider.of(context).setProfile(EquipmentProfiles.of(context).first);
}
},
child: child,
),
), ),
); );
} }

View file

@ -3,7 +3,6 @@ import 'package:lightmeter/data/models/metering_screen_layout_config.dart';
import 'package:lightmeter/generated/l10n.dart'; import 'package:lightmeter/generated/l10n.dart';
import 'package:lightmeter/providers/user_preferences_provider.dart'; import 'package:lightmeter/providers/user_preferences_provider.dart';
import 'package:lightmeter/res/dimens.dart'; import 'package:lightmeter/res/dimens.dart';
import 'package:m3_lightmeter_iap/m3_lightmeter_iap.dart';
class MeteringScreenLayoutFeaturesDialog extends StatefulWidget { class MeteringScreenLayoutFeaturesDialog extends StatefulWidget {
const MeteringScreenLayoutFeaturesDialog({super.key}); const MeteringScreenLayoutFeaturesDialog({super.key});
@ -26,23 +25,18 @@ class _MeteringScreenLayoutFeaturesDialogState extends State<MeteringScreenLayou
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
content: SizedBox( content: SizedBox(
width: double.maxFinite, width: double.maxFinite,
child: Column( child: ListView(
mainAxisSize: MainAxisSize.min, shrinkWrap: true,
children: [ children: [
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL), padding: const EdgeInsets.symmetric(horizontal: Dimens.paddingL),
child: Text(S.of(context).meteringScreenLayoutHint), child: Text(S.of(context).meteringScreenLayoutHint),
), ),
const SizedBox(height: Dimens.grid16), const SizedBox(height: Dimens.grid16),
ListView( _featureListTile(MeteringScreenLayoutFeature.equipmentProfiles),
shrinkWrap: true, _featureListTile(MeteringScreenLayoutFeature.extremeExposurePairs),
children: [ _featureListTile(MeteringScreenLayoutFeature.filmPicker),
_featureListTile(MeteringScreenLayoutFeature.equipmentProfiles), _featureListTile(MeteringScreenLayoutFeature.histogram),
_featureListTile(MeteringScreenLayoutFeature.extremeExposurePairs),
_featureListTile(MeteringScreenLayoutFeature.filmPicker),
_featureListTile(MeteringScreenLayoutFeature.histogram),
],
),
], ],
), ),
), ),
@ -54,9 +48,6 @@ class _MeteringScreenLayoutFeaturesDialogState extends State<MeteringScreenLayou
), ),
TextButton( TextButton(
onPressed: () { onPressed: () {
if (!_features[MeteringScreenLayoutFeature.equipmentProfiles]!) {
EquipmentProfileProvider.of(context).setProfile(EquipmentProfiles.of(context).first);
}
UserPreferencesProvider.of(context).setMeteringScreenLayout(_features); UserPreferencesProvider.of(context).setMeteringScreenLayout(_features);
Navigator.of(context).pop(); Navigator.of(context).pop();
}, },
@ -82,7 +73,7 @@ class _MeteringScreenLayoutFeaturesDialogState extends State<MeteringScreenLayou
String _toStringLocalized(BuildContext context, MeteringScreenLayoutFeature feature) { String _toStringLocalized(BuildContext context, MeteringScreenLayoutFeature feature) {
switch (feature) { switch (feature) {
case MeteringScreenLayoutFeature.equipmentProfiles: case MeteringScreenLayoutFeature.equipmentProfiles:
return S.of(context).meteringScreenLayoutHintEquipmentProfiles; return S.of(context).equipmentProfiles;
case MeteringScreenLayoutFeature.extremeExposurePairs: case MeteringScreenLayoutFeature.extremeExposurePairs:
return S.of(context).meteringScreenFeatureExtremeExposurePairs; return S.of(context).meteringScreenFeatureExtremeExposurePairs;
case MeteringScreenLayoutFeature.filmPicker: case MeteringScreenLayoutFeature.filmPicker:

View file

@ -1,7 +1,7 @@
name: lightmeter name: lightmeter
description: Lightmeter app inspired by Material 3 design system. description: Lightmeter app inspired by Material 3 design system.
publish_to: "none" publish_to: "none"
version: 0.14.1+40 version: 0.14.0+39
environment: environment:
sdk: ">=3.0.0 <4.0.0" sdk: ">=3.0.0 <4.0.0"