Kaynağa Gözat

Merge branch 'master' into fix-number

CaiJingLong 6 yıl önce
ebeveyn
işleme
7a844b2091
No account linked to committer's email address

+ 13
- 0
.vscode/launch.json Dosyayı Görüntüle

1
+{
2
+    // 使用 IntelliSense 了解相关属性。 
3
+    // 悬停以查看现有属性的描述。
4
+    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
5
+    "version": "0.2.0",
6
+    "configurations": [
7
+        {
8
+            "name": "Flutter",
9
+            "request": "launch",
10
+            "type": "dart"
11
+        }
12
+    ]
13
+}

+ 1
- 1
README.md Dosyayı Görüntüle

44
 
44
 
45
 ```dart
45
 ```dart
46
 void _pickImage() async {
46
 void _pickImage() async {
47
-    List<AssetEntity> imgList = await PhotoPicker.pickImage(
47
+    List<AssetEntity> imgList = await PhotoPicker.pickAsset(
48
       context: context,
48
       context: context,
49
       // BuildContext requied
49
       // BuildContext requied
50
 
50
 

+ 9
- 6
example/lib/main.dart Dosyayı Görüntüle

31
   String currentSelected = "";
31
   String currentSelected = "";
32
 
32
 
33
   void _pickImage() async {
33
   void _pickImage() async {
34
-    List<AssetEntity> imgList = await PhotoPicker.pickImage(
34
+    List<AssetEntity> imgList = await PhotoPicker.pickAsset(
35
+      // BuildContext required
35
       context: context,
36
       context: context,
36
-      // BuildContext requied
37
 
37
 
38
       /// The following are optional parameters.
38
       /// The following are optional parameters.
39
       themeColor: Colors.green,
39
       themeColor: Colors.green,
50
       // max picker image count
50
       // max picker image count
51
       provider: I18nProvider.chinese,
51
       provider: I18nProvider.chinese,
52
       // i18n provider ,default is chinese. , you can custom I18nProvider or use ENProvider()
52
       // i18n provider ,default is chinese. , you can custom I18nProvider or use ENProvider()
53
-      rowCount: 5,
53
+      rowCount: 3,
54
       // item row count
54
       // item row count
55
       textColor: Colors.white,
55
       textColor: Colors.white,
56
       // text color
56
       // text color
61
       checkBoxBuilderDelegate: DefaultCheckBoxBuilderDelegate(
61
       checkBoxBuilderDelegate: DefaultCheckBoxBuilderDelegate(
62
         activeColor: Colors.white,
62
         activeColor: Colors.white,
63
         unselectedColor: Colors.white,
63
         unselectedColor: Colors.white,
64
-      ), // default is DefaultCheckBoxBuilderDelegate ,or you make custom delegate to create checkbox
64
+      ),
65
+      // default is DefaultCheckBoxBuilderDelegate ,or you make custom delegate to create checkbox
66
+
67
+      loadingDelegate: this,
68
+      // if you want to build custom loading widget,extends LoadingDelegate, [see example/lib/main.dart]
65
 
69
 
66
-      loadingDelegate:
67
-          this, // if you want to build custom loading widget,extends LoadingDelegate, [see example/lib/main.dart]
70
+      badgeDelegate: const DurationBadgeDelegate(),
68
     );
71
     );
69
 
72
 
70
     if (imgList == null) {
73
     if (imgList == null) {

+ 50
- 4
lib/photo.dart Dosyayı Görüntüle

3
 import 'dart:async';
3
 import 'dart:async';
4
 
4
 
5
 import 'package:flutter/material.dart';
5
 import 'package:flutter/material.dart';
6
+import 'package:photo/src/delegate/badge_delegate.dart';
6
 import 'package:photo/src/delegate/checkbox_builder_delegate.dart';
7
 import 'package:photo/src/delegate/checkbox_builder_delegate.dart';
7
 import 'package:photo/src/delegate/loading_delegate.dart';
8
 import 'package:photo/src/delegate/loading_delegate.dart';
8
 import 'package:photo/src/delegate/sort_delegate.dart';
9
 import 'package:photo/src/delegate/sort_delegate.dart';
17
 export 'package:photo/src/delegate/sort_delegate.dart';
18
 export 'package:photo/src/delegate/sort_delegate.dart';
18
 export 'package:photo/src/provider/i18n_provider.dart'
19
 export 'package:photo/src/provider/i18n_provider.dart'
19
     show I18NCustomProvider, I18nProvider, CNProvider, ENProvider;
20
     show I18NCustomProvider, I18nProvider, CNProvider, ENProvider;
21
+export 'package:photo/src/delegate/badge_delegate.dart';
20
 
22
 
21
 class PhotoPicker {
23
 class PhotoPicker {
22
   static PhotoPicker _instance;
24
   static PhotoPicker _instance;
30
 
32
 
31
   static const String rootRouteName = "photo_picker_image";
33
   static const String rootRouteName = "photo_picker_image";
32
 
34
 
35
+  /// use new method [pickAsset]
36
+  ///
37
+  /// This method will be removed in the future.
38
+  @deprecated
39
+  static Future<List<AssetEntity>> pickImage({
40
+    @required BuildContext context,
41
+    int rowCount = 4,
42
+    int maxSelected = 9,
43
+    double padding = 0.5,
44
+    double itemRadio = 1.0,
45
+    Color themeColor,
46
+    Color dividerColor,
47
+    Color textColor,
48
+    Color disableColor,
49
+    int thumbSize = 64,
50
+    I18nProvider provider = I18nProvider.chinese,
51
+    SortDelegate sortDelegate,
52
+    CheckBoxBuilderDelegate checkBoxBuilderDelegate,
53
+    LoadingDelegate loadingDelegate,
54
+  }) {
55
+    return pickAsset(
56
+      context: context,
57
+      rowCount: rowCount,
58
+      maxSelected: maxSelected,
59
+      padding: padding,
60
+      itemRadio: itemRadio,
61
+      themeColor: themeColor,
62
+      dividerColor: dividerColor,
63
+      textColor: textColor,
64
+      disableColor: disableColor,
65
+      thumbSize: thumbSize,
66
+      provider: provider,
67
+      sortDelegate: sortDelegate,
68
+      checkBoxBuilderDelegate: checkBoxBuilderDelegate,
69
+      loadingDelegate: loadingDelegate,
70
+    );
71
+  }
72
+
33
   /// 没有授予权限的时候,会开启一个dialog去帮助用户去应用设置页面开启权限
73
   /// 没有授予权限的时候,会开启一个dialog去帮助用户去应用设置页面开启权限
34
-  /// 确定开启设置页面,取消关闭弹窗
74
+  /// 确定开启设置页面,取消关闭弹窗,无论选择什么,返回值都是null
35
   ///
75
   ///
36
   ///
76
   ///
37
   /// 当用户给予权限后
77
   /// 当用户给予权限后
38
   ///
78
   ///
39
   ///   当用户确定时,返回一个图片[AssetEntity]列表
79
   ///   当用户确定时,返回一个图片[AssetEntity]列表
40
   ///
80
   ///
41
-  ///   当用户取消时
81
+  ///   当用户取消时返回一个空数组
82
+  ///
83
+  /// 关于参数可以查看readme文档介绍
42
   ///
84
   ///
43
   /// if user not grand permission, then return null and show a dialog to help user open setting.
85
   /// if user not grand permission, then return null and show a dialog to help user open setting.
44
-  /// sure is open setting cancel ,cancel to dismiss dialog
86
+  /// sure is open setting cancel ,cancel to dismiss dialog, return null
45
   ///
87
   ///
46
   /// when user give permission.
88
   /// when user give permission.
47
   ///
89
   ///
48
   ///   when user sure , return a [AssetEntity] of [List]
90
   ///   when user sure , return a [AssetEntity] of [List]
49
   ///
91
   ///
50
   ///   when user cancel selected,result is empty list
92
   ///   when user cancel selected,result is empty list
51
-  static Future<List<AssetEntity>> pickImage({
93
+  ///
94
+  /// params see readme.md
95
+  static Future<List<AssetEntity>> pickAsset({
52
     @required BuildContext context,
96
     @required BuildContext context,
53
     int rowCount = 4,
97
     int rowCount = 4,
54
     int maxSelected = 9,
98
     int maxSelected = 9,
63
     SortDelegate sortDelegate,
107
     SortDelegate sortDelegate,
64
     CheckBoxBuilderDelegate checkBoxBuilderDelegate,
108
     CheckBoxBuilderDelegate checkBoxBuilderDelegate,
65
     LoadingDelegate loadingDelegate,
109
     LoadingDelegate loadingDelegate,
110
+    BadgeDelegate badgeDelegate = const DefaultBadgeDelegate(),
66
   }) {
111
   }) {
67
     assert(provider != null, "provider must be not null");
112
     assert(provider != null, "provider must be not null");
68
     assert(context != null, "context must be not null");
113
     assert(context != null, "context must be not null");
90
       sortDelegate: sortDelegate,
135
       sortDelegate: sortDelegate,
91
       checkBoxBuilderDelegate: checkBoxBuilderDelegate,
136
       checkBoxBuilderDelegate: checkBoxBuilderDelegate,
92
       loadingDelegate: loadingDelegate,
137
       loadingDelegate: loadingDelegate,
138
+      badgeDelegate: badgeDelegate,
93
     );
139
     );
94
 
140
 
95
     return PhotoPicker()._pickImage(
141
     return PhotoPicker()._pickImage(

+ 83
- 0
lib/src/delegate/badge_delegate.dart Dosyayı Görüntüle

1
+import 'package:flutter/material.dart';
2
+import 'package:photo_manager/photo_manager.dart';
3
+
4
+abstract class BadgeDelegate {
5
+  const BadgeDelegate();
6
+
7
+  Widget buildBadge(BuildContext context, AssetType type, Duration duration);
8
+}
9
+
10
+class DefaultBadgeDelegate extends BadgeDelegate {
11
+  final AlignmentGeometry alignment;
12
+
13
+  const DefaultBadgeDelegate({
14
+    this.alignment = Alignment.topLeft,
15
+  });
16
+
17
+  @override
18
+  Widget buildBadge(BuildContext context, AssetType type, Duration duration) {
19
+    if (type == AssetType.video) {
20
+      return Padding(
21
+        padding: const EdgeInsets.all(2.0),
22
+        child: Align(
23
+          alignment: alignment,
24
+          child: Container(
25
+            decoration: BoxDecoration(
26
+              color: Theme.of(context).primaryColor,
27
+              borderRadius: BorderRadius.circular(3.0),
28
+            ),
29
+            child: Text(
30
+              "video",
31
+              style: const TextStyle(
32
+                fontSize: 12.0,
33
+                color: Colors.white,
34
+              ),
35
+            ),
36
+            padding: const EdgeInsets.all(4.0),
37
+          ),
38
+        ),
39
+      );
40
+    }
41
+
42
+    return Container();
43
+  }
44
+}
45
+
46
+class DurationBadgeDelegate extends BadgeDelegate {
47
+  final AlignmentGeometry alignment;
48
+  const DurationBadgeDelegate({this.alignment = Alignment.bottomRight});
49
+
50
+  @override
51
+  Widget buildBadge(BuildContext context, AssetType type, Duration duration) {
52
+    if (type == AssetType.video) {
53
+      var s = duration.inSeconds;
54
+      var m = duration.inMinutes;
55
+      var h = duration.inHours;
56
+
57
+      String text =
58
+          "$h:${m.toString().padLeft(2, '0')}:${s.toString().padLeft(2, '0')}";
59
+
60
+      return Padding(
61
+        padding: const EdgeInsets.all(2.0),
62
+        child: Align(
63
+          alignment: alignment,
64
+          child: Container(
65
+            decoration: BoxDecoration(
66
+              color: Theme.of(context).primaryColor.withOpacity(0.65),
67
+            ),
68
+            child: Text(
69
+              text,
70
+              style: const TextStyle(
71
+                fontSize: 12.0,
72
+                color: Colors.white,
73
+              ),
74
+            ),
75
+            padding: const EdgeInsets.all(4.0),
76
+          ),
77
+        ),
78
+      );
79
+    }
80
+
81
+    return Container();
82
+  }
83
+}

+ 4
- 0
lib/src/entity/options.dart Dosyayı Görüntüle

1
 import 'package:flutter/material.dart';
1
 import 'package:flutter/material.dart';
2
+import 'package:photo/src/delegate/badge_delegate.dart';
2
 import 'package:photo/src/delegate/checkbox_builder_delegate.dart';
3
 import 'package:photo/src/delegate/checkbox_builder_delegate.dart';
3
 import 'package:photo/src/delegate/loading_delegate.dart';
4
 import 'package:photo/src/delegate/loading_delegate.dart';
4
 import 'package:photo/src/delegate/sort_delegate.dart';
5
 import 'package:photo/src/delegate/sort_delegate.dart';
28
 
29
 
29
   final LoadingDelegate loadingDelegate;
30
   final LoadingDelegate loadingDelegate;
30
 
31
 
32
+  final BadgeDelegate badgeDelegate;
33
+
31
   const Options({
34
   const Options({
32
     this.rowCount,
35
     this.rowCount,
33
     this.maxSelected,
36
     this.maxSelected,
41
     this.sortDelegate,
44
     this.sortDelegate,
42
     this.checkBoxBuilderDelegate,
45
     this.checkBoxBuilderDelegate,
43
     this.loadingDelegate,
46
     this.loadingDelegate,
47
+    this.badgeDelegate,
44
   });
48
   });
45
 }
49
 }

+ 55
- 19
lib/src/ui/page/photo_main_page.dart Dosyayı Görüntüle

1
 import 'dart:typed_data';
1
 import 'dart:typed_data';
2
 
2
 
3
 import 'package:flutter/material.dart';
3
 import 'package:flutter/material.dart';
4
+import 'package:photo/src/delegate/badge_delegate.dart';
4
 import 'package:photo/src/delegate/loading_delegate.dart';
5
 import 'package:photo/src/delegate/loading_delegate.dart';
5
 import 'package:photo/src/engine/lru_cache.dart';
6
 import 'package:photo/src/engine/lru_cache.dart';
6
 import 'package:photo/src/entity/options.dart';
7
 import 'package:photo/src/entity/options.dart';
190
 
191
 
191
   Widget _buildItem(BuildContext context, int index) {
192
   Widget _buildItem(BuildContext context, int index) {
192
     var data = list[index];
193
     var data = list[index];
193
-    return GestureDetector(
194
-      onTap: () => _onItemClick(data, index),
195
-      child: Stack(
196
-        children: <Widget>[
197
-          ImageItem(
198
-            entity: data,
199
-            themeColor: themeColor,
200
-            size: options.thumbSize,
201
-            loadingDelegate: options.loadingDelegate,
202
-          ),
203
-          _buildMask(containsEntity(data)),
204
-          _buildSelected(data),
205
-        ],
194
+    return RepaintBoundary(
195
+      child: GestureDetector(
196
+        onTap: () => _onItemClick(data, index),
197
+        child: Stack(
198
+          children: <Widget>[
199
+            ImageItem(
200
+              entity: data,
201
+              themeColor: themeColor,
202
+              size: options.thumbSize,
203
+              loadingDelegate: options.loadingDelegate,
204
+              badgeDelegate: options.badgeDelegate,
205
+            ),
206
+            _buildMask(containsEntity(data)),
207
+            _buildSelected(data),
208
+          ],
209
+        ),
206
       ),
210
       ),
207
     );
211
     );
208
   }
212
   }
491
 
495
 
492
   final LoadingDelegate loadingDelegate;
496
   final LoadingDelegate loadingDelegate;
493
 
497
 
498
+  final BadgeDelegate badgeDelegate;
499
+
494
   const ImageItem({
500
   const ImageItem({
495
     Key key,
501
     Key key,
496
     this.entity,
502
     this.entity,
497
     this.themeColor,
503
     this.themeColor,
498
     this.size = 64,
504
     this.size = 64,
499
     this.loadingDelegate,
505
     this.loadingDelegate,
506
+    this.badgeDelegate,
500
   }) : super(key: key);
507
   }) : super(key: key);
501
 
508
 
502
   @override
509
   @override
503
   Widget build(BuildContext context) {
510
   Widget build(BuildContext context) {
504
     var thumb = ImageLruCache.getData(entity, size);
511
     var thumb = ImageLruCache.getData(entity, size);
505
     if (thumb != null) {
512
     if (thumb != null) {
506
-      return _buildImageItem(thumb);
513
+      return _buildImageItem(context, thumb);
507
     }
514
     }
508
 
515
 
509
     return FutureBuilder<Uint8List>(
516
     return FutureBuilder<Uint8List>(
513
         if (snapshot.connectionState == ConnectionState.done &&
520
         if (snapshot.connectionState == ConnectionState.done &&
514
             futureData != null) {
521
             futureData != null) {
515
           ImageLruCache.setData(entity, size, futureData);
522
           ImageLruCache.setData(entity, size, futureData);
516
-          return _buildImageItem(futureData);
523
+          return _buildImageItem(context, futureData);
517
         }
524
         }
518
         return Center(
525
         return Center(
519
-          child:
520
-              loadingDelegate.buildPreviewLoading(context, entity, themeColor),
526
+          child: loadingDelegate.buildPreviewLoading(
527
+            context,
528
+            entity,
529
+            themeColor,
530
+          ),
521
         );
531
         );
522
       },
532
       },
523
     );
533
     );
524
   }
534
   }
525
 
535
 
526
-  Widget _buildImageItem(Uint8List data) {
527
-    return Image.memory(
536
+  Widget _buildImageItem(BuildContext context, Uint8List data) {
537
+    var image = Image.memory(
528
       data,
538
       data,
529
       width: double.infinity,
539
       width: double.infinity,
530
       height: double.infinity,
540
       height: double.infinity,
531
       fit: BoxFit.cover,
541
       fit: BoxFit.cover,
532
     );
542
     );
543
+    // FutureBuilder()
544
+    var badge = FutureBuilder<Duration>(
545
+      future: entity.videoDuration,
546
+      builder: (ctx, snapshot) {
547
+        if (snapshot.hasData && snapshot != null) {
548
+          var buildBadge =
549
+              badgeDelegate?.buildBadge(context, entity.type, snapshot.data);
550
+          if (buildBadge == null) {
551
+            return Container();
552
+          } else {
553
+            return buildBadge;
554
+          }
555
+        } else {
556
+          return Container();
557
+        }
558
+      },
559
+    );
560
+
561
+    return Stack(
562
+      children: <Widget>[
563
+        image,
564
+        IgnorePointer(
565
+          child: badge,
566
+        ),
567
+      ],
568
+    );
533
   }
569
   }
534
 }
570
 }

+ 27
- 25
lib/src/ui/page/photo_preview_page.dart Dosyayı Görüntüle

267
 
267
 
268
   Widget _buildThumbItem(BuildContext context, int index) {
268
   Widget _buildThumbItem(BuildContext context, int index) {
269
     var item = previewList[index];
269
     var item = previewList[index];
270
-    return GestureDetector(
271
-      onTap: () => changeSelected(item, index),
272
-      child: Container(
273
-        width: 80.0,
274
-        child: Stack(
275
-          children: <Widget>[
276
-            ImageItem(
277
-              themeColor: themeColor,
278
-              entity: item,
279
-              size: options.thumbSize,
280
-              loadingDelegate: options.loadingDelegate,
281
-            ),
282
-            IgnorePointer(
283
-              child: StreamBuilder(
284
-                stream: pageStream,
285
-                builder: (BuildContext context, AsyncSnapshot snapshot) {
286
-                  if (selectedList.contains(item)) {
287
-                    return Container();
288
-                  }
289
-                  return Container(
290
-                    color: Colors.white.withOpacity(0.5),
291
-                  );
292
-                },
270
+    return RepaintBoundary(
271
+      child: GestureDetector(
272
+        onTap: () => changeSelected(item, index),
273
+        child: Container(
274
+          width: 80.0,
275
+          child: Stack(
276
+            children: <Widget>[
277
+              ImageItem(
278
+                themeColor: themeColor,
279
+                entity: item,
280
+                size: options.thumbSize,
281
+                loadingDelegate: options.loadingDelegate,
293
               ),
282
               ),
294
-            ),
295
-          ],
283
+              IgnorePointer(
284
+                child: StreamBuilder(
285
+                  stream: pageStream,
286
+                  builder: (BuildContext context, AsyncSnapshot snapshot) {
287
+                    if (selectedList.contains(item)) {
288
+                      return Container();
289
+                    }
290
+                    return Container(
291
+                      color: Colors.white.withOpacity(0.5),
292
+                    );
293
+                  },
294
+                ),
295
+              ),
296
+            ],
297
+          ),
296
         ),
298
         ),
297
       ),
299
       ),
298
     );
300
     );