Skip to content

Commit 8f47661

Browse files
authored
Merge pull request #225 from Piwigo/receive-image-share
Add support for sharing images from external apps - Build issues fixed by foojay resolve - New model in a future PR - Dependencies bump fixed white screen issue - workmanager update fixed notification issue
2 parents b46f4ca + 7f3b30e commit 8f47661

16 files changed

Lines changed: 223 additions & 64 deletions

.fvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"flutter": "3.32.5"
2+
"flutter": "3.32.8"
33
}

android/app/build.gradle.kts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ plugins {
88
id("dev.flutter.flutter-gradle-plugin")
99
}
1010

11+
java {
12+
toolchain {
13+
languageVersion = JavaLanguageVersion.of(17)
14+
}
15+
}
1116
// https://docs.flutter.dev/deployment/android#configure-signing-in-gradle
1217
val keystoreProperties = Properties()
1318
val keystorePropertiesFile = rootProject.file("key.properties")
@@ -30,10 +35,6 @@ android {
3035
targetCompatibility = JavaVersion.VERSION_17
3136
}
3237

33-
kotlinOptions {
34-
jvmTarget = JavaVersion.VERSION_17.toString()
35-
}
36-
3738
defaultConfig {
3839
applicationId = "com.piwigo.piwigo_ng"
3940
multiDexEnabled = true
@@ -45,10 +46,10 @@ android {
4546

4647
signingConfigs {
4748
create("release") {
48-
keyAlias = keystoreProperties["keyAlias"] as String
49-
keyPassword = keystoreProperties["keyPassword"] as String
49+
keyAlias = keystoreProperties["keyAlias"] as? String
50+
keyPassword = keystoreProperties["keyPassword"] as? String
5051
storeFile = keystoreProperties["storeFile"]?.let { file(it) }
51-
storePassword = keystoreProperties["storePassword"] as String
52+
storePassword = keystoreProperties["storePassword"] as? String
5253
}
5354
}
5455

android/app/src/main/AndroidManifest.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@
3737
<action android:name="android.intent.action.MAIN"/>
3838
<category android:name="android.intent.category.LAUNCHER"/>
3939
</intent-filter>
40+
<intent-filter>
41+
<action android:name="android.intent.action.SEND" />
42+
<category android:name="android.intent.category.DEFAULT" />
43+
<data android:mimeType="image/*" />
44+
</intent-filter>
45+
<intent-filter>
46+
<action android:name="android.intent.action.SEND_MULTIPLE" />
47+
<category android:name="android.intent.category.DEFAULT" />
48+
<data android:mimeType="image/*" />
49+
</intent-filter>
4050
</activity>
4151

4252
<!-- Don't delete the meta-data below.

android/gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists
6-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
6+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip

android/settings.gradle.kts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@ pluginManagement {
1717
}
1818

1919
plugins {
20+
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
2021
id("dev.flutter.flutter-plugin-loader") version "1.0.0"
21-
id("com.android.application") version "8.10.1" apply false
22-
id("org.jetbrains.kotlin.android") version "2.0.21" apply false
22+
id("com.android.application") version "8.12.1" apply false
23+
id("org.jetbrains.kotlin.android") version "2.2.0" apply false
2324
}
2425

2526
include(":app")

l10n/app_en.arb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,16 @@
313313
"moveCategoryError_title": "Move Fail",
314314
"moveCategoryError_message": "Failed to move your album",
315315

316+
"selectCategory": "Select Album",
317+
"selectCategory_select": "Please select an album or sub-album.",
318+
"selectCategory_message": "{count, plural, =1{Are you sure you want to upload the image into the album {parent} ?} other{Are you sure you want to upload the images into the album {parent} ?}}",
319+
"@selectCategory_message" : {
320+
"placeholders": {
321+
"count": {},
322+
"parent": {}
323+
}
324+
},
325+
316326

317327
"categoryPrivacy": "Manage Permissions",
318328
"categoryPrivacy_subtitle": "Manage access permissions of \"{album_name}\".",

lib/app.dart

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'package:flutter_localizations/flutter_localizations.dart';
44
import 'package:image_picker/image_picker.dart';
55
import 'package:piwigo_ng/services/app_providers.dart';
66
import 'package:piwigo_ng/services/preferences_service.dart';
7+
import 'package:piwigo_ng/services/receive_sharing.dart';
78
import 'package:piwigo_ng/utils/overscroll_behavior.dart';
89
import 'package:piwigo_ng/utils/themes.dart';
910
import 'package:piwigo_ng/views/album/album_page.dart';
@@ -92,10 +93,9 @@ class App extends StatelessWidget {
9293
}
9394

9495
Route<dynamic> generateRoute(RouteSettings settings) {
96+
String? routeName;
9597
Map<String, dynamic> arguments = {};
96-
if (settings.arguments != null) {
97-
arguments = settings.arguments as Map<String, dynamic>;
98-
}
98+
bool externalAppSharedFiles = SharedIntent.sharedFiles != null && SharedIntent.sharedFiles!.isNotEmpty;
9999

100100
bool isAdmin = appPreferences.getBool(Preferences.isAdminKey) ?? false;
101101

@@ -107,7 +107,14 @@ Route<dynamic> generateRoute(RouteSettings settings) {
107107
);
108108
}
109109

110-
switch (settings.name) {
110+
if (externalAppSharedFiles) {
111+
routeName = UploadPage.routeName;
112+
} else {
113+
routeName = settings.name;
114+
arguments = _extractArguments(settings);
115+
}
116+
117+
switch (routeName) {
111118
case LoginPage.routeName:
112119
return MaterialPageRoute(
113120
builder: (_) => const LoginPage(),
@@ -164,13 +171,7 @@ Route<dynamic> generateRoute(RouteSettings settings) {
164171
settings: settings,
165172
);
166173
case UploadPage.routeName:
167-
return MaterialPageRoute(
168-
builder: (_) => UploadPage(
169-
imageList: arguments["images"] ?? <XFile>[],
170-
albumId: arguments["category"],
171-
),
172-
settings: settings,
173-
);
174+
return _createUploadPageRoute(settings, externalAppSharedFiles);
174175
case UploadStatusPage.routeName:
175176
return MaterialPageRoute(
176177
builder: (_) => UploadStatusPage(),
@@ -228,3 +229,41 @@ Route<dynamic> generateRoute(RouteSettings settings) {
228229
);
229230
}
230231
}
232+
233+
Map<String, dynamic> _extractArguments(RouteSettings settings) {
234+
if (settings.arguments != null) {
235+
return settings.arguments as Map<String, dynamic>;
236+
}
237+
return {};
238+
}
239+
240+
MaterialPageRoute<dynamic> _createUploadPageRoute(RouteSettings settings, bool externalAppSharedFiles) {
241+
Map<String, dynamic> arguments = {};
242+
243+
if (externalAppSharedFiles) {
244+
arguments['images'] = SharedIntent.sharedFiles;
245+
SharedIntent.cleanupSharedFiles();
246+
247+
// Create new RouteSettings with updated arguments
248+
return MaterialPageRoute(
249+
builder: (_) => UploadPage(
250+
imageList: arguments["images"] ?? <XFile>[],
251+
albumId: arguments["category"],
252+
),
253+
settings: RouteSettings( // Create new RouteSettings here
254+
name: UploadPage.routeName,
255+
arguments: arguments,
256+
),
257+
);
258+
} else {
259+
// For other cases, use original settings
260+
arguments = _extractArguments(settings);
261+
return MaterialPageRoute(
262+
builder: (_) => UploadPage(
263+
imageList: arguments["images"] ?? <XFile>[],
264+
albumId: arguments["category"],
265+
),
266+
settings: settings,
267+
);
268+
}
269+
}

lib/components/modals/move_or_copy_modal.dart renamed to lib/components/modals/select_move_or_copy_modal.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import 'package:piwigo_ng/network/albums.dart';
55
import 'package:piwigo_ng/network/api_error.dart';
66
import 'package:piwigo_ng/utils/localizations.dart';
77

8-
class MoveOrCopyModal extends StatefulWidget {
9-
const MoveOrCopyModal({
8+
class SelectMoveOrCopyModal extends StatefulWidget {
9+
const SelectMoveOrCopyModal({
1010
Key? key,
1111
this.album,
1212
this.isImage = false,
@@ -22,10 +22,10 @@ class MoveOrCopyModal extends StatefulWidget {
2222
final Future<dynamic> Function(AlbumModel)? onSelected;
2323

2424
@override
25-
_MoveOrCopyModalState createState() => _MoveOrCopyModalState();
25+
_SelectMoveOrCopyModalState createState() => _SelectMoveOrCopyModalState();
2626
}
2727

28-
class _MoveOrCopyModalState extends State<MoveOrCopyModal> {
28+
class _SelectMoveOrCopyModalState extends State<SelectMoveOrCopyModal> {
2929
late final Future<ApiResponse<List<AlbumModel>>> _albumFuture;
3030
late final List<int> _disabledAlbums;
3131

@@ -209,7 +209,7 @@ class _ExpansionAlbumTileState extends State<ExpansionAlbumTile> {
209209
child: Align(
210210
alignment: Alignment.centerLeft,
211211
child: Text(
212-
"${List.generate(widget.index, (index) => '.').join()}${widget.index > 0 ? ' ' : ''}${widget.album.name}",
212+
"${List.generate(widget.index, (index) => ' ').join()} > ${widget.index > 0 ? ' ' : ''}${widget.album.name}",
213213
overflow: TextOverflow.ellipsis,
214214
style: _disabled ? Theme.of(context).textTheme.bodySmall : Theme.of(context).textTheme.bodyMedium,
215215
),

lib/main.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,14 @@ import 'package:piwigo_ng/network/api_client.dart';
88
import 'package:piwigo_ng/services/auto_upload_manager.dart';
99
import 'package:piwigo_ng/services/notification_service.dart';
1010
import 'package:piwigo_ng/services/preferences_service.dart';
11+
import 'package:piwigo_ng/services/receive_sharing.dart';
1112
import 'package:piwigo_ng/services/theme_provider.dart';
1213
import 'package:shared_preferences/shared_preferences.dart';
1314

1415
void main() async {
1516
WidgetsFlutterBinding.ensureInitialized();
1617
_setUITheme();
18+
await SharedIntent.receiveSharedData();
1719
HttpOverrides.global = SSLHttpOverrides();
1820
appPreferences = await SharedPreferences.getInstance();
1921
runApp(const App());

lib/services/receive_sharing.dart

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import 'package:image_picker/image_picker.dart';
2+
import 'package:listen_sharing_intent/listen_sharing_intent.dart';
3+
4+
class SharedIntent {
5+
static List<XFile>? sharedFiles;
6+
static Future<List<XFile>?> receiveSharedData() async {
7+
try {
8+
// Get the instance of ReceiveSharingIntent
9+
ReceiveSharingIntent receiveSharingIntent = await ReceiveSharingIntent.instance;
10+
11+
// Get the initial shared data
12+
List<SharedMediaFile> receivedFiles = await receiveSharingIntent.getInitialMedia();
13+
14+
if (receivedFiles.isNotEmpty) {
15+
// Transform SharedMediaFile to XFile
16+
sharedFiles = receivedFiles.map((sharedFile) => XFile(sharedFile.path)).toList();
17+
return sharedFiles;
18+
} else {
19+
return null;
20+
}
21+
} catch (e) {
22+
print('Error receiving shared data: $e');
23+
return null;
24+
}
25+
}
26+
static void cleanupSharedFiles() {
27+
sharedFiles = null;
28+
}
29+
}

0 commit comments

Comments
 (0)