Skip to content

Commit 9ec4261

Browse files
committed
Upload history view
1 parent e621886 commit 9ec4261

5 files changed

Lines changed: 214 additions & 53 deletions

File tree

l10n/app_en.arb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,10 @@
195195
"categoryUpload_takePhoto": "Take Photo",
196196
"categoryUpload_takeVideo": "Take Video",
197197

198+
"uploadList_title": "Upload Status",
199+
"uploadList_uploading": "Uploading",
200+
"uploadList_history": "History",
201+
198202

199203
"setDefaultCategory_select": "Please select an album or sub-album which will become the new root album.",
200204
"setDefaultCategory_title": "Default Album",

lib/api/upload.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'package:piwigo_ng/components/dialogs/confirm_dialog.dart';
1717
import 'package:piwigo_ng/services/preferences_service.dart';
1818
import 'package:piwigo_ng/services/upload_notifier.dart';
1919
import 'package:piwigo_ng/utils/localizations.dart';
20+
import 'package:piwigo_ng/views/upload/upload_status_page.dart';
2021
import 'package:provider/provider.dart';
2122

2223
import '../services/chunked_uploader.dart';
@@ -99,6 +100,8 @@ Future<List<int>> uploadPhotos(
99100

100101
uploadNotifier.addItems(items);
101102

103+
App.navigatorKey.currentState?.popAndPushNamed(UploadStatusPage.routeName);
104+
102105
await Future.wait(List<Future<void>>.generate(items.length, (index) async {
103106
UploadItem item = items[index];
104107
try {

lib/components/cards/album_card.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,10 @@ class AlbumCardContent extends StatelessWidget {
213213
}
214214
return CachedNetworkImage(
215215
imageUrl: album.urlRepresentative!,
216-
fit: BoxFit.cover,
216+
imageBuilder: (context, provider) => Image(
217+
image: provider,
218+
fit: BoxFit.cover,
219+
),
217220
progressIndicatorBuilder: (context, url, download) => Center(
218221
child: CircularProgressIndicator(
219222
value: download.progress,

lib/utils/themes.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,20 @@ final ThemeData lightTheme = ThemeData.light().copyWith(
3636
foregroundColor: AppColors.accent,
3737
titleTextStyle: TextStyle(fontSize: 20.0, color: AppColors.black),
3838
),
39+
bottomNavigationBarTheme: BottomNavigationBarThemeData(
40+
selectedItemColor: AppColors.accent,
41+
selectedLabelStyle: TextStyle(
42+
fontSize: 14,
43+
color: AppColors.accent,
44+
fontWeight: FontWeight.w500,
45+
),
46+
unselectedItemColor: AppColors.black,
47+
unselectedLabelStyle: TextStyle(
48+
fontSize: 14,
49+
color: AppColors.black,
50+
fontWeight: FontWeight.normal,
51+
),
52+
),
3953
iconTheme: const IconThemeData(
4054
color: AppColors.accent,
4155
),
@@ -176,6 +190,20 @@ final ThemeData darkTheme = ThemeData.dark().copyWith(
176190
),
177191
titleTextStyle: TextStyle(fontSize: 20.0, color: AppColors.white),
178192
),
193+
bottomNavigationBarTheme: BottomNavigationBarThemeData(
194+
selectedItemColor: AppColors.accent,
195+
selectedLabelStyle: TextStyle(
196+
fontSize: 14,
197+
color: AppColors.accent,
198+
fontWeight: FontWeight.w500,
199+
),
200+
unselectedItemColor: AppColors.white,
201+
unselectedLabelStyle: TextStyle(
202+
fontSize: 14,
203+
color: AppColors.white,
204+
fontWeight: FontWeight.normal,
205+
),
206+
),
179207
iconTheme: const IconThemeData(
180208
color: AppColors.accent,
181209
),

lib/views/upload/upload_status_page.dart

Lines changed: 175 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,70 +15,193 @@ class UploadStatusPage extends StatefulWidget {
1515
}
1616

1717
class _UploadStatusPageState extends State<UploadStatusPage> {
18+
final PageController _pageController = PageController();
19+
final ScrollController _scrollController = ScrollController();
20+
21+
int _page = 0;
22+
1823
@override
1924
Widget build(BuildContext context) {
2025
return Scaffold(
2126
appBar: AppBar(
27+
centerTitle: true,
2228
scrolledUnderElevation: 5.0,
2329
title: Text(
24-
appStrings.tabBar_upload,
30+
appStrings.uploadList_title,
2531
style: Theme.of(context).appBarTheme.titleTextStyle,
2632
),
2733
),
28-
body: Consumer<UploadNotifier>(builder: (context, uploadNotifier, child) {
29-
if (uploadNotifier.uploadList.isEmpty) {
30-
return Center(
31-
child: Text(appStrings.noImages),
32-
);
33-
}
34-
return ListView.separated(
35-
padding: EdgeInsets.symmetric(vertical: 8.0),
36-
itemCount: uploadNotifier.uploadList.length,
37-
itemBuilder: (context, index) {
38-
UploadItem item = uploadNotifier.uploadList[index];
39-
return ListTile(
40-
dense: true,
41-
leading: ClipRRect(
42-
borderRadius: BorderRadius.circular(5.0),
43-
child: AspectRatio(
44-
aspectRatio: 1,
45-
child: Image.file(
46-
item.file,
47-
fit: BoxFit.cover,
48-
),
34+
body: PageView(
35+
controller: _pageController,
36+
onPageChanged: (page) => setState(() {
37+
_page = page;
38+
}),
39+
children: [
40+
_buildUploadList,
41+
_buildHistoryList,
42+
],
43+
),
44+
floatingActionButton: ScrollUpFloatingButton(
45+
controller: _scrollController,
46+
),
47+
bottomNavigationBar: BottomNavigationBar(
48+
currentIndex: _page,
49+
onTap: (index) => _pageController.animateToPage(
50+
index,
51+
duration: const Duration(milliseconds: 300),
52+
curve: Curves.ease,
53+
),
54+
items: [
55+
BottomNavigationBarItem(
56+
icon: Icon(Icons.list),
57+
label: appStrings.uploadList_uploading,
58+
),
59+
BottomNavigationBarItem(
60+
icon: Icon(Icons.history),
61+
label: appStrings.uploadList_history,
62+
),
63+
],
64+
),
65+
);
66+
}
67+
68+
Widget get _buildUploadList {
69+
return Consumer<UploadNotifier>(builder: (context, uploadNotifier, child) {
70+
if (uploadNotifier.uploadList.isEmpty) {
71+
return Center(
72+
child: Text(appStrings.noImages),
73+
);
74+
}
75+
return ListView.separated(
76+
padding: EdgeInsets.symmetric(vertical: 8.0),
77+
itemCount: uploadNotifier.uploadList.length,
78+
itemBuilder: (context, index) {
79+
UploadItem item = uploadNotifier.uploadList[index];
80+
return ListTile(
81+
dense: true,
82+
leading: ClipRRect(
83+
borderRadius: BorderRadius.circular(5.0),
84+
child: AspectRatio(
85+
aspectRatio: 1,
86+
child: Image.file(
87+
item.file,
88+
fit: BoxFit.cover,
4989
),
5090
),
51-
title: Text(
52-
item.file.path.split('/').last,
53-
style: Theme.of(context).textTheme.bodyMedium,
54-
),
55-
subtitle: StreamBuilder<double>(
56-
stream: item.progress.stream,
57-
initialData: 0.0,
58-
builder: (context, snapshot) {
59-
if (snapshot.hasData) {
60-
return LinearProgressIndicator(
61-
backgroundColor: Theme.of(context).colorScheme.secondary.withOpacity(0.3),
62-
value: min(snapshot.data!, 1.0),
63-
);
64-
}
65-
return LinearProgressIndicator();
66-
},
67-
),
68-
trailing: IconButton(
69-
onPressed: () {
70-
item.cancelToken.cancel();
71-
uploadNotifier.itemUploadCompleted(item);
72-
},
73-
icon: Icon(Icons.close),
74-
),
75-
);
76-
},
77-
separatorBuilder: (context, index) {
78-
return const Divider();
79-
},
91+
),
92+
title: Text(
93+
item.file.path.split('/').last,
94+
style: Theme.of(context).textTheme.bodyMedium,
95+
),
96+
subtitle: StreamBuilder<double>(
97+
stream: item.progress.stream,
98+
initialData: 0.0,
99+
builder: (context, snapshot) {
100+
if (snapshot.hasData) {
101+
return LinearProgressIndicator(
102+
backgroundColor: Theme.of(context).colorScheme.secondary.withOpacity(0.3),
103+
value: min(snapshot.data!, 1.0),
104+
);
105+
}
106+
return LinearProgressIndicator();
107+
},
108+
),
109+
trailing: IconButton(
110+
onPressed: () {
111+
item.cancelToken.cancel();
112+
uploadNotifier.itemUploadCompleted(item);
113+
},
114+
icon: Icon(Icons.close),
115+
),
116+
);
117+
},
118+
separatorBuilder: (context, index) {
119+
return const Divider();
120+
},
121+
);
122+
});
123+
}
124+
125+
Widget get _buildHistoryList {
126+
return Consumer<UploadNotifier>(builder: (context, uploadNotifier, child) {
127+
if (uploadNotifier.uploadHistoryList.isEmpty) {
128+
return Center(
129+
child: Text(appStrings.noImages),
80130
);
81-
}),
131+
}
132+
return ListView.separated(
133+
controller: _scrollController,
134+
padding: EdgeInsets.symmetric(vertical: 8.0),
135+
itemCount: uploadNotifier.uploadHistoryList.length,
136+
itemBuilder: (context, index) {
137+
UploadItem item = uploadNotifier.uploadHistoryList[index];
138+
return ListTile(
139+
dense: true,
140+
leading: ClipRRect(
141+
borderRadius: BorderRadius.circular(5.0),
142+
child: AspectRatio(
143+
aspectRatio: 1,
144+
child: Image.file(
145+
item.file,
146+
fit: BoxFit.cover,
147+
),
148+
),
149+
),
150+
title: Text(
151+
item.file.path.split('/').last,
152+
style: Theme.of(context).textTheme.bodyMedium,
153+
),
154+
subtitle: Builder(builder: (context) {
155+
if (item.error) {
156+
return Text(appStrings.errorHUD_label);
157+
} else if (item.cancelToken.isCancelled) {
158+
return Text(appStrings.uploadCancelled_title);
159+
}
160+
return Text(appStrings.completeHUD_label);
161+
}),
162+
);
163+
},
164+
separatorBuilder: (context, index) {
165+
return const Divider();
166+
},
167+
);
168+
});
169+
}
170+
}
171+
172+
class ScrollUpFloatingButton extends AnimatedWidget {
173+
const ScrollUpFloatingButton({
174+
Key? key,
175+
required this.controller,
176+
}) : super(key: key, listenable: controller);
177+
178+
static const Duration showDuration = Duration(milliseconds: 300);
179+
static const Duration scrollDuration = Duration(milliseconds: 700);
180+
static const Curve showCurve = Curves.ease;
181+
182+
final ScrollController controller;
183+
184+
@override
185+
Widget build(BuildContext context) {
186+
bool isHidden = !controller.hasClients || controller.offset < kToolbarHeight;
187+
return AnimatedScale(
188+
duration: showDuration,
189+
curve: showCurve,
190+
scale: isHidden ? 0.0 : 1.0,
191+
child: AnimatedOpacity(
192+
duration: showDuration,
193+
curve: showCurve,
194+
opacity: isHidden ? 0.0 : 1.0,
195+
child: FloatingActionButton(
196+
backgroundColor: Colors.grey.withOpacity(0.8),
197+
onPressed: () => controller.animateTo(
198+
0.0,
199+
duration: scrollDuration,
200+
curve: showCurve,
201+
),
202+
child: Icon(Icons.arrow_upward),
203+
),
204+
),
82205
);
83206
}
84207
}

0 commit comments

Comments
 (0)