Skip to content

Commit a78dd9c

Browse files
committed
Upload and download notifications
1 parent 28dcdc3 commit a78dd9c

12 files changed

Lines changed: 112 additions & 64 deletions

lib/api/albums.dart

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ Future<ApiResult<List<AlbumModel>>> fetchAlbums(int albumID) async {
3939
List<dynamic> jsonAlbums = json.decode(response.data)['result']['categories'];
4040
List<AlbumModel> albums = List<AlbumModel>.from(jsonAlbums.map(
4141
(album) {
42-
print(album);
4342
bool canUpload = false;
4443
if ((appPreferences.getBool(Preferences.isAdminKey) ?? false) ||
4544
uploadCategoryIdList.contains(album['id'].toString())) {

lib/api/authentication.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Future<ApiResult<bool>> loginUser(
4242
);
4343
}
4444

45+
ApiClient.cookieJar.deleteAll();
4546
FlutterSecureStorage secureStorage = const FlutterSecureStorage();
4647
await secureStorage.write(key: 'SERVER_URL', value: url);
4748

lib/api/images.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,8 +164,6 @@ Future<List<XFile>?> downloadImages(
164164
bool showNotification = true,
165165
bool cached = false,
166166
}) async {
167-
final isPermissionStatusGranted = await _requestPermissions();
168-
if (!isPermissionStatusGranted) return null;
169167
String? dirPath = (await getTemporaryDirectory()).path;
170168
if (!cached) {
171169
dirPath = await Preferences.getDownloadDestination;
@@ -181,7 +179,7 @@ Future<List<XFile>?> downloadImages(
181179
}
182180
});
183181

184-
if (showNotification) {
182+
if (showNotification && Preferences.getDownloadNotification) {
185183
if (files.isNotEmpty) {
186184
await _showDownloadNotification(
187185
success: true,
@@ -235,12 +233,12 @@ Future<int> deleteImages(
235233

236234
Future<bool> deleteImage(ImageModel image) async {
237235
Map<String, String> queries = {
238-
"format": "json",
239-
"method": "pwg.images.delete",
236+
'format': 'json',
237+
'method': 'pwg.images.delete',
240238
};
241239
FormData formData = FormData.fromMap({
242-
"image_id": image.id,
243-
"pwg_token": appPreferences.getString(Preferences.tokenKey),
240+
'image_id': image.id,
241+
'pwg_token': appPreferences.getString(Preferences.tokenKey),
244242
});
245243
try {
246244
Response response = await ApiClient.post(

lib/api/upload.dart

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,48 +45,55 @@ Future<List<Map<String, dynamic>>> uploadPhotos(
4545
}) async {
4646
List<Map<String, dynamic>> result = [];
4747
List<int> uploadCompletedList = [];
48+
List<UploadItem> items = [];
4849
FlutterSecureStorage storage = const FlutterSecureStorage();
4950
String? url = await storage.read(key: 'SERVER_URL');
5051
if (url == null) return [];
5152
String? username = await storage.read(key: 'SERVER_USERNAME');
5253
String? password = await storage.read(key: 'SERVER_PASSWORD');
5354
UploadNotifier uploadNotifier = App.appKey.currentContext!.read<UploadNotifier>();
5455

56+
/// Creates Upload Item list for the upload notifier
5557
for (var photo in photos) {
5658
File? compressedFile;
57-
UploadItem? item;
59+
if (Preferences.getRemoveMetadata) {
60+
compressedFile = await compressFile(photo);
61+
} else {
62+
compressedFile = File(photo.path);
63+
}
64+
items.add(UploadItem(
65+
file: compressedFile,
66+
albumId: albumId,
67+
));
68+
}
69+
70+
uploadNotifier.addItems(items);
71+
72+
/// Upload loop
73+
for (var item in items) {
5874
try {
59-
if (Preferences.getRemoveMetadata) {
60-
compressedFile = await compressFile(photo);
61-
} else {
62-
compressedFile = File(photo.path);
63-
}
64-
item = UploadItem(
65-
file: compressedFile,
66-
albumId: albumId,
67-
);
68-
uploadNotifier.addItem(item);
75+
/// Make Request
6976
Response? response = await uploadChunk(
70-
photo: compressedFile,
77+
photo: item.file,
7178
category: albumId,
7279
url: url,
7380
username: username,
7481
password: password,
7582
info: info,
7683
onProgress: (progress) {
7784
debugPrint("$progress");
78-
item?.progress.sink.add(progress);
85+
item.progress.sink.add(progress);
7986
},
8087
);
8188
if (response != null) {
8289
var data = json.decode(response.data);
8390
if (data['stat'] != 'fail') {
8491
result.add({
8592
'id': data['result']['id'],
86-
'name': photo.name,
87-
'filename': photo.path.split('/').last,
8893
'url': data['result']['element_url'],
8994
});
95+
96+
/// Notify provider upload completed
9097
uploadNotifier.itemUploadCompleted(item);
9198
if (Preferences.getDeleteAfterUpload) {
9299
// todo: delete real file path, not the cached one.
@@ -98,17 +105,16 @@ Future<List<Map<String, dynamic>>> uploadPhotos(
98105
uploadNotifier.itemUploadCompleted(item, error: true);
99106
}
100107
} catch (e) {
101-
if (item != null) {
102-
uploadNotifier.itemUploadCompleted(item, error: true);
103-
}
104108
debugPrint("$e");
105109
}
106110
}
107-
if (result.isEmpty) {
108-
_showUploadNotification(success: false);
109-
return [];
111+
if (Preferences.getUploadNotification) {
112+
if (result.isEmpty) {
113+
_showUploadNotification(success: false);
114+
}
115+
_showUploadNotification(success: true);
110116
}
111-
_showUploadNotification(success: true);
117+
if (result.isEmpty) return [];
112118
uploadCompletedList = result.map<int>((e) => e['id']).toList();
113119
try {
114120
await uploadCompleted(uploadCompletedList, albumId);
@@ -131,7 +137,10 @@ Future<Response?> uploadChunk({
131137
String? username,
132138
String? password,
133139
}) async {
134-
Map<String, String> queries = {"format": "json", "method": "pwg.images.uploadAsync"};
140+
Map<String, String> queries = {
141+
'format': 'json',
142+
'method': 'pwg.images.uploadAsync',
143+
};
135144
Map<String, dynamic> fields = {
136145
'username': username,
137146
'password': password,
@@ -151,7 +160,7 @@ Future<Response?> uploadChunk({
151160
));
152161

153162
return await chunkedUploader.upload(
154-
path: "/ws.php",
163+
path: '/ws.php',
155164
filePath: photo.absolute.path,
156165
maxChunkSize: 100000,
157166
params: queries,

lib/services/notification_service.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
3-
import 'package:open_file/open_file.dart';
3+
import 'package:open_filex/open_filex.dart';
44

55
final FlutterLocalNotificationsPlugin localNotification = FlutterLocalNotificationsPlugin();
66

@@ -18,7 +18,7 @@ void initLocalNotifications() {
1818
Future<void> onSelectNotification(NotificationResponse response) async {
1919
debugPrint("Notification payload: ${response.payload}");
2020
if (response.payload == null) return;
21-
OpenResult result = await OpenFile.open(response.payload);
21+
OpenResult result = await OpenFilex.open(response.payload);
2222
debugPrint(result.message);
2323
}
2424

lib/services/preferences_service.dart

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,19 +90,19 @@ class Preferences {
9090
return appPreferences.getDouble(uploadQualityKey) ?? Settings.defaultUploadQuality;
9191
}
9292

93-
static const String downloadDestination = 'DOWNLOAD_DESTINATION';
93+
static const String downloadDestinationKey = 'DOWNLOAD_DESTINATION';
9494
static Future<String?> get getDownloadDestination async {
95-
return appPreferences.getString(downloadDestination) ?? await pickDirectoryPath();
95+
return appPreferences.getString(downloadDestinationKey) ?? await pickDirectoryPath();
9696
}
9797

98-
static const String downloadNotification = 'DOWNLOAD_NOTIFICATION';
98+
static const String downloadNotificationKey = 'DOWNLOAD_NOTIFICATION';
9999
static bool get getDownloadNotification {
100-
return appPreferences.getBool(downloadNotification) ?? true;
100+
return appPreferences.getBool(downloadNotificationKey) ?? true;
101101
}
102102

103-
static const String uploadNotification = 'UPLOAD_NOTIFICATION';
103+
static const String uploadNotificationKey = 'UPLOAD_NOTIFICATION';
104104
static bool get getUploadNotification {
105-
return appPreferences.getBool(uploadNotification) ?? true;
105+
return appPreferences.getBool(uploadNotificationKey) ?? true;
106106
}
107107

108108
// ------------ Set preferences ------------

lib/services/upload_notifier.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ class UploadNotifier extends ChangeNotifier {
1414
notifyListeners();
1515
}
1616

17+
void addItems(List<UploadItem> item) {
18+
_uploadList.addAll(item);
19+
notifyListeners();
20+
}
21+
1722
void itemUploadCompleted(UploadItem item, {bool error = false}) {
1823
_uploadList.remove(item);
1924
item.error = error;
@@ -44,5 +49,5 @@ class UploadItem {
4449
required this.file,
4550
required this.albumId,
4651
this.error = false,
47-
}) : progress = StreamController<double>();
52+
}) : progress = StreamController<double>.broadcast();
4853
}

lib/utils/image_actions.dart

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@ import 'package:piwigo_ng/services/preferences_service.dart';
1616
import 'package:piwigo_ng/utils/localizations.dart';
1717
import 'package:piwigo_ng/views/image/edit_image_page.dart';
1818

19+
final ImagePicker _picker = ImagePicker();
20+
1921
Future<List<XFile>?> onPickImages() async {
2022
try {
23+
// List<XFile> images = await _picker.pickMultiImage(
24+
// imageQuality: (Preferences.getUploadQuality * 100).round(),
25+
// requestFullMetadata: Preferences.getRemoveMetadata,
26+
// );
27+
// if (images.isNotEmpty) return images;
2128
final FilePickerResult? result = await FilePicker.platform.pickFiles(
2229
allowMultiple: true,
2330
type: FileType.media,
@@ -37,18 +44,17 @@ Future<XFile?> onTakePhoto(BuildContext context) async {
3744
);
3845
if (choice == null) return null;
3946
try {
40-
final ImagePicker picker = ImagePicker();
4147
XFile? image;
4248
switch (choice) {
4349
case 0:
44-
image = await picker.pickImage(
50+
image = await _picker.pickImage(
4551
source: ImageSource.camera,
4652
imageQuality: (Preferences.getUploadQuality * 100).round(),
4753
requestFullMetadata: Preferences.getRemoveMetadata,
4854
);
4955
break;
5056
case 1:
51-
image = await picker.pickVideo(source: ImageSource.camera);
57+
image = await _picker.pickVideo(source: ImageSource.camera);
5258
break;
5359
}
5460
return image;

lib/views/authentication/login_form_view.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -257,10 +257,10 @@ class _LoginFormViewState extends State<LoginFormView> {
257257
: null,
258258
),
259259
Padding(
260-
padding: const EdgeInsets.only(top: 12),
260+
padding: const EdgeInsets.only(top: 12.0),
261261
child: AnimatedPiwigoButton(
262262
controller: _btnController,
263-
disabled: _urlError,
263+
// disabled: _urlError,
264264
color: Theme.of(context).primaryColor,
265265
onPressed: _onLogin,
266266
child: Text(

lib/views/image/image_view_page.dart

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ class _ImageViewPageState extends State<ImageViewPage> {
185185
return WillPopScope(
186186
onWillPop: _onWillPop,
187187
child: AnnotatedRegion<SystemUiOverlayStyle>(
188-
// Changes System overlay colors to match black background
188+
/// Changes System overlay colors to match black background
189189
value: SystemUiOverlayStyle.light.copyWith(
190190
systemNavigationBarColor: Colors.black.withOpacity(0.1),
191191
statusBarColor: Colors.black.withOpacity(0.1),
@@ -202,8 +202,9 @@ class _ImageViewPageState extends State<ImageViewPage> {
202202
children: [
203203
_content,
204204
_top,
205-
// Show bottom on portrait mode only
206-
// (to keep vertical space in landscape mode).
205+
206+
/// Show bottom on portrait mode only
207+
/// (to keep vertical space in landscape mode).
207208
if (orientation == Orientation.portrait) _bottom,
208209
],
209210
);
@@ -320,7 +321,7 @@ class _ImageViewPageState extends State<ImageViewPage> {
320321
behavior: HitTestBehavior.opaque,
321322
onTap: () => _onToggleOverlay(MediaQuery.of(context).orientation),
322323
child: PhotoViewGallery.builder(
323-
// Compatibility with PageView and PhotoView
324+
/// Compatibility with PageView and PhotoView
324325
pageController: _pageController,
325326
onPageChanged: (page) => setState(() {
326327
_page = page;
@@ -331,10 +332,12 @@ class _ImageViewPageState extends State<ImageViewPage> {
331332
itemCount: _imageList.length,
332333
builder: (context, index) {
333334
final ImageModel image = _imageList[index];
334-
// Check mime type of file (multiple test to ensure it is not null)
335+
print(image.derivatives);
336+
337+
/// Check mime type of file (multiple test to ensure it is not null)
335338
String? mimeType = mime(image.file) ?? mime(image.elementUrl) ?? mime(image.derivatives.medium.url);
336339
if (mimeType != null && mimeType.startsWith('video')) {
337-
// Returns video player
340+
/// Returns video player
338341
return PhotoViewGalleryPageOptions.customChild(
339342
disableGestures: true,
340343
child: VideoView(
@@ -346,7 +349,8 @@ class _ImageViewPageState extends State<ImageViewPage> {
346349
),
347350
);
348351
}
349-
// Default behavior: Zoomable image
352+
353+
/// Default behavior: Zoomable image
350354
return PhotoViewGalleryPageOptions(
351355
imageProvider: NetworkImage(
352356
image.getDerivativeFromString(Preferences.getImageFullScreenSize)?.url ?? '',

0 commit comments

Comments
 (0)