title_bar_widget.dart 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. import 'package:flutter/material.dart';
  2. import 'package:photos/theme/ente_theme.dart';
  3. import 'package:photos/ui/components/buttons/icon_button_widget.dart';
  4. class TitleBarWidget extends StatelessWidget {
  5. final IconButtonWidget? leading;
  6. final String? title;
  7. final String? caption;
  8. final Widget? flexibleSpaceTitle;
  9. final String? flexibleSpaceCaption;
  10. final List<Widget>? actionIcons;
  11. final bool isTitleH2WithoutLeading;
  12. final bool isFlexibleSpaceDisabled;
  13. final bool isOnTopOfScreen;
  14. final Color? backgroundColor;
  15. final bool isSliver;
  16. const TitleBarWidget({
  17. this.leading,
  18. this.title,
  19. this.caption,
  20. this.flexibleSpaceTitle,
  21. this.flexibleSpaceCaption,
  22. this.actionIcons,
  23. this.isTitleH2WithoutLeading = false,
  24. this.isFlexibleSpaceDisabled = false,
  25. this.isOnTopOfScreen = true,
  26. this.backgroundColor,
  27. this.isSliver = true,
  28. super.key,
  29. });
  30. @override
  31. Widget build(BuildContext context) {
  32. const toolbarHeight = 48.0;
  33. if (isSliver) {
  34. return SliverAppBar(
  35. backgroundColor: backgroundColor,
  36. primary: isOnTopOfScreen ? true : false,
  37. toolbarHeight: toolbarHeight,
  38. leadingWidth: 48,
  39. automaticallyImplyLeading: false,
  40. pinned: true,
  41. expandedHeight: isFlexibleSpaceDisabled ? toolbarHeight : 102,
  42. centerTitle: false,
  43. titleSpacing: 4,
  44. title: TitleWidget(
  45. title: title,
  46. caption: caption,
  47. isTitleH2WithoutLeading: isTitleH2WithoutLeading,
  48. ),
  49. actions: [
  50. Padding(
  51. padding: const EdgeInsets.symmetric(horizontal: 4),
  52. child: Row(
  53. children: _actionsWithPaddingInBetween(),
  54. ),
  55. ),
  56. ],
  57. leading: isTitleH2WithoutLeading
  58. ? null
  59. : leading ??
  60. IconButtonWidget(
  61. icon: Icons.arrow_back_outlined,
  62. iconButtonType: IconButtonType.primary,
  63. onTap: () {
  64. Navigator.pop(context);
  65. },
  66. ),
  67. flexibleSpace: isFlexibleSpaceDisabled
  68. ? null
  69. : FlexibleSpaceBarWidget(
  70. flexibleSpaceTitle,
  71. flexibleSpaceCaption,
  72. toolbarHeight,
  73. ),
  74. );
  75. } else {
  76. return AppBar(
  77. backgroundColor: backgroundColor,
  78. primary: isOnTopOfScreen ? true : false,
  79. toolbarHeight: toolbarHeight,
  80. leadingWidth: 48,
  81. automaticallyImplyLeading: false,
  82. centerTitle: false,
  83. titleSpacing: 4,
  84. title: TitleWidget(
  85. title: title,
  86. caption: caption,
  87. isTitleH2WithoutLeading: isTitleH2WithoutLeading,
  88. ),
  89. actions: [
  90. Padding(
  91. padding: const EdgeInsets.symmetric(horizontal: 4),
  92. child: Row(
  93. children: _actionsWithPaddingInBetween(),
  94. ),
  95. ),
  96. ],
  97. leading: isTitleH2WithoutLeading
  98. ? null
  99. : leading ??
  100. IconButtonWidget(
  101. icon: Icons.arrow_back_outlined,
  102. iconButtonType: IconButtonType.primary,
  103. onTap: () {
  104. Navigator.pop(context);
  105. },
  106. ),
  107. flexibleSpace: isFlexibleSpaceDisabled
  108. ? null
  109. : FlexibleSpaceBarWidget(
  110. flexibleSpaceTitle,
  111. flexibleSpaceCaption,
  112. toolbarHeight,
  113. ),
  114. );
  115. }
  116. }
  117. _actionsWithPaddingInBetween() {
  118. if (actionIcons == null) {
  119. return <Widget>[const SizedBox.shrink()];
  120. }
  121. final actions = <Widget>[];
  122. bool addWhiteSpace = false;
  123. final length = actionIcons!.length;
  124. int index = 0;
  125. if (length == 0) {
  126. return <Widget>[const SizedBox.shrink()];
  127. }
  128. if (length == 1) {
  129. return actionIcons;
  130. }
  131. while (index < length) {
  132. if (!addWhiteSpace) {
  133. actions.add(actionIcons![index]);
  134. index++;
  135. addWhiteSpace = true;
  136. } else {
  137. actions.add(const SizedBox(width: 4));
  138. addWhiteSpace = false;
  139. }
  140. }
  141. return actions;
  142. }
  143. }
  144. class TitleWidget extends StatelessWidget {
  145. final String? title;
  146. final String? caption;
  147. final bool isTitleH2WithoutLeading;
  148. const TitleWidget({
  149. this.title,
  150. this.caption,
  151. required this.isTitleH2WithoutLeading,
  152. super.key,
  153. });
  154. @override
  155. Widget build(BuildContext context) {
  156. final textTheme = getEnteTextTheme(context);
  157. return Padding(
  158. padding: EdgeInsets.only(left: isTitleH2WithoutLeading ? 16 : 0),
  159. child: Column(
  160. crossAxisAlignment: CrossAxisAlignment.start,
  161. mainAxisAlignment: MainAxisAlignment.start,
  162. children: [
  163. title == null
  164. ? const SizedBox.shrink()
  165. : Text(
  166. title!,
  167. style: isTitleH2WithoutLeading
  168. ? textTheme.h2Bold
  169. : textTheme.largeBold,
  170. ),
  171. caption == null || isTitleH2WithoutLeading
  172. ? const SizedBox.shrink()
  173. : Text(
  174. caption!,
  175. style: textTheme.miniMuted,
  176. ),
  177. ],
  178. ),
  179. );
  180. }
  181. }
  182. class FlexibleSpaceBarWidget extends StatelessWidget {
  183. final Widget? flexibleSpaceTitle;
  184. final String? flexibleSpaceCaption;
  185. final double toolbarHeight;
  186. const FlexibleSpaceBarWidget(
  187. this.flexibleSpaceTitle,
  188. this.flexibleSpaceCaption,
  189. this.toolbarHeight, {
  190. super.key,
  191. });
  192. @override
  193. Widget build(BuildContext context) {
  194. final textTheme = getEnteTextTheme(context);
  195. return FlexibleSpaceBar(
  196. background: SafeArea(
  197. child: Column(
  198. crossAxisAlignment: CrossAxisAlignment.start,
  199. mainAxisSize: MainAxisSize.min,
  200. children: <Widget>[
  201. SizedBox(height: toolbarHeight),
  202. Padding(
  203. padding: const EdgeInsets.symmetric(
  204. vertical: 4,
  205. horizontal: 16,
  206. ),
  207. child: Column(
  208. crossAxisAlignment: CrossAxisAlignment.start,
  209. children: [
  210. flexibleSpaceTitle == null
  211. ? const SizedBox.shrink()
  212. : flexibleSpaceTitle!,
  213. flexibleSpaceCaption == null
  214. ? const SizedBox.shrink()
  215. : Text(
  216. flexibleSpaceCaption!,
  217. style: textTheme.smallMuted,
  218. overflow: TextOverflow.ellipsis,
  219. maxLines: 1,
  220. ),
  221. ],
  222. ),
  223. ),
  224. ],
  225. ),
  226. ),
  227. );
  228. }
  229. }