Fix install/status related issues

This commit is contained in:
franzap
2024-10-13 21:08:33 -03:00
parent f280099def
commit 4527fb20b8
5 changed files with 47 additions and 51 deletions
+26 -18
View File
@@ -54,7 +54,7 @@ class App extends BaseApp with DataModelMixin<App> {
.firstOrNull;
}
bool get canInstall => localApp.value?.status == AppInstallStatus.installable;
bool get canInstall => localApp.value?.status == null;
bool get canUpdate => localApp.value?.status == AppInstallStatus.updatable;
bool get isUpdated => localApp.value?.status == AppInstallStatus.updated;
@@ -65,7 +65,7 @@ class App extends BaseApp with DataModelMixin<App> {
final adapter = DataModel.adapterFor(this) as AppAdapter;
final notifier =
adapter.ref.read(installationProgressProvider(id!.toString()).notifier);
adapter.ref.read(installationProgressProvider(id!).notifier);
final installPermission = await Permission.requestInstallPackages.status;
if (!installPermission.isGranted) {
@@ -99,7 +99,7 @@ class App extends BaseApp with DataModelMixin<App> {
if (result['isSuccess']) {
await file.delete();
await adapter.ref.localApps.localAppAdapter
.updateInstallStatus(appId: id?.toString());
.refreshUpdateStatus(appId: identifier);
notifier.state = IdleInstallProgress();
} else {
const msg = 'Android rejected installation';
@@ -112,6 +112,7 @@ class App extends BaseApp with DataModelMixin<App> {
await installOnDevice();
} else {
if (fileExists) {
// If file exists download was probably partial, remove
await file.delete();
}
@@ -180,24 +181,31 @@ mixin AppAdapter on Adapter<App> {
final releases = await ref.releases.findAll(
params: {'#d': latestReleaseIdentifiers},
);
// TODO: Deprecated, will be removed
// 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(
final deprecatedApps =
apps.where((app) => app.linkedReplaceableEvents.isEmpty);
final deprecatedReleases = await ref.releases.findAll(
params: {
'#a': oldApps.map((app) => app.getReplaceableEventLink().formatted)
'#a':
deprecatedApps.map((app) => app.getReplaceableEventLink().formatted)
},
);
final oldReleasesLatest =
oldReleases.sorted((a, b) => b.createdAt!.compareTo(a.createdAt!));
final metadataIds = [...releases, ...oldReleases]
.map((r) => r.linkedEvents)
.nonNulls
.expand((_) => _);
final groupedDeprecatedReleases =
deprecatedReleases.groupListsBy((r) => r.app.value!);
for (final e in groupedDeprecatedReleases.entries) {
final mostRecentRelease =
e.value.sorted((a, b) => b.createdAt!.compareTo(a.createdAt!)).first;
releases.add(mostRecentRelease);
}
// End deprecated
final metadataIds =
releases.map((r) => r.linkedEvents).nonNulls.expand((_) => _);
final userIds = {
for (final app in apps) app.signer.id,
@@ -206,7 +214,7 @@ mixin AppAdapter on Adapter<App> {
// Metadata and users probably go to separate relays
// so query in parallel
final rs = await Future.wait([
await Future.wait([
ref.fileMetadata.findAll(params: {
'ids': metadataIds,
'#m': [kAndroidMimeType],
@@ -214,7 +222,7 @@ mixin AppAdapter on Adapter<App> {
}),
ref.users.findAll(params: {'authors': userIds}),
]);
await ref.localApps.localAppAdapter.updateInstallStatus();
await ref.localApps.localAppAdapter.refreshUpdateStatus();
return apps;
}
@@ -235,7 +243,7 @@ mixin AppAdapter on Adapter<App> {
params.remove('installed');
final apps = await fetchAppModels(params);
// Once apps are loaded, check for installed status
await ref.localApps.localAppAdapter.updateInstallStatus();
await ref.localApps.localAppAdapter.refreshUpdateStatus();
return apps;
}
}
@@ -269,7 +277,7 @@ mixin AppAdapter on Adapter<App> {
return null;
}
await ref.localApps.localAppAdapter
.updateInstallStatus(appId: id.toString());
.refreshUpdateStatus(appId: id.toString());
return apps.first;
}
@@ -348,7 +356,7 @@ class ErrorInstallProgress extends AppInstallProgress {
}
final installationProgressProvider =
StateProvider.family<AppInstallProgress, String>(
StateProvider.family<AppInstallProgress, Object>(
(_, arg) => IdleInstallProgress());
final appsToUpdateProvider = StateProvider((_) => 0);
+15 -25
View File
@@ -39,7 +39,7 @@ class LocalApp extends DataModel<LocalApp> {
}
mixin LocalAppAdapter on Adapter<LocalApp> {
Future<void> updateInstallStatus({String? appId}) async {
Future<void> refreshUpdateStatus({String? appId}) async {
if (!Platform.isAndroid) {
return;
}
@@ -55,18 +55,24 @@ mixin LocalAppAdapter on Adapter<LocalApp> {
: installedPackageInfos.map((i) => i.packageName).nonNulls;
final localApps = findManyLocalByIds(ids);
final apps = ref.apps.appAdapter.findWhereIdInLocal(ids);
for (final i in installedPackageInfos) {
final appId = i.packageName!;
final localApp = localApps.firstWhereOrNull((app) => appId == app.id) ??
LocalApp(id: i.packageName!);
final app = apps.firstWhereOrNull((a) => a.identifier == appId);
final installedVersion = i.versionName;
final installedVersionCode = i.versionCode;
final app = ref.apps.appAdapter.findWhereIdInLocal([appId]).firstOrNull;
final status =
determineInstallStatus(app, installedVersion, installedVersionCode);
determineUpdateStatus(app, installedVersion, installedVersionCode);
if (status == null) {
continue;
}
final localApp = localApps.firstWhereOrNull((app) => appId == app.id) ??
LocalApp(id: i.packageName!);
localApp
.copyWith(
installedVersion: installedVersion,
@@ -81,18 +87,16 @@ mixin LocalAppAdapter on Adapter<LocalApp> {
ref.read(appsToUpdateProvider.notifier).state = rs.first['c'];
}
AppInstallStatus? determineInstallStatus(
AppInstallStatus? determineUpdateStatus(
App? app, String? installedVersion, int? installedVersionCode) {
if (app == null || app.releases.isEmpty || app.latestMetadata == null) {
return null;
}
if (installedVersion == null) {
return AppInstallStatus.installable;
if (installedVersion == null || installedVersionCode == null) {
return null;
}
var comp = 0;
if (app.latestMetadata!.versionCode != null &&
installedVersionCode != null &&
app.id != 'store.zap.app') {
if (app.latestMetadata!.versionCode != null && app.id != 'store.zap.app') {
// Note: need to exclude zap.store because development versions always
// carry a lower version code (e.g. 12) than published ones (e.g. 2012)
comp = app.latestMetadata!.versionCode!.compareTo(installedVersionCode);
@@ -107,24 +111,10 @@ mixin LocalAppAdapter on Adapter<LocalApp> {
// else it's a downgrade, which is not installable
return AppInstallStatus.downgrade;
}
@override
LocalApp deserializeLocal(Map<String, dynamic> map, {String? key}) {
// TODO: implement deserializeLocal
return super.deserializeLocal(map, key: key);
}
@override
Map<String, dynamic> serializeLocal(LocalApp model,
{bool withRelationships = true}) {
final z = super.serializeLocal(model, withRelationships: withRelationships);
return z;
}
}
enum AppInstallStatus {
updated,
updatable,
installable,
downgrade,
}
-1
View File
@@ -63,6 +63,5 @@ Map<String, dynamic> _$LocalAppToJson(LocalApp instance) => <String, dynamic>{
const _$AppInstallStatusEnumMap = {
AppInstallStatus.updated: 'updated',
AppInstallStatus.updatable: 'updatable',
AppInstallStatus.installable: 'installable',
AppInstallStatus.downgrade: 'downgrade',
};
+2 -1
View File
@@ -163,10 +163,11 @@ final dataLibrariesInitializer = FutureProvider<void>((ref) async {
]);
// Trigger app install status calculations
ref.localApps.localAppAdapter.refreshUpdateStatus(); // do not await
_lifecycleListener = AppLifecycleListener(
onStateChange: (state) async {
if (state == AppLifecycleState.resumed) {
await ref.localApps.localAppAdapter.updateInstallStatus();
await ref.localApps.localAppAdapter.refreshUpdateStatus();
}
},
);
+4 -6
View File
@@ -27,14 +27,14 @@ class InstallButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final progress = ref.watch(installationProgressProvider(app.identifier!));
final progress = ref.watch(installationProgressProvider(app.id!));
final status = app.localApp.value?.status;
return GestureDetector(
onTap: switch (status) {
AppInstallStatus.downgrade => null,
AppInstallStatus.updated => () {
packageManager.openApp(app.id!.toString());
packageManager.openApp(app.identifier!);
},
_ => switch (progress) {
IdleInstallProgress() => () {
@@ -56,10 +56,8 @@ class InstallButton extends ConsumerWidget {
ErrorInstallProgress(:final e) => () {
// show error and reset state to idle
context.showError((e as dynamic).message);
ref
.read(installationProgressProvider(app.id!.toString())
.notifier)
.state = IdleInstallProgress();
ref.read(installationProgressProvider(app.id!).notifier).state =
IdleInstallProgress();
},
_ => null,
}