Browse Source

大图页面的展示和基础框架

Caijinglong 6 years ago
parent
commit
97f0e46061

+ 4
- 4
lib/photo.dart View File

1
 library photo;
1
 library photo;
2
 
2
 
3
-import 'package:flutter/material.dart';
4
 import 'dart:async';
3
 import 'dart:async';
5
 
4
 
5
+import 'package:flutter/material.dart';
6
 import 'package:photo/src/entity/options.dart';
6
 import 'package:photo/src/entity/options.dart';
7
 import 'package:photo/src/provider/i18n_provider.dart';
7
 import 'package:photo/src/provider/i18n_provider.dart';
8
 import 'package:photo/src/ui/dialog/not_permission_dialog.dart';
8
 import 'package:photo/src/ui/dialog/not_permission_dialog.dart';
9
-import 'package:photo/src/ui/page/photo_main_page.dart';
9
+import 'package:photo/src/ui/photo_app.dart';
10
 import 'package:photo_manager/photo_manager.dart';
10
 import 'package:photo_manager/photo_manager.dart';
11
 
11
 
12
 /// A Calculator.
12
 /// A Calculator.
62
       rowCount: rowCount,
62
       rowCount: rowCount,
63
       dividerColor: dividerColor,
63
       dividerColor: dividerColor,
64
       maxSelected: maxSelected,
64
       maxSelected: maxSelected,
65
-      itemRadio:itemRadio,
65
+      itemRadio: itemRadio,
66
       padding: padding,
66
       padding: padding,
67
       disableColor: disableColor,
67
       disableColor: disableColor,
68
       textColor: textColor,
68
       textColor: textColor,
98
       BuildContext context, Options options, I18nProvider provider) {
98
       BuildContext context, Options options, I18nProvider provider) {
99
     return Navigator.of(context).push(
99
     return Navigator.of(context).push(
100
       MaterialPageRoute(
100
       MaterialPageRoute(
101
-        builder: (ctx) => PhotoMainPage(
101
+        builder: (ctx) => PhotoApp(
102
               options: options,
102
               options: options,
103
               provider: provider,
103
               provider: provider,
104
             ),
104
             ),

+ 23
- 0
lib/src/provider/config_provider.dart View File

1
+import 'package:flutter/material.dart';
2
+import 'package:photo/src/entity/options.dart';
3
+import 'package:photo/src/provider/i18n_provider.dart';
4
+
5
+class ConfigProvider extends InheritedWidget {
6
+  final Options options;
7
+  final I18nProvider provider;
8
+
9
+  ConfigProvider({
10
+    @required this.options,
11
+    @required this.provider,
12
+    @required Widget child,
13
+    Key key,
14
+  }) : super(key: key, child: child);
15
+
16
+  @override
17
+  bool updateShouldNotify(InheritedWidget oldWidget) {
18
+    return true;
19
+  }
20
+
21
+  static ConfigProvider of(BuildContext context) =>
22
+      context.inheritFromWidgetOfExactType(ConfigProvider);
23
+}

+ 52
- 22
lib/src/ui/page/photo_main_page.dart View File

3
 import 'package:flutter/material.dart';
3
 import 'package:flutter/material.dart';
4
 import 'package:photo/src/engine/lru_cache.dart';
4
 import 'package:photo/src/engine/lru_cache.dart';
5
 import 'package:photo/src/entity/options.dart';
5
 import 'package:photo/src/entity/options.dart';
6
+import 'package:photo/src/provider/config_provider.dart';
6
 import 'package:photo/src/provider/gallery_list_provider.dart';
7
 import 'package:photo/src/provider/gallery_list_provider.dart';
7
 import 'package:photo/src/provider/i18n_provider.dart';
8
 import 'package:photo/src/provider/i18n_provider.dart';
8
 import 'package:photo/src/provider/selected_provider.dart';
9
 import 'package:photo/src/provider/selected_provider.dart';
9
 import 'package:photo/src/ui/dialog/change_gallery_dialog.dart';
10
 import 'package:photo/src/ui/dialog/change_gallery_dialog.dart';
11
+import 'package:photo/src/ui/page/photo_preview_page.dart';
10
 import 'package:photo_manager/photo_manager.dart';
12
 import 'package:photo_manager/photo_manager.dart';
11
 
13
 
12
 class PhotoMainPage extends StatefulWidget {
14
 class PhotoMainPage extends StatefulWidget {
13
-  final Options options;
14
-  final I18nProvider provider;
15
+  final ValueChanged<List<ImageEntity>> onClose;
15
 
16
 
16
-  const PhotoMainPage({Key key, this.options, this.provider}) : super(key: key);
17
+  const PhotoMainPage({
18
+    Key key,
19
+    this.onClose,
20
+  }) : super(key: key);
17
 
21
 
18
   @override
22
   @override
19
   _PhotoMainPageState createState() => _PhotoMainPageState();
23
   _PhotoMainPageState createState() => _PhotoMainPageState();
21
 
25
 
22
 class _PhotoMainPageState extends State<PhotoMainPage>
26
 class _PhotoMainPageState extends State<PhotoMainPage>
23
     with SelectedProvider, GalleryListProvider {
27
     with SelectedProvider, GalleryListProvider {
24
-  Options get options => widget.options;
28
+  Options get options => ConfigProvider.of(context).options;
25
 
29
 
26
-  I18nProvider get i18nProvider => widget.provider;
30
+  I18nProvider get i18nProvider => ConfigProvider.of(context).provider;
27
 
31
 
28
   List<ImageEntity> list = [];
32
   List<ImageEntity> list = [];
29
 
33
 
65
       color: options.textColor,
69
       color: options.textColor,
66
       fontSize: 14.0,
70
       fontSize: 14.0,
67
     );
71
     );
68
-    return WillPopScope(
72
+    return Theme(
73
+      data: Theme.of(context).copyWith(primaryColor: options.themeColor),
69
       child: DefaultTextStyle(
74
       child: DefaultTextStyle(
70
         style: textStyle,
75
         style: textStyle,
71
         child: Scaffold(
76
         child: Scaffold(
72
           appBar: AppBar(
77
           appBar: AppBar(
73
-            backgroundColor: options.themeColor,
78
+            leading: IconButton(
79
+              icon: Icon(Icons.close),
80
+              onPressed: _cancel,
81
+            ),
74
             title: Text(
82
             title: Text(
75
               i18nProvider.getTitleText(options),
83
               i18nProvider.getTitleText(options),
76
             ),
84
             ),
93
             options: options,
101
             options: options,
94
             galleryName: currentPath.name,
102
             galleryName: currentPath.name,
95
             onGalleryChange: _onGalleryChange,
103
             onGalleryChange: _onGalleryChange,
104
+            onTapPreview: _onTapPreview,
96
             selectedProvider: this,
105
             selectedProvider: this,
97
             galleryListProvider: this,
106
             galleryListProvider: this,
98
           ),
107
           ),
99
         ),
108
         ),
100
       ),
109
       ),
101
-      onWillPop: () async {
102
-        selectedList.clear();
103
-        Navigator.of(context).pop(selectedList);
104
-        return false;
105
-      },
106
     );
110
     );
107
   }
111
   }
108
 
112
 
113
+  void _cancel() {
114
+    selectedList.clear();
115
+    widget.onClose(selectedList);
116
+  }
117
+
109
   @override
118
   @override
110
   bool isUpperLimit() {
119
   bool isUpperLimit() {
111
     var result = selectedCount == options.maxSelected;
120
     var result = selectedCount == options.maxSelected;
114
   }
123
   }
115
 
124
 
116
   void sure() {
125
   void sure() {
117
-    Navigator.pop(context, selectedList);
126
+    widget.onClose?.call(selectedList);
118
   }
127
   }
119
 
128
 
120
   void _showTip(String msg) {
129
   void _showTip(String msg) {
141
     var imageList = await currentPath.imageList;
150
     var imageList = await currentPath.imageList;
142
     this.list.clear();
151
     this.list.clear();
143
     this.list.addAll(imageList);
152
     this.list.addAll(imageList);
144
-    print(list);
145
     setState(() {});
153
     setState(() {});
146
   }
154
   }
147
 
155
 
258
       setState(() {});
266
       setState(() {});
259
     });
267
     });
260
   }
268
   }
269
+
270
+  void _onTapPreview() {
271
+    Navigator.of(context).push(
272
+      MaterialPageRoute(
273
+        builder: (ctx) => ConfigProvider(
274
+              provider: ConfigProvider.of(context).provider,
275
+              options: options,
276
+              child: PhotoPreviewPage(
277
+                selectedProvider: this,
278
+                list: List.of(selectedList),
279
+              ),
280
+            ),
281
+      ),
282
+    );
283
+  }
261
 }
284
 }
262
 
285
 
263
 class _BottomWidget extends StatefulWidget {
286
 class _BottomWidget extends StatefulWidget {
272
   final String galleryName;
295
   final String galleryName;
273
 
296
 
274
   final GalleryListProvider galleryListProvider;
297
   final GalleryListProvider galleryListProvider;
298
+  final VoidCallback onTapPreview;
275
 
299
 
276
   const _BottomWidget({
300
   const _BottomWidget({
277
     Key key,
301
     Key key,
281
     this.selectedProvider,
305
     this.selectedProvider,
282
     this.galleryName = "",
306
     this.galleryName = "",
283
     this.galleryListProvider,
307
     this.galleryListProvider,
308
+    this.onTapPreview,
284
   }) : super(key: key);
309
   }) : super(key: key);
285
 
310
 
286
   @override
311
   @override
295
   @override
320
   @override
296
   Widget build(BuildContext context) {
321
   Widget build(BuildContext context) {
297
     var textStyle = TextStyle(fontSize: 14.0, color: options.textColor);
322
     var textStyle = TextStyle(fontSize: 14.0, color: options.textColor);
298
-    print(MediaQuery.of(context).padding.bottom);
299
     const textPadding = const EdgeInsets.symmetric(horizontal: 16.0);
323
     const textPadding = const EdgeInsets.symmetric(horizontal: 16.0);
300
     return Container(
324
     return Container(
301
       color: options.themeColor,
325
       color: options.themeColor,
302
       child: SafeArea(
326
       child: SafeArea(
303
         bottom: true,
327
         bottom: true,
328
+        top: false,
304
         child: Container(
329
         child: Container(
305
           height: 44.0,
330
           height: 44.0,
306
           child: Row(
331
           child: Row(
321
               Expanded(
346
               Expanded(
322
                 child: Container(),
347
                 child: Container(),
323
               ),
348
               ),
324
-              Container(
325
-                height: 44.0,
326
-                alignment: Alignment.center,
327
-                child: Text(
328
-                  i18nProvider.getPreviewText(options, widget.selectedProvider),
329
-                  style: textStyle,
349
+              GestureDetector(
350
+                behavior: HitTestBehavior.translucent,
351
+                onTap: widget.onTapPreview,
352
+                child: Container(
353
+                  height: 44.0,
354
+                  alignment: Alignment.center,
355
+                  child: Text(
356
+                    i18nProvider.getPreviewText(
357
+                        options, widget.selectedProvider),
358
+                    style: textStyle,
359
+                  ),
360
+                  padding: textPadding,
330
                 ),
361
                 ),
331
-                padding: textPadding,
332
               ),
362
               ),
333
             ],
363
             ],
334
           ),
364
           ),

+ 123
- 0
lib/src/ui/page/photo_preview_page.dart View File

1
+import 'dart:async';
2
+import 'dart:io';
3
+
4
+import 'package:flutter/material.dart';
5
+import 'package:photo/src/entity/options.dart';
6
+import 'package:photo/src/provider/config_provider.dart';
7
+import 'package:photo/src/provider/selected_provider.dart';
8
+import 'package:photo_manager/photo_manager.dart';
9
+
10
+class PhotoPreviewPage extends StatefulWidget {
11
+  final SelectedProvider selectedProvider;
12
+
13
+  final List<ImageEntity> list;
14
+
15
+  const PhotoPreviewPage({Key key, this.selectedProvider, this.list})
16
+      : super(key: key);
17
+
18
+  @override
19
+  _PhotoPreviewPageState createState() => _PhotoPreviewPageState();
20
+}
21
+
22
+class _PhotoPreviewPageState extends State<PhotoPreviewPage> {
23
+  ConfigProvider get config => ConfigProvider.of(context);
24
+
25
+  Options get options => config.options;
26
+
27
+  Color get themeColor => options.themeColor;
28
+
29
+  Color get textColor => options.textColor;
30
+
31
+  List<ImageEntity> get list => widget.list;
32
+
33
+  StreamController<int> pageChangeController = StreamController.broadcast();
34
+
35
+  @override
36
+  void initState() {
37
+    super.initState();
38
+    pageChangeController.add(0);
39
+  }
40
+
41
+  @override
42
+  void dispose() {
43
+    pageChangeController.close();
44
+    super.dispose();
45
+  }
46
+
47
+  @override
48
+  Widget build(BuildContext context) {
49
+    return Theme(
50
+      data: Theme.of(context).copyWith(primaryColor: options.themeColor),
51
+      child: Scaffold(
52
+        appBar: AppBar(
53
+          backgroundColor: config.options.themeColor,
54
+          title: StreamBuilder(
55
+            stream: pageChangeController.stream,
56
+            initialData: 0,
57
+            builder: (ctx, snap) => Text(
58
+                  "${snap.data + 1}/${widget.list.length}",
59
+                ),
60
+          ),
61
+        ),
62
+        body: PageView.builder(
63
+          itemBuilder: _buildItem,
64
+          itemCount: list.length,
65
+          onPageChanged: _onPageChanged,
66
+        ),
67
+        bottomNavigationBar: _buildBottom(),
68
+      ),
69
+    );
70
+  }
71
+
72
+  Widget _buildBottom() {
73
+    return Container(
74
+      height: 44.0,
75
+      color: themeColor,
76
+    );
77
+  }
78
+
79
+  Widget _buildItem(BuildContext context, int index) {
80
+    var data = list[index];
81
+    return BigPhotoImage(
82
+      imageEntity: data,
83
+    );
84
+  }
85
+
86
+  void _onPageChanged(int value) {
87
+    pageChangeController.add(value);
88
+  }
89
+}
90
+
91
+class BigPhotoImage extends StatefulWidget {
92
+  final ImageEntity imageEntity;
93
+
94
+  const BigPhotoImage({Key key, this.imageEntity}) : super(key: key);
95
+
96
+  @override
97
+  _BigPhotoImageState createState() => _BigPhotoImageState();
98
+}
99
+
100
+class _BigPhotoImageState extends State<BigPhotoImage>
101
+    with AutomaticKeepAliveClientMixin {
102
+  @override
103
+  Widget build(BuildContext context) {
104
+    return FutureBuilder(
105
+      future: widget.imageEntity.file,
106
+      builder: (BuildContext context, AsyncSnapshot<File> snapshot) {
107
+        var file = snapshot.data;
108
+        if (snapshot.connectionState == ConnectionState.done && file != null) {
109
+          return Image.file(
110
+            file,
111
+            fit: BoxFit.contain,
112
+            width: double.infinity,
113
+            height: double.infinity,
114
+          );
115
+        }
116
+        return Container();
117
+      },
118
+    );
119
+  }
120
+
121
+  @override
122
+  bool get wantKeepAlive => true;
123
+}

+ 26
- 0
lib/src/ui/photo_app.dart View File

1
+import 'package:flutter/material.dart';
2
+import 'package:photo/src/entity/options.dart';
3
+import 'package:photo/src/provider/config_provider.dart';
4
+import 'package:photo/src/provider/i18n_provider.dart';
5
+import 'package:photo/src/ui/page/photo_main_page.dart';
6
+import 'package:photo_manager/photo_manager.dart';
7
+
8
+class PhotoApp extends StatelessWidget {
9
+  final Options options;
10
+  final I18nProvider provider;
11
+
12
+  const PhotoApp({Key key, this.options, this.provider}) : super(key: key);
13
+
14
+  @override
15
+  Widget build(BuildContext context) {
16
+    return ConfigProvider(
17
+      provider: provider,
18
+      options: options,
19
+      child: PhotoMainPage(
20
+        onClose: (List<ImageEntity> value) {
21
+          Navigator.pop(context, value);
22
+        },
23
+      ),
24
+    );
25
+  }
26
+}