Skip to content

Commit 3bbbd6d

Browse files
committed
Working Auto upload
1 parent 1a542d4 commit 3bbbd6d

5 files changed

Lines changed: 142 additions & 45 deletions

File tree

lib/api/upload.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import 'package:piwigo_ng/services/upload_notifier.dart';
1818
import 'package:piwigo_ng/utils/localizations.dart';
1919
import 'package:piwigo_ng/views/upload/upload_status_page.dart';
2020
import 'package:provider/provider.dart';
21+
import 'package:shared_preferences/shared_preferences.dart';
2122

2223
import '../services/chunked_uploader.dart';
2324
import '../services/notification_service.dart';
@@ -104,9 +105,17 @@ Future<List<int>> uploadPhotos(
104105
}
105106
}
106107
} on DioError catch (e) {
107-
debugPrint("${e.type}");
108+
debugPrint("${e.message}");
109+
debugPrint("${e.stackTrace}");
110+
uploadNotifier.itemUploadCompleted(item, error: true);
111+
nbError++;
108112
} catch (e) {
113+
if (e is Error) {
114+
debugPrint("$e");
115+
debugPrint("${e.stackTrace}");
116+
}
109117
debugPrint("$e");
118+
uploadNotifier.itemUploadCompleted(item, error: true);
110119
nbError++;
111120
}
112121
}));
@@ -148,7 +157,7 @@ Future<Response?> uploadChunk({
148157

149158
if (info['name'] != '' && info['name'] != null) fields['name'] = info['name'];
150159
if (info['comment'] != '' && info['comment'] != null) fields['comment'] = info['comment'];
151-
if (info['tag_ids'].isNotEmpty) fields['tag_ids'] = info['tag_ids'].join(',');
160+
if (info['tag_ids']?.isNotEmpty ?? false) fields['tag_ids'] = info['tag_ids'].join(',');
152161
if (info['level'] != -1) fields['level'] = info['level'];
153162

154163
ChunkedUploader chunkedUploader = ChunkedUploader(Dio(
@@ -194,13 +203,14 @@ Future<File> compressFile(XFile file) async {
194203
}
195204

196205
Future<bool> uploadCompleted(List<int> imageId, int categoryId) async {
206+
SharedPreferences prefs = await SharedPreferences.getInstance();
197207
Map<String, String> queries = {
198208
'format': 'json',
199209
'method': 'pwg.images.uploadCompleted',
200210
};
201211
FormData formData = FormData.fromMap({
202212
'image_id': imageId,
203-
'pwg_token': appPreferences.getString(Preferences.tokenKey),
213+
'pwg_token': prefs.getString(Preferences.tokenKey),
204214
'category_id': categoryId,
205215
});
206216

@@ -216,13 +226,14 @@ Future<bool> uploadCompleted(List<int> imageId, int categoryId) async {
216226
}
217227

218228
Future<bool> communityUploadCompleted(List<int> imageId, int categoryId) async {
229+
SharedPreferences prefs = await SharedPreferences.getInstance();
219230
Map<String, String> queries = {
220231
'format': 'json',
221232
'method': 'community.images.uploadCompleted',
222233
};
223234
FormData formData = FormData.fromMap({
224235
'image_id': imageId,
225-
'pwg_token': appPreferences.getString(Preferences.tokenKey),
236+
'pwg_token': prefs.getString(Preferences.tokenKey),
226237
'category_id': categoryId,
227238
});
228239
try {

lib/services/auto_upload_manager.dart

Lines changed: 98 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import 'package:connectivity_plus/connectivity_plus.dart';
55
import 'package:dio/dio.dart';
66
import 'package:flutter/material.dart';
77
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
8+
import 'package:image_picker/image_picker.dart';
9+
import 'package:piwigo_ng/api/api_client.dart';
810
import 'package:piwigo_ng/api/api_error.dart';
911
import 'package:piwigo_ng/api/authentication.dart';
1012
import 'package:piwigo_ng/api/upload.dart';
@@ -54,19 +56,11 @@ class AutoUploadManager {
5456
}
5557
final Directory? appDocDir = await getUploadDirectory();
5658
if (appDocDir == null) return false;
57-
print(appDocDir.listSync());
5859
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);
60+
List<File> files = dirFiles.where((file) => file is File).map<File>((e) => e as File).toList();
61+
debugPrint("List files: ${files.toString()}");
62+
await autoUploadPhotos(files);
63+
return true;
7064
}
7165

7266
Future<Directory?> getUploadDirectory() async {
@@ -86,21 +80,31 @@ class AutoUploadManager {
8680
String? username = await storage.read(key: 'SERVER_USERNAME');
8781
String? password = await storage.read(key: 'SERVER_PASSWORD');
8882
int nbError = 0;
89-
String? albumJson = appPreferences.getString(AutoUploadPrefs.autoUploadDestinationKey);
83+
String? albumJson = prefs.getString(AutoUploadPrefs.autoUploadDestinationKey);
9084
if (albumJson == null) return null;
9185
AlbumModel destination = AlbumModel.fromJson(json.decode(albumJson));
9286

87+
print('Try login');
9388
// todo: login
9489
// login
95-
ApiResult<bool> success = await loginUser(url, username: username ?? '', password: password ?? '');
90+
ApiResult<bool> success = await loginUser(
91+
url,
92+
username: username ?? '',
93+
password: password ?? '',
94+
);
95+
9696
if (!(success.data ?? false)) {
97-
debugPrint('login error');
97+
print('login error');
9898
return;
9999
}
100+
print('Login success');
100101

101102
// upload
102-
await Future.wait(List<Future<void>>.generate(photos.length, (index) async {
103-
File file = photos[index];
103+
for (File file in photos) {
104+
print("Try upload ${file.path}");
105+
if (prefs.getBool(Preferences.removeMetadataKey) ?? Settings.defaultRemoveMetadata) {
106+
file = await compressFile(XFile(file.path));
107+
}
104108
try {
105109
// Make Request
106110
Response? response = await uploadChunk(
@@ -109,15 +113,13 @@ class AutoUploadManager {
109113
url: url,
110114
username: username,
111115
password: password,
112-
onProgress: (progress) {
113-
debugPrint("${file.path} | $progress");
114-
},
115116
);
116117

117118
// Handle result
118119
if (response == null || json.decode(response.data)['stat'] == 'fail') {
119120
nbError++;
120121
} else {
122+
print("Upload success ${response.data}");
121123
var data = json.decode(response.data);
122124
result.add(data['result']['id']);
123125
if (prefs.getBool(Preferences.deleteAfterUploadKey) ?? false) {
@@ -126,25 +128,99 @@ class AutoUploadManager {
126128
}
127129
} on DioError catch (e) {
128130
debugPrint("${e.type}");
131+
nbError++;
132+
} on Error catch (e) {
133+
debugPrint("$e");
134+
debugPrint("${e.stackTrace}");
135+
nbError++;
129136
} catch (e) {
130137
debugPrint("$e");
131138
nbError++;
132139
}
133-
}));
140+
}
134141

135142
// notifications
136143
showAutoUploadNotification(nbError, result.length);
137144
if (result.isEmpty) return;
145+
print('Empty lunge');
138146
// empty lunge
139147
try {
140-
await uploadCompleted(result, destination.id);
148+
bool uploadCompletedSuccess = await uploadCompleted(result, destination.id);
149+
print(uploadCompletedSuccess);
141150
if (await methodExist('community.images.uploadCompleted')) {
142151
await communityUploadCompleted(result, destination.id);
143152
}
144153
} on DioError catch (e) {
145154
debugPrint(e.message);
146155
}
147156
}
157+
158+
Future<ApiResult<bool>> loginAutoUpload(
159+
String url, {
160+
String username = '',
161+
String password = '',
162+
}) async {
163+
if (url.isEmpty) {
164+
return ApiResult<bool>(
165+
data: false,
166+
error: ApiErrors.wrongServerUrl,
167+
);
168+
}
169+
170+
ApiClient.cookieJar.deleteAll();
171+
FlutterSecureStorage secureStorage = const FlutterSecureStorage();
172+
await secureStorage.write(key: 'SERVER_URL', value: url);
173+
174+
if (username.isEmpty && password.isEmpty) {
175+
return ApiResult<bool>(
176+
data: false,
177+
error: ApiErrors.wrongServerUrl,
178+
);
179+
}
180+
181+
Map<String, String> queries = {
182+
'format': 'json',
183+
'method': 'pwg.session.login',
184+
};
185+
Map<String, String> fields = {
186+
'username': username,
187+
'password': password,
188+
};
189+
190+
try {
191+
Response response = await ApiClient.post(
192+
data: FormData.fromMap(fields),
193+
options: Options(contentType: Headers.formUrlEncodedContentType),
194+
queryParameters: queries,
195+
);
196+
197+
if (response.statusCode == 200) {
198+
var data = json.decode(response.data);
199+
if (data['stat'] == 'fail') {
200+
return ApiResult<bool>(
201+
data: false,
202+
error: ApiErrors.wrongLoginId,
203+
);
204+
}
205+
await sessionStatus();
206+
return ApiResult<bool>(
207+
data: true,
208+
);
209+
}
210+
return ApiResult<bool>(
211+
data: false,
212+
error: ApiErrors.wrongLoginId,
213+
);
214+
} on DioError catch (e) {
215+
debugPrint(e.message);
216+
} catch (e) {
217+
debugPrint('Error $e');
218+
}
219+
return ApiResult<bool>(
220+
data: false,
221+
error: ApiErrors.wrongServerUrl,
222+
);
223+
}
148224
}
149225

150226
@pragma('vm:entry-point')

lib/services/chunked_uploader.dart

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:async';
2+
import 'dart:convert';
23
import 'dart:io';
34
import 'dart:math';
45

@@ -69,6 +70,7 @@ class UploadRequest {
6970
String originalSum;
7071
List<String> chunkSums = [];
7172
originalSum = await generateMd5(_file.openRead());
73+
7274
for (int i = 0; i < _chunksCount; i++) {
7375
final start = _getChunkStart(i);
7476
final end = _getChunkEnd(i);
@@ -82,21 +84,26 @@ class UploadRequest {
8284
final chunkStream = _getChunkStream(start, end);
8385

8486
final formData = FormData.fromMap({
85-
"chunks": _chunksCount,
86-
"chunk": i,
87-
"chunk_sum": chunkSums[i],
88-
"original_sum": originalSum,
89-
"file": MultipartFile(chunkStream, end - start, filename: fileName),
87+
'chunks': _chunksCount,
88+
'chunk': i,
89+
'chunk_sum': chunkSums[i],
90+
'original_sum': originalSum,
91+
'file': MultipartFile(chunkStream, end - start, filename: fileName),
9092
...data
9193
});
92-
finalResponse = await dio.request(
94+
95+
Response response = await dio.request(
9396
path,
9497
data: formData,
9598
queryParameters: params,
9699
cancelToken: cancelToken,
97100
options: Options(method: method, contentType: contentType),
98101
onSendProgress: (current, total) => _updateProgress(i, current, total),
99102
);
103+
104+
if (response.data != null && json.decode(response.data)?['result']?['id'] != null) {
105+
finalResponse = response;
106+
}
100107
}
101108
return finalResponse;
102109
}

lib/services/notification_service.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:open_filex/open_filex.dart';
44
import 'package:piwigo_ng/services/preferences_service.dart';
55
import 'package:piwigo_ng/utils/localizations.dart';
66
import 'package:piwigo_ng/utils/settings.dart';
7+
import 'package:shared_preferences/shared_preferences.dart';
78

89
final FlutterLocalNotificationsPlugin localNotification = FlutterLocalNotificationsPlugin();
910

@@ -91,10 +92,11 @@ Future<void> showUploadNotification([int nbError = 0, int nbImage = 0]) async {
9192
}
9293

9394
Future<void> showAutoUploadNotification([int nbError = 0, int nbImage = 0]) async {
94-
if (!Preferences.getUploadNotification) return;
95+
SharedPreferences prefs = await SharedPreferences.getInstance();
96+
if (!(prefs.getBool(Preferences.uploadNotificationKey) ?? false)) return;
9597
final android = AndroidNotificationDetails(
96-
'piwigo-ng-upload',
97-
'Piwigo NG Upload',
98+
'piwigo-ng-auto-upload',
99+
'Piwigo NG Auto Upload',
98100
channelDescription: 'piwigo-ng',
99101
priority: Priority.high,
100102
importance: Importance.high,

lib/services/preferences_service.dart

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -136,22 +136,23 @@ class Preferences {
136136

137137
/// Saves server info retrieved from pwg.session.getStatus API call
138138
static void saveStatus(StatusModel status) async {
139-
appPreferences.setString(accountUsernameKey, status.username);
140-
appPreferences.setString(tokenKey, status.pwgToken);
141-
appPreferences.setString(versionKey, status.version);
142-
appPreferences.setStringList(availableSizesKey, status.availableSizes);
139+
SharedPreferences prefs = await SharedPreferences.getInstance();
140+
prefs.setString(accountUsernameKey, status.username);
141+
prefs.setString(tokenKey, status.pwgToken);
142+
prefs.setString(versionKey, status.version);
143+
prefs.setStringList(availableSizesKey, status.availableSizes);
143144
if (status.realStatus != null) {
144-
appPreferences.setString(communityStatusKey, status.status);
145+
prefs.setString(communityStatusKey, status.status);
145146
status.status = status.realStatus!;
146147
}
147148
if (['admin', 'webmaster'].contains(status.status)) {
148-
appPreferences.setBool(isAdminKey, true);
149-
appPreferences.setInt(uploadChunkSizeKey, status.uploadFormChunkSize ?? 0);
150-
appPreferences.setString(fileTypesKey, status.uploadFileTypes ?? '');
149+
prefs.setBool(isAdminKey, true);
150+
prefs.setInt(uploadChunkSizeKey, status.uploadFormChunkSize ?? 0);
151+
prefs.setString(fileTypesKey, status.uploadFileTypes ?? '');
151152
} else {
152-
appPreferences.setBool(isAdminKey, false);
153+
prefs.setBool(isAdminKey, false);
153154
}
154-
appPreferences.setString(userStatusKey, status.status);
155+
prefs.setString(userStatusKey, status.status);
155156
}
156157
}
157158

0 commit comments

Comments
 (0)