mirror of
https://github.com/zapstore/zapstore.git
synced 2026-10-05 20:48:24 +00:00
The "Always trust" switch was shown using profile availability, which can be null even when the user is signed in, and could also appear when trust could not be saved. Use signer readiness (`activePubkey` + `activeSigner`) as the visibility condition. This makes the dialog behavior consistent with real trust persistence capability.
149 lines
5.2 KiB
Dart
149 lines
5.2 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
|
import 'package:gap/gap.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:models/models.dart';
|
|
import 'package:zapstore/utils/extensions.dart';
|
|
import 'package:zapstore/widgets/author_container.dart';
|
|
import 'package:zapstore/widgets/common/base_dialog.dart';
|
|
import 'package:zapstore/widgets/download_text_container.dart';
|
|
import 'package:zapstore/widgets/relevant_who_follow_container.dart';
|
|
import 'package:zapstore/widgets/sign_in_button.dart';
|
|
|
|
class InstallAlertDialog extends HookConsumerWidget {
|
|
const InstallAlertDialog({super.key, required this.app});
|
|
|
|
final App app;
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
// Query publisher profile (app.pubkey is always present)
|
|
final publisherState = ref.watch(
|
|
query<Profile>(
|
|
authors: {app.pubkey},
|
|
source: const LocalAndRemoteSource(
|
|
relays: {'social', 'vertex'},
|
|
cachedFor: Duration(hours: 2),
|
|
),
|
|
),
|
|
);
|
|
final publisher = switch (publisherState) {
|
|
StorageData(:final models) => models.firstOrNull,
|
|
_ => null,
|
|
};
|
|
if (publisher == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
final trustedSignerNotifier = useState(false);
|
|
final signedInPubkey = ref.watch(Signer.activePubkeyProvider);
|
|
final activeSigner = ref.watch(Signer.activeSignerProvider);
|
|
final canPersistTrust = signedInPubkey != null && activeSigner != null;
|
|
final theme = Theme.of(context);
|
|
final baseTextSize = theme.textTheme.bodyMedium?.fontSize ?? 14.0;
|
|
|
|
return BaseDialog(
|
|
title: const BaseDialogTitle('Trust this app?'),
|
|
content: BaseDialogContent(
|
|
children: [
|
|
if (app.isRelaySigned) ...[
|
|
AuthorContainer(
|
|
profile: publisher,
|
|
beforeText: 'The',
|
|
afterText:
|
|
' relay makes the ${app.name ?? app.identifier} app available but did not develop it or sign its APK. ',
|
|
oneLine: false,
|
|
size: baseTextSize,
|
|
),
|
|
Gap(10),
|
|
DownloadTextContainer(
|
|
beforeText:
|
|
'${app.name ?? app.identifier} will be installed from its original release location:',
|
|
oneLine: false,
|
|
showFullUrl: true,
|
|
url: app.latestFileMetadata!.urls.first,
|
|
size: baseTextSize,
|
|
),
|
|
] else ...[
|
|
canPersistTrust
|
|
? RelevantWhoFollowContainer(app: app, size: baseTextSize)
|
|
: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.start,
|
|
children: [
|
|
AuthorContainer(
|
|
profile: publisher,
|
|
beforeText:
|
|
'${app.name ?? app.identifier} is published by',
|
|
afterText: '.',
|
|
oneLine: false,
|
|
size: baseTextSize,
|
|
),
|
|
const Gap(14),
|
|
SignInButton(
|
|
label:
|
|
'Sign in to view the publisher\'s reputable followers',
|
|
minimal: true,
|
|
requireNip55: true,
|
|
),
|
|
],
|
|
),
|
|
// Only show "Always trust" when signed in (requires signer to persist)
|
|
if (canPersistTrust) ...[
|
|
const Gap(14),
|
|
Row(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
Switch(
|
|
value: trustedSignerNotifier.value,
|
|
onChanged: (value) {
|
|
trustedSignerNotifier.value = value;
|
|
},
|
|
),
|
|
Gap(4),
|
|
Expanded(
|
|
child: Row(
|
|
children: [
|
|
Text(
|
|
'Always trust',
|
|
style: theme.textTheme.bodyMedium?.copyWith(
|
|
color: theme.colorScheme.onSurface,
|
|
),
|
|
),
|
|
Gap(4),
|
|
AuthorContainer(
|
|
beforeText: '',
|
|
profile: publisher,
|
|
size: baseTextSize,
|
|
),
|
|
],
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
],
|
|
],
|
|
),
|
|
actions: [
|
|
TextButton(
|
|
onPressed: () {
|
|
// NOTE: can't use context.pop()
|
|
Navigator.of(context).pop();
|
|
},
|
|
child: const Text('Cancel'),
|
|
),
|
|
FilledButton(
|
|
onPressed: () {
|
|
Navigator.of(
|
|
context,
|
|
).pop((trustPermanently: trustedSignerNotifier.value));
|
|
},
|
|
style: FilledButton.styleFrom(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
|
),
|
|
child: const Text('Trust and install app'),
|
|
),
|
|
],
|
|
);
|
|
}
|
|
}
|