mirror of
https://github.com/vodemn/m3_lightmeter.git
synced 2024-11-22 07:20:39 +00:00
animated equipment list
This commit is contained in:
parent
7d535e8c0c
commit
24320313ce
1 changed files with 145 additions and 56 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:lightmeter/res/dimens.dart';
|
import 'package:lightmeter/res/dimens.dart';
|
||||||
|
@ -24,7 +26,8 @@ class EquipmentProfileContainer extends StatefulWidget {
|
||||||
State<EquipmentProfileContainer> createState() => EquipmentProfileContainerState();
|
State<EquipmentProfileContainer> createState() => EquipmentProfileContainerState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class EquipmentProfileContainerState extends State<EquipmentProfileContainer> {
|
class EquipmentProfileContainerState extends State<EquipmentProfileContainer>
|
||||||
|
with TickerProviderStateMixin {
|
||||||
late EquipmentProfileData _equipmentData = EquipmentProfileData(
|
late EquipmentProfileData _equipmentData = EquipmentProfileData(
|
||||||
id: widget.data.id,
|
id: widget.data.id,
|
||||||
name: widget.data.name,
|
name: widget.data.name,
|
||||||
|
@ -33,7 +36,12 @@ class EquipmentProfileContainerState extends State<EquipmentProfileContainer> {
|
||||||
shutterSpeedValues: widget.data.shutterSpeedValues,
|
shutterSpeedValues: widget.data.shutterSpeedValues,
|
||||||
isoValues: widget.data.isoValues,
|
isoValues: widget.data.isoValues,
|
||||||
);
|
);
|
||||||
bool _expanded = false;
|
|
||||||
|
late final AnimationController _controller = AnimationController(
|
||||||
|
duration: Dimens.durationM,
|
||||||
|
vsync: this,
|
||||||
|
);
|
||||||
|
bool get _expanded => _controller.isCompleted;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(EquipmentProfileContainer oldWidget) {
|
void didUpdateWidget(EquipmentProfileContainer oldWidget) {
|
||||||
|
@ -48,6 +56,12 @@ class EquipmentProfileContainerState extends State<EquipmentProfileContainer> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Card(
|
return Card(
|
||||||
|
@ -58,61 +72,52 @@ class EquipmentProfileContainerState extends State<EquipmentProfileContainer> {
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(
|
title: Row(
|
||||||
_equipmentData.name,
|
children: [
|
||||||
maxLines: 1,
|
_AnimatedNameLeading(controller: _controller),
|
||||||
overflow: TextOverflow.ellipsis,
|
const SizedBox(width: Dimens.grid8),
|
||||||
|
Text(
|
||||||
|
_equipmentData.name,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
trailing: Row(
|
trailing: Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
mainAxisAlignment: MainAxisAlignment.end,
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
_collapseButton(),
|
_AnimatedArrowButton(
|
||||||
|
controller: _controller,
|
||||||
|
onPressed: () => _expanded ? collapse() : expand(),
|
||||||
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: widget.onDelete,
|
onPressed: widget.onDelete,
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () => _expanded ? _showNameDialog() : expand(),
|
||||||
showDialog<String>(
|
|
||||||
context: context,
|
|
||||||
builder: (_) => EquipmentProfileNameDialog(initialValue: _equipmentData.name),
|
|
||||||
).then((value) {
|
|
||||||
if (value != null) {
|
|
||||||
_equipmentData = _equipmentData.copyWith(name: value);
|
|
||||||
widget.onUpdate(_equipmentData);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
AnimatedSize(
|
_AnimatedEquipmentListTiles(
|
||||||
alignment: Alignment.topCenter,
|
controller: _controller,
|
||||||
duration: Dimens.durationM,
|
equipmentData: _equipmentData,
|
||||||
child: _expanded
|
onApertureValuesSelected: (value) {
|
||||||
? EquipmentListTiles(
|
_equipmentData = _equipmentData.copyWith(apertureValues: value);
|
||||||
selectedApertureValues: _equipmentData.apertureValues,
|
widget.onUpdate(_equipmentData);
|
||||||
selectedIsoValues: _equipmentData.isoValues,
|
},
|
||||||
selectedNdValues: _equipmentData.ndValues,
|
onIsoValuesSelecred: (value) {
|
||||||
selectedShutterSpeedValues: _equipmentData.shutterSpeedValues,
|
_equipmentData = _equipmentData.copyWith(isoValues: value);
|
||||||
onApertureValuesSelected: (value) {
|
widget.onUpdate(_equipmentData);
|
||||||
_equipmentData = _equipmentData.copyWith(apertureValues: value);
|
},
|
||||||
widget.onUpdate(_equipmentData);
|
onNdValuesSelected: (value) {
|
||||||
},
|
_equipmentData = _equipmentData.copyWith(ndValues: value);
|
||||||
onIsoValuesSelecred: (value) {
|
widget.onUpdate(_equipmentData);
|
||||||
_equipmentData = _equipmentData.copyWith(isoValues: value);
|
},
|
||||||
widget.onUpdate(_equipmentData);
|
onShutterSpeedValuesSelected: (value) {
|
||||||
},
|
_equipmentData = _equipmentData.copyWith(shutterSpeedValues: value);
|
||||||
onNdValuesSelected: (value) {
|
widget.onUpdate(_equipmentData);
|
||||||
_equipmentData = _equipmentData.copyWith(ndValues: value);
|
},
|
||||||
widget.onUpdate(_equipmentData);
|
|
||||||
},
|
|
||||||
onShutterSpeedValuesSelected: (value) {
|
|
||||||
_equipmentData = _equipmentData.copyWith(shutterSpeedValues: value);
|
|
||||||
widget.onUpdate(_equipmentData);
|
|
||||||
},
|
|
||||||
)
|
|
||||||
: Row(mainAxisSize: MainAxisSize.max),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -120,18 +125,21 @@ class EquipmentProfileContainerState extends State<EquipmentProfileContainer> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _collapseButton() {
|
void _showNameDialog() {
|
||||||
return IconButton(
|
showDialog<String>(
|
||||||
onPressed: _expanded ? collapse : expand,
|
context: context,
|
||||||
icon: Icon(_expanded ? Icons.keyboard_arrow_up : Icons.keyboard_arrow_down),
|
builder: (_) => EquipmentProfileNameDialog(initialValue: _equipmentData.name),
|
||||||
);
|
).then((value) {
|
||||||
|
if (value != null) {
|
||||||
|
_equipmentData = _equipmentData.copyWith(name: value);
|
||||||
|
widget.onUpdate(_equipmentData);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void expand() {
|
void expand() {
|
||||||
widget.onExpand();
|
widget.onExpand();
|
||||||
setState(() {
|
_controller.forward();
|
||||||
_expanded = true;
|
|
||||||
});
|
|
||||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||||
Scrollable.ensureVisible(
|
Scrollable.ensureVisible(
|
||||||
context,
|
context,
|
||||||
|
@ -141,8 +149,89 @@ class EquipmentProfileContainerState extends State<EquipmentProfileContainer> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void collapse() {
|
void collapse() {
|
||||||
setState(() {
|
_controller.reverse();
|
||||||
_expanded = false;
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
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.grid24),
|
||||||
|
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 EquipmentProfileData 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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue