Files
zapstore/lib/utils/extensions.dart
2026-02-06 13:48:43 -03:00

115 lines
4.3 KiB
Dart

import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:models/models.dart';
import 'package:zapstore/constants/app_constants.dart';
import 'package:zapstore/services/package_manager/package_manager.dart';
export 'package:zapstore/constants/app_constants.dart';
extension WidgetExt on WidgetRef {
StorageNotifier get storage => read(storageNotifierProvider.notifier);
PackageManager get packageManager => read(packageManagerProvider.notifier);
}
extension ContextExt on BuildContext {
TextTheme get textTheme => Theme.of(this).textTheme;
}
extension AppExt on App {
/// Whether this app is one of Zapstore's own apps
bool get isZapstoreApp => identifier == kZapstoreAppIdentifier;
/// Whether this app is signed by Zapstore pubkey
bool get isSignedByZapstore => pubkey == kZapstorePubkey;
/// Whether this app is "relay signed" - indexed by Zapstore but not a Zapstore app itself
bool get isRelaySigned => isSignedByZapstore && !isZapstoreApp;
/// Returns PackageInfo if installed, otherwise null
PackageInfo? get installedPackage =>
ref.read(packageManagerProvider).installed[identifier];
/// Whether the app is installed on the device
bool get isInstalled =>
ref.read(packageManagerProvider.notifier).isInstalled(identifier);
/// Latest file metadata associated to the latest release
/// Prefers SoftwareAsset (new format) over FileMetadata (old format)
/// Note: assumes latest metadata has been loaded for the current platform
FileMetadata? get latestFileMetadata =>
latestRelease.value?.latestAsset.value ??
latestRelease.value?.latestMetadata.value;
/// Whether there is an update available for the installed app.
/// Delegates to PackageManager (versionCode-only comparison).
bool get hasUpdate {
final latest = latestFileMetadata;
if (latest == null) return false;
return ref.read(packageManagerProvider.notifier).hasUpdate(identifier, latest);
}
/// Whether the relay version would be a downgrade from the installed version.
/// Delegates to PackageManager (versionCode-only comparison).
bool get hasDowngrade {
final latest = latestFileMetadata;
if (latest == null) return false;
return ref.read(packageManagerProvider.notifier).hasDowngrade(identifier, latest);
}
/// Whether the installed app is up to date (installed and no update)
bool get isUpdated => isInstalled && !hasUpdate;
}
extension WidgetRefExt on WidgetRef {
Ref get ref => read(Provider((ref) => ref));
}
/// Extension to handle both old and new format certificate hashes
extension FileMetadataExt on FileMetadata {
/// Returns the APK certificate hash, checking new format first then old
/// New format (SoftwareAsset): apkCertificateHashes (Set)
/// Old format (FileMetadata): apkSignatureHash (String?)
String? get certificateHash {
// Try new format first (SoftwareAsset has apkCertificateHashes)
if (this is SoftwareAsset) {
final hashes = (this as SoftwareAsset).apkCertificateHashes;
if (hashes.isNotEmpty) return hashes.first;
}
// Fall back to old format
return apkSignatureHash;
}
/// Returns all APK certificate hashes
Set<String> get certificateHashes {
// Try new format first
if (this is SoftwareAsset) {
final hashes = (this as SoftwareAsset).apkCertificateHashes;
if (hashes.isNotEmpty) return hashes;
}
// Fall back to old format (single hash as set)
return apkSignatureHash != null ? {apkSignatureHash!} : {};
}
}
/// String abbreviation utilities
extension StringAbbreviationExt on String {
/// Abbreviates a string to show beginning and end with ellipsis
/// Default: shows first 6 and last 6 chars if string is longer than 12
String abbreviate({int start = 6, int end = 6}) {
final t = trim();
final minLength = start + end;
if (t.length <= minLength) return t;
return '${t.substring(0, start)}...${t.substring(t.length - end)}';
}
/// Abbreviates npub identifiers to "npub1abc...xyz" format
/// Shows first 9 chars (npub1 + 4 chars) and last 7 chars
/// Returns original string if not an npub identifier
String abbreviateNpub() {
if (!startsWith('npub1') || length < 20) {
return this;
}
return '${substring(0, 9)}...${substring(length - 7)}';
}
}