diff --git a/lib/models/app.dart b/lib/models/app.dart index 1593565..0ae6984 100644 --- a/lib/models/app.dart +++ b/lib/models/app.dart @@ -173,15 +173,27 @@ mixin AppAdapter on Adapter { ); // Find all appid@version ($3) as we need to pick one tag to query on // (filters by kind ($1) and pubkey ($2) done locally) + final latestReleaseIdentifiers = + apps.map((app) => app.linkedReplaceableEvents.firstOrNull?.$3).nonNulls; final releases = await ref.releases.findAll( + params: {'#d': latestReleaseIdentifiers}, + ); + // TODO: Deprecated + // Some developers without access to the latest zapstore-cli + // have not published their apps with latest release identifiers + // so load as usual + final oldApps = + apps.where((app) => !latestReleaseIdentifiers.contains(app.identifier)); + final oldReleases = await ref.releases.findAll( params: { - '#d': apps - .map((app) => app.linkedReplaceableEvents.firstOrNull?.$3) - .nonNulls + '#a': oldApps.map((app) => app.getReplaceableEventLink().formatted) }, ); - final metadataIds = - releases.map((r) => r.tagMap['e']).nonNulls.expand((_) => _); + + final metadataIds = [...releases, ...oldReleases] + .map((r) => r.tagMap['e']) + .nonNulls + .expand((_) => _); await ref.fileMetadata.findAll(params: { 'ids': metadataIds, @@ -277,7 +289,7 @@ mixin AppAdapter on Adapter { map['id'] = (map['kind'] as int, map['pubkey'].toString(), appId).formatted; map['signer'] = map['pubkey']; - map['developer'] = tagMap['zap']?.firstOrNull?[1]; + map['developer'] = tagMap['zap']?.firstOrNull; map['localApp'] = appId; } diff --git a/lib/models/local_app.dart b/lib/models/local_app.dart index a6594b5..4a272c0 100644 --- a/lib/models/local_app.dart +++ b/lib/models/local_app.dart @@ -43,34 +43,41 @@ mixin LocalAppAdapter on Adapter { if (!Platform.isAndroid) { return; } + try { + // NOTE: Using packageManager.getPackageInfo(packageName: appId) + // throws an uncatchable error every time it queries a non-installed package + final infos = await packageManager.getInstalledPackages(); - final infos = appId != null - ? [await packageManager.getPackageInfo(packageName: appId)].nonNulls - : await packageManager.getInstalledPackages(); + final installedPackageInfos = infos!.where((i) => + !kExcludedAppIdNamespaces.any((e) => i.packageName!.startsWith(e))); - final installedPackageInfos = infos!.where((i) => - !kExcludedAppIdNamespaces.any((e) => i.packageName!.startsWith(e))); + final ids = appId != null + ? [appId] + : installedPackageInfos.map((i) => i.packageName).nonNulls; - final localApps = findManyLocalByIds( - installedPackageInfos.map((i) => i.packageName).nonNulls); + final localApps = findManyLocalByIds(ids); - for (final i in installedPackageInfos) { - final appId = i.packageName!; - final localApp = localApps.firstWhereOrNull((app) => appId == app.id) ?? - LocalApp(id: i.packageName!); - final installedVersion = i.versionName; - final installedVersionCode = i.versionCode; + for (final i in installedPackageInfos) { + final appId = i.packageName!; + final localApp = localApps.firstWhereOrNull((app) => appId == app.id) ?? + LocalApp(id: i.packageName!); + final installedVersion = i.versionName; + final installedVersionCode = i.versionCode; - final app = ref.apps.appAdapter.findWhereIdInLocal([appId]).firstOrNull; - final status = - determineInstallStatus(app, installedVersion, installedVersionCode); + final app = ref.apps.appAdapter.findWhereIdInLocal([appId]).firstOrNull; + final status = + determineInstallStatus(app, installedVersion, installedVersionCode); - localApp - .copyWith( - installedVersion: installedVersion, - installedVersionCode: installedVersionCode, - status: status) - .saveLocal(); + localApp + .copyWith( + installedVersion: installedVersion, + installedVersionCode: installedVersionCode, + status: status) + .saveLocal(); + } + } catch (e) { + // TODO DEAL WITH + // print(e); } // Update number of apps diff --git a/lib/models/user.dart b/lib/models/user.dart index 6a667f3..8d890ad 100644 --- a/lib/models/user.dart +++ b/lib/models/user.dart @@ -1,6 +1,5 @@ import 'dart:convert'; -import 'package:collection/collection.dart'; import 'package:flutter_data/flutter_data.dart'; import 'package:purplebase/purplebase.dart'; import 'package:zapstore/models/nostr_adapter.dart'; @@ -32,66 +31,15 @@ class User extends BaseUser with DataModelMixin { } mixin UserAdapter on NostrAdapter { - // TODO: All this still necessary with purplebase? @override DeserializedData deserialize(Object? data, {String? key}) { - final Iterable> list = - (data is Iterable ? data : [data as Map]).cast(); + final list = data is Iterable ? data : [data as Map]; - final k0s = list - .where((e) { - // filter shitty kind 0s - if (e['kind'] != 0 || !e['content'].toString().startsWith('{')) { - return false; - } - final map = Map.from(jsonDecode(e['content'])); - final name = map['name'] ?? map['display_name'] ?? map['displayName']; - return name != null; - }) - .toList() - .groupSetsBy((e) => e['pubkey'] as String); - final k3s = list - .where((e) => e['kind'] == 3) - .toList() - .groupSetsBy((e) => e['pubkey'] as String); - - // collect contacts and then assign them to user - final included = >{}; - for (final _ in k3s.entries) { - final sl = _.value.sorted( - (a, b) => (b['created_at'] as int).compareTo(a['created_at'])); - final k3 = sl.first; - final contactMaps = []; - for (final [_, id, ..._] in k3['tags'] as Iterable) { - if (!existsId(id)) { - contactMaps.add({ - 'id': id, - 'content': '', - 'pubkey': id, - 'created_at': DateTime.now().millisecondsSinceEpoch ~/ 1000, - 'kind': 0, - 'tags': [], - }); - } - } - final data = super.deserialize(contactMaps); - included[k3['pubkey']] = data.models; + for (final Map map in list) { + map['id'] = map['pubkey']; } - final users = []; - for (final _ in k0s.entries) { - final sl = _.value.sorted( - (a, b) => (b['created_at'] as int).compareTo(a['created_at'])); - final k0 = sl.first; - final id = k0['id'] = k0['pubkey']; - if (included.containsKey(id)) { - k0['following'] = included[id]!.map((e) => e.id).toList(); - } - users.addAll(super.deserialize(k0).models); - } - - return DeserializedData(users, - included: included.values.expand((_) => _).toList()); + return super.deserialize(data); } @override @@ -110,7 +58,7 @@ mixin UserAdapter on NostrAdapter { } final result = await socialRelays.queryRaw(RelayRequest( - kinds: {0, 3}, + kinds: {0}, // 3 authors: {...authors}, )); @@ -166,7 +114,7 @@ mixin UserAdapter on NostrAdapter { } final result = await socialRelays.queryRaw(RelayRequest( - kinds: {0, 3}, + kinds: {0}, // 3 tags: params ?? {}, authors: {publicKey}, )); diff --git a/lib/screens/app_detail_screen.dart b/lib/screens/app_detail_screen.dart index 221cfc6..894a8f1 100644 --- a/lib/screens/app_detail_screen.dart +++ b/lib/screens/app_detail_screen.dart @@ -2,7 +2,6 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:flutter_markdown/flutter_markdown.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -31,17 +30,10 @@ class AppDetailScreen extends HookConsumerWidget { alsoWatch: (_) => {_.releases, _.releases.artifacts, _.signer, _.developer}); - // TODO: Workaround for bug in watchAll (when remote=true) - // TODO: Just fetch the signer, no need to refetch again?? - useFuture(useMemoized(() { - return ref.apps - .findOne(model.identifier!, remote: true, params: {'includes': true}); - })); - final app = state.model ?? model; return RefreshIndicator( - onRefresh: () => ref.apps.findOne(model.id!), + onRefresh: () => ref.apps.findOne(model.identifier!, remote: true), child: Column( children: [ Expanded(