file_icons_widget.dart 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import 'package:flutter/material.dart';
  2. import 'package:photos/ente_theme_data.dart';
  3. import 'package:photos/models/collection.dart';
  4. import 'package:photos/models/trash_file.dart';
  5. import 'package:photos/theme/colors.dart';
  6. import 'package:photos/ui/sharing/user_avator_widget.dart';
  7. import 'package:photos/utils/date_time_util.dart';
  8. class ThumbnailPlaceHolder extends StatelessWidget {
  9. const ThumbnailPlaceHolder({Key? key}) : super(key: key);
  10. @override
  11. Widget build(BuildContext context) {
  12. return Container(
  13. alignment: Alignment.center,
  14. color: Theme.of(context).colorScheme.galleryThumbBackgroundColor,
  15. );
  16. }
  17. }
  18. class UnSyncedIcon extends StatelessWidget {
  19. const UnSyncedIcon({Key? key}) : super(key: key);
  20. @override
  21. Widget build(BuildContext context) {
  22. return const _BottomLeftOverlayIcon(
  23. Icons.cloud_off_outlined,
  24. baseSize: 18,
  25. );
  26. }
  27. }
  28. class DeviceIcon extends StatelessWidget {
  29. const DeviceIcon({Key? key}) : super(key: key);
  30. @override
  31. Widget build(BuildContext context) {
  32. return const _BottomLeftOverlayIcon(
  33. Icons.mobile_friendly_rounded,
  34. baseSize: 18,
  35. color: Color.fromRGBO(1, 222, 77, 0.8),
  36. );
  37. }
  38. }
  39. class CloudOnlyIcon extends StatelessWidget {
  40. const CloudOnlyIcon({Key? key}) : super(key: key);
  41. @override
  42. Widget build(BuildContext context) {
  43. return const _BottomLeftOverlayIcon(
  44. Icons.cloud_done_outlined,
  45. baseSize: 18,
  46. color: Color.fromRGBO(1, 222, 77, 0.8),
  47. );
  48. }
  49. }
  50. class FavoriteOverlayIcon extends StatelessWidget {
  51. const FavoriteOverlayIcon({Key? key}) : super(key: key);
  52. @override
  53. Widget build(BuildContext context) {
  54. return const _BottomLeftOverlayIcon(
  55. Icons.favorite_rounded,
  56. baseSize: 22,
  57. );
  58. }
  59. }
  60. class ArchiveOverlayIcon extends StatelessWidget {
  61. const ArchiveOverlayIcon({Key? key}) : super(key: key);
  62. @override
  63. Widget build(BuildContext context) {
  64. return const _BottomLeftOverlayIcon(
  65. Icons.archive_outlined,
  66. color: fixedStrokeMutedWhite,
  67. );
  68. }
  69. }
  70. class LivePhotoOverlayIcon extends StatelessWidget {
  71. const LivePhotoOverlayIcon({Key? key}) : super(key: key);
  72. @override
  73. Widget build(BuildContext context) {
  74. return const _BottomRightOverlayIcon(
  75. Icons.album_outlined,
  76. baseSize: 18,
  77. );
  78. }
  79. }
  80. class VideoOverlayIcon extends StatelessWidget {
  81. const VideoOverlayIcon({Key? key}) : super(key: key);
  82. @override
  83. Widget build(BuildContext context) {
  84. return const SizedBox(
  85. height: 64,
  86. child: Icon(
  87. Icons.play_circle_outline,
  88. size: 40,
  89. color: Colors.white70,
  90. ),
  91. );
  92. }
  93. }
  94. class OwnerAvatarOverlayIcon extends StatelessWidget {
  95. final User user;
  96. const OwnerAvatarOverlayIcon(this.user, {Key? key}) : super(key: key);
  97. @override
  98. Widget build(BuildContext context) {
  99. return Align(
  100. alignment: Alignment.topRight,
  101. child: Padding(
  102. padding: const EdgeInsets.only(right: 4, top: 4),
  103. child: UserAvatarWidget(
  104. user,
  105. type: AvatarType.tiny,
  106. thumbnailView: true,
  107. ),
  108. ),
  109. );
  110. }
  111. }
  112. class TrashedFileOverlayText extends StatelessWidget {
  113. final TrashFile file;
  114. const TrashedFileOverlayText(this.file, {Key? key}) : super(key: key);
  115. @override
  116. Widget build(BuildContext context) {
  117. return Container(
  118. decoration: BoxDecoration(
  119. gradient: LinearGradient(
  120. begin: Alignment.bottomCenter,
  121. end: Alignment.topCenter,
  122. colors: [Colors.black.withOpacity(0.33), Colors.transparent],
  123. ),
  124. ),
  125. alignment: Alignment.bottomCenter,
  126. padding: const EdgeInsets.only(bottom: 5),
  127. child: Text(
  128. daysLeft(file.deleteBy),
  129. style: Theme.of(context)
  130. .textTheme
  131. .subtitle2!
  132. .copyWith(color: Colors.white), //same for both themes
  133. ),
  134. );
  135. }
  136. }
  137. // Base variations
  138. /// Icon overlay in the bottom left.
  139. ///
  140. /// This usually indicates ente specific state of a file, e.g. if it is
  141. /// favorited/archived.
  142. class _BottomLeftOverlayIcon extends StatelessWidget {
  143. final IconData icon;
  144. /// Overriddable color. Default is a fixed white.
  145. final Color color;
  146. /// Overriddable default size. This is just the initial hint, the actual size
  147. /// is dynamic based on the widget's width (so that we show smaller icons in
  148. /// smaller thumbnails).
  149. final double baseSize;
  150. const _BottomLeftOverlayIcon(
  151. this.icon, {
  152. Key? key,
  153. this.baseSize = 24,
  154. this.color = Colors.white, // fixed
  155. }) : super(key: key);
  156. @override
  157. Widget build(BuildContext context) {
  158. return LayoutBuilder(
  159. builder: (context, constraints) {
  160. double inset = 4;
  161. double size = baseSize;
  162. if (constraints.hasBoundedWidth) {
  163. final w = constraints.maxWidth;
  164. if (w > 125) {
  165. size = 24;
  166. } else if (w < 75) {
  167. inset = 3;
  168. size = 16;
  169. }
  170. }
  171. return Container(
  172. decoration: const BoxDecoration(
  173. gradient: LinearGradient(
  174. begin: Alignment.bottomLeft,
  175. end: Alignment.center,
  176. colors: [
  177. Color.fromRGBO(0, 0, 0, 0.14),
  178. Color.fromRGBO(0, 0, 0, 0.05),
  179. Color.fromRGBO(0, 0, 0, 0.0),
  180. ],
  181. stops: [0, 0.6, 1],
  182. ),
  183. ),
  184. child: Align(
  185. alignment: Alignment.bottomLeft,
  186. child: Padding(
  187. padding: EdgeInsets.only(left: inset, bottom: inset),
  188. child: Icon(
  189. icon,
  190. size: size,
  191. color: color,
  192. ),
  193. ),
  194. ),
  195. );
  196. },
  197. );
  198. }
  199. }
  200. /// Icon overlay in the bottom right.
  201. ///
  202. /// This usually indicates information about the file itself, e.g. whether it is
  203. /// a live photo, or the duration of the video.
  204. class _BottomRightOverlayIcon extends StatelessWidget {
  205. final IconData icon;
  206. /// Overriddable color. Default is a fixed white.
  207. final Color color;
  208. /// Overriddable default size. This is just the initial hint, the actual size
  209. /// is dynamic based on the widget's width (so that we show smaller icons in
  210. /// smaller thumbnails).
  211. final double baseSize;
  212. const _BottomRightOverlayIcon(
  213. this.icon, {
  214. Key? key,
  215. this.baseSize = 24,
  216. this.color = Colors.white, // fixed
  217. }) : super(key: key);
  218. @override
  219. Widget build(BuildContext context) {
  220. return LayoutBuilder(
  221. builder: (context, constraints) {
  222. double inset = 4;
  223. double size = baseSize;
  224. if (constraints.hasBoundedWidth) {
  225. final w = constraints.maxWidth;
  226. if (w > 120) {
  227. size = 24;
  228. } else if (w < 75) {
  229. inset = 3;
  230. size = 16;
  231. }
  232. }
  233. return Container(
  234. decoration: const BoxDecoration(
  235. gradient: LinearGradient(
  236. begin: Alignment.bottomRight,
  237. end: Alignment.center,
  238. colors: [
  239. Color.fromRGBO(0, 0, 0, 0.14),
  240. Color.fromRGBO(0, 0, 0, 0.05),
  241. Color.fromRGBO(0, 0, 0, 0.0),
  242. ],
  243. stops: [0, 0.6, 1],
  244. ),
  245. ),
  246. child: Align(
  247. alignment: Alignment.bottomRight,
  248. child: Padding(
  249. padding: EdgeInsets.only(bottom: inset, right: inset),
  250. child: Icon(
  251. icon,
  252. size: size,
  253. color: color,
  254. ),
  255. ),
  256. ),
  257. );
  258. },
  259. );
  260. }
  261. }