11import 'dart:async' ;
22
3+ import 'package:auto_size_text/auto_size_text.dart' ;
34import 'package:flutter/material.dart' ;
45
56import 'package:piwigo_ng/api/API.dart' ;
@@ -13,6 +14,9 @@ import 'package:piwigo_ng/views/SettingsViewPage.dart';
1314import 'package:piwigo_ng/views/components/appbars.dart' ;
1415import 'package:piwigo_ng/views/components/dialogs/dialogs.dart' ;
1516
17+ import '../api/SearchAPI.dart' ;
18+ import 'ImageViewPage.dart' ;
19+
1620class RootCategoryViewPage extends StatefulWidget {
1721 final bool isAdmin;
1822
@@ -24,11 +28,21 @@ class _RootCategoryViewPageState extends State<RootCategoryViewPage> with Single
2428 String _rootCategory;
2529 TextEditingController _searchController = TextEditingController ();
2630 ScrollController _scrollController = ScrollController ();
31+ bool _isSearching = false ;
32+
33+ Future <Map <String ,dynamic >> _albumsFuture;
34+ Future <Map <String ,dynamic >> _imagesFuture;
2735
2836 @override
2937 void initState () {
3038 super .initState ();
3139 _rootCategory = "0" ;
40+ _searchController.addListener (() {
41+ _getData ();
42+ setState (() {
43+ _isSearching = _searchController.text.length > 0 ;
44+ });
45+ });
3246 WidgetsBinding .instance.addPostFrameCallback ((_) {
3347 API .uploader = Uploader (context);
3448 });
@@ -38,35 +52,89 @@ class _RootCategoryViewPageState extends State<RootCategoryViewPage> with Single
3852 super .dispose ();
3953 }
4054
55+ _getData () {
56+ _albumsFuture = fetchAlbums (_rootCategory);
57+ _imagesFuture = searchAlbums (_searchController.text);
58+ }
59+
4160 @override
4261 Widget build (BuildContext context) {
4362 ThemeData _theme = Theme .of (context);
4463 return Scaffold (
45- resizeToAvoidBottomInset: true ,
46- body: NestedScrollView (
47- controller: _scrollController,
48- headerSliverBuilder: (context, innerBoxScrolled) => [
49- // AppBarExpandable(
50- AppBarExpandableSearch (
51- scrollController: _scrollController,
52- textController: _searchController,
53- leading: IconButton (
54- onPressed: () {
55- Navigator .of (context).push (
56- MaterialPageRoute (builder: (context) => SettingsPage ()),
57- );
58- },
59- icon: Icon (Icons .settings, color: _theme.iconTheme.color),
60- ),
61- title: appStrings (context).tabBar_albums,
62- ),
63- ],
64- body: GestureDetector (
65- onTap: () {
66- FocusScope .of (context).unfocus ();
64+ body: GestureDetector (
65+ onTap: () {
66+ FocusScope .of (context).unfocus ();
67+ },
68+ child: NestedScrollView (
69+ controller: _scrollController,
70+ headerSliverBuilder: (context, bool ) {
71+ return [
72+ AppBarExpandable (
73+ scrollController: _scrollController,
74+ leading: IconButton (
75+ onPressed: () {
76+ Navigator .of (context).push (
77+ MaterialPageRoute (builder: (context) => SettingsPage ()),
78+ );
79+ },
80+ icon: Icon (Icons .settings, color: _theme.iconTheme.color),
81+ ),
82+ title: appStrings (context).tabBar_albums,
83+ ),
84+ AppBarExpandableSearch (
85+ textController: _searchController,
86+ ),
87+ ];
6788 },
68- child: FutureBuilder <Map <String ,dynamic >>(
69- future: fetchAlbums (_rootCategory), // Albums of the list
89+ body: Builder (builder: (context) {
90+ if (_isSearching) {
91+ return FutureBuilder <Map <String ,dynamic >>(
92+ future: _imagesFuture, // Albums of the list
93+ builder: (BuildContext context, AsyncSnapshot imagesSnapshot) {
94+ if (imagesSnapshot.hasData){
95+ if (imagesSnapshot.data['stat' ] == 'fail' ) {
96+ return Center (
97+ child: Text (appStrings (context).categoryImageList_noDataError),
98+ );
99+ }
100+ var images = imagesSnapshot.data['result' ]['images' ];
101+ var nbImages = images.length;
102+ return RefreshIndicator (
103+ displacement: 20 ,
104+ notificationPredicate: (notification) {
105+ return notification.metrics.atEdge;
106+ },
107+ onRefresh: () {
108+ setState (() {
109+ print ("refresh" );
110+ });
111+ return Future .delayed (Duration (milliseconds: 1000 ));
112+ },
113+ child: SingleChildScrollView (
114+ physics: NeverScrollableScrollPhysics (),
115+ child: Column (
116+ children: [
117+ _imageGrid (images),
118+ Center (
119+ child: Container (
120+ padding: EdgeInsets .all (10 ),
121+ child: Text (appStrings (context).imageCount (nbImages), style: TextStyle (fontSize: 20 , color: _theme.textTheme.bodyText2.color, fontWeight: FontWeight .w300)),
122+ ),
123+ ),
124+ ],
125+ ),
126+ ),
127+ );
128+ } else {
129+ return Center (
130+ child: CircularProgressIndicator (),
131+ );
132+ }
133+ },
134+ );
135+ }
136+ return FutureBuilder <Map <String ,dynamic >>(
137+ future: _albumsFuture, // Albums of the list
70138 builder: (BuildContext context, AsyncSnapshot albumSnapshot) {
71139 if (albumSnapshot.hasData){
72140 if (albumSnapshot.data['stat' ] == 'fail' ) {
@@ -93,6 +161,7 @@ class _RootCategoryViewPageState extends State<RootCategoryViewPage> with Single
93161 return Future .delayed (Duration (milliseconds: 1000 ));
94162 },
95163 child: SingleChildScrollView (
164+ physics: NeverScrollableScrollPhysics (),
96165 child: Column (
97166 children: [
98167 _albumGrid (albums),
@@ -111,11 +180,12 @@ class _RootCategoryViewPageState extends State<RootCategoryViewPage> with Single
111180 child: CircularProgressIndicator (),
112181 );
113182 }
114- }
115- ),
183+ },
184+ );
185+ }),
116186 ),
117187 ),
118- floatingActionButton: widget.isAdmin? FloatingActionButton (
188+ floatingActionButton: widget.isAdmin ? FloatingActionButton (
119189 onPressed: () {
120190 showDialog (
121191 context: context,
@@ -129,7 +199,7 @@ class _RootCategoryViewPageState extends State<RootCategoryViewPage> with Single
129199 });
130200 },
131201 child: Icon (Icons .create_new_folder, color: _theme.primaryColorLight, size: 30 ),
132- ) : Container () ,
202+ ) : null ,
133203 );
134204 }
135205
@@ -156,4 +226,58 @@ class _RootCategoryViewPageState extends State<RootCategoryViewPage> with Single
156226 },
157227 );
158228 }
229+ Widget _imageGrid (dynamic images) {
230+ return GridView .builder (
231+ gridDelegate: SliverGridDelegateWithFixedCrossAxisCount (
232+ crossAxisCount: getImageCrossAxisCount (context),
233+ mainAxisSpacing: 3.0 ,
234+ crossAxisSpacing: 3.0 ,
235+ ),
236+ padding: EdgeInsets .symmetric (horizontal: 5 ),
237+ itemCount: images.length,
238+ shrinkWrap: true ,
239+ physics: NeverScrollableScrollPhysics (),
240+ itemBuilder: (BuildContext context, int index) {
241+ var image = images[index];
242+ return InkWell (
243+ onTap: () {
244+ Navigator .of (context).push (
245+ MaterialPageRoute (builder: (context) => ImageViewPage (
246+ images: images,
247+ index: index,
248+ isAdmin: widget.isAdmin,
249+ )),
250+ ).whenComplete (() => setState (() {}));
251+ },
252+ child: Stack (
253+ alignment: Alignment .center,
254+ children: [
255+ Container (
256+ width: double .infinity,
257+ height: double .infinity,
258+ child: Image .network (images[index]["derivatives" ][API .prefs.getString ('thumbnail_size' )]["url" ],
259+ fit: BoxFit .cover,
260+ ),
261+ ),
262+ API .prefs.getBool ('show_thumbnail_title' )? Align (
263+ alignment: Alignment .bottomCenter,
264+ child: Container (
265+ width: double .infinity,
266+ color: Color (0x80ffffff ),
267+ child: AutoSizeText ('${image ['name' ]}' ,
268+ overflow: TextOverflow .ellipsis,
269+ maxLines: 1 ,
270+ style: TextStyle (fontSize: 12 ),
271+ maxFontSize: 14 , minFontSize: 7 ,
272+ textAlign: TextAlign .center,
273+ ),
274+ ),
275+ ) : Center (),
276+ ],
277+ ),
278+ );
279+ },
280+ );
281+ }
282+
159283}
0 commit comments