Replace receive_sharing_intent; add background upload service; fix add-account login page
Sharing a large file to Noo used to black-screen and silently kick back to the home screen: receive_sharing_intent copies the entire shared file into the cache dir synchronously on the main thread before Flutter even renders, which Android's watchdog eventually kills. Replaced with hand-rolled handling in MainActivity.kt that only ever reads cheap Uri metadata up front (ShareIntentService), so the destination picker always appears instantly regardless of file size. The destination picker (ShareUploadView) now mirrors the Files tab's own controls/filters/listing instead of a bare folder list, and the actual prepare+upload is handed off to ShareUploadService.kt, a real Android foreground service with a single cancellable progress notification for the whole batch - this survives the app being closed right after the user confirms a destination, the same guarantee a file-manager app's own upload notification gives. Also fixes the "add another account" login page: it used to open in url_launcher's bare inAppWebView, which has no close button and can hide the status bar. LoginWebViewView is a real screen this app owns instead (package:webview_flutter), with a normal AppBar/close button/safe area, and can now auto-close itself on successful login. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
/// A file shared to Noo from another app's "Share to..." sheet, before its
|
||||
/// bytes have been touched - just the `content://` Uri and whatever cheap
|
||||
/// metadata Android will hand over without reading the file itself.
|
||||
class SharedFileRef {
|
||||
final String uri;
|
||||
final String name;
|
||||
final String? mimeType;
|
||||
final int? size;
|
||||
|
||||
const SharedFileRef({
|
||||
required this.uri,
|
||||
required this.name,
|
||||
this.mimeType,
|
||||
this.size,
|
||||
});
|
||||
|
||||
factory SharedFileRef.fromMap(Map<dynamic, dynamic> map) {
|
||||
return SharedFileRef(
|
||||
uri: map['uri'] as String,
|
||||
name: map['name'] as String? ?? 'shared_file',
|
||||
mimeType: map['mimeType'] as String?,
|
||||
size: (map['size'] as num?)?.toInt(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Talks to `MainActivity.kt`'s hand-rolled share-intent handling (see its
|
||||
/// doc comment for why this isn't the receive_sharing_intent plugin): it
|
||||
/// only ever exposes cheap Uri metadata up front. Actually reading a shared
|
||||
/// file's bytes - preparing and uploading it - is [UploadService]'s job
|
||||
/// (`ShareUploadService.kt`'s Android foreground service), not this one.
|
||||
class ShareIntentService {
|
||||
static const _methodChannel = MethodChannel('dev.ayushya.noo/share_intent');
|
||||
static const _newShareChannel = EventChannel(
|
||||
'dev.ayushya.noo/share_intent/new',
|
||||
);
|
||||
|
||||
/// Whatever was shared to launch the app cold (empty if it was launched
|
||||
/// normally, not via a share).
|
||||
static Future<List<SharedFileRef>> getInitialShare() async {
|
||||
final result = await _methodChannel.invokeMethod<List<dynamic>>(
|
||||
'getInitialShare',
|
||||
);
|
||||
return (result ?? [])
|
||||
.cast<Map<dynamic, dynamic>>()
|
||||
.map(SharedFileRef.fromMap)
|
||||
.toList();
|
||||
}
|
||||
|
||||
/// Emits whenever another share arrives while the app is already running.
|
||||
static Stream<List<SharedFileRef>> get onNewShare {
|
||||
return _newShareChannel.receiveBroadcastStream().map((event) {
|
||||
return (event as List<dynamic>)
|
||||
.cast<Map<dynamic, dynamic>>()
|
||||
.map(SharedFileRef.fromMap)
|
||||
.toList();
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user