Ver código fonte

未被纳入管理的文件

Caijinglong 6 anos atrás
pai
commit
4764392b7c

+ 3
- 0
.gitignore Ver arquivo

@@ -8,3 +8,6 @@ build/
8 8
 ios/.generated/
9 9
 ios/Flutter/Generated.xcconfig
10 10
 ios/Runner/GeneratedPluginRegistrant.*
11
+
12
+.idea/
13
+*.iml

+ 1
- 0
example/android/app/src/main/java/com/example/example/MainActivity.java Ver arquivo

@@ -1,6 +1,7 @@
1 1
 package com.example.example;
2 2
 
3 3
 import android.os.Bundle;
4
+
4 5
 import io.flutter.app.FlutterActivity;
5 6
 import io.flutter.plugins.GeneratedPluginRegistrant;
6 7
 

+ 4
- 0
example/ios/Runner/Info.plist Ver arquivo

@@ -26,6 +26,10 @@
26 26
 	<string>LaunchScreen</string>
27 27
 	<key>UIMainStoryboardFile</key>
28 28
 	<string>Main</string>
29
+
30
+	<key>NSPhotoLibraryUsageDescription</key>
31
+    <string>App需要您的同意,才能访问相册</string>
32
+
29 33
 	<key>UISupportedInterfaceOrientations</key>
30 34
 	<array>
31 35
 		<string>UIInterfaceOrientationPortrait</string>

+ 9
- 0
example/lib/main.dart Ver arquivo

@@ -49,6 +49,11 @@ class _MyHomePageState extends State<MyHomePage> {
49 49
   void _incrementCounter() {
50 50
     PhotoPicker.pickImage(
51 51
       context: context,
52
+      themeColor: Colors.green,
53
+      padding: 5.0,
54
+      dividerColor: Colors.deepOrange,
55
+      disableColor: Colors.grey,
56
+      itemRadio: 0.88,
52 57
     );
53 58
   }
54 59
 
@@ -102,4 +107,8 @@ class _MyHomePageState extends State<MyHomePage> {
102 107
       ), // This trailing comma makes auto-formatting nicer for build methods.
103 108
     );
104 109
   }
110
+
111
+  void _test(){
112
+//    Navigator.of(context).pop
113
+  }
105 114
 }

+ 70
- 9
lib/photo.dart Ver arquivo

@@ -1,10 +1,11 @@
1 1
 library photo;
2 2
 
3 3
 import 'package:flutter/material.dart';
4
-
5
-import 'package:photo_manager/photo_manager.dart';
6
-
7 4
 import 'package:photo/src/entity/options.dart';
5
+import 'package:photo/src/page/not_permission_dialog.dart';
6
+import 'package:photo/src/page/photo_main_page.dart';
7
+import 'package:photo/src/provider/i18n_provider.dart';
8
+import 'package:photo_manager/photo_manager.dart';
8 9
 
9 10
 /// A Calculator.
10 11
 class PhotoPicker {
@@ -17,29 +18,89 @@ class PhotoPicker {
17 18
     return _instance;
18 19
   }
19 20
 
20
-  void pickImage({
21
+  /// 没有授予权限的时候,会开启一个dialog去帮助用户去应用设置页面开启权限
22
+  /// 确定开启设置页面,取消关闭弹窗
23
+  ///
24
+  ///
25
+  /// 当用户给予权限后
26
+  ///
27
+  ///   当用户确定时,返回一个图片[ImageEntity]列表
28
+  ///
29
+  ///   当用户取消时
30
+  ///
31
+  /// if user not grand permission, then return null and show a dialog to help user open setting.
32
+  /// sure is open setting cancel ,cancel to dismiss dialog
33
+  ///
34
+  /// when user give permission.
35
+  ///
36
+  ///   when user sure , return a [ImageEntity] of [List]
37
+  ///
38
+  ///   when user cancel selected,result is empty list
39
+  static Future<List<ImageEntity>> pickImage({
21 40
     @required BuildContext context,
22
-    int rowCount = 3,
41
+    int rowCount = 4,
23 42
     int maxSelected = 9,
24 43
     double padding = 0.5,
44
+    double itemRadio = 1.0,
25 45
     Color themeColor,
26 46
     Color dividerColor,
27 47
     Color textColor,
28
-    Color paddingColor,
48
+    Color disableColor,
49
+    I18nProvider provider = I18nProvider.chinese,
29 50
   }) {
51
+    assert(provider != null, "provider must be not null");
52
+    assert(context != null, "context must be not null");
53
+
30 54
     themeColor ??= Theme.of(context)?.primaryColor ?? Colors.black;
31 55
     dividerColor ??= Theme.of(context)?.dividerColor ?? Colors.grey;
32
-    paddingColor ??= Theme.of(context)?.dividerColor ?? Colors.grey;
56
+    disableColor ??= Theme.of(context)?.dividerColor ?? Colors.grey;
33 57
     textColor ??= Colors.white;
34 58
 
35
-    Options(
59
+    var options = Options(
36 60
       rowCount: rowCount,
37 61
       dividerColor: dividerColor,
38 62
       maxSelected: maxSelected,
63
+      itemRadio:itemRadio,
39 64
       padding: padding,
40
-      paddingColor: paddingColor,
65
+      paddingColor: disableColor,
41 66
       textColor: textColor,
42 67
       themeColor: themeColor,
43 68
     );
69
+
70
+    return PhotoPicker()._pickImage(context, options, provider);
71
+  }
72
+
73
+  Future<List<ImageEntity>> _pickImage(
74
+    BuildContext context,
75
+    Options options,
76
+    I18nProvider provider,
77
+  ) async {
78
+    var requestPermission = await ImageScanner.requestPermission();
79
+    if (requestPermission != true) {
80
+      var result = await showDialog(
81
+        context: context,
82
+        builder: (ctx) => NotPermissionDialog(
83
+              provider.getNotPermissionText(options),
84
+            ),
85
+      );
86
+      if (result == true) {
87
+        ImageScanner.openSetting();
88
+      }
89
+      return null;
90
+    }
91
+
92
+    return _openGalleryContentPage(context, options, provider);
93
+  }
94
+
95
+  Future<List<ImageEntity>> _openGalleryContentPage(
96
+      BuildContext context, Options options, I18nProvider provider) {
97
+    return Navigator.of(context).push(
98
+      MaterialPageRoute(
99
+        builder: (ctx) => PhotoMainPage(
100
+              options: options,
101
+              provider: provider,
102
+            ),
103
+      ),
104
+    );
44 105
   }
45 106
 }

+ 54
- 0
lib/src/engine/lru_cache.dart Ver arquivo

@@ -0,0 +1,54 @@
1
+import 'dart:collection';
2
+import 'dart:typed_data';
3
+
4
+import 'package:photo_manager/photo_manager.dart';
5
+
6
+class ImageLruCache {
7
+  static LRUMap<ImageEntity, Uint8List> _map = LRUMap(500);
8
+
9
+  static Uint8List getData(ImageEntity entity) {
10
+    return _map.get(entity);
11
+  }
12
+
13
+  static void setData(ImageEntity entity, Uint8List list) {
14
+    _map.put(entity, list);
15
+  }
16
+}
17
+
18
+// Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file
19
+// for details. All rights reserved. Use of this source code is governed by a
20
+// BSD-style license that can be found in the LICENSE file.
21
+
22
+typedef EvictionHandler<K, V>(K key, V value);
23
+
24
+class LRUMap<K, V> {
25
+  final LinkedHashMap<K, V> _map = new LinkedHashMap<K, V>();
26
+  final int _maxSize;
27
+  final EvictionHandler<K, V> _handler;
28
+
29
+  LRUMap(this._maxSize, [this._handler]);
30
+
31
+  V get(K key) {
32
+    V value = _map.remove(key);
33
+    if (value != null) {
34
+      _map[key] = value;
35
+    }
36
+    return value;
37
+  }
38
+
39
+  void put(K key, V value) {
40
+    _map.remove(key);
41
+    _map[key] = value;
42
+    if (_map.length > _maxSize) {
43
+      K evictedKey = _map.keys.first;
44
+      V evictedValue = _map.remove(evictedKey);
45
+      if (_handler != null) {
46
+        _handler(evictedKey, evictedValue);
47
+      }
48
+    }
49
+  }
50
+
51
+  void remove(K key) {
52
+    _map.remove(key);
53
+  }
54
+}

+ 23
- 8
lib/src/entity/options.dart Ver arquivo

@@ -2,19 +2,34 @@ import 'package:flutter/material.dart';
2 2
 
3 3
 class Options {
4 4
   final int rowCount;
5
+
5 6
   final int maxSelected;
7
+
6 8
   final double padding;
9
+
10
+  final double itemRadio;
11
+
7 12
   final Color themeColor;
13
+
8 14
   final Color dividerColor;
15
+
9 16
   final Color textColor;
17
+
10 18
   final Color paddingColor;
11 19
 
12
-  const Options(
13
-      {this.rowCount,
14
-      this.maxSelected,
15
-      this.padding,
16
-      this.themeColor,
17
-      this.dividerColor,
18
-      this.textColor,
19
-      this.paddingColor});
20
+  const Options({
21
+    this.rowCount,
22
+    this.maxSelected,
23
+    this.padding,
24
+    this.itemRadio,
25
+    this.themeColor,
26
+    this.dividerColor,
27
+    this.textColor,
28
+    this.paddingColor,
29
+  });
30
+
31
+  @override
32
+  String toString() {
33
+    return 'Options{rowCount: $rowCount, maxSelected: $maxSelected, padding: $padding, themeColor: $themeColor, dividerColor: $dividerColor, textColor: $textColor, paddingColor: $paddingColor}';
34
+  }
20 35
 }

+ 3
- 0
lib/src/error/permission_error.dart Ver arquivo

@@ -0,0 +1,3 @@
1
+class NoPermissionError implements Exception {
2
+  const NoPermissionError();
3
+}

+ 39
- 0
lib/src/page/not_permission_dialog.dart Ver arquivo

@@ -0,0 +1,39 @@
1
+import 'package:flutter/material.dart';
2
+import 'package:photo/src/provider/i18n_provider.dart';
3
+
4
+class NotPermissionDialog extends StatefulWidget {
5
+  final I18NPermissionProvider provider;
6
+
7
+  const NotPermissionDialog(this.provider);
8
+
9
+  @override
10
+  _NotPermissionDialogState createState() => _NotPermissionDialogState();
11
+}
12
+
13
+class _NotPermissionDialogState extends State<NotPermissionDialog> {
14
+  @override
15
+  Widget build(BuildContext context) {
16
+    var provider = widget.provider;
17
+    return AlertDialog(
18
+      title: Text(provider.titleText),
19
+      actions: <Widget>[
20
+        FlatButton(
21
+          onPressed: _onCancel,
22
+          child: Text(provider.cancelText),
23
+        ),
24
+        FlatButton(
25
+          onPressed: _onSure,
26
+          child: Text(provider.sureText),
27
+        ),
28
+      ],
29
+    );
30
+  }
31
+
32
+  void _onCancel() {
33
+    Navigator.pop(context);
34
+  }
35
+
36
+  void _onSure() {
37
+    Navigator.pop(context, true);
38
+  }
39
+}

+ 308
- 0
lib/src/page/photo_main_page.dart Ver arquivo

@@ -0,0 +1,308 @@
1
+import 'dart:typed_data';
2
+
3
+import 'package:flutter/material.dart';
4
+import 'package:photo/src/engine/lru_cache.dart';
5
+import 'package:photo/src/entity/options.dart';
6
+import 'package:photo/src/provider/i18n_provider.dart';
7
+import 'package:photo/src/provider/selected_provider.dart';
8
+import 'package:photo_manager/photo_manager.dart';
9
+
10
+class PhotoMainPage extends StatefulWidget {
11
+  final Options options;
12
+  final I18nProvider provider;
13
+
14
+  const PhotoMainPage({Key key, this.options, this.provider}) : super(key: key);
15
+
16
+  @override
17
+  _PhotoMainPageState createState() => _PhotoMainPageState();
18
+}
19
+
20
+class _PhotoMainPageState extends State<PhotoMainPage> with SelectedProvider {
21
+  Options get options => widget.options;
22
+
23
+  I18nProvider get i18nProvider => widget.provider;
24
+
25
+  List<ImageEntity> selectedList = [];
26
+  List<ImageParentPath> pathList = [];
27
+
28
+  List<ImageEntity> list = [];
29
+
30
+  Color get themeColor => options.themeColor;
31
+
32
+  ImageParentPath _currentPath;
33
+
34
+  ImageParentPath get currentPath {
35
+    if (_currentPath == null) {
36
+      return null;
37
+    }
38
+    return _currentPath;
39
+  }
40
+
41
+  set currentPath(ImageParentPath value) {
42
+    _currentPath = value;
43
+  }
44
+
45
+  @override
46
+  void initState() {
47
+    super.initState();
48
+    _refreshList();
49
+  }
50
+
51
+  @override
52
+  Widget build(BuildContext context) {
53
+    var textStyle = TextStyle(
54
+      color: options.textColor,
55
+      fontSize: 14.0,
56
+    );
57
+    return DefaultTextStyle(
58
+      style: textStyle,
59
+      child: Scaffold(
60
+        appBar: AppBar(
61
+          backgroundColor: options.themeColor,
62
+          title: Text(
63
+            i18nProvider.getTitleText(options),
64
+          ),
65
+          actions: <Widget>[
66
+            FlatButton(
67
+              child: Text(
68
+                i18nProvider.getSureText(options, this),
69
+                style: textStyle,
70
+              ),
71
+              onPressed: sure,
72
+            ),
73
+          ],
74
+        ),
75
+        body: _buildBody(),
76
+        bottomSheet: _BottomWidget(
77
+          provider: i18nProvider,
78
+          options: options,
79
+          onGalleryChange: _onGalleryChange,
80
+          selectedProvider: this,
81
+        ),
82
+      ),
83
+    );
84
+  }
85
+
86
+  void _refreshList() async {
87
+    pathList = await ImageScanner.getImagePathList();
88
+    var path = pathList[0];
89
+    var imageList = await path.imageList;
90
+    this.list.clear();
91
+    this.list.addAll(imageList);
92
+    print(list);
93
+    setState(() {});
94
+  }
95
+
96
+  Widget _buildBody() {
97
+    return Container(
98
+      color: options.paddingColor,
99
+      child: GridView.builder(
100
+        gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
101
+          crossAxisCount: options.rowCount,
102
+          childAspectRatio: options.itemRadio,
103
+          crossAxisSpacing: options.padding,
104
+          mainAxisSpacing: options.padding,
105
+        ),
106
+        itemBuilder: _buildItem,
107
+        itemCount: list.length,
108
+      ),
109
+    );
110
+  }
111
+
112
+  @override
113
+  int get selectedCount => selectedList.length;
114
+
115
+  @override
116
+  bool containsEntity(ImageEntity entity) {
117
+    return selectedList.contains(entity);
118
+  }
119
+
120
+  @override
121
+  int indexOfSelected(ImageEntity entity) {
122
+    return selectedList.indexOf(entity);
123
+  }
124
+
125
+  Widget _buildItem(BuildContext context, int index) {
126
+    var data = list[index];
127
+    return GestureDetector(
128
+      onTap: () => _onItemClick(data),
129
+      child: Stack(
130
+        children: <Widget>[
131
+          ImageItem(
132
+            entity: data,
133
+            themeColor: themeColor,
134
+          ),
135
+          _buildMask(containsEntity(data)),
136
+          _buildSelected(data),
137
+        ],
138
+      ),
139
+    );
140
+  }
141
+
142
+  _buildMask(bool showMask) {
143
+    return IgnorePointer(
144
+      child: AnimatedContainer(
145
+        color: showMask ? Colors.black.withOpacity(0.5) : Colors.transparent,
146
+        duration: Duration(milliseconds: 300),
147
+      ),
148
+    );
149
+  }
150
+
151
+  Widget _buildSelected(ImageEntity entity) {
152
+    var currentSelected = containsEntity(entity);
153
+    return Positioned(
154
+      right: 0.0,
155
+      width: 36.0,
156
+      height: 36.0,
157
+      child: GestureDetector(
158
+        onTap: () {
159
+          changeCheck(!currentSelected, entity);
160
+        },
161
+        behavior: HitTestBehavior.translucent,
162
+        child: _buildText(entity),
163
+      ),
164
+    );
165
+  }
166
+
167
+  Widget _buildText(ImageEntity entity) {
168
+    var isSelected = containsEntity(entity);
169
+    Widget child;
170
+    BoxDecoration decoration;
171
+    if (isSelected) {
172
+      child = Text(
173
+        (indexOfSelected(entity) + 1).toString(),
174
+        textAlign: TextAlign.center,
175
+        style: TextStyle(
176
+          fontSize: 12.0,
177
+          color: options.textColor,
178
+        ),
179
+      );
180
+      decoration = BoxDecoration(color: themeColor);
181
+    } else {
182
+      decoration = BoxDecoration(
183
+        borderRadius: BorderRadius.circular(1.0),
184
+        border: Border.all(
185
+          color: themeColor,
186
+        ),
187
+      );
188
+    }
189
+    return Padding(
190
+      padding: const EdgeInsets.all(8.0),
191
+      child: AnimatedContainer(
192
+        duration: Duration(milliseconds: 300),
193
+        decoration: decoration,
194
+        alignment: Alignment.center,
195
+        child: child,
196
+      ),
197
+    );
198
+  }
199
+
200
+  void changeCheck(bool value, ImageEntity entity) {
201
+    if (value) {
202
+      selectedList.add(entity);
203
+    } else {
204
+      selectedList.remove(entity);
205
+    }
206
+    setState(() {});
207
+  }
208
+
209
+  void sure() {}
210
+
211
+  void _onItemClick(ImageEntity data) {}
212
+
213
+  void _onGalleryChange(ImageParentPath value) {}
214
+}
215
+
216
+class _BottomWidget extends StatefulWidget {
217
+  final ValueChanged<ImageParentPath> onGalleryChange;
218
+
219
+  final Options options;
220
+
221
+  final I18nProvider provider;
222
+
223
+  final SelectedProvider selectedProvider;
224
+
225
+  final String galleryName;
226
+
227
+  const _BottomWidget({
228
+    Key key,
229
+    this.onGalleryChange,
230
+    this.options,
231
+    this.provider,
232
+    this.selectedProvider,
233
+    this.galleryName = "",
234
+  }) : super(key: key);
235
+
236
+  @override
237
+  __BottomWidgetState createState() => __BottomWidgetState();
238
+}
239
+
240
+class __BottomWidgetState extends State<_BottomWidget> {
241
+  Options get options => widget.options;
242
+
243
+  I18nProvider get i18nProvider => widget.provider;
244
+
245
+  @override
246
+  Widget build(BuildContext context) {
247
+    return Container(
248
+      color: options.themeColor,
249
+      height: 44.0,
250
+      child: Row(
251
+        children: <Widget>[
252
+          Text(
253
+            widget.galleryName,
254
+          ),
255
+        ],
256
+      ),
257
+    );
258
+  }
259
+}
260
+
261
+class ImageItem extends StatelessWidget {
262
+  final ImageEntity entity;
263
+
264
+  final Color themeColor;
265
+
266
+  const ImageItem({
267
+    Key key,
268
+    this.entity,
269
+    this.themeColor,
270
+  }) : super(key: key);
271
+
272
+  @override
273
+  Widget build(BuildContext context) {
274
+    var thumb = ImageLruCache.getData(entity);
275
+    if (thumb != null) {
276
+      return _buildImageItem(thumb);
277
+    }
278
+    return FutureBuilder<Uint8List>(
279
+      future: entity.thumbData,
280
+      builder: (BuildContext context, AsyncSnapshot<Uint8List> snapshot) {
281
+        var futureData = snapshot.data;
282
+        if (snapshot.connectionState == ConnectionState.done &&
283
+            futureData != null) {
284
+          ImageLruCache.setData(entity, futureData);
285
+          return _buildImageItem(futureData);
286
+        }
287
+        return Center(
288
+          child: Container(
289
+            width: 20.0,
290
+            height: 20.0,
291
+            child: CircularProgressIndicator(
292
+              valueColor: AlwaysStoppedAnimation(themeColor),
293
+            ),
294
+          ),
295
+        );
296
+      },
297
+    );
298
+  }
299
+
300
+  Widget _buildImageItem(Uint8List data) {
301
+    return Image.memory(
302
+      data,
303
+      width: double.infinity,
304
+      height: double.infinity,
305
+      fit: BoxFit.cover,
306
+    );
307
+  }
308
+}

+ 93
- 3
lib/src/provider/i18n_provider.dart Ver arquivo

@@ -1,7 +1,8 @@
1 1
 import 'package:photo/src/entity/options.dart';
2
-import 'package:photo/src/provider/SelectedProvider.dart';
2
+import 'package:photo/src/provider/selected_provider.dart';
3 3
 
4 4
 abstract class I18nProvider {
5
+  const I18nProvider._();
5 6
 
6 7
   String getTitleText(Options options);
7 8
 
@@ -9,13 +10,20 @@ abstract class I18nProvider {
9 10
 
10 11
   String getPreviewText(Options options, SelectedProvider selectedProvider);
11 12
 
12
-  static I18nProvider chinese = _CNProvider();
13
+  String getSelectedOptionsText(Options options);
13 14
 
14
-  static I18nProvider english = _ENProvider();
15
+  String getMaxTipText(Options options);
15 16
 
17
+  I18NPermissionProvider getNotPermissionText(Options options);
18
+
19
+  static const I18nProvider chinese = _CNProvider();
20
+
21
+  static const I18nProvider english = _ENProvider();
16 22
 }
17 23
 
18 24
 class _CNProvider extends I18nProvider {
25
+  const _CNProvider() : super._();
26
+
19 27
   @override
20 28
   String getTitleText(Options options) {
21 29
     return "图片选择";
@@ -30,9 +38,27 @@ class _CNProvider extends I18nProvider {
30 38
   String getSureText(Options options, SelectedProvider selectedProvider) {
31 39
     return "确定(${selectedProvider.selectedCount}/${options.maxSelected})";
32 40
   }
41
+
42
+  @override
43
+  String getSelectedOptionsText(Options options) {
44
+    return "选择";
45
+  }
46
+
47
+  @override
48
+  String getMaxTipText(Options options) {
49
+    return "您已经选择了${options.maxSelected}张图片";
50
+  }
51
+
52
+  @override
53
+  I18NPermissionProvider getNotPermissionText(Options options) {
54
+    return I18NPermissionProvider(
55
+        cancelText: "取消", sureText: "去开启", titleText: "没有访问相册的权限");
56
+  }
33 57
 }
34 58
 
35 59
 class _ENProvider extends I18nProvider {
60
+  const _ENProvider() : super._();
61
+
36 62
   @override
37 63
   String getTitleText(Options options) {
38 64
     return "image picker";
@@ -47,4 +73,68 @@ class _ENProvider extends I18nProvider {
47 73
   String getSureText(Options options, SelectedProvider selectedProvider) {
48 74
     return "sure(${selectedProvider.selectedCount}/${options.maxSelected})";
49 75
   }
76
+
77
+  @override
78
+  String getSelectedOptionsText(Options options) {
79
+    return "selected";
80
+  }
81
+
82
+  @override
83
+  String getMaxTipText(Options options) {
84
+    return "select ${options.maxSelected} pictures at most";
85
+  }
86
+
87
+  @override
88
+  I18NPermissionProvider getNotPermissionText(Options options) {
89
+    return I18NPermissionProvider(
90
+        cancelText: "cancel",
91
+        sureText: "allow",
92
+        titleText: "No permission to access gallery");
93
+  }
94
+}
95
+
96
+abstract class I18NCustomProvider implements I18nProvider {
97
+  final String maxTipText;
98
+  final String previewText;
99
+  final String selectedOptionsText;
100
+  final String sureText;
101
+  final String titleText;
102
+  final I18NPermissionProvider notPermissionText;
103
+
104
+  I18NCustomProvider(
105
+      this.maxTipText,
106
+      this.previewText,
107
+      this.selectedOptionsText,
108
+      this.sureText,
109
+      this.titleText,
110
+      this.notPermissionText);
111
+
112
+  @override
113
+  String getMaxTipText(Options options) {
114
+    return maxTipText;
115
+  }
116
+
117
+  @override
118
+  String getSelectedOptionsText(Options options) {
119
+    return selectedOptionsText;
120
+  }
121
+
122
+  @override
123
+  String getTitleText(Options options) {
124
+    return titleText;
125
+  }
126
+
127
+  @override
128
+  I18NPermissionProvider getNotPermissionText(Options options) {
129
+    return notPermissionText;
130
+  }
131
+}
132
+
133
+class I18NPermissionProvider {
134
+  final String titleText;
135
+  final String sureText;
136
+  final String cancelText;
137
+
138
+  const I18NPermissionProvider(
139
+      {this.titleText, this.sureText, this.cancelText});
50 140
 }

+ 9
- 0
lib/src/provider/selected_provider.dart Ver arquivo

@@ -1,3 +1,12 @@
1
+import 'package:photo_manager/photo_manager.dart';
2
+
1 3
 abstract class SelectedProvider {
4
+
2 5
   int get selectedCount;
6
+
7
+  bool containsEntity(ImageEntity entity);
8
+
9
+  int indexOfSelected(ImageEntity entity);
10
+
11
+  void sure();
3 12
 }

+ 2
- 2
pubspec.lock Ver arquivo

@@ -211,8 +211,8 @@ packages:
211 211
     dependency: "direct main"
212 212
     description:
213 213
       path: "."
214
-      ref: HEAD
215
-      resolved-ref: "567b73d36baad10092d72bde41fc5e64e39594c5"
214
+      ref: "0a808b0a537e5203095a6b70aa5c42ca4d5a9c9a"
215
+      resolved-ref: "0a808b0a537e5203095a6b70aa5c42ca4d5a9c9a"
216 216
       url: "https://github.com/CaiJingLong/flutter_photo_manager"
217 217
     source: git
218 218
     version: "0.0.1"

+ 1
- 0
pubspec.yaml Ver arquivo

@@ -13,6 +13,7 @@ dependencies:
13 13
   photo_manager:
14 14
     git:
15 15
       url: https://github.com/CaiJingLong/flutter_photo_manager
16
+      ref: 0a808b0a537e5203095a6b70aa5c42ca4d5a9c9a
16 17
 
17 18
 dev_dependencies:
18 19
   flutter_test: