Bläddra i källkod

load asset paged.

Caijinglong 5 år sedan
förälder
incheckning
420b7050e1

+ 60
- 0
lib/src/provider/asset_provider.dart Visa fil

@@ -0,0 +1,60 @@
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 Visa fil

@@ -1,12 +1,14 @@
1 1
 import 'package:flutter/material.dart';
2 2
 import 'package:photo/src/entity/options.dart';
3
+import 'package:photo/src/provider/asset_provider.dart';
3 4
 import 'package:photo/src/provider/i18n_provider.dart';
4 5
 
5
-class ConfigProvider extends InheritedWidget {
6
+class PhotoPickerProvider extends InheritedWidget {
6 7
   final Options options;
7 8
   final I18nProvider provider;
9
+  final AssetProvider assetProvider = AssetProvider();
8 10
 
9
-  ConfigProvider({
11
+  PhotoPickerProvider({
10 12
     @required this.options,
11 13
     @required this.provider,
12 14
     @required Widget child,
@@ -18,6 +20,9 @@ class ConfigProvider extends InheritedWidget {
18 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 Visa fil

@@ -7,6 +7,7 @@ import 'package:photo/src/delegate/loading_delegate.dart';
7 7
 import 'package:photo/src/engine/lru_cache.dart';
8 8
 import 'package:photo/src/engine/throttle.dart';
9 9
 import 'package:photo/src/entity/options.dart';
10
+import 'package:photo/src/provider/asset_provider.dart';
10 11
 import 'package:photo/src/provider/config_provider.dart';
11 12
 import 'package:photo/src/provider/gallery_list_provider.dart';
12 13
 import 'package:photo/src/provider/i18n_provider.dart';
@@ -38,9 +39,11 @@ class _PhotoMainPageState extends State<PhotoMainPage>
38 39
     with SelectedProvider, GalleryListProvider {
39 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 48
   Color get themeColor => options.themeColor;
46 49
 
@@ -227,12 +230,9 @@ class _PhotoMainPageState extends State<PhotoMainPage>
227 230
     galleryPathList.clear();
228 231
     galleryPathList.addAll(pathList);
229 232
 
230
-    List<AssetEntity> imageList;
231
-
232 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 238
     for (var path in pathList) {
@@ -241,10 +241,6 @@ class _PhotoMainPageState extends State<PhotoMainPage>
241 241
       }
242 242
     }
243 243
 
244
-    this.list.clear();
245
-    if (imageList != null) {
246
-      this.list.addAll(imageList);
247
-    }
248 244
     setState(() {
249 245
       _isInit = true;
250 246
     });
@@ -259,6 +255,10 @@ class _PhotoMainPageState extends State<PhotoMainPage>
259 255
       return _buildLoading();
260 256
     }
261 257
 
258
+    final noMore = assetProvider.noMore;
259
+
260
+    final count = assetProvider.count + (noMore ? 0 : 1);
261
+
262 262
     return Container(
263 263
       color: options.dividerColor,
264 264
       child: GridView.builder(
@@ -270,12 +270,18 @@ class _PhotoMainPageState extends State<PhotoMainPage>
270 270
           mainAxisSpacing: options.padding,
271 271
         ),
272 272
         itemBuilder: _buildItem,
273
-        itemCount: list.length,
273
+        itemCount: count,
274 274
       ),
275 275
     );
276 276
   }
277 277
 
278 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 285
     var data = list[index];
280 286
     return RepaintBoundary(
281 287
       child: GestureDetector(
@@ -297,6 +303,11 @@ class _PhotoMainPageState extends State<PhotoMainPage>
297 303
     );
298 304
   }
299 305
 
306
+  _loadMore() async {
307
+    await assetProvider.loadMore();
308
+    setState(() {});
309
+  }
310
+
300 311
   _buildMask(bool showMask) {
301 312
     return IgnorePointer(
302 313
       child: AnimatedContainer(
@@ -364,17 +375,22 @@ class _PhotoMainPageState extends State<PhotoMainPage>
364 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 392
       setState(() {});
377
-    });
393
+    }
378 394
   }
379 395
 
380 396
   void _onItemClick(AssetEntity data, int index) {
@@ -383,8 +399,8 @@ class _PhotoMainPageState extends State<PhotoMainPage>
383 399
     Navigator.of(context).push(
384 400
       MaterialPageRoute(
385 401
         builder: (ctx) {
386
-          return ConfigProvider(
387
-            provider: ConfigProvider.of(context).provider,
402
+          return PhotoPickerProvider(
403
+            provider: PhotoPickerProvider.of(context).provider,
388 404
             options: options,
389 405
             child: PhotoPreviewPage(
390 406
               selectedProvider: this,
@@ -392,6 +408,8 @@ class _PhotoMainPageState extends State<PhotoMainPage>
392 408
               initIndex: index,
393 409
               changeProviderOnCheckChange: true,
394 410
               result: result,
411
+              isPreview: false,
412
+              assetProvider: assetProvider,
395 413
             ),
396 414
           );
397 415
         },
@@ -411,14 +429,16 @@ class _PhotoMainPageState extends State<PhotoMainPage>
411 429
     isPushed = true;
412 430
     var v = await Navigator.of(context).push(
413 431
       MaterialPageRoute(
414
-        builder: (ctx) => ConfigProvider(
415
-          provider: ConfigProvider.of(context).provider,
432
+        builder: (ctx) => PhotoPickerProvider(
433
+          provider: PhotoPickerProvider.of(context).provider,
416 434
           options: options,
417 435
           child: PhotoPreviewPage(
418 436
             selectedProvider: this,
419 437
             list: List.of(selectedList),
420 438
             changeProviderOnCheckChange: false,
421 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 Visa fil

@@ -3,6 +3,7 @@ import 'dart:typed_data';
3 3
 
4 4
 import 'package:flutter/material.dart';
5 5
 import 'package:photo/src/entity/options.dart';
6
+import 'package:photo/src/provider/asset_provider.dart';
6 7
 import 'package:photo/src/provider/config_provider.dart';
7 8
 import 'package:photo/src/provider/selected_provider.dart';
8 9
 import 'package:photo/src/ui/page/photo_main_page.dart';
@@ -18,16 +19,23 @@ class PhotoPreviewPage extends StatefulWidget {
18 19
   /// 这个参数是控制在内部点击check后是否实时修改provider状态
19 20
   final bool changeProviderOnCheckChange;
20 21
 
22
+  /// 是否通过预览进来的
23
+  final bool isPreview;
24
+
21 25
   /// 这里封装了结果
22 26
   final PhotoPreviewResult result;
23 27
 
28
+  final AssetProvider assetProvider;
29
+
24 30
   const PhotoPreviewPage({
25 31
     Key key,
26 32
     @required this.selectedProvider,
27 33
     @required this.list,
28 34
     @required this.changeProviderOnCheckChange,
29 35
     @required this.result,
36
+    @required this.assetProvider,
30 37
     this.initIndex = 0,
38
+    this.isPreview = false,
31 39
   }) : super(key: key);
32 40
 
33 41
   @override
@@ -35,7 +43,8 @@ class PhotoPreviewPage extends StatefulWidget {
35 43
 }
36 44
 
37 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 49
   Options get options => config.options;
41 50
 
@@ -45,7 +54,12 @@ class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
45 54
 
46 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 64
   StreamController<int> pageChangeController = StreamController.broadcast();
51 65
 
@@ -96,6 +110,13 @@ class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
96 110
 
97 111
   @override
98 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 120
     var data = Theme.of(context);
100 121
     var textStyle = TextStyle(
101 122
       color: options.textColor,
@@ -114,33 +135,35 @@ class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
114 135
           title: StreamBuilder(
115 136
             stream: pageStream,
116 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 147
           actions: <Widget>[
125 148
             StreamBuilder(
126 149
               stream: pageStream,
127 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 163
         body: PageView.builder(
141 164
           controller: pageController,
142 165
           itemBuilder: _buildItem,
143
-          itemCount: list.length,
166
+          itemCount: totalCount,
144 167
           onPageChanged: _onPageChanged,
145 168
         ),
146 169
         bottomSheet: _buildThumb(),
@@ -244,6 +267,10 @@ class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
244 267
   }
245 268
 
246 269
   Widget _buildItem(BuildContext context, int index) {
270
+    if (!widget.isPreview && index >= list.length - 5) {
271
+      _loadMore();
272
+    }
273
+
247 274
     var data = list[index];
248 275
     return BigPhotoImage(
249 276
       assetEntity: data,
@@ -251,6 +278,10 @@ class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
251 278
     );
252 279
   }
253 280
 
281
+  Future<void> _loadMore() async {
282
+    assetProvider.loadMore();
283
+  }
284
+
254 285
   Widget _buildLoadingWidget(AssetEntity entity) {
255 286
     return options.loadingDelegate
256 287
         .buildBigImageLoading(context, entity, themeColor);
@@ -263,13 +294,13 @@ class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
263 294
   Widget _buildThumb() {
264 295
     return StreamBuilder(
265 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 304
       stream: pageStream,
274 305
     );
275 306
   }

+ 1
- 1
lib/src/ui/photo_app.dart Visa fil

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