zefyr

ct_asset_picker.dart 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. library ct_assets_picker;
  2. import 'dart:developer';
  3. import 'dart:io';
  4. import 'dart:math' as math;
  5. import 'dart:typed_data';
  6. import 'dart:ui' as ui;
  7. import 'package:extended_image/extended_image.dart';
  8. import 'package:flutter/foundation.dart';
  9. import 'package:flutter/material.dart';
  10. import 'package:flutter/rendering.dart';
  11. import 'package:flutter/services.dart';
  12. import 'package:intl/intl.dart';
  13. import 'package:notus/notus.dart';
  14. import 'package:provider/provider.dart';
  15. import 'package:wechat_assets_picker/wechat_assets_picker.dart';
  16. import 'package:image_picker/image_picker.dart';
  17. import 'package:zefyr/src/widgets/iconfont.dart';
  18. import 'package:zefyr/src/widgets/theme.dart';
  19. import 'package:zefyr/src/widgets/toolbar.dart';
  20. export 'package:wechat_assets_picker/wechat_assets_picker.dart'
  21. show RequestType, AssetEntity, AssetType, PhotoManager;
  22. export 'package:image_picker/image_picker.dart' show CameraDevice;
  23. part 'src/constants/constants.dart';
  24. part 'src/constants/screens.dart';
  25. part 'src/delegate/asset_picker_builder_delegate.dart';
  26. part 'src/delegate/asset_picker_quick_builder_delegate.dart';
  27. part 'src/delegate/asset_picker_viewer_builder_delegate.dart';
  28. part 'src/delegate/asset_picker_sort_delegate.dart';
  29. part 'src/delegate/asset_picker_text_delegate.dart';
  30. part 'src/widget/slide_page_transition_builder.dart';
  31. part 'src/widget/asset_picker_viewer.dart';
  32. part 'src/widget/rounded_check_box.dart';
  33. part 'src/provider/asset_picker_provider.dart';
  34. part 'src/entity/asset_picker_entity.dart';
  35. class ExtendedAssetPicker {
  36. static Future<AssetPickerEntity> pickAssets(
  37. BuildContext context, {
  38. int maxAssets = 9,
  39. int pageSize = 320,
  40. int pathThumbSize = 200,
  41. int gridCount = 4,
  42. List<int> previewThumbSize,
  43. RequestType requestType,
  44. SpecialPickerType specialPickerType,
  45. List<AssetEntity> selectedAssets,
  46. Color themeColor,
  47. ThemeData pickerTheme,
  48. SortPathDelegate sortPathDelegate,
  49. AssetsPickerTextDelegate textDelegate,
  50. FilterOptionGroup filterOptions,
  51. WidgetBuilder specialItemBuilder,
  52. SpecialItemPosition specialItemPosition = SpecialItemPosition.none,
  53. bool allowSpecialItemWhenEmpty = false,
  54. Curve routeCurve = Curves.easeIn,
  55. Duration routeDuration = const Duration(milliseconds: 300),
  56. }) async {
  57. if (maxAssets == null || maxAssets < 1) {
  58. throw ArgumentError(
  59. 'maxAssets must be greater than 1.',
  60. );
  61. }
  62. if (pageSize != null && pageSize % gridCount != 0) {
  63. throw ArgumentError(
  64. 'pageSize must be a multiple of gridCount.',
  65. );
  66. }
  67. if (pickerTheme != null && themeColor != null) {
  68. throw ArgumentError(
  69. 'Theme and theme color cannot be set at the same time.',
  70. );
  71. }
  72. if (specialPickerType != null && requestType != null) {
  73. throw ArgumentError(
  74. 'specialPickerType and requestType cannot be set at the same time.',
  75. );
  76. } else {
  77. if (specialPickerType == SpecialPickerType.wechatMoment) {
  78. requestType = RequestType.common;
  79. } else {
  80. requestType ??= RequestType.image;
  81. }
  82. }
  83. if ((specialItemBuilder == null &&
  84. specialItemPosition != SpecialItemPosition.none) ||
  85. (specialItemBuilder != null &&
  86. specialItemPosition == SpecialItemPosition.none)) {
  87. throw ArgumentError('Custom item didn\'t set properly.');
  88. }
  89. final theme = Theme.of(context);
  90. try {
  91. final isPermissionGranted = await PhotoManager.requestPermission();
  92. if (isPermissionGranted) {
  93. final provider = ExtendedAssetPickerProvider(
  94. maxAssets: maxAssets,
  95. pageSize: pageSize,
  96. pathThumbSize: pathThumbSize,
  97. selectedAssets: selectedAssets,
  98. requestType: requestType,
  99. sortPathDelegate: sortPathDelegate ?? CustomSortPathDelegate(),
  100. filterOptions: filterOptions,
  101. routeDuration: routeDuration,
  102. );
  103. final Widget picker =
  104. ChangeNotifierProvider<DefaultAssetPickerProvider>.value(
  105. value: provider,
  106. child: AssetPicker<AssetEntity, AssetPathEntity>(
  107. key: Constants.pickerKey,
  108. builder: ExtendedAssetPickerBuilderDelegate(
  109. provider: provider,
  110. gridCount: gridCount,
  111. textDelegate: textDelegate ??
  112. (Intl.getCurrentLocale() == 'zh_CN'
  113. ? DefaultAssetsPickerTextDelegate()
  114. : EnglishTextDelegate()),
  115. themeColor: themeColor,
  116. pickerTheme: theme,
  117. previewThumbSize: previewThumbSize,
  118. specialPickerType: specialPickerType,
  119. specialItemPosition: specialItemPosition,
  120. specialItemBuilder: specialItemBuilder,
  121. allowSpecialItemWhenEmpty: allowSpecialItemWhenEmpty,
  122. ),
  123. ),
  124. );
  125. final result = await Navigator.of(
  126. context,
  127. rootNavigator: true,
  128. ).push<AssetPickerEntity>(
  129. SlidePageTransitionBuilder<AssetPickerEntity>(
  130. builder: picker,
  131. transitionCurve: routeCurve,
  132. transitionDuration: routeDuration,
  133. ),
  134. );
  135. return result;
  136. } else {
  137. return null;
  138. }
  139. } catch (e) {
  140. realDebugPrint('Error when calling assets picker: $e');
  141. return null;
  142. }
  143. }
  144. static Future<AssetEntity> pickSingleAsset(
  145. BuildContext context, {
  146. int pageSize = 320,
  147. int pathThumbSize = 200,
  148. int gridCount = 4,
  149. List<int> previewThumbSize,
  150. RequestType requestType,
  151. SpecialPickerType specialPickerType,
  152. List<AssetEntity> selectedAssets,
  153. Color themeColor,
  154. ThemeData pickerTheme,
  155. SortPathDelegate sortPathDelegate,
  156. AssetsPickerTextDelegate textDelegate,
  157. FilterOptionGroup filterOptions,
  158. WidgetBuilder specialItemBuilder,
  159. SpecialItemPosition specialItemPosition = SpecialItemPosition.none,
  160. bool allowSpecialItemWhenEmpty = false,
  161. Curve routeCurve = Curves.easeIn,
  162. Duration routeDuration = const Duration(milliseconds: 300),
  163. }) async {
  164. final result = await ExtendedAssetPicker.pickAssets(
  165. context,
  166. maxAssets: 1,
  167. pageSize: pageSize,
  168. pathThumbSize: pathThumbSize,
  169. gridCount: gridCount,
  170. previewThumbSize: previewThumbSize,
  171. requestType: requestType,
  172. specialPickerType: specialPickerType,
  173. themeColor: themeColor,
  174. pickerTheme: pickerTheme,
  175. sortPathDelegate: sortPathDelegate,
  176. textDelegate: textDelegate,
  177. filterOptions: filterOptions,
  178. specialItemBuilder: specialItemBuilder,
  179. specialItemPosition: specialItemPosition,
  180. allowSpecialItemWhenEmpty: allowSpecialItemWhenEmpty,
  181. routeCurve: routeCurve,
  182. routeDuration: routeDuration,
  183. );
  184. if (result != null) {
  185. return result.assets?.first;
  186. }
  187. return null;
  188. }
  189. static Future<File> getImageFromCamera({
  190. ImageSource source = ImageSource.camera,
  191. double maxWidth,
  192. double maxHeight,
  193. int imageQuality = 100,
  194. CameraDevice preferredCameraDevice = CameraDevice.rear,
  195. }) {
  196. return ImagePicker()
  197. .getImage(
  198. source: source,
  199. maxWidth: maxWidth,
  200. maxHeight: maxHeight,
  201. imageQuality: imageQuality,
  202. preferredCameraDevice: preferredCameraDevice)
  203. .then((result) {
  204. if (result != null) {
  205. return File(result.path);
  206. }
  207. return null;
  208. });
  209. }
  210. static Widget buildQuickPicker(
  211. BuildContext context, {
  212. AssetPickerProvider provider,
  213. int gridCount = 4,
  214. List<int> previewThumbSize,
  215. SpecialPickerType specialPickerType,
  216. Color themeColor,
  217. ThemeData pickerTheme,
  218. AssetsPickerTextDelegate textDelegate,
  219. WidgetBuilder specialItemBuilder,
  220. SpecialItemPosition specialItemPosition = SpecialItemPosition.none,
  221. bool allowSpecialItemWhenEmpty = false,
  222. }) {
  223. final theme = Theme.of(context);
  224. return ChangeNotifierProvider<DefaultAssetPickerProvider>.value(
  225. value: provider,
  226. child: AssetPicker<AssetEntity, AssetPathEntity>(
  227. key: Constants.pickerKey,
  228. builder: ExtendedAssetPickerQuickBuilderDelegate(
  229. provider: provider,
  230. textDelegate: textDelegate ??
  231. (Intl.getCurrentLocale() == 'zh_CN'
  232. ? ExtendedChineseTextDelegate()
  233. : ExtendedEnglishTextDelegate()),
  234. themeColor: themeColor,
  235. pickerTheme: theme,
  236. previewThumbSize: previewThumbSize,
  237. specialPickerType: specialPickerType,
  238. specialItemPosition: specialItemPosition,
  239. specialItemBuilder: specialItemBuilder,
  240. allowSpecialItemWhenEmpty: allowSpecialItemWhenEmpty,
  241. ),
  242. ),
  243. );
  244. }
  245. }