mirror of
https://github.com/h3pdesign/Neon-Vision-Editor
synced 2026-04-21 13:27:16 +00:00
Make updater progress visible during install
This commit is contained in:
parent
5c10470c6b
commit
f588bf717b
5 changed files with 143 additions and 35 deletions
|
|
@ -361,7 +361,7 @@
|
|||
CODE_SIGNING_ALLOWED = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 594;
|
||||
CURRENT_PROJECT_VERSION = 595;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = CS727NF72U;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
|
|
@ -444,7 +444,7 @@
|
|||
CODE_SIGNING_ALLOWED = YES;
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 594;
|
||||
CURRENT_PROJECT_VERSION = 595;
|
||||
DEAD_CODE_STRIPPING = YES;
|
||||
DEVELOPMENT_TEAM = CS727NF72U;
|
||||
ENABLE_APP_SANDBOX = YES;
|
||||
|
|
|
|||
|
|
@ -272,8 +272,7 @@ final class AppUpdateManager: ObservableObject {
|
|||
automaticPromptToken &+= 1
|
||||
}
|
||||
|
||||
if source == .automatic,
|
||||
autoDownloadEnabled,
|
||||
if autoDownloadEnabled,
|
||||
installNowSupported {
|
||||
Task { [weak self] in
|
||||
await self?.attemptAutoInstall(interactive: false)
|
||||
|
|
@ -447,6 +446,33 @@ final class AppUpdateManager: ObservableObject {
|
|||
installNowDisabledReason == nil
|
||||
}
|
||||
|
||||
var isUserVisibleUpdateInProgress: Bool {
|
||||
status == .checking || isInstalling || awaitingInstallCompletionAction
|
||||
}
|
||||
|
||||
var userVisibleUpdateStatusTitle: String {
|
||||
if status == .checking {
|
||||
return "Checking for updates…"
|
||||
}
|
||||
if isInstalling {
|
||||
return installPhase.isEmpty ? "Installing update…" : installPhase
|
||||
}
|
||||
if awaitingInstallCompletionAction {
|
||||
return "Update ready to install"
|
||||
}
|
||||
return lastCheckResultSummary
|
||||
}
|
||||
|
||||
var userVisibleUpdateStatusDetail: String? {
|
||||
if status == .checking {
|
||||
return "Current version: \(currentVersion)"
|
||||
}
|
||||
if awaitingInstallCompletionAction {
|
||||
return installMessage ?? "The update is staged and will install after the app closes."
|
||||
}
|
||||
return installMessage
|
||||
}
|
||||
|
||||
var installNowDisabledReason: String? {
|
||||
guard ReleaseRuntimePolicy.isUpdaterEnabledForCurrentDistribution else {
|
||||
return "Updater is disabled for this distribution channel."
|
||||
|
|
|
|||
|
|
@ -77,12 +77,12 @@ struct AppUpdaterDialog: View {
|
|||
switch appUpdateManager.status {
|
||||
case .idle, .checking:
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
ProgressView()
|
||||
Text("Checking for updates…")
|
||||
.font(.headline)
|
||||
Text("Current version: \(appUpdateManager.currentVersion)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
liveUpdateStatusSection
|
||||
if appUpdateManager.status == .checking {
|
||||
Text("Current version: \(appUpdateManager.currentVersion)")
|
||||
.font(.subheadline)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(12)
|
||||
|
|
@ -146,19 +146,8 @@ struct AppUpdaterDialog: View {
|
|||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
|
||||
if appUpdateManager.isInstalling {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
ProgressView(value: appUpdateManager.installProgress, total: 1.0) {
|
||||
Text(appUpdateManager.installPhase.isEmpty ? "Installing update…" : appUpdateManager.installPhase)
|
||||
.font(.caption)
|
||||
}
|
||||
Text("\(Int((appUpdateManager.installProgress * 100).rounded()))%")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
.accessibilityLabel("Update install progress")
|
||||
.accessibilityValue("\(Int((appUpdateManager.installProgress * 100).rounded())) percent")
|
||||
if appUpdateManager.isUserVisibleUpdateInProgress {
|
||||
liveUpdateStatusSection
|
||||
}
|
||||
|
||||
if let installMessage = appUpdateManager.installMessage {
|
||||
|
|
@ -179,6 +168,44 @@ struct AppUpdaterDialog: View {
|
|||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var liveUpdateStatusSection: some View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
if appUpdateManager.isInstalling {
|
||||
ProgressView(value: appUpdateManager.installProgress, total: 1.0) {
|
||||
Text(appUpdateManager.userVisibleUpdateStatusTitle)
|
||||
.font(.caption)
|
||||
}
|
||||
Text("\(Int((appUpdateManager.installProgress * 100).rounded()))%")
|
||||
.font(.caption2)
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
ProgressView {
|
||||
Text(appUpdateManager.userVisibleUpdateStatusTitle)
|
||||
.font(.headline)
|
||||
}
|
||||
}
|
||||
|
||||
if let detail = appUpdateManager.userVisibleUpdateStatusDetail,
|
||||
!detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
Text(detail)
|
||||
.font(.caption)
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
.accessibilityElement(children: .combine)
|
||||
.accessibilityLabel("Update status")
|
||||
.accessibilityValue(accessibilityProgressValue)
|
||||
}
|
||||
|
||||
private var accessibilityProgressValue: String {
|
||||
if appUpdateManager.isInstalling {
|
||||
return "\(Int((appUpdateManager.installProgress * 100).rounded())) percent"
|
||||
}
|
||||
return appUpdateManager.userVisibleUpdateStatusTitle
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var actionRow: some View {
|
||||
HStack {
|
||||
|
|
|
|||
|
|
@ -2153,7 +2153,7 @@ struct ContentView: View {
|
|||
}
|
||||
|
||||
private var rootViewWithStateObservers: some View {
|
||||
basePlatformRootView
|
||||
applyUpdateVisibilityObservers(to: basePlatformRootView)
|
||||
.onAppear {
|
||||
handleSettingsAndEditorDefaultsOnAppear()
|
||||
}
|
||||
|
|
@ -2163,23 +2163,12 @@ struct ContentView: View {
|
|||
viewModel.isLineWrapEnabled = target
|
||||
}
|
||||
}
|
||||
.onReceive(NotificationCenter.default.publisher(for: .whitespaceScalarInspectionResult)) { notif in
|
||||
guard matchesCurrentWindow(notif) else { return }
|
||||
if let msg = notif.userInfo?[EditorCommandUserInfo.inspectionMessage] as? String {
|
||||
whitespaceInspectorMessage = msg
|
||||
}
|
||||
}
|
||||
.onChange(of: viewModel.isLineWrapEnabled) { _, enabled in
|
||||
guard projectOverrideLineWrapEnabled == nil else { return }
|
||||
if settingsLineWrapEnabled != enabled {
|
||||
settingsLineWrapEnabled = enabled
|
||||
}
|
||||
}
|
||||
.onChange(of: appUpdateManager.automaticPromptToken) { _, _ in
|
||||
if appUpdateManager.consumeAutomaticPromptIfNeeded() {
|
||||
showUpdaterDialog(checkNow: false)
|
||||
}
|
||||
}
|
||||
.onChange(of: settingsThemeName) { _, _ in
|
||||
scheduleHighlightRefresh()
|
||||
}
|
||||
|
|
@ -2214,6 +2203,31 @@ struct ContentView: View {
|
|||
.onChange(of: showMarkdownPreviewPane) { _, _ in
|
||||
persistSessionIfReady()
|
||||
}
|
||||
}
|
||||
|
||||
private func applyUpdateVisibilityObservers<Content: View>(to view: Content) -> some View {
|
||||
view
|
||||
.onReceive(NotificationCenter.default.publisher(for: .whitespaceScalarInspectionResult)) { notif in
|
||||
guard matchesCurrentWindow(notif) else { return }
|
||||
if let msg = notif.userInfo?[EditorCommandUserInfo.inspectionMessage] as? String {
|
||||
whitespaceInspectorMessage = msg
|
||||
}
|
||||
}
|
||||
.onChange(of: appUpdateManager.automaticPromptToken) { _, _ in
|
||||
if appUpdateManager.consumeAutomaticPromptIfNeeded() {
|
||||
showUpdaterDialog(checkNow: false)
|
||||
}
|
||||
}
|
||||
.onChange(of: appUpdateManager.isInstalling) { _, isInstalling in
|
||||
if isInstalling && !showUpdateDialog {
|
||||
showUpdaterDialog(checkNow: false)
|
||||
}
|
||||
}
|
||||
.onChange(of: appUpdateManager.awaitingInstallCompletionAction) { _, awaitingAction in
|
||||
if awaitingAction && !showUpdateDialog {
|
||||
showUpdaterDialog(checkNow: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var rootViewWithPlatformLifecycleObservers: some View {
|
||||
|
|
|
|||
|
|
@ -3249,6 +3249,47 @@ struct NeonSettingsView: View {
|
|||
}
|
||||
}
|
||||
|
||||
if appUpdateManager.isUserVisibleUpdateInProgress {
|
||||
VStack(alignment: .leading, spacing: UI.space8) {
|
||||
Text("Update Activity")
|
||||
.font(.subheadline.weight(.semibold))
|
||||
if appUpdateManager.isInstalling {
|
||||
ProgressView(value: appUpdateManager.installProgress, total: 1.0) {
|
||||
Text(appUpdateManager.userVisibleUpdateStatusTitle)
|
||||
.font(Typography.footnote)
|
||||
}
|
||||
Text("\(Int((appUpdateManager.installProgress * 100).rounded()))%")
|
||||
.font(Typography.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
} else {
|
||||
ProgressView {
|
||||
Text(appUpdateManager.userVisibleUpdateStatusTitle)
|
||||
.font(Typography.footnote)
|
||||
}
|
||||
}
|
||||
if let detail = appUpdateManager.userVisibleUpdateStatusDetail,
|
||||
!detail.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
|
||||
Text(detail)
|
||||
.font(Typography.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
.textSelection(.enabled)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(UI.space12)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: UI.cardCorner, style: .continuous)
|
||||
.fill(Color.secondary.opacity(0.08))
|
||||
)
|
||||
.accessibilityElement(children: .combine)
|
||||
.accessibilityLabel("Update activity")
|
||||
.accessibilityValue(
|
||||
appUpdateManager.isInstalling
|
||||
? "\(Int((appUpdateManager.installProgress * 100).rounded())) percent"
|
||||
: appUpdateManager.userVisibleUpdateStatusTitle
|
||||
)
|
||||
}
|
||||
|
||||
Text("Uses GitHub release assets only. App Store Connect releases are not used by this updater.")
|
||||
.font(Typography.footnote)
|
||||
.foregroundStyle(.secondary)
|
||||
|
|
|
|||
Loading…
Reference in a new issue