Skip to content

Commit 28dcdc3

Browse files
committed
Upload provider
1 parent 51f7d97 commit 28dcdc3

9 files changed

Lines changed: 232 additions & 126 deletions

File tree

android/app/src/main/AndroidManifest.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33

44
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
55
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
6+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
7+
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
8+
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
69
<uses-permission android:name="android.permission.CAMERA" />
710
<uses-permission android:name="android.permission.INTERNET"/>
811
<uses-permission android:name="android.permission.VIBRATE" />

lib/api/upload.dart

Lines changed: 56 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@ import 'package:image_picker/image_picker.dart';
1111
import 'package:path_provider/path_provider.dart';
1212
import 'package:piwigo_ng/api/api_client.dart';
1313
import 'package:piwigo_ng/api/authentication.dart';
14+
import 'package:piwigo_ng/app.dart';
1415
import 'package:piwigo_ng/services/preferences_service.dart';
16+
import 'package:piwigo_ng/services/upload_notifier.dart';
1517
import 'package:piwigo_ng/utils/localizations.dart';
18+
import 'package:provider/provider.dart';
1619

1720
import '../services/chunked_uploader.dart';
1821
import '../services/notification_service.dart';
@@ -38,7 +41,7 @@ Future<void> _showUploadNotification({bool success = true}) async {
3841
Future<List<Map<String, dynamic>>> uploadPhotos(
3942
List<XFile> photos,
4043
int albumId, {
41-
Map<String, dynamic>? info,
44+
Map<String, dynamic> info = const {},
4245
}) async {
4346
List<Map<String, dynamic>> result = [];
4447
List<int> uploadCompletedList = [];
@@ -47,13 +50,22 @@ Future<List<Map<String, dynamic>>> uploadPhotos(
4750
if (url == null) return [];
4851
String? username = await storage.read(key: 'SERVER_USERNAME');
4952
String? password = await storage.read(key: 'SERVER_PASSWORD');
50-
try {
51-
for (var photo in photos) {
52-
File? compressedFile = await compressFile(photo);
53-
if (compressedFile == null) {
53+
UploadNotifier uploadNotifier = App.appKey.currentContext!.read<UploadNotifier>();
54+
55+
for (var photo in photos) {
56+
File? compressedFile;
57+
UploadItem? item;
58+
try {
59+
if (Preferences.getRemoveMetadata) {
60+
compressedFile = await compressFile(photo);
61+
} else {
5462
compressedFile = File(photo.path);
5563
}
56-
// todo: upload video without chunk
64+
item = UploadItem(
65+
file: compressedFile,
66+
albumId: albumId,
67+
);
68+
uploadNotifier.addItem(item);
5769
Response? response = await uploadChunk(
5870
photo: compressedFile,
5971
category: albumId,
@@ -63,30 +75,41 @@ Future<List<Map<String, dynamic>>> uploadPhotos(
6375
info: info,
6476
onProgress: (progress) {
6577
debugPrint("$progress");
78+
item?.progress.sink.add(progress);
6679
},
6780
);
68-
print(response);
6981
if (response != null) {
7082
var data = json.decode(response.data);
71-
if (data["stat"] != "fail") {
83+
if (data['stat'] != 'fail') {
7284
result.add({
73-
"name": photo.name,
74-
"filename": photo.path.split("/").last,
75-
"url": data["result"]["element_url"],
85+
'id': data['result']['id'],
86+
'name': photo.name,
87+
'filename': photo.path.split('/').last,
88+
'url': data['result']['element_url'],
7689
});
77-
uploadCompletedList.add(data["result"]["id"]);
90+
uploadNotifier.itemUploadCompleted(item);
91+
if (Preferences.getDeleteAfterUpload) {
92+
// todo: delete real file path, not the cached one.
93+
}
94+
} else {
95+
uploadNotifier.itemUploadCompleted(item, error: true);
7896
}
97+
} else {
98+
uploadNotifier.itemUploadCompleted(item, error: true);
7999
}
100+
} catch (e) {
101+
if (item != null) {
102+
uploadNotifier.itemUploadCompleted(item, error: true);
103+
}
104+
debugPrint("$e");
80105
}
81-
_showUploadNotification(success: true);
82-
} on DioError catch (e) {
106+
}
107+
if (result.isEmpty) {
83108
_showUploadNotification(success: false);
84-
debugPrint(e.message);
85-
} on Error catch (e) {
86-
debugPrint(e.toString());
109+
return [];
87110
}
88-
if (uploadCompletedList.isEmpty) return [];
89-
111+
_showUploadNotification(success: true);
112+
uploadCompletedList = result.map<int>((e) => e['id']).toList();
90113
try {
91114
await uploadCompleted(uploadCompletedList, albumId);
92115
if (await methodExist('community.images.uploadCompleted')) {
@@ -103,7 +126,7 @@ Future<Response?> uploadChunk({
103126
required File photo,
104127
required int category,
105128
required String url,
106-
Map<String, dynamic>? info,
129+
Map<String, dynamic> info = const {},
107130
Function(double)? onProgress,
108131
String? username,
109132
String? password,
@@ -116,6 +139,11 @@ Future<Response?> uploadChunk({
116139
'category': category,
117140
};
118141

142+
if (info['name'] != '' && info['name'] != null) fields['name'] = info['name'];
143+
if (info['comment'] != '' && info['comment'] != null) fields['comment'] = info['comment'];
144+
if (info['tag_ids'].isNotEmpty) fields['tag_ids'] = info['tag_ids'];
145+
if (info['level'] != -1) fields['level'] = info['level'];
146+
119147
ChunkedUploader chunkedUploader = ChunkedUploader(Dio(
120148
BaseOptions(
121149
baseUrl: url,
@@ -136,23 +164,25 @@ Future<Response?> uploadChunk({
136164
);
137165
}
138166

139-
Future<File?> compressFile(XFile file) async {
167+
Future<File> compressFile(XFile file) async {
140168
try {
141169
final filePath = file.path;
142170
var dir = await getTemporaryDirectory();
143-
String filename = filePath.split('/').last;
144-
final outPath = "${dir.path}/compressed/$filename";
171+
final String filename = filePath.split('/').last;
172+
final outPath = "${dir.absolute.path}/$filename";
145173

146174
var result = await FlutterImageCompress.compressAndGetFile(
147175
filePath,
148176
outPath,
149-
quality: 10,
177+
quality: (Preferences.getUploadQuality * 100).round(),
178+
keepExif: false,
150179
);
151-
return result;
180+
debugPrint("Upload Compress $result");
181+
if (result != null) return result;
152182
} catch (e) {
153183
debugPrint(e.toString());
154184
}
155-
return null;
185+
return File(file.path);
156186
}
157187

158188
Future<bool> uploadCompleted(List<int> imageId, int categoryId) async {

lib/services/app_providers.dart

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:piwigo_ng/services/theme_provider.dart';
3+
import 'package:piwigo_ng/services/upload_notifier.dart';
34
import 'package:piwigo_ng/utils/LocaleProvider.dart';
45
import 'package:provider/provider.dart';
56

@@ -14,13 +15,18 @@ class AppProviders extends StatelessWidget {
1415
create: (_) => LocaleNotifier(),
1516
child: ChangeNotifierProvider(
1617
create: (_) => ThemeNotifier(),
17-
child: Consumer<LocaleNotifier>(builder: (context, localNotifier, child) {
18-
return Consumer<ThemeNotifier>(
19-
builder: (context, themeNotifier, child) {
20-
return builder(localNotifier, themeNotifier);
18+
child: ChangeNotifierProvider(
19+
create: (_) => UploadNotifier(),
20+
child: Consumer<LocaleNotifier>(
21+
builder: (context, localNotifier, child) {
22+
return Consumer<ThemeNotifier>(
23+
builder: (context, themeNotifier, child) {
24+
return builder(localNotifier, themeNotifier);
25+
},
26+
);
2127
},
22-
);
23-
}),
28+
),
29+
),
2430
),
2531
);
2632
}

lib/services/upload_notifier.dart

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import 'dart:async';
2+
import 'dart:io';
3+
4+
import 'package:flutter/material.dart';
5+
6+
class UploadNotifier extends ChangeNotifier {
7+
final List<UploadItem> _uploadList = [];
8+
final List<UploadItem> _uploadHistoryList = [];
9+
10+
UploadNotifier();
11+
12+
void addItem(UploadItem item) {
13+
_uploadList.add(item);
14+
notifyListeners();
15+
}
16+
17+
void itemUploadCompleted(UploadItem item, {bool error = false}) {
18+
_uploadList.remove(item);
19+
item.error = error;
20+
_uploadHistoryList.add(item);
21+
notifyListeners();
22+
}
23+
24+
void removeItem(UploadItem item) {
25+
_uploadList.remove(item);
26+
notifyListeners();
27+
}
28+
29+
void clearHistory() {
30+
_uploadHistoryList.clear();
31+
}
32+
33+
List<UploadItem> get uploadList => _uploadList;
34+
List<UploadItem> get uploadHistoryList => _uploadHistoryList;
35+
}
36+
37+
class UploadItem {
38+
final File file;
39+
final StreamController<double> progress;
40+
final int albumId;
41+
bool error;
42+
43+
UploadItem({
44+
required this.file,
45+
required this.albumId,
46+
this.error = false,
47+
}) : progress = StreamController<double>();
48+
}

lib/services/upload_provider.dart

Lines changed: 0 additions & 35 deletions
This file was deleted.

lib/utils/image_actions.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'package:piwigo_ng/components/modals/move_or_copy_modal.dart';
1212
import 'package:piwigo_ng/components/snackbars.dart';
1313
import 'package:piwigo_ng/models/album_model.dart';
1414
import 'package:piwigo_ng/models/image_model.dart';
15+
import 'package:piwigo_ng/services/preferences_service.dart';
1516
import 'package:piwigo_ng/utils/localizations.dart';
1617
import 'package:piwigo_ng/views/image/edit_image_page.dart';
1718

@@ -40,7 +41,11 @@ Future<XFile?> onTakePhoto(BuildContext context) async {
4041
XFile? image;
4142
switch (choice) {
4243
case 0:
43-
image = await picker.pickImage(source: ImageSource.camera);
44+
image = await picker.pickImage(
45+
source: ImageSource.camera,
46+
imageQuality: (Preferences.getUploadQuality * 100).round(),
47+
requestFullMetadata: Preferences.getRemoveMetadata,
48+
);
4449
break;
4550
case 1:
4651
image = await picker.pickVideo(source: ImageSource.camera);

0 commit comments

Comments
 (0)