Add Supa account and search changes

This commit is contained in:
Fabian Freund
2026-05-22 18:10:22 +02:00
parent 3a19865b2e
commit 51289f1266
374 changed files with 54061 additions and 5013 deletions
@@ -27,6 +27,7 @@ import 'package:simple_intent_receiver/simple_intent_receiver.dart';
import 'package:uri_to_file/uri_to_file.dart' as uri_to_file;
import 'package:weblibre/core/logger.dart';
import 'package:weblibre/data/models/received_intent_parameter.dart';
import 'package:weblibre/features/account/domain/services/account_callback_handler.dart';
import 'package:weblibre/features/intent_gatekeeper/domain/entities/intent_source_policy.dart';
import 'package:weblibre/features/intent_gatekeeper/domain/services/intent_gatekeeper.dart';
import 'package:weblibre/features/share_intent/domain/entities/intent_container_mode.dart';
@@ -42,6 +43,13 @@ _buildSharingIntentTransformer(
IntentGatekeeper gatekeeper,
) => StreamTransformer<Intent, ReceivedIntentParameter>.fromHandlers(
handleData: (intent, sink) async {
if (_extractAccountCallback(intent) != null) {
// Account callback intents are consumed by accountCallbackStreamProvider —
// suppress them from the regular share/sharing intent pipeline so they
// don't open a browser tab.
return;
}
final alwaysAllowPackage =
intent.extra[_alwaysAllowPackageExtra] as String?;
if (alwaysAllowPackage != null) {
@@ -150,10 +158,76 @@ _buildSharingIntentTransformer(
},
);
/// Shared intent receiver instance. Both the sharing intent stream
/// and the account callback handler listen to its broadcast events.
@Riverpod(keepAlive: true)
Raw<IntentReceiver> intentReceiver(Ref ref) {
final receiver = IntentReceiver.setUp();
ref.onDispose(receiver.dispose);
return receiver;
}
/// Runs the receiver event stream through [transformer] and forwards it into a
/// fresh single-subscription controller wired up to [ref]'s lifecycle.
///
/// Centralising this in one helper means the two intent-consuming providers
/// below (sharing intents + account callbacks) agree on the receiver semantics:
/// `receiver.events` includes the recovered cold-start intent for each
/// listener, plus all live intents.
Raw<Stream<T>> _consumeIntents<T>(
Ref ref,
IntentReceiver receiver,
StreamTransformer<Intent, T> transformer,
) {
final controller = StreamController<T>();
final sub = receiver.events
.transform(transformer)
.listen(controller.add, onError: controller.addError);
ref.onDispose(() {
unawaited(sub.cancel());
unawaited(controller.close());
});
return controller.stream;
}
@Riverpod(keepAlive: true)
Raw<Stream<ReceivedIntentParameter>> sharingIntentStream(Ref ref) {
final receiver = IntentReceiver.setUp();
final receiver = ref.watch(intentReceiverProvider);
final gatekeeper = ref.watch(intentGatekeeperProvider.notifier);
return receiver.events.transform(_buildSharingIntentTransformer(gatekeeper));
return _consumeIntents(
ref,
receiver,
_buildSharingIntentTransformer(gatekeeper),
);
}
/// Stream of account callback handoff codes extracted from deep link intents.
@Riverpod(keepAlive: true)
Raw<Stream<String>> accountCallbackStream(Ref ref) {
final receiver = ref.watch(intentReceiverProvider);
return _consumeIntents(ref, receiver, _accountCallbackTransformer);
}
/// Transformer that yields handoff codes for matching VIEW intents and
/// drops everything else. Shared with the sharing-intent suppression
/// branch via [_extractAccountCallback] so the two streams agree on which
/// intents are "account callbacks".
final _accountCallbackTransformer =
StreamTransformer<Intent, String>.fromHandlers(
handleData: (intent, sink) {
final callback = _extractAccountCallback(intent);
if (callback != null) {
sink.add(callback.handoffCode);
}
},
);
AccountCallback? _extractAccountCallback(Intent intent) {
if (intent.action != 'android.intent.action.VIEW' || intent.data == null) {
return null;
}
return tryParseAccountCallback(intent.data!);
}
@@ -8,6 +8,60 @@ part of 'sharing_intent.dart';
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: type=lint, type=warning
/// Shared intent receiver instance. Both the sharing intent stream
/// and the account callback handler listen to its broadcast events.
@ProviderFor(intentReceiver)
final intentReceiverProvider = IntentReceiverProvider._();
/// Shared intent receiver instance. Both the sharing intent stream
/// and the account callback handler listen to its broadcast events.
final class IntentReceiverProvider
extends
$FunctionalProvider<
Raw<IntentReceiver>,
Raw<IntentReceiver>,
Raw<IntentReceiver>
>
with $Provider<Raw<IntentReceiver>> {
/// Shared intent receiver instance. Both the sharing intent stream
/// and the account callback handler listen to its broadcast events.
IntentReceiverProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'intentReceiverProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$intentReceiverHash();
@$internal
@override
$ProviderElement<Raw<IntentReceiver>> $createElement(
$ProviderPointer pointer,
) => $ProviderElement(pointer);
@override
Raw<IntentReceiver> create(Ref ref) {
return intentReceiver(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(Raw<IntentReceiver> value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<Raw<IntentReceiver>>(value),
);
}
}
String _$intentReceiverHash() => r'61527e0581f56e82a8eec830ad541c8593502df3';
@ProviderFor(sharingIntentStream)
final sharingIntentStreamProvider = SharingIntentStreamProvider._();
@@ -56,4 +110,57 @@ final class SharingIntentStreamProvider
}
String _$sharingIntentStreamHash() =>
r'21b189c5df56f81ed5ab88115c11ddce1189cfb7';
r'02cef0c00bcb9416f8daf420977f58764c8efaca';
/// Stream of account callback handoff codes extracted from deep link intents.
@ProviderFor(accountCallbackStream)
final accountCallbackStreamProvider = AccountCallbackStreamProvider._();
/// Stream of account callback handoff codes extracted from deep link intents.
final class AccountCallbackStreamProvider
extends
$FunctionalProvider<
Raw<Stream<String>>,
Raw<Stream<String>>,
Raw<Stream<String>>
>
with $Provider<Raw<Stream<String>>> {
/// Stream of account callback handoff codes extracted from deep link intents.
AccountCallbackStreamProvider._()
: super(
from: null,
argument: null,
retry: null,
name: r'accountCallbackStreamProvider',
isAutoDispose: false,
dependencies: null,
$allTransitiveDependencies: null,
);
@override
String debugGetCreateSourceHash() => _$accountCallbackStreamHash();
@$internal
@override
$ProviderElement<Raw<Stream<String>>> $createElement(
$ProviderPointer pointer,
) => $ProviderElement(pointer);
@override
Raw<Stream<String>> create(Ref ref) {
return accountCallbackStream(ref);
}
/// {@macro riverpod.override_with_value}
Override overrideWithValue(Raw<Stream<String>> value) {
return $ProviderOverride(
origin: this,
providerOverride: $SyncValueProvider<Raw<Stream<String>>>(value),
);
}
}
String _$accountCallbackStreamHash() =>
r'669354c8000657bcaea046ab6318f89cb10dd7fc';