소스 검색

load asset paged.

Caijinglong 5 년 전
부모
커밋
420b7050e1

+ 60
- 0
lib/src/provider/asset_provider.dart 파일 보기

1
+import 'dart:async';
2
+
3
+import 'package:photo_manager/photo_manager.dart';
4
+
5
+class AssetProvider {
6
+  Map<AssetPathEntity, AssetPaging> _dataMap = {};
7
+
8
+  AssetPathEntity _current;
9
+
10
+  AssetPathEntity get current => _current;
11
+
12
+  set current(AssetPathEntity current) {
13
+    _current = current;
14
+    if (_dataMap[current] == null) {
15
+      final paging = AssetPaging(current);
16
+      _dataMap[current] = paging;
17
+    }
18
+  }
19
+
20
+  List<AssetEntity> get data => _dataMap[current]?.data ?? [];
21
+
22
+  Future<void> loadMore() async {
23
+    final paging = getPaging();
24
+    if (paging != null) {
25
+      await paging.loadMore();
26
+    }
27
+  }
28
+
29
+  AssetPaging getPaging() => _dataMap[current];
30
+
31
+  bool get noMore => getPaging()?.noMore ?? false;
32
+
33
+  int get count => data?.length ?? 0;
34
+}
35
+
36
+class AssetPaging {
37
+  int page = 0;
38
+
39
+  List<AssetEntity> data = [];
40
+
41
+  final AssetPathEntity path;
42
+
43
+  final int pageCount;
44
+
45
+  bool noMore = false;
46
+
47
+  AssetPaging(this.path, {this.pageCount = 50});
48
+
49
+  Future<void> loadMore() async {
50
+    if (noMore == true) {
51
+      return;
52
+    }
53
+    var data = await path.getAssetListPaged(page, pageCount);
54
+    if (data.length == 0) {
55
+      noMore = true;
56
+    }
57
+    page++;
58
+    this.data.addAll(data);
59
+  }
60
+}

+ 9
- 4
lib/src/provider/config_provider.dart 파일 보기

1
 import 'package:flutter/material.dart';
1
 import 'package:flutter/material.dart';
2
 import 'package:photo/src/entity/options.dart';
2
 import 'package:photo/src/entity/options.dart';
3
+import 'package:photo/src/provider/asset_provider.dart';
3
 import 'package:photo/src/provider/i18n_provider.dart';
4
 import 'package:photo/src/provider/i18n_provider.dart';
4
 
5
 
5
-class ConfigProvider extends InheritedWidget {
6
+class PhotoPickerProvider extends InheritedWidget {
6
   final Options options;
7
   final Options options;
7
   final I18nProvider provider;
8
   final I18nProvider provider;
9
+  final AssetProvider assetProvider = AssetProvider();
8
 
10
 
9
-  ConfigProvider({
11
+  PhotoPickerProvider({
10
     @required this.options,
12
     @required this.options,
11
     @required this.provider,
13
     @required this.provider,
12
     @required Widget child,
14
     @required Widget child,
18
     return true;
20
     return true;
19
   }
21
   }
20
 
22
 
21
-  static ConfigProvider of(BuildContext context) =>
22
-      context.inheritFromWidgetOfExactType(ConfigProvider);
23
+  static PhotoPickerProvider of(BuildContext context) =>
24
+      context.inheritFromWidgetOfExactType(PhotoPickerProvider);
25
+
26
+  static AssetProvider assetProviderOf(BuildContext context) =>
27
+      of(context).assetProvider;
23
 }
28
 }

+ 46
- 26
lib/src/ui/page/photo_main_page.dart 파일 보기

7
 import 'package:photo/src/engine/lru_cache.dart';
7
 import 'package:photo/src/engine/lru_cache.dart';
8
 import 'package:photo/src/engine/throttle.dart';
8
 import 'package:photo/src/engine/throttle.dart';
9
 import 'package:photo/src/entity/options.dart';
9
 import 'package:photo/src/entity/options.dart';
10
+import 'package:photo/src/provider/asset_provider.dart';
10
 import 'package:photo/src/provider/config_provider.dart';
11
 import 'package:photo/src/provider/config_provider.dart';
11
 import 'package:photo/src/provider/gallery_list_provider.dart';
12
 import 'package:photo/src/provider/gallery_list_provider.dart';
12
 import 'package:photo/src/provider/i18n_provider.dart';
13
 import 'package:photo/src/provider/i18n_provider.dart';
38
     with SelectedProvider, GalleryListProvider {
39
     with SelectedProvider, GalleryListProvider {
39
   Options get options => widget.options;
40
   Options get options => widget.options;
40
 
41
 
41
-  I18nProvider get i18nProvider => ConfigProvider.of(context).provider;
42
+  I18nProvider get i18nProvider => PhotoPickerProvider.of(context).provider;
43
+  AssetProvider get assetProvider =>
44
+      PhotoPickerProvider.of(context).assetProvider;
42
 
45
 
43
-  List<AssetEntity> list = [];
46
+  List<AssetEntity> get list => assetProvider.data;
44
 
47
 
45
   Color get themeColor => options.themeColor;
48
   Color get themeColor => options.themeColor;
46
 
49
 
227
     galleryPathList.clear();
230
     galleryPathList.clear();
228
     galleryPathList.addAll(pathList);
231
     galleryPathList.addAll(pathList);
229
 
232
 
230
-    List<AssetEntity> imageList;
231
-
232
     if (pathList.isNotEmpty) {
233
     if (pathList.isNotEmpty) {
233
-      imageList = await pathList[0].assetList;
234
-      _sortAssetList(imageList);
235
-      _currentPath = pathList[0];
234
+      assetProvider.current = pathList[0];
235
+      await assetProvider.loadMore();
236
     }
236
     }
237
 
237
 
238
     for (var path in pathList) {
238
     for (var path in pathList) {
241
       }
241
       }
242
     }
242
     }
243
 
243
 
244
-    this.list.clear();
245
-    if (imageList != null) {
246
-      this.list.addAll(imageList);
247
-    }
248
     setState(() {
244
     setState(() {
249
       _isInit = true;
245
       _isInit = true;
250
     });
246
     });
259
       return _buildLoading();
255
       return _buildLoading();
260
     }
256
     }
261
 
257
 
258
+    final noMore = assetProvider.noMore;
259
+
260
+    final count = assetProvider.count + (noMore ? 0 : 1);
261
+
262
     return Container(
262
     return Container(
263
       color: options.dividerColor,
263
       color: options.dividerColor,
264
       child: GridView.builder(
264
       child: GridView.builder(
270
           mainAxisSpacing: options.padding,
270
           mainAxisSpacing: options.padding,
271
         ),
271
         ),
272
         itemBuilder: _buildItem,
272
         itemBuilder: _buildItem,
273
-        itemCount: list.length,
273
+        itemCount: count,
274
       ),
274
       ),
275
     );
275
     );
276
   }
276
   }
277
 
277
 
278
   Widget _buildItem(BuildContext context, int index) {
278
   Widget _buildItem(BuildContext context, int index) {
279
+    final noMore = assetProvider.noMore;
280
+    if (!noMore && index == assetProvider.count) {
281
+      _loadMore();
282
+      return _buildLoading();
283
+    }
284
+
279
     var data = list[index];
285
     var data = list[index];
280
     return RepaintBoundary(
286
     return RepaintBoundary(
281
       child: GestureDetector(
287
       child: GestureDetector(
297
     );
303
     );
298
   }
304
   }
299
 
305
 
306
+  _loadMore() async {
307
+    await assetProvider.loadMore();
308
+    setState(() {});
309
+  }
310
+
300
   _buildMask(bool showMask) {
311
   _buildMask(bool showMask) {
301
     return IgnorePointer(
312
     return IgnorePointer(
302
       child: AnimatedContainer(
313
       child: AnimatedContainer(
364
     setState(() {});
375
     setState(() {});
365
   }
376
   }
366
 
377
 
367
-  void _onGalleryChange(AssetPathEntity assetPathEntity) {
368
-    _currentPath = assetPathEntity;
369
-
370
-    _currentPath.assetList.then((v) async {
371
-      _sortAssetList(v);
372
-      list.clear();
373
-      list.addAll(v);
374
-      scrollController.jumpTo(0.0);
375
-      await checkPickImageEntity();
378
+  void _onGalleryChange(AssetPathEntity assetPathEntity) async {
379
+    // _currentPath = assetPathEntity;
380
+
381
+    // _currentPath.assetList.then((v) async {
382
+    //   _sortAssetList(v);
383
+    //   list.clear();
384
+    //   list.addAll(v);
385
+    //   scrollController.jumpTo(0.0);
386
+    //   await checkPickImageEntity();
387
+    //   setState(() {});
388
+    // });
389
+    if (assetPathEntity != assetProvider.current) {
390
+      assetProvider.current = assetPathEntity;
391
+      await assetProvider.loadMore();
376
       setState(() {});
392
       setState(() {});
377
-    });
393
+    }
378
   }
394
   }
379
 
395
 
380
   void _onItemClick(AssetEntity data, int index) {
396
   void _onItemClick(AssetEntity data, int index) {
383
     Navigator.of(context).push(
399
     Navigator.of(context).push(
384
       MaterialPageRoute(
400
       MaterialPageRoute(
385
         builder: (ctx) {
401
         builder: (ctx) {
386
-          return ConfigProvider(
387
-            provider: ConfigProvider.of(context).provider,
402
+          return PhotoPickerProvider(
403
+            provider: PhotoPickerProvider.of(context).provider,
388
             options: options,
404
             options: options,
389
             child: PhotoPreviewPage(
405
             child: PhotoPreviewPage(
390
               selectedProvider: this,
406
               selectedProvider: this,
392
               initIndex: index,
408
               initIndex: index,
393
               changeProviderOnCheckChange: true,
409
               changeProviderOnCheckChange: true,
394
               result: result,
410
               result: result,
411
+              isPreview: false,
412
+              assetProvider: assetProvider,
395
             ),
413
             ),
396
           );
414
           );
397
         },
415
         },
411
     isPushed = true;
429
     isPushed = true;
412
     var v = await Navigator.of(context).push(
430
     var v = await Navigator.of(context).push(
413
       MaterialPageRoute(
431
       MaterialPageRoute(
414
-        builder: (ctx) => ConfigProvider(
415
-          provider: ConfigProvider.of(context).provider,
432
+        builder: (ctx) => PhotoPickerProvider(
433
+          provider: PhotoPickerProvider.of(context).provider,
416
           options: options,
434
           options: options,
417
           child: PhotoPreviewPage(
435
           child: PhotoPreviewPage(
418
             selectedProvider: this,
436
             selectedProvider: this,
419
             list: List.of(selectedList),
437
             list: List.of(selectedList),
420
             changeProviderOnCheckChange: false,
438
             changeProviderOnCheckChange: false,
421
             result: result,
439
             result: result,
440
+            isPreview: true,
441
+            assetProvider: assetProvider,
422
           ),
442
           ),
423
         ),
443
         ),
424
       ),
444
       ),

+ 55
- 24
lib/src/ui/page/photo_preview_page.dart 파일 보기

3
 
3
 
4
 import 'package:flutter/material.dart';
4
 import 'package:flutter/material.dart';
5
 import 'package:photo/src/entity/options.dart';
5
 import 'package:photo/src/entity/options.dart';
6
+import 'package:photo/src/provider/asset_provider.dart';
6
 import 'package:photo/src/provider/config_provider.dart';
7
 import 'package:photo/src/provider/config_provider.dart';
7
 import 'package:photo/src/provider/selected_provider.dart';
8
 import 'package:photo/src/provider/selected_provider.dart';
8
 import 'package:photo/src/ui/page/photo_main_page.dart';
9
 import 'package:photo/src/ui/page/photo_main_page.dart';
18
   /// 这个参数是控制在内部点击check后是否实时修改provider状态
19
   /// 这个参数是控制在内部点击check后是否实时修改provider状态
19
   final bool changeProviderOnCheckChange;
20
   final bool changeProviderOnCheckChange;
20
 
21
 
22
+  /// 是否通过预览进来的
23
+  final bool isPreview;
24
+
21
   /// 这里封装了结果
25
   /// 这里封装了结果
22
   final PhotoPreviewResult result;
26
   final PhotoPreviewResult result;
23
 
27
 
28
+  final AssetProvider assetProvider;
29
+
24
   const PhotoPreviewPage({
30
   const PhotoPreviewPage({
25
     Key key,
31
     Key key,
26
     @required this.selectedProvider,
32
     @required this.selectedProvider,
27
     @required this.list,
33
     @required this.list,
28
     @required this.changeProviderOnCheckChange,
34
     @required this.changeProviderOnCheckChange,
29
     @required this.result,
35
     @required this.result,
36
+    @required this.assetProvider,
30
     this.initIndex = 0,
37
     this.initIndex = 0,
38
+    this.isPreview = false,
31
   }) : super(key: key);
39
   }) : super(key: key);
32
 
40
 
33
   @override
41
   @override
35
 }
43
 }
36
 
44
 
37
 class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
45
 class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
38
-  ConfigProvider get config => ConfigProvider.of(context);
46
+  PhotoPickerProvider get config => PhotoPickerProvider.of(context);
47
+  AssetProvider get assetProvider => widget.assetProvider;
39
 
48
 
40
   Options get options => config.options;
49
   Options get options => config.options;
41
 
50
 
45
 
54
 
46
   SelectedProvider get selectedProvider => widget.selectedProvider;
55
   SelectedProvider get selectedProvider => widget.selectedProvider;
47
 
56
 
48
-  List<AssetEntity> get list => widget.list;
57
+  List<AssetEntity> get list {
58
+    if (!widget.isPreview) {
59
+      return assetProvider.data;
60
+    }
61
+    return widget.list;
62
+  }
49
 
63
 
50
   StreamController<int> pageChangeController = StreamController.broadcast();
64
   StreamController<int> pageChangeController = StreamController.broadcast();
51
 
65
 
96
 
110
 
97
   @override
111
   @override
98
   Widget build(BuildContext context) {
112
   Widget build(BuildContext context) {
113
+    int totalCount = assetProvider.current.assetCount ?? 0;
114
+    if (!widget.isPreview) {
115
+      totalCount = assetProvider.current.assetCount;
116
+    } else {
117
+      totalCount = list.length;
118
+    }
119
+
99
     var data = Theme.of(context);
120
     var data = Theme.of(context);
100
     var textStyle = TextStyle(
121
     var textStyle = TextStyle(
101
       color: options.textColor,
122
       color: options.textColor,
114
           title: StreamBuilder(
135
           title: StreamBuilder(
115
             stream: pageStream,
136
             stream: pageStream,
116
             initialData: widget.initIndex,
137
             initialData: widget.initIndex,
117
-            builder: (ctx, snap) => Text(
118
-                  "${snap.data + 1}/${widget.list.length}",
119
-                  style: TextStyle(
120
-                    color: options.textColor,
121
-                  ),
138
+            builder: (ctx, snap) {
139
+              return Text(
140
+                "${snap.data + 1}/$totalCount",
141
+                style: TextStyle(
142
+                  color: options.textColor,
122
                 ),
143
                 ),
144
+              );
145
+            },
123
           ),
146
           ),
124
           actions: <Widget>[
147
           actions: <Widget>[
125
             StreamBuilder(
148
             StreamBuilder(
126
               stream: pageStream,
149
               stream: pageStream,
127
               builder: (ctx, s) => FlatButton(
150
               builder: (ctx, s) => FlatButton(
128
-                    splashColor: Colors.transparent,
129
-                    onPressed: selectedList.length == 0 ? null : sure,
130
-                    child: Text(
131
-                      config.provider.getSureText(options, selectedList.length),
132
-                      style: selectedList.length == 0
133
-                          ? textStyle.copyWith(color: options.disableColor)
134
-                          : textStyle,
135
-                    ),
136
-                  ),
151
+                splashColor: Colors.transparent,
152
+                onPressed: selectedList.length == 0 ? null : sure,
153
+                child: Text(
154
+                  config.provider.getSureText(options, selectedList.length),
155
+                  style: selectedList.length == 0
156
+                      ? textStyle.copyWith(color: options.disableColor)
157
+                      : textStyle,
158
+                ),
159
+              ),
137
             ),
160
             ),
138
           ],
161
           ],
139
         ),
162
         ),
140
         body: PageView.builder(
163
         body: PageView.builder(
141
           controller: pageController,
164
           controller: pageController,
142
           itemBuilder: _buildItem,
165
           itemBuilder: _buildItem,
143
-          itemCount: list.length,
166
+          itemCount: totalCount,
144
           onPageChanged: _onPageChanged,
167
           onPageChanged: _onPageChanged,
145
         ),
168
         ),
146
         bottomSheet: _buildThumb(),
169
         bottomSheet: _buildThumb(),
244
   }
267
   }
245
 
268
 
246
   Widget _buildItem(BuildContext context, int index) {
269
   Widget _buildItem(BuildContext context, int index) {
270
+    if (!widget.isPreview && index >= list.length - 5) {
271
+      _loadMore();
272
+    }
273
+
247
     var data = list[index];
274
     var data = list[index];
248
     return BigPhotoImage(
275
     return BigPhotoImage(
249
       assetEntity: data,
276
       assetEntity: data,
251
     );
278
     );
252
   }
279
   }
253
 
280
 
281
+  Future<void> _loadMore() async {
282
+    assetProvider.loadMore();
283
+  }
284
+
254
   Widget _buildLoadingWidget(AssetEntity entity) {
285
   Widget _buildLoadingWidget(AssetEntity entity) {
255
     return options.loadingDelegate
286
     return options.loadingDelegate
256
         .buildBigImageLoading(context, entity, themeColor);
287
         .buildBigImageLoading(context, entity, themeColor);
263
   Widget _buildThumb() {
294
   Widget _buildThumb() {
264
     return StreamBuilder(
295
     return StreamBuilder(
265
       builder: (ctx, snapshot) => Container(
296
       builder: (ctx, snapshot) => Container(
266
-            height: 80.0,
267
-            child: ListView.builder(
268
-              itemBuilder: _buildThumbItem,
269
-              itemCount: previewList.length,
270
-              scrollDirection: Axis.horizontal,
271
-            ),
272
-          ),
297
+        height: 80.0,
298
+        child: ListView.builder(
299
+          itemBuilder: _buildThumbItem,
300
+          itemCount: previewList.length,
301
+          scrollDirection: Axis.horizontal,
302
+        ),
303
+      ),
273
       stream: pageStream,
304
       stream: pageStream,
274
     );
305
     );
275
   }
306
   }

+ 1
- 1
lib/src/ui/photo_app.dart 파일 보기

20
 
20
 
21
   @override
21
   @override
22
   Widget build(BuildContext context) {
22
   Widget build(BuildContext context) {
23
-    return ConfigProvider(
23
+    return PhotoPickerProvider(
24
       provider: provider,
24
       provider: provider,
25
       options: options,
25
       options: options,
26
       child: PhotoMainPage(
26
       child: PhotoMainPage(