Подавление уведомлений в открытом чате, ускорение переходов между экранами, инициалы на экране разблокировки, плавный keyboard offset
This commit is contained in:
@@ -288,7 +288,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.10;
|
MARKETING_VERSION = 1.1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.rosetta.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.rosetta.dev;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
@@ -327,7 +327,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"@executable_path/Frameworks",
|
"@executable_path/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.0.10;
|
MARKETING_VERSION = 1.1.0;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = com.rosetta.dev;
|
PRODUCT_BUNDLE_IDENTIFIER = com.rosetta.dev;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ struct AuthCoordinator: View {
|
|||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
.opacity(fadeOverlay ? 1 : 0)
|
.opacity(fadeOverlay ? 1 : 0)
|
||||||
.allowsHitTesting(fadeOverlay)
|
.allowsHitTesting(fadeOverlay)
|
||||||
.animation(.easeInOut(duration: 0.08), value: fadeOverlay)
|
.animation(.easeInOut(duration: 0.035), value: fadeOverlay)
|
||||||
}
|
}
|
||||||
.overlay(alignment: .leading) {
|
.overlay(alignment: .leading) {
|
||||||
if canSwipeBack {
|
if canSwipeBack {
|
||||||
@@ -174,9 +174,9 @@ private extension AuthCoordinator {
|
|||||||
navigationDirection = .forward
|
navigationDirection = .forward
|
||||||
fadeOverlay = true
|
fadeOverlay = true
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
try? await Task.sleep(nanoseconds: 80_000_000)
|
try? await Task.sleep(nanoseconds: 35_000_000)
|
||||||
currentScreen = screen
|
currentScreen = screen
|
||||||
try? await Task.sleep(nanoseconds: 20_000_000)
|
try? await Task.sleep(nanoseconds: 10_000_000)
|
||||||
fadeOverlay = false
|
fadeOverlay = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,19 +119,22 @@ struct ChatDetailView: View {
|
|||||||
.toolbar(.hidden, for: .tabBar)
|
.toolbar(.hidden, for: .tabBar)
|
||||||
.task {
|
.task {
|
||||||
isViewActive = true
|
isViewActive = true
|
||||||
|
// Suppress notifications & clear badge immediately (no 600ms delay).
|
||||||
|
// setDialogActive only touches MessageRepository.activeDialogs (Set),
|
||||||
|
// does NOT mutate DialogRepository, so ForEach won't rebuild.
|
||||||
|
MessageRepository.shared.setDialogActive(route.publicKey, isActive: true)
|
||||||
|
clearDeliveredNotifications(for: route.publicKey)
|
||||||
// Reset idle timer — user is actively viewing a chat.
|
// Reset idle timer — user is actively viewing a chat.
|
||||||
SessionManager.shared.recordUserInteraction()
|
SessionManager.shared.recordUserInteraction()
|
||||||
// Request user info (non-mutating, won't trigger list rebuild)
|
// Request user info (non-mutating, won't trigger list rebuild)
|
||||||
requestUserInfoIfNeeded()
|
requestUserInfoIfNeeded()
|
||||||
// Delay ALL dialog mutations to let navigation transition complete.
|
// Delay DialogRepository mutations to let navigation transition complete.
|
||||||
// Without this, DialogRepository update rebuilds ChatListView's ForEach
|
// Without this, DialogRepository update rebuilds ChatListView's ForEach
|
||||||
// mid-navigation, recreating the NavigationLink and canceling the push.
|
// mid-navigation, recreating the NavigationLink and canceling the push.
|
||||||
try? await Task.sleep(for: .milliseconds(600))
|
try? await Task.sleep(for: .milliseconds(600))
|
||||||
guard isViewActive else { return }
|
guard isViewActive else { return }
|
||||||
activateDialog()
|
activateDialog()
|
||||||
markDialogAsRead()
|
markDialogAsRead()
|
||||||
// Clear delivered notifications from this sender
|
|
||||||
clearDeliveredNotifications(for: route.publicKey)
|
|
||||||
// Subscribe to opponent's online status (Android parity) — only after settled
|
// Subscribe to opponent's online status (Android parity) — only after settled
|
||||||
SessionManager.shared.subscribeToOnlineStatus(publicKey: route.publicKey)
|
SessionManager.shared.subscribeToOnlineStatus(publicKey: route.publicKey)
|
||||||
// Desktop parity: force-refresh user info (incl. online status) on chat open.
|
// Desktop parity: force-refresh user info (incl. online status) on chat open.
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ struct RosettaApp: App {
|
|||||||
.ignoresSafeArea()
|
.ignoresSafeArea()
|
||||||
.opacity(transitionOverlay ? 1 : 0)
|
.opacity(transitionOverlay ? 1 : 0)
|
||||||
.allowsHitTesting(transitionOverlay)
|
.allowsHitTesting(transitionOverlay)
|
||||||
.animation(.easeInOut(duration: 0.08), value: transitionOverlay)
|
.animation(.easeInOut(duration: 0.035), value: transitionOverlay)
|
||||||
}
|
}
|
||||||
.preferredColorScheme(.dark)
|
.preferredColorScheme(.dark)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
@@ -228,9 +228,9 @@ struct RosettaApp: App {
|
|||||||
guard !transitionOverlay else { return }
|
guard !transitionOverlay else { return }
|
||||||
transitionOverlay = true
|
transitionOverlay = true
|
||||||
Task { @MainActor in
|
Task { @MainActor in
|
||||||
try? await Task.sleep(nanoseconds: 80_000_000) // wait for overlay fade-in
|
try? await Task.sleep(nanoseconds: 35_000_000) // wait for overlay fade-in
|
||||||
appState = newState
|
appState = newState
|
||||||
try? await Task.sleep(nanoseconds: 20_000_000) // brief settle
|
try? await Task.sleep(nanoseconds: 10_000_000) // brief settle
|
||||||
transitionOverlay = false
|
transitionOverlay = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user