iOS Share Extension: pick the destination inside the share sheet
SwiftUI folder picker in the extension (WebDAV PROPFIND), account shared via a Keychain group, upload on a background session that outlives the extension and is finished by the app. The inbox + notification hand-off remains as the fallback (no account / 'choose later'). Shared code moves to ios/Shared. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5.5
parent
525504bc47
commit
afc9b90963
+11
-1
@@ -22,6 +22,7 @@ import 'providers/shares_controller.dart';
|
||||
import 'providers/sync_status_controller.dart';
|
||||
import 'providers/trash_controller.dart';
|
||||
import 'services/pick_intent_service.dart';
|
||||
import 'services/share_account_service.dart';
|
||||
import 'services/share_intent_service.dart';
|
||||
import 'theme/app_theme.dart';
|
||||
import 'theme/design_tokens.dart';
|
||||
@@ -58,7 +59,16 @@ void main() {
|
||||
providers: [
|
||||
ChangeNotifierProvider(create: (_) => ConnectivityController()),
|
||||
ChangeNotifierProvider(
|
||||
create: (context) => SessionController(context.read()),
|
||||
create: (context) {
|
||||
final session = SessionController(context.read());
|
||||
// iOS's Share Extension has no Flutter engine; it picks its
|
||||
// folders/uploads as whichever account was last published here.
|
||||
session.addAccountReadyListener(
|
||||
() => ShareAccountService.publish(session),
|
||||
);
|
||||
session.addAccountClearedListener(ShareAccountService.clear);
|
||||
return session;
|
||||
},
|
||||
),
|
||||
ChangeNotifierProvider(create: (_) => SettingsController()),
|
||||
// Before SyncStatusController, which follows its Files Cache rule
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import '../providers/session_controller.dart';
|
||||
import 'native_channel.dart';
|
||||
|
||||
/// Tells the native side which account is active, so iOS's Share Extension -
|
||||
/// a separate process with no Flutter engine - can list folders and upload as
|
||||
/// it without opening the app (`ios/Runner/Native/NativeServices.swift`'s
|
||||
/// `share_account`, stored in a Keychain group shared with the extension).
|
||||
/// Android has no equivalent (its share intent opens the app itself), so
|
||||
/// there the channel simply doesn't exist and both calls are no-ops.
|
||||
class ShareAccountService {
|
||||
static const _channel = MethodChannel('dev.ayushya.noo/share_account');
|
||||
|
||||
/// Publishes the active account (call whenever one becomes active).
|
||||
static Future<void> publish(SessionController session) async {
|
||||
final authHeader = session.service?.authHeaders['Authorization'];
|
||||
if (authHeader == null || session.serverUrl.isEmpty) return;
|
||||
final host = Uri.tryParse(session.serverUrl)?.host ?? session.serverUrl;
|
||||
await invokeIfAvailable(_channel, 'setAccount', {
|
||||
'serverUrl': session.serverUrl,
|
||||
'username': session.username,
|
||||
'authHeader': authHeader,
|
||||
'displayName': '${session.username}@$host',
|
||||
});
|
||||
}
|
||||
|
||||
/// Forgets it (sign-out / switching away) so the extension stops offering
|
||||
/// uploads to an account that's no longer signed in.
|
||||
static Future<void> clear() => invokeIfAvailable(_channel, 'clearAccount');
|
||||
}
|
||||
Reference in New Issue
Block a user