menu_item_child_widgets.dart 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. import 'package:flutter/material.dart';
  2. import 'package:photos/models/execution_states.dart';
  3. import 'package:photos/theme/ente_theme.dart';
  4. import 'package:photos/ui/common/loading_widget.dart';
  5. class TrailingWidget extends StatefulWidget {
  6. final ValueNotifier executionStateNotifier;
  7. final IconData? trailingIcon;
  8. final Color? trailingIconColor;
  9. final Widget? trailingWidget;
  10. final bool trailingIconIsMuted;
  11. final double trailingExtraMargin;
  12. final bool showExecutionStates;
  13. const TrailingWidget({
  14. required this.executionStateNotifier,
  15. this.trailingIcon,
  16. this.trailingIconColor,
  17. this.trailingWidget,
  18. required this.trailingIconIsMuted,
  19. required this.trailingExtraMargin,
  20. required this.showExecutionStates,
  21. super.key,
  22. });
  23. @override
  24. State<TrailingWidget> createState() => _TrailingWidgetState();
  25. }
  26. class _TrailingWidgetState extends State<TrailingWidget> {
  27. Widget? trailingWidget;
  28. @override
  29. void initState() {
  30. widget.showExecutionStates
  31. ? widget.executionStateNotifier.addListener(_executionStateListener)
  32. : null;
  33. super.initState();
  34. }
  35. @override
  36. void dispose() {
  37. widget.executionStateNotifier.removeListener(_executionStateListener);
  38. super.dispose();
  39. }
  40. @override
  41. Widget build(BuildContext context) {
  42. if (trailingWidget == null || !widget.showExecutionStates) {
  43. _setTrailingIcon();
  44. }
  45. return AnimatedSwitcher(
  46. duration: const Duration(milliseconds: 175),
  47. switchInCurve: Curves.easeInExpo,
  48. switchOutCurve: Curves.easeOutExpo,
  49. child: trailingWidget,
  50. );
  51. }
  52. void _executionStateListener() {
  53. final colorScheme = getEnteColorScheme(context);
  54. setState(() {
  55. if (widget.executionStateNotifier.value == ExecutionState.idle) {
  56. _setTrailingIcon();
  57. } else if (widget.executionStateNotifier.value ==
  58. ExecutionState.inProgress) {
  59. trailingWidget = EnteLoadingWidget(
  60. color: colorScheme.strokeMuted,
  61. );
  62. } else if (widget.executionStateNotifier.value ==
  63. ExecutionState.successful) {
  64. trailingWidget = Icon(
  65. Icons.check_outlined,
  66. size: 22,
  67. color: colorScheme.primary500,
  68. );
  69. } else {
  70. trailingWidget = const SizedBox.shrink();
  71. }
  72. });
  73. }
  74. void _setTrailingIcon() {
  75. if (widget.trailingIcon != null) {
  76. trailingWidget = Padding(
  77. padding: EdgeInsets.only(
  78. right: widget.trailingExtraMargin,
  79. ),
  80. child: Icon(
  81. widget.trailingIcon,
  82. color: widget.trailingIconIsMuted
  83. ? getEnteColorScheme(context).strokeMuted
  84. : widget.trailingIconColor,
  85. ),
  86. );
  87. } else {
  88. trailingWidget = widget.trailingWidget ?? const SizedBox.shrink();
  89. }
  90. }
  91. }
  92. class ExpansionTrailingIcon extends StatelessWidget {
  93. final bool isExpanded;
  94. final IconData? trailingIcon;
  95. final Color? trailingIconColor;
  96. const ExpansionTrailingIcon({
  97. required this.isExpanded,
  98. this.trailingIcon,
  99. this.trailingIconColor,
  100. super.key,
  101. });
  102. @override
  103. Widget build(BuildContext context) {
  104. return AnimatedOpacity(
  105. duration: const Duration(milliseconds: 100),
  106. curve: Curves.easeInOut,
  107. opacity: isExpanded ? 0 : 1,
  108. child: AnimatedSwitcher(
  109. transitionBuilder: (child, animation) {
  110. return ScaleTransition(scale: animation, child: child);
  111. },
  112. duration: const Duration(milliseconds: 200),
  113. switchInCurve: Curves.easeOut,
  114. child: isExpanded
  115. ? const SizedBox.shrink()
  116. : Icon(
  117. trailingIcon,
  118. color: trailingIconColor,
  119. ),
  120. ),
  121. );
  122. }
  123. }
  124. class LeadingWidget extends StatelessWidget {
  125. final IconData? leadingIcon;
  126. final Color? leadingIconColor;
  127. final Widget? leadingIconWidget;
  128. // leadIconSize deafult value is 20.
  129. final double leadingIconSize;
  130. const LeadingWidget({
  131. required this.leadingIconSize,
  132. this.leadingIcon,
  133. this.leadingIconColor,
  134. this.leadingIconWidget,
  135. super.key,
  136. });
  137. @override
  138. Widget build(BuildContext context) {
  139. return Padding(
  140. padding: const EdgeInsets.only(right: 10),
  141. child: SizedBox(
  142. height: leadingIconSize,
  143. width: leadingIconSize,
  144. child: leadingIcon == null
  145. ? (leadingIconWidget != null
  146. ? FittedBox(
  147. fit: BoxFit.contain,
  148. child: leadingIconWidget,
  149. )
  150. : const SizedBox.shrink())
  151. : FittedBox(
  152. fit: BoxFit.contain,
  153. child: Icon(
  154. leadingIcon,
  155. color: leadingIconColor ??
  156. getEnteColorScheme(context).strokeBase,
  157. ),
  158. ),
  159. ),
  160. );
  161. }
  162. }