mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 20:48:24 +00:00
Remove background flag, fix redirect to Amber
This commit is contained in:
@@ -11,3 +11,10 @@ const kFranzapPubkey =
|
||||
|
||||
/// Identifier for storing user bookmarks
|
||||
const kAppBookmarksIdentifier = 'zapstore-bookmarks';
|
||||
|
||||
/// Amber signer package ID
|
||||
const kAmberPackageId = 'com.greenart7c3.nostrsigner';
|
||||
|
||||
/// Amber signer naddr
|
||||
const kAmberNaddr =
|
||||
'naddr1qqdkxmmd9enhyet9deshyaphvvejumn0wd68yumfvahx2uszyp6hjpmdntls5n8aa7n7ypzlyjrv0ewch33ml3452wtjx0smhl93jqcyqqq8uzcgpp6ky';
|
||||
|
||||
@@ -275,7 +275,6 @@ Future<void> onSignInSuccess(Ref ref) async {
|
||||
RequestFilter<AppCatalogRelayList>(authors: {pubkey}).toRequest(),
|
||||
source: const RemoteSource(
|
||||
relays: 'bootstrap',
|
||||
background: false,
|
||||
stream: false,
|
||||
),
|
||||
),
|
||||
|
||||
+3
-33
@@ -36,27 +36,6 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
return GoRouter(
|
||||
initialLocation: '/search',
|
||||
routes: [
|
||||
// Top-level deep link route: /apps/:naddr
|
||||
// Redirect to search branch to show with nav bar
|
||||
GoRoute(
|
||||
path: '/apps/:naddr',
|
||||
redirect: (context, state) {
|
||||
final naddr = state.pathParameters['naddr'];
|
||||
if (naddr == null || naddr.isEmpty) {
|
||||
return '/search';
|
||||
}
|
||||
// Decode naddr to get app identifier
|
||||
try {
|
||||
final decoded = Utils.decodeShareableIdentifier(naddr);
|
||||
if (decoded is AddressData && decoded.identifier.isNotEmpty) {
|
||||
return '/search/app/${decoded.identifier}';
|
||||
}
|
||||
} catch (_) {
|
||||
// Invalid naddr
|
||||
}
|
||||
return '/search';
|
||||
},
|
||||
),
|
||||
// Top-level route for market:// intents
|
||||
// Redirect to search branch to show with nav bar
|
||||
GoRoute(
|
||||
@@ -80,10 +59,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
GoRoute(
|
||||
path: '/search',
|
||||
builder: (context, state) => const SearchScreen(),
|
||||
routes: [
|
||||
_appDetailRoute(),
|
||||
_userRoute(),
|
||||
],
|
||||
routes: [_appDetailRoute(), _userRoute()],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -93,10 +69,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
GoRoute(
|
||||
path: '/updates',
|
||||
builder: (context, state) => const UpdatesScreen(),
|
||||
routes: [
|
||||
_appDetailRoute(),
|
||||
_userRoute(),
|
||||
],
|
||||
routes: [_appDetailRoute(), _userRoute()],
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -106,10 +79,7 @@ final routerProvider = Provider<GoRouter>((ref) {
|
||||
GoRoute(
|
||||
path: '/profile',
|
||||
builder: (context, state) => const ProfileScreen(),
|
||||
routes: [
|
||||
_appDetailRoute(),
|
||||
_userRoute(),
|
||||
],
|
||||
routes: [_appDetailRoute(), _userRoute()],
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -48,14 +48,32 @@ class _AppLoaderView extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final platform = ref.read(packageManagerProvider.notifier).platform;
|
||||
|
||||
// Check if appId is an naddr and decode it
|
||||
String? identifier;
|
||||
String? author;
|
||||
|
||||
if (appId.startsWith('naddr1')) {
|
||||
try {
|
||||
final decoded = Utils.decodeShareableIdentifier(appId);
|
||||
if (decoded is AddressData) {
|
||||
identifier = decoded.identifier;
|
||||
author = decoded.author;
|
||||
}
|
||||
} catch (e) {
|
||||
// Invalid naddr, fall through to use appId as-is
|
||||
}
|
||||
}
|
||||
|
||||
// If we decoded an naddr, query by author/identifier, otherwise by #d tag
|
||||
final appsState = ref.watch(
|
||||
query<App>(
|
||||
authors: author != null ? {author} : null,
|
||||
tags: {
|
||||
'#d': {appId},
|
||||
'#d': {identifier ?? appId},
|
||||
'#f': {platform},
|
||||
},
|
||||
limit: 1,
|
||||
source: const LocalAndRemoteSource(stream: false, background: true),
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
|
||||
subscriptionPrefix: 'app-detail-loader',
|
||||
),
|
||||
);
|
||||
@@ -79,7 +97,10 @@ class _AppLoaderView extends ConsumerWidget {
|
||||
// Loading state
|
||||
return const Scaffold(
|
||||
body: SafeArea(
|
||||
child: Padding(padding: EdgeInsets.all(16), child: AppDetailSkeleton()),
|
||||
child: SingleChildScrollView(
|
||||
padding: EdgeInsets.all(16),
|
||||
child: AppDetailSkeleton(),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -125,20 +146,22 @@ class _AppDetailView extends HookConsumerWidget {
|
||||
final appState = ref.watch(
|
||||
model<App>(
|
||||
app,
|
||||
and: (a) => {
|
||||
a.latestRelease,
|
||||
if (a.latestRelease.value != null)
|
||||
a.latestRelease.value!.latestMetadata,
|
||||
},
|
||||
and: (a) => {a.latestRelease, a.latestRelease.value?.latestMetadata},
|
||||
source: LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
|
||||
subscriptionPrefix: 'app-detail',
|
||||
),
|
||||
);
|
||||
|
||||
// Query author profile from social relays
|
||||
final authorState = ref.watch(query<Profile>(
|
||||
authors: {app.pubkey},
|
||||
source: const LocalAndRemoteSource(relays: {'social', 'vertex'}, cachedFor: Duration(hours: 2)),
|
||||
));
|
||||
final authorState = ref.watch(
|
||||
query<Profile>(
|
||||
authors: {app.pubkey},
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: {'social', 'vertex'},
|
||||
cachedFor: Duration(hours: 2),
|
||||
),
|
||||
),
|
||||
);
|
||||
final author = switch (authorState) {
|
||||
StorageData(:final models) => models.firstOrNull,
|
||||
_ => null,
|
||||
@@ -227,9 +250,7 @@ class _AppDetailView extends HookConsumerWidget {
|
||||
final first = segments.isNotEmpty
|
||||
? segments.first
|
||||
: 'search';
|
||||
context.push(
|
||||
'/$first/user/${author.pubkey}',
|
||||
);
|
||||
context.push('/$first/user/${author.pubkey}');
|
||||
},
|
||||
)
|
||||
: const AuthorSkeleton(),
|
||||
@@ -327,7 +348,10 @@ class _AppDetailView extends HookConsumerWidget {
|
||||
),
|
||||
),
|
||||
|
||||
CommentsSection(app: currentApp, fileMetadata: latestMetadata),
|
||||
CommentsSection(
|
||||
app: currentApp,
|
||||
fileMetadata: latestMetadata,
|
||||
),
|
||||
|
||||
// Debug section - only visible for specific pubkey
|
||||
if (showDebugSections)
|
||||
|
||||
@@ -177,9 +177,8 @@ class _AuthenticationSection extends ConsumerWidget {
|
||||
|
||||
Widget _buildSignInOptions(BuildContext context, WidgetRef ref) {
|
||||
final packageManager = ref.watch(packageManagerProvider);
|
||||
const amberPackageId = 'com.greenart7c3.nostrsigner';
|
||||
final isAmberInstalled = packageManager.any(
|
||||
(p) => p.appId == amberPackageId,
|
||||
(p) => p.appId == kAmberPackageId,
|
||||
);
|
||||
|
||||
return Column(
|
||||
@@ -241,10 +240,7 @@ class _SignInButtonWithAmberCheck extends ConsumerWidget {
|
||||
return AsyncButtonBuilder(
|
||||
onPressed: () async {
|
||||
if (!isAmberInstalled) {
|
||||
// Navigate to Amber app page (within profile tab to keep bottom nav)
|
||||
context.push(
|
||||
'/profile/apps/naddr1qqdkxmmd9enhyet9deshyaphvvejumn0wd68yumfvahx2uszyp6hjpmdntls5n8aa7n7ypzlyjrv0ewch33ml3452wtjx0smhl93jqcyqqq8uzcgpp6ky',
|
||||
);
|
||||
context.push('/profile/app/$kAmberNaddr');
|
||||
} else {
|
||||
await ref.read(amberSignerProvider).signIn();
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ class SearchScreen extends HookConsumerWidget {
|
||||
source: const RemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: false,
|
||||
background: false,
|
||||
),
|
||||
subscriptionPrefix: 'search-results',
|
||||
),
|
||||
|
||||
@@ -44,11 +44,7 @@ class UserScreen extends HookConsumerWidget {
|
||||
app.latestRelease,
|
||||
app.latestRelease.value?.latestMetadata,
|
||||
},
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: false,
|
||||
background: true,
|
||||
),
|
||||
source: const LocalAndRemoteSource(relays: 'AppCatalog', stream: false),
|
||||
subscriptionPrefix: 'user-apps',
|
||||
),
|
||||
);
|
||||
@@ -64,15 +60,10 @@ class UserScreen extends HookConsumerWidget {
|
||||
authors: {pubkey},
|
||||
limit: 20,
|
||||
and: (pack) => {pack.apps},
|
||||
source: const LocalAndRemoteSource(
|
||||
stream: false,
|
||||
background: true,
|
||||
relays: 'social',
|
||||
),
|
||||
source: const LocalAndRemoteSource(stream: false, relays: 'social'),
|
||||
andSource: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: false,
|
||||
background: true,
|
||||
),
|
||||
subscriptionPrefix: 'user-packs',
|
||||
),
|
||||
|
||||
@@ -92,7 +92,6 @@ Future<bool> _checkForUpdatesInBackground() async {
|
||||
source: const RemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: false,
|
||||
background: false,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -107,7 +106,6 @@ Future<bool> _checkForUpdatesInBackground() async {
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: false,
|
||||
background: false,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ final bookmarksProvider = FutureProvider<Set<String>>((ref) async {
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'social',
|
||||
stream: false,
|
||||
background: false, // Single fetch; no live streaming
|
||||
),
|
||||
subscriptionPrefix: 'user-bookmarks',
|
||||
),
|
||||
|
||||
@@ -79,12 +79,10 @@ class CategorizedAppsNotifier extends StateNotifier<CategorizedApps> {
|
||||
},
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
background: true,
|
||||
stream: true,
|
||||
),
|
||||
andSource: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
background: true,
|
||||
stream: false,
|
||||
),
|
||||
subscriptionPrefix: 'updates',
|
||||
@@ -113,7 +111,6 @@ class CategorizedAppsNotifier extends StateNotifier<CategorizedApps> {
|
||||
RequestFilter<Profile>(authors: authorPubkeys).toRequest(),
|
||||
source: const RemoteSource(
|
||||
relays: 'social',
|
||||
background: false,
|
||||
stream: false,
|
||||
),
|
||||
);
|
||||
|
||||
@@ -100,7 +100,7 @@ extension AppsExt on Iterable<App> {
|
||||
.nonNulls
|
||||
.toList(),
|
||||
),
|
||||
source: const LocalAndRemoteSource(stream: false, background: true),
|
||||
source: const LocalAndRemoteSource(stream: false),
|
||||
);
|
||||
|
||||
if (withAuthors) {
|
||||
@@ -113,7 +113,6 @@ extension AppsExt on Iterable<App> {
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'vertex',
|
||||
stream: false,
|
||||
background: true,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,11 @@ class AppPackContainer extends HookConsumerWidget {
|
||||
and: (pack) => {pack.apps},
|
||||
source: const LocalAndRemoteSource(
|
||||
stream: true,
|
||||
background: true,
|
||||
relays: 'social',
|
||||
),
|
||||
andSource: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: false,
|
||||
background: true,
|
||||
),
|
||||
subscriptionPrefix: 'app-pack',
|
||||
),
|
||||
|
||||
@@ -2,15 +2,12 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:zapstore/constants/app_constants.dart';
|
||||
import 'package:zapstore/main.dart';
|
||||
import 'package:zapstore/services/notification_service.dart';
|
||||
import 'package:zapstore/services/package_manager/package_manager.dart';
|
||||
import 'package:zapstore/utils/debug_utils.dart';
|
||||
|
||||
const _amberPackageId = 'com.greenart7c3.nostrsigner';
|
||||
const _amberNaddr =
|
||||
'naddr1qqdkxmmd9enhyet9deshyaphvvejumn0wd68yumfvahx2uszyp6hjpmdntls5n8aa7n7ypzlyjrv0ewch33ml3452wtjx0smhl93jqcyqqq8uzcgpp6ky';
|
||||
|
||||
/// Reusable sign-in prompt widget for dialogs and bottom sheets.
|
||||
/// Displays a styled tappable message prompting the user to sign in.
|
||||
class SignInPrompt extends HookConsumerWidget {
|
||||
@@ -24,7 +21,7 @@ class SignInPrompt extends HookConsumerWidget {
|
||||
final theme = Theme.of(context);
|
||||
final packageManager = ref.watch(packageManagerProvider);
|
||||
final isAmberInstalled = packageManager.any(
|
||||
(p) => p.appId == _amberPackageId,
|
||||
(p) => p.appId == kAmberPackageId,
|
||||
);
|
||||
final isLoading = useState(false);
|
||||
|
||||
@@ -32,8 +29,12 @@ class SignInPrompt extends HookConsumerWidget {
|
||||
if (isLoading.value) return;
|
||||
|
||||
if (!isAmberInstalled) {
|
||||
context.showInfo('Install Amber to sign in with your Nostr identity');
|
||||
context.push('/profile/apps/$_amberNaddr');
|
||||
context.showInfo(
|
||||
'Install Amber to sign in with your Nostr identity',
|
||||
actions: [
|
||||
('Open Amber', () async => context.push('/search/app/$kAmberNaddr')),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
isLoading.value = true;
|
||||
try {
|
||||
|
||||
@@ -30,7 +30,6 @@ class CommentsSection extends HookConsumerWidget {
|
||||
},
|
||||
source: LocalAndRemoteSource(
|
||||
stream: true,
|
||||
background: true,
|
||||
relays: 'social',
|
||||
),
|
||||
subscriptionPrefix: 'app-comments',
|
||||
|
||||
@@ -281,7 +281,6 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
stream: true,
|
||||
background: true,
|
||||
),
|
||||
andSource: const LocalAndRemoteSource(
|
||||
relays: 'AppCatalog',
|
||||
@@ -337,7 +336,7 @@ class LatestReleasesNotifier extends StateNotifier<LatestReleasesState> {
|
||||
'#f': {'android-arm64-v8a'},
|
||||
},
|
||||
).toRequest(),
|
||||
source: const LocalAndRemoteSource(stream: false, background: false),
|
||||
source: const LocalAndRemoteSource(stream: false),
|
||||
);
|
||||
|
||||
if (olderPage.isNotEmpty) {
|
||||
|
||||
@@ -193,7 +193,6 @@ final relevantWhoFollowProvider = FutureProvider.autoDispose
|
||||
source: const LocalAndRemoteSource(
|
||||
relays: 'social',
|
||||
stream: false,
|
||||
background: false,
|
||||
),
|
||||
);
|
||||
return profiles;
|
||||
|
||||
@@ -2,15 +2,12 @@ import 'package:async_button_builder/async_button_builder.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:zapstore/constants/app_constants.dart';
|
||||
import 'package:zapstore/main.dart';
|
||||
import 'package:zapstore/services/notification_service.dart';
|
||||
import 'package:zapstore/services/package_manager/package_manager.dart';
|
||||
import 'package:zapstore/utils/debug_utils.dart';
|
||||
|
||||
const _amberPackageId = 'com.greenart7c3.nostrsigner';
|
||||
const _amberNaddr =
|
||||
'naddr1qqdkxmmd9enhyet9deshyaphvvejumn0wd68yumfvahx2uszyp6hjpmdntls5n8aa7n7ypzlyjrv0ewch33ml3452wtjx0smhl93jqcyqqq8uzcgpp6ky';
|
||||
|
||||
class SignInButton extends ConsumerWidget {
|
||||
const SignInButton({
|
||||
super.key,
|
||||
@@ -27,14 +24,18 @@ class SignInButton extends ConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final packageManager = ref.watch(packageManagerProvider);
|
||||
final isAmberInstalled = packageManager.any(
|
||||
(p) => p.appId == _amberPackageId,
|
||||
(p) => p.appId == kAmberPackageId,
|
||||
);
|
||||
|
||||
return AsyncButtonBuilder(
|
||||
onPressed: () async {
|
||||
if (!isAmberInstalled) {
|
||||
context.showInfo('Install Amber to sign in with your Nostr identity');
|
||||
context.push('/profile/apps/$_amberNaddr');
|
||||
context.showInfo(
|
||||
'Install Amber to sign in with your Nostr identity',
|
||||
actions: [
|
||||
('Open Amber', () async => context.push('/search/app/$kAmberNaddr')),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
try {
|
||||
await ref.read(amberSignerProvider).signIn();
|
||||
|
||||
Reference in New Issue
Block a user