Skip to content

Commit 1a542d4

Browse files
committed
Auto upload functions, storage authorisation missing...
1 parent 1a3b9e1 commit 1a542d4

9 files changed

Lines changed: 326 additions & 116 deletions

File tree

l10n/app_en.arb

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -875,21 +875,21 @@
875875
"settings_autoUploadDestination": "Destination",
876876
"settings_autoUploadDestinationInvalid": "Invalid destination album",
877877
"settings_autoUploadDestinationInfo": "Please select the album or sub-album into which photos and videos will be auto-uploaded.",
878-
"settings_autoUploadPeriod": "Every",
879-
"settings_autoUploadPeriodMinutes": "{count, plural, =1{1 minute} other{{count} minutes}}",
880-
"@settings_autoUploadPeriodMinutes" : {
878+
"settings_autoUploadFrequency": "Every",
879+
"settings_autoUploadFrequencyMinutes": "{count, plural, =1{1 minute} other{{count} minutes}}",
880+
"@settings_autoUploadFrequencyMinutes" : {
881881
"placeholders": {
882882
"count": {}
883883
}
884884
},
885-
"settings_autoUploadPeriodHours": "{count, plural, =1{1 hour} other{{count} hours}}",
886-
"@settings_autoUploadPeriodHours" : {
885+
"settings_autoUploadFrequencyHours": "{count, plural, =1{1 hour} other{{count} hours}}",
886+
"@settings_autoUploadFrequencyHours" : {
887887
"placeholders": {
888888
"count": {}
889889
}
890890
},
891-
"settings_autoUploadPeriodDays": "{count, plural, =1{1 day} other{{count} days}}",
892-
"@settings_autoUploadPeriodDays" : {
891+
"settings_autoUploadFrequencyDays": "{count, plural, =1{1 day} other{{count} days}}",
892+
"@settings_autoUploadFrequencyDays" : {
893893
"placeholders": {
894894
"count": {}
895895
}

lib/api/authentication.dart

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,14 @@ Future<ApiResult<bool>> loginUser(
6060
);
6161
}
6262

63-
Map<String, String> queries = {'format': 'json', 'method': 'pwg.session.login'};
64-
Map<String, String> fields = {'username': username, 'password': password};
63+
Map<String, String> queries = {
64+
'format': 'json',
65+
'method': 'pwg.session.login',
66+
};
67+
Map<String, String> fields = {
68+
'username': username,
69+
'password': password,
70+
};
6571

6672
try {
6773
Response response = await ApiClient.post(

lib/api/upload.dart

Lines changed: 1 addition & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import 'package:dio/dio.dart';
66
import 'package:flutter/material.dart';
77
import 'package:flutter/services.dart';
88
import 'package:flutter_image_compress/flutter_image_compress.dart';
9-
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
109
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
1110
import 'package:image_picker/image_picker.dart';
1211
import 'package:path_provider/path_provider.dart';
@@ -23,37 +22,6 @@ import 'package:provider/provider.dart';
2322
import '../services/chunked_uploader.dart';
2423
import '../services/notification_service.dart';
2524

26-
Future<void> _showUploadNotification([int nbError = 0, int nbImage = 0]) async {
27-
if (!Preferences.getUploadNotification) return;
28-
final android = AndroidNotificationDetails(
29-
'piwigo-ng-upload',
30-
'Piwigo NG Upload',
31-
channelDescription: 'piwigo-ng',
32-
priority: Priority.high,
33-
importance: Importance.high,
34-
);
35-
final platform = NotificationDetails(android: android);
36-
late String title;
37-
String? message;
38-
if (nbError == 0 && nbImage == 0) {
39-
// Upload cancelled
40-
title = appStrings.uploadCancelled_title;
41-
} else if (nbError == 0 && nbImage > 0) {
42-
// Upload completed
43-
title = appStrings.imageUploadCompleted_title;
44-
message = nbImage == 1 ? appStrings.imageUploadCompleted_message : appStrings.imageUploadCompleted_message1;
45-
} else if (nbError > 0 && nbImage != nbError) {
46-
// Upload partially completed
47-
title = appStrings.coreDataStore_WarningTitle;
48-
message = appStrings.imageUploadCompleted_warning;
49-
} else {
50-
// Upload failed
51-
title = appStrings.uploadError_title;
52-
message = appStrings.uploadError_message;
53-
}
54-
await localNotification.show(1, title, message, platform);
55-
}
56-
5725
Future<List<int>> uploadPhotos(
5826
List<XFile> photos,
5927
int albumId, {
@@ -143,7 +111,7 @@ Future<List<int>> uploadPhotos(
143111
}
144112
}));
145113

146-
_showUploadNotification(nbError, result.length);
114+
showUploadNotification(nbError, result.length);
147115
if (result.isEmpty) return [];
148116
try {
149117
await uploadCompleted(result, albumId);

lib/models/album_model.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,32 @@ class AlbumModel {
6262
dateLast = json['date_last'],
6363
dateLastMax = json['max_date_last'],
6464
canUpload = json['can_upload'] ?? true;
65+
66+
Map<String, dynamic> toJson() => {
67+
'id': id,
68+
'name': name,
69+
'fullname': fullName,
70+
'comment': comment,
71+
'url': url,
72+
'tn_url': urlRepresentative,
73+
'permalink': permalink,
74+
'status': status,
75+
'uppercats': upperCategories,
76+
'id_uppercat': idUpperCategory,
77+
'global_rank': globalRank,
78+
'nb_images': nbImages,
79+
'total_nb_images': nbTotalImages,
80+
'nb_categories': nbCategories,
81+
'sub_categories': List.generate(children.length, (i) => children[i].toJson()),
82+
'representative_picture_id': idRepresentative,
83+
'date_last': dateLast,
84+
'max_date_last': dateLastMax,
85+
'can_upload': canUpload,
86+
};
87+
88+
@override
89+
operator ==(other) => other is AlbumModel && id == other.id;
90+
91+
@override
92+
int get hashCode => Object.hash(id, name);
6593
}

lib/services/auto_upload_manager.dart

Lines changed: 119 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,17 @@
1+
import 'dart:convert';
12
import 'dart:io';
23

4+
import 'package:connectivity_plus/connectivity_plus.dart';
5+
import 'package:dio/dio.dart';
36
import 'package:flutter/material.dart';
4-
import 'package:path_provider/path_provider.dart';
7+
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
8+
import 'package:piwigo_ng/api/api_error.dart';
9+
import 'package:piwigo_ng/api/authentication.dart';
10+
import 'package:piwigo_ng/api/upload.dart';
11+
import 'package:piwigo_ng/models/album_model.dart';
12+
import 'package:piwigo_ng/services/notification_service.dart';
513
import 'package:piwigo_ng/services/preferences_service.dart';
14+
import 'package:piwigo_ng/utils/settings.dart';
615
import 'package:shared_preferences/shared_preferences.dart';
716
import 'package:workmanager/workmanager.dart';
817

@@ -16,44 +25,133 @@ class AutoUploadManager {
1625
}
1726

1827
Future<void> endAutoUpload() async {
19-
appPreferences.setBool(
20-
Preferences.autoUploadKey,
21-
false,
22-
);
28+
SharedPreferences prefs = await SharedPreferences.getInstance();
29+
prefs.setBool(AutoUploadPrefs.autoUploadKey, false);
2330
await _manager.cancelByUniqueName(taskKey);
2431
}
2532

2633
Future<void> startAutoUpload() async {
27-
appPreferences.setBool(
28-
Preferences.autoUploadKey,
29-
true,
30-
);
34+
SharedPreferences prefs = await SharedPreferences.getInstance();
35+
int hours = prefs.getInt(AutoUploadPrefs.autoUploadFrequencyKey) ?? Settings.defaultAutoUploadFrequency;
36+
prefs.setBool(AutoUploadPrefs.autoUploadKey, true);
3137
await _manager.registerPeriodicTask(
3238
taskKey,
3339
taskKey,
34-
frequency: const Duration(minutes: 15),
40+
frequency: Duration(hours: hours),
3541
);
3642
}
3743

44+
Future<bool> autoUpload() async {
45+
SharedPreferences prefs = await SharedPreferences.getInstance();
46+
if (prefs.getBool(Preferences.wifiUploadKey) ?? false) {
47+
print('Check wifi only');
48+
var connectivity = await Connectivity().checkConnectivity();
49+
if (connectivity != ConnectivityResult.wifi) {
50+
print('No wifi');
51+
return Future.value(false);
52+
}
53+
print('Has wifi');
54+
}
55+
final Directory? appDocDir = await getUploadDirectory();
56+
if (appDocDir == null) return false;
57+
print(appDocDir.listSync());
58+
List<FileSystemEntity> dirFiles = appDocDir.listSync();
59+
print(dirFiles);
60+
List<File> files = dirFiles
61+
.where((file) {
62+
print(file.runtimeType);
63+
return file is File;
64+
})
65+
.map<File>((e) => e as File)
66+
.toList();
67+
debugPrint(files.toString());
68+
autoUploadPhotos(files);
69+
return Future.value(true);
70+
}
71+
3872
Future<Directory?> getUploadDirectory() async {
39-
return await getTemporaryDirectory();
73+
SharedPreferences prefs = await SharedPreferences.getInstance();
74+
String? path = prefs.getString(AutoUploadPrefs.autoUploadSourceKey);
75+
if (path == null) return null;
76+
return Directory(path);
77+
}
78+
79+
Future<void> autoUploadPhotos(List<File> photos) async {
80+
if (photos.isEmpty) return;
81+
List<int> result = [];
82+
SharedPreferences prefs = await SharedPreferences.getInstance();
83+
FlutterSecureStorage storage = const FlutterSecureStorage();
84+
String? url = await storage.read(key: 'SERVER_URL');
85+
if (url == null) return;
86+
String? username = await storage.read(key: 'SERVER_USERNAME');
87+
String? password = await storage.read(key: 'SERVER_PASSWORD');
88+
int nbError = 0;
89+
String? albumJson = appPreferences.getString(AutoUploadPrefs.autoUploadDestinationKey);
90+
if (albumJson == null) return null;
91+
AlbumModel destination = AlbumModel.fromJson(json.decode(albumJson));
92+
93+
// todo: login
94+
// login
95+
ApiResult<bool> success = await loginUser(url, username: username ?? '', password: password ?? '');
96+
if (!(success.data ?? false)) {
97+
debugPrint('login error');
98+
return;
99+
}
100+
101+
// upload
102+
await Future.wait(List<Future<void>>.generate(photos.length, (index) async {
103+
File file = photos[index];
104+
try {
105+
// Make Request
106+
Response? response = await uploadChunk(
107+
photo: file,
108+
category: destination.id,
109+
url: url,
110+
username: username,
111+
password: password,
112+
onProgress: (progress) {
113+
debugPrint("${file.path} | $progress");
114+
},
115+
);
116+
117+
// Handle result
118+
if (response == null || json.decode(response.data)['stat'] == 'fail') {
119+
nbError++;
120+
} else {
121+
var data = json.decode(response.data);
122+
result.add(data['result']['id']);
123+
if (prefs.getBool(Preferences.deleteAfterUploadKey) ?? false) {
124+
// todo: delete file
125+
}
126+
}
127+
} on DioError catch (e) {
128+
debugPrint("${e.type}");
129+
} catch (e) {
130+
debugPrint("$e");
131+
nbError++;
132+
}
133+
}));
134+
135+
// notifications
136+
showAutoUploadNotification(nbError, result.length);
137+
if (result.isEmpty) return;
138+
// empty lunge
139+
try {
140+
await uploadCompleted(result, destination.id);
141+
if (await methodExist('community.images.uploadCompleted')) {
142+
await communityUploadCompleted(result, destination.id);
143+
}
144+
} on DioError catch (e) {
145+
debugPrint(e.message);
146+
}
40147
}
41148
}
42149

43150
@pragma('vm:entry-point')
44151
void callbackDispatcher() {
45152
Workmanager().executeTask((task, inputData) async {
46-
final SharedPreferences prefs = await SharedPreferences.getInstance();
47153
debugPrint("Background $task");
48-
debugPrint(prefs.getString('UPLOAD_AUTHOR_NAME') ?? '');
49-
final Directory? appDocDir = await AutoUploadManager().getUploadDirectory();
50-
if (appDocDir == null) return false;
51-
debugPrint(appDocDir.listSync().toString());
52-
// final List<File> files = appDocDir.listSync().whereType<File>().toList();
53-
// List<XFile> uploadFiles = files.map<XFile>((file) => XFile(file.path)).toList();
54-
// final result = await uploadPhotos(uploadFiles, 92);
55-
// debugPrint(result.toString());
56-
return Future.value(true);
154+
return await AutoUploadManager().autoUpload();
57155
});
58156
}
59157

lib/services/notification_service.dart

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
33
import 'package:open_filex/open_filex.dart';
4+
import 'package:piwigo_ng/services/preferences_service.dart';
5+
import 'package:piwigo_ng/utils/localizations.dart';
6+
import 'package:piwigo_ng/utils/settings.dart';
47

58
final FlutterLocalNotificationsPlugin localNotification = FlutterLocalNotificationsPlugin();
69

@@ -55,3 +58,62 @@ Future<void> showLocalNotification({
5558
payload: payload,
5659
);
5760
}
61+
62+
Future<void> showUploadNotification([int nbError = 0, int nbImage = 0]) async {
63+
if (!Preferences.getUploadNotification) return;
64+
final android = AndroidNotificationDetails(
65+
'piwigo-ng-upload',
66+
'Piwigo NG Upload',
67+
channelDescription: 'piwigo-ng',
68+
priority: Priority.high,
69+
importance: Importance.high,
70+
);
71+
final platform = NotificationDetails(android: android);
72+
late String title;
73+
String? message;
74+
if (nbError == 0 && nbImage == 0) {
75+
// Upload cancelled
76+
title = appStrings.uploadCancelled_title;
77+
} else if (nbError == 0 && nbImage > 0) {
78+
// Upload completed
79+
title = appStrings.imageUploadCompleted_title;
80+
message = nbImage == 1 ? appStrings.imageUploadCompleted_message : appStrings.imageUploadCompleted_message1;
81+
} else if (nbError > 0 && nbImage != nbError) {
82+
// Upload partially completed
83+
title = appStrings.coreDataStore_WarningTitle;
84+
message = appStrings.imageUploadCompleted_warning;
85+
} else {
86+
// Upload failed
87+
title = appStrings.uploadError_title;
88+
message = appStrings.uploadError_message;
89+
}
90+
await localNotification.show(Settings.uploadNotificationId, title, message, platform);
91+
}
92+
93+
Future<void> showAutoUploadNotification([int nbError = 0, int nbImage = 0]) async {
94+
if (!Preferences.getUploadNotification) return;
95+
final android = AndroidNotificationDetails(
96+
'piwigo-ng-upload',
97+
'Piwigo NG Upload',
98+
channelDescription: 'piwigo-ng',
99+
priority: Priority.high,
100+
importance: Importance.high,
101+
);
102+
final platform = NotificationDetails(android: android);
103+
late String title;
104+
String? message;
105+
if (nbError == 0 && nbImage > 0) {
106+
// Upload completed
107+
title = appStrings.imageUploadCompleted_title;
108+
message = nbImage == 1 ? appStrings.imageUploadCompleted_message : appStrings.imageUploadCompleted_message1;
109+
} else if (nbError > 0 && nbImage != nbError) {
110+
// Upload partially completed
111+
title = appStrings.coreDataStore_WarningTitle;
112+
message = appStrings.imageUploadCompleted_warning;
113+
} else {
114+
// Upload failed
115+
title = appStrings.uploadError_title;
116+
message = appStrings.uploadError_message;
117+
}
118+
await localNotification.show(Settings.autoUploadNotificationId, title, message, platform);
119+
}

0 commit comments

Comments
 (0)