Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: integrate auto_updater for macOS #7328

Merged
merged 9 commits into from
Feb 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions frontend/appflowy_flutter/dsa_pub.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-----BEGIN PUBLIC KEY-----
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
p6Dfx6Mqf0+pSpyZcf+qW1vlk3q92g==
-----END PUBLIC KEY-----
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,6 @@ void main() {
await tester.enterUserName('local_user');

// Scroll to sign-in
await tester.scrollUntilVisible(
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);

await tester.tapButton(find.byType(AccountSignInOutButton));

// sign up with Google
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,6 @@ void main() {
await tester.openSettings();
await tester.openSettingsPage(SettingsPage.account);

// Scroll to sign-in
await tester.scrollUntilVisible(
find.byType(AccountSignInOutButton),
100,
scrollable: find.findSettingsScrollable(),
);
await tester.tapButton(find.byType(AccountSignInOutButton));

tester.expectToSeeGoogleLoginButton();
Expand Down
44 changes: 22 additions & 22 deletions frontend/appflowy_flutter/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -175,36 +175,36 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/webview_flutter_wkwebview/ios"

SPEC CHECKSUMS:
app_links: e70ca16b4b0f88253b3b3660200d4a10b4ea9795
appflowy_backend: 144c20d8bfb298c4e10fa3fa6701a9f41bf98b88
connectivity_plus: bf0076dd84a130856aa636df1c71ccaff908fa1d
device_info_plus: 97af1d7e84681a90d0693e63169a5d50e0839a0d
app_links: c5161ac5ab5383ad046884568b4b91cb52df5d91
appflowy_backend: 78f6a053f756e6bc29bcc5a2106cbe77b756e97a
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac
DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
file_picker: 9b3292d7c8bc68c8a7bf8eb78f730e49c8efc517
flowy_infra_ui: 931b73a18b54a392ab6152eebe29a63a30751f53
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
image_picker_ios: c560581cceedb403a6ff17f2f816d7fea1421fc1
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
irondash_engine_context: 3458bf979b90d616ffb8ae03a150bafe2e860cc9
keyboard_height_plugin: 43fa8bba20fd5c4fdeed5076466b8b9d43cc6b86
open_filex: 6e26e659846ec990262224a12ef1c528bb4edbe4
package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4
path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46
permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2
fluttertoast: 76fea30fcf04176325f6864c87306927bd7d2038
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a
integration_test: d5929033778cc4991a187e4e1a85396fa4f59b3a
irondash_engine_context: 8e58ca8e0212ee9d1c7dc6a42121849986c88486
keyboard_height_plugin: ef70a8181b29f27670e9e2450814ca6b6dc05b05
open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
permission_handler_apple: 4ed2196e43d0651e8ff7ca3483a069d469701f2d
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
SDWebImage: b9a731e1d6307f44ca703b3976d18c24ca561e84
Sentry: 1fe34e9c2cbba1e347623610d26db121dcb569f1
sentry_flutter: a39c2a2d67d5e5b9cb0b94a4985c76dd5b3fc737
share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f
shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78
sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec
super_native_extensions: 4916b3c627a9c7fffdc48a23a9eca0b1ac228fa7
sentry_flutter: e24b397f9a61fa5bbefd8279c3b2242ca86faa90
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7
sqflite: c35dad70033b8862124f8337cc994a809fcd9fa3
super_native_extensions: b763c02dc3a8fd078389f410bf15149179020cb4
SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780
Toast: 91b396c56ee72a5790816f40d3a94dd357abc196
url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe
webview_flutter_wkwebview: 2a23822e9039b7b1bc52e5add778e5d89ad488d1
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d
webview_flutter_wkwebview: 45a041c7831641076618876de3ba75c712860c6b

PODFILE CHECKSUM: d0d9b4ff572d8695c38eb3f9b490f55cdfc57eca

Expand Down
4 changes: 2 additions & 2 deletions frontend/appflowy_flutter/lib/startup/deps_resolver.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import 'package:appflowy/ai/service/ai_client.dart';
import 'package:appflowy/ai/service/appflowy_ai_service.dart';
import 'package:appflowy/core/config/kv.dart';
import 'package:appflowy/core/network_monitor.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/plugins/document/application/prelude.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/copy_and_paste/clipboard_service.dart';
import 'package:appflowy/ai/service/ai_client.dart';
import 'package:appflowy/plugins/trash/application/prelude.dart';
import 'package:appflowy/shared/appflowy_cache_manager.dart';
import 'package:appflowy/shared/custom_image_cache_manager.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/appflowy_cloud_task.dart';
import 'package:appflowy/ai/service/appflowy_ai_service.dart';
import 'package:appflowy/user/application/auth/af_cloud_auth_service.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/prelude.dart';
Expand Down
3 changes: 2 additions & 1 deletion frontend/appflowy_flutter/lib/startup/startup.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import 'dart:async';
import 'dart:io';

import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/startup/tasks/feature_flag_task.dart';
import 'package:appflowy/util/expand_views.dart';
import 'package:appflowy/workspace/application/settings/prelude.dart';
import 'package:appflowy_backend/appflowy_backend.dart';
Expand Down Expand Up @@ -139,6 +138,8 @@ class FlowyRunner {
// The DeviceOrApplicationInfoTask should be placed before the AppWidgetTask to fetch the app information.
// It is unable to get the device information from the test environment.
const ApplicationInfoTask(),
// The auto update task should be placed after the ApplicationInfoTask to fetch the latest version.
if (!mode.isIntegrationTest) AutoUpdateTask(),
const HotKeyTask(),
if (isAppFlowyCloudEnabled) InitAppFlowyCloudTask(),
const InitAppWidgetTask(),
Expand Down
188 changes: 188 additions & 0 deletions frontend/appflowy_flutter/lib/startup/tasks/auto_update_task.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/tasks/app_widget.dart';
import 'package:appflowy/startup/tasks/device_info_task.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/log.dart';
import 'package:auto_updater/auto_updater.dart';
import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:universal_platform/universal_platform.dart';

import '../startup.dart';

class AutoUpdateTask extends LaunchTask {
AutoUpdateTask();

// static const _feedUrl =
// 'https://github.com/LucasXu0/AppFlowy/releases/latest/download/appcast-{os}-{arch}.xml';
final _listener = _AppFlowyAutoUpdaterListener();

@override
Future<void> initialize(LaunchContext context) async {
// Enable auto update when the integration of Windows and Linux is completed.
return;
// // the auto updater is not supported on mobile and linux
// if (UniversalPlatform.isMobile || UniversalPlatform.isLinux) {
// return;
// }

// Log.info(
// '[AutoUpdate] current version: ${ApplicationInfo.applicationVersion}, current cpu architecture: ${ApplicationInfo.architecture}',
// );

// autoUpdater.addListener(_listener);

// // Since the appcast.xml is not supported the arch, we separate the feed url by os and arch.
// final feedUrl = _feedUrl
// .replaceAll('{os}', ApplicationInfo.os)
// .replaceAll('{arch}', ApplicationInfo.architecture);
// Log.info('[AutoUpdate] feed url: $feedUrl');

// await autoUpdater.setFeedURL(feedUrl);
// await autoUpdater.checkForUpdateInformation();

// ApplicationInfo.isCriticalUpdateNotifier.addListener(
// _showCriticalUpdateDialog,
// );
}

@override
Future<void> dispose() async {
autoUpdater.removeListener(_listener);

ApplicationInfo.isCriticalUpdateNotifier.removeListener(
_showCriticalUpdateDialog,
);
}

void _showCriticalUpdateDialog() {
showCustomConfirmDialog(
context: AppGlobals.rootNavKey.currentContext!,
title: LocaleKeys.autoUpdate_criticalUpdateTitle.tr(),
description: LocaleKeys.autoUpdate_criticalUpdateDescription.tr(
namedArgs: {
'currentVersion': ApplicationInfo.applicationVersion,
'newVersion': ApplicationInfo.latestVersion,
},
),
builder: (context) => const SizedBox.shrink(),
// if the update is critical, dont allow the user to dismiss the dialog
barrierDismissible: false,
showCloseButton: false,
enableKeyboardListener: false,
closeOnConfirm: false,
confirmLabel: LocaleKeys.autoUpdate_criticalUpdateButton.tr(),
onConfirm: () async {
await autoUpdater.checkForUpdates();
},
);
}
}

class _AppFlowyAutoUpdaterListener extends UpdaterListener {
@override
void onUpdaterBeforeQuitForUpdate(AppcastItem? item) {}

@override
void onUpdaterCheckingForUpdate(Appcast? appcast) {
// Due to the reason documented in the following link, the update will not be found if the user has skipped the update.
// We have to check the skipped version manually.
// https://sparkle-project.org/documentation/api-reference/Classes/SPUUpdater.html#/c:objc(cs)SPUUpdater(im)checkForUpdateInformation
final items = appcast?.items;
if (items != null) {
final String? currentPlatform;
if (UniversalPlatform.isMacOS) {
currentPlatform = 'macos';
} else if (UniversalPlatform.isWindows) {
currentPlatform = 'windows';
} else {
currentPlatform = null;
}

final matchingItem = items.firstWhereOrNull(
(item) => item.os == currentPlatform,
);

if (matchingItem != null) {
_updateVersionNotifier(matchingItem);

Log.info(
'[AutoUpdate] latest version: ${matchingItem.displayVersionString}',
);
}
}
}

@override
void onUpdaterError(UpdaterError? error) {
Log.error('[AutoUpdate] On update error: $error');
}

@override
void onUpdaterUpdateNotAvailable(UpdaterError? error) {
Log.info('[AutoUpdate] Update not available $error');
}

@override
void onUpdaterUpdateAvailable(AppcastItem? item) {
_updateVersionNotifier(item);

Log.info('[AutoUpdate] Update available: ${item?.displayVersionString}');
}

@override
void onUpdaterUpdateDownloaded(AppcastItem? item) {
Log.info('[AutoUpdate] Update downloaded: ${item?.displayVersionString}');
}

@override
void onUpdaterUpdateCancelled(AppcastItem? item) {
_updateVersionNotifier(item);

Log.info('[AutoUpdate] Update cancelled: ${item?.displayVersionString}');
}

@override
void onUpdaterUpdateInstalled(AppcastItem? item) {
_updateVersionNotifier(item);

Log.info('[AutoUpdate] Update installed: ${item?.displayVersionString}');
}

@override
void onUpdaterUpdateSkipped(AppcastItem? item) {
_updateVersionNotifier(item);

Log.info('[AutoUpdate] Update skipped: ${item?.displayVersionString}');
}

void _updateVersionNotifier(AppcastItem? item) {
if (item != null) {
ApplicationInfo.latestAppcastItem = item;
ApplicationInfo.latestVersionNotifier.value =
item.displayVersionString ?? '';
}
}
}

class AppFlowyAutoUpdateVersion {
AppFlowyAutoUpdateVersion({
required this.latestVersion,
required this.currentVersion,
required this.isForceUpdate,
});

factory AppFlowyAutoUpdateVersion.initial() => AppFlowyAutoUpdateVersion(
latestVersion: '0.0.0',
currentVersion: '0.0.0',
isForceUpdate: false,
);

final String latestVersion;
final String currentVersion;

final bool isForceUpdate;

bool get isUpdateAvailable => latestVersion != currentVersion;
}
Loading
Loading