feat(market): saved searches with in-app alerts (Wallapop-style)
Save the current market search (query + facets) and get notified when a matching offer appears in your zone while the app is open, with a catch-up scan on start. Adds a save affordance in the search bar, a saved-searches list (apply/delete) with a per-search new-match badge, an AppBar entry badged with the unseen total, and notification-tap routing to the list. Alerts evaluate against the user's current area, dedup via seen keys, and skip own/blocked/hidden/non-active offers. en+es strings.
This commit is contained in:
parent
c0cd299408
commit
93028c4933
9 changed files with 549 additions and 4 deletions
|
|
@ -41,6 +41,8 @@ import '../services/plantare_service.dart';
|
|||
import '../services/profile_cache.dart';
|
||||
import '../services/profile_store.dart';
|
||||
import '../services/saved_offers_store.dart';
|
||||
import '../services/saved_search_alert_service.dart';
|
||||
import '../services/saved_searches_store.dart';
|
||||
import '../services/social_account_store.dart';
|
||||
import '../services/social_connection.dart';
|
||||
import '../services/social_service.dart';
|
||||
|
|
@ -189,6 +191,9 @@ Future<void> configureDependencies() async {
|
|||
..registerSingleton<SavedOffersStore>(
|
||||
SavedOffersStore(secretStore, accountScope: scope),
|
||||
)
|
||||
..registerSingleton<SavedSearchesStore>(
|
||||
SavedSearchesStore(secretStore, accountScope: scope),
|
||||
)
|
||||
..registerSingleton<ExportImportService>(
|
||||
ExportImportService(
|
||||
repository: varietyRepository,
|
||||
|
|
@ -273,6 +278,18 @@ Future<void> configureDependencies() async {
|
|||
selfSecretKey: socialService.identity.privateKeyHex,
|
||||
connection: connection,
|
||||
),
|
||||
)
|
||||
// Watches the market for offers matching the user's saved searches and
|
||||
// fires an OS alert on a fresh match. Started in `Bootstrap`.
|
||||
..registerSingleton<SavedSearchAlertService>(
|
||||
SavedSearchAlertService(
|
||||
connection: connection,
|
||||
selfPubkey: socialService.publicKeyHex,
|
||||
store: getIt<SavedSearchesStore>(),
|
||||
settings: getIt<SocialSettings>(),
|
||||
notifications: getIt<NotificationService>(),
|
||||
alertTitle: (s) => t.savedSearches.alert(label: s.label),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +326,10 @@ Future<void> switchSocialAccount(int account) async {
|
|||
await getIt<PlantareService>().stop();
|
||||
await getIt.unregister<PlantareService>();
|
||||
}
|
||||
if (getIt.isRegistered<SavedSearchAlertService>()) {
|
||||
await getIt<SavedSearchAlertService>().stop();
|
||||
await getIt.unregister<SavedSearchAlertService>();
|
||||
}
|
||||
if (getIt.isRegistered<SocialConnection>()) {
|
||||
await getIt<SocialConnection>().dispose();
|
||||
await getIt.unregister<SocialConnection>();
|
||||
|
|
@ -324,6 +345,8 @@ Future<void> switchSocialAccount(int account) async {
|
|||
await getIt.unregister<ProfileCache>();
|
||||
await getIt<SavedOffersStore>().close();
|
||||
await getIt.unregister<SavedOffersStore>();
|
||||
await getIt<SavedSearchesStore>().close();
|
||||
await getIt.unregister<SavedSearchesStore>();
|
||||
|
||||
// Re-register the per-identity stores under the new scope, then the identity.
|
||||
getIt
|
||||
|
|
@ -339,6 +362,9 @@ Future<void> switchSocialAccount(int account) async {
|
|||
..registerSingleton<SavedOffersStore>(
|
||||
SavedOffersStore(secretStore, accountScope: scope),
|
||||
)
|
||||
..registerSingleton<SavedSearchesStore>(
|
||||
SavedSearchesStore(secretStore, accountScope: scope),
|
||||
)
|
||||
..registerSingleton<UnreadService>(
|
||||
UnreadService(getIt<MessageStore>(), secretStore),
|
||||
);
|
||||
|
|
@ -373,16 +399,26 @@ Future<void> switchSocialAccount(int account) async {
|
|||
selfSecretKey: social.identity.privateKeyHex,
|
||||
connection: connection,
|
||||
);
|
||||
final savedSearchAlerts = SavedSearchAlertService(
|
||||
connection: connection,
|
||||
selfPubkey: social.publicKeyHex,
|
||||
store: getIt<SavedSearchesStore>(),
|
||||
settings: getIt<SocialSettings>(),
|
||||
notifications: getIt<NotificationService>(),
|
||||
alertTitle: (s) => t.savedSearches.alert(label: s.label),
|
||||
);
|
||||
getIt
|
||||
..registerSingleton<SocialService>(social)
|
||||
..registerSingleton<SocialConnection>(connection)
|
||||
..registerSingleton<InboxService>(inbox)
|
||||
..registerSingleton<SyncService>(sync)
|
||||
..registerSingleton<PlantareService>(plantares);
|
||||
..registerSingleton<PlantareService>(plantares)
|
||||
..registerSingleton<SavedSearchAlertService>(savedSearchAlerts);
|
||||
// Subscribe the listeners BEFORE the connection starts connecting.
|
||||
inbox.start();
|
||||
sync.start();
|
||||
plantares.start();
|
||||
savedSearchAlerts.start();
|
||||
connection.start();
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue