diff --git a/Signal/src/ViewControllers/HomeView/Chat List/CLVViewState.swift b/Signal/src/ViewControllers/HomeView/Chat List/CLVViewState.swift index 5501485d69..8c800d8e19 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/CLVViewState.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/CLVViewState.swift @@ -88,6 +88,12 @@ class CLVViewState { } } + var hasConsumedMediaTierCapacity: Bool? { + didSet { + settingsButtonCreator.updateState(hasConsumedMediaTierCapacity: hasConsumedMediaTierCapacity) + } + } + let backupDownloadProgressViewState = CLVBackupDownloadProgressView.State() // MARK: - Initializer diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ChatListSettingsButtonState.swift b/Signal/src/ViewControllers/HomeView/Chat List/ChatListSettingsButtonState.swift index b3a5aaa5a2..57eae2f3a5 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ChatListSettingsButtonState.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ChatListSettingsButtonState.swift @@ -16,6 +16,7 @@ final class ChatListSettingsButtonState { var hasArchivedChats: Bool = false var hasUnreadPaymentNotification: Bool = false var hasBackupError: Bool = false + var hasConsumedMediaTierCapacity: Bool = false var showAvatarBackupBadge: Bool = false var showMenuBackupBadge: Bool = false @@ -26,6 +27,7 @@ final class ChatListSettingsButtonState { hasArchivedChats: Bool? = nil, hasUnreadPaymentNotification: Bool? = nil, hasBackupError: Bool? = nil, + hasConsumedMediaTierCapacity: Bool? = nil, showAvatarBackupBadge: Bool? = nil, showMenuBackupBadge: Bool? = nil, ) { @@ -46,6 +48,10 @@ final class ChatListSettingsButtonState { didUpdate = didUpdate || self.hasBackupError != hasBackupError self.hasBackupError = hasBackupError } + if let hasConsumedMediaTierCapacity { + didUpdate = didUpdate || self.hasConsumedMediaTierCapacity != hasConsumedMediaTierCapacity + self.hasConsumedMediaTierCapacity = hasConsumedMediaTierCapacity + } if let showAvatarBackupBadge { didUpdate = didUpdate || self.showAvatarBackupBadge != showAvatarBackupBadge self.showAvatarBackupBadge = showAvatarBackupBadge diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Notifications.swift b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Notifications.swift index 2b821c76ec..edc1b789a1 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Notifications.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Notifications.swift @@ -103,6 +103,12 @@ extension ChatListViewController { name: .backupExportJobDidRun, object: nil ) + NotificationCenter.default.addObserver( + self, + selector: #selector(hasConsumedMediaTierCapacityStateDidChange), + name: .hasConsumedMediaTierCapacityStatusDidChange, + object: nil + ) viewState.backupDownloadProgressViewState.downloadQueueStatus = DependenciesBridge.shared.backupAttachmentDownloadQueueStatusReporter.currentStatus(for: .fullsize) @@ -144,6 +150,12 @@ extension ChatListViewController { updateBackupErrorStateWithSneakyTransaction() } + @objc + private func hasConsumedMediaTierCapacityStateDidChange(_ notification: NSNotification) { + AssertIsOnMainThread() + updateHasConsumedMediaTierCapacityWithSneakyTransaction() + } + @objc private func preferContactAvatarsPreferenceDidChange(_ notification: NSNotification) { AssertIsOnMainThread() diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Reminders.swift b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Reminders.swift index 52b3be7cb7..350471a533 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Reminders.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController+Reminders.swift @@ -210,6 +210,11 @@ extension ChatListViewController { set { viewState.hasBackupFailure = newValue } } + var hasConsumedMediaTierCapacity: Bool? { + get { viewState.hasConsumedMediaTierCapacity } + set { viewState.hasConsumedMediaTierCapacity = newValue } + } + public var reminderViewCell: UITableViewCell { reminderViews.reminderViewCell } fileprivate var reminderStackView: UIStackView { reminderViews.reminderStackView } @@ -284,6 +289,13 @@ extension ChatListViewController { self.hasBackupFailureState = result } + public func updateHasConsumedMediaTierCapacityWithSneakyTransaction() { + let backupSettingsStore = BackupSettingsStore() + self.hasConsumedMediaTierCapacity = SSKEnvironment.shared.databaseStorageRef.read { tx in + backupSettingsStore.hasConsumedMediaTierCapacity(tx: tx) + } + } + public func updateUnreadPaymentNotificationsCountWithSneakyTransaction() { AssertIsOnMainThread() diff --git a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController.swift b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController.swift index e3f8481383..c3d2c46d18 100644 --- a/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController.swift +++ b/Signal/src/ViewControllers/HomeView/Chat List/ChatListViewController.swift @@ -147,6 +147,7 @@ public class ChatListViewController: OWSViewController, HomeTabViewController { // Update Backup error state updateBackupErrorStateWithSneakyTransaction() + updateHasConsumedMediaTierCapacityWithSneakyTransaction() // During main app launch, the chat list becomes visible _before_ // app is foreground and active. Therefore we need to make an @@ -447,6 +448,7 @@ public class ChatListViewController: OWSViewController, HomeTabViewController { databaseStorage: db, shouldShowUnreadPaymentBadge: viewState.settingsButtonCreator.hasUnreadPaymentNotification, shouldShowBackupFailureBadge: viewState.settingsButtonCreator.showAvatarBackupBadge, + shouldShowOutOfMediaTierCapacityBadge: viewState.settingsButtonCreator.hasConsumedMediaTierCapacity, delegate: self, buildActions: { settingsAction -> [UIMenuElement] in var contextMenuActions: [UIMenuElement] = [] @@ -478,6 +480,22 @@ public class ChatListViewController: OWSViewController, HomeTabViewController { ) ]) ) + } else if viewState.settingsButtonCreator.hasConsumedMediaTierCapacity { + let image = Theme.iconImage(.backup).withBadge(color: UIColor.Signal.red) + contextMenuActions.append( + UIMenu(options: [.displayInline], children: [ + UIAction( + title: OWSLocalizedString( + "HOME_VIEW_TITLE_BACKUP_OUT_OF_STORAGE_QUOTA", + comment: "Title for the conversation list's backup storage full context menu action." + ), + image: image, + handler: { _ in + SignalApp.shared.showAppSettings(mode: .backups) + } + ) + ]) + ) } // FIXME: combine viewState.inboxFilter and renderState.viewInfo.inboxFilter to avoid bugs with them getting out of sync diff --git a/Signal/src/ViewControllers/HomeView/HomeTabViewController.swift b/Signal/src/ViewControllers/HomeView/HomeTabViewController.swift index 5b2e13633c..941be6cb3f 100644 --- a/Signal/src/ViewControllers/HomeView/HomeTabViewController.swift +++ b/Signal/src/ViewControllers/HomeView/HomeTabViewController.swift @@ -17,6 +17,7 @@ extension HomeTabViewController { databaseStorage: SDSDatabaseStorage, shouldShowUnreadPaymentBadge: Bool = false, shouldShowBackupFailureBadge: Bool = false, + shouldShowOutOfMediaTierCapacityBadge: Bool = false, delegate: ContextMenuButtonDelegate? = nil, buildActions: (_ settingsAction: UIMenuElement) -> [UIMenuElement], showAppSettings: @escaping () -> Void @@ -79,6 +80,12 @@ extension HomeTabViewController { contextButton.autoPinEdgesToSuperviewEdges() PaymentsViewUtils.addUnreadBadge(toView: wrapper) barButtonView = wrapper + } else if shouldShowOutOfMediaTierCapacityBadge { + let wrapper = UIView.container() + wrapper.addSubview(contextButton) + contextButton.autoPinEdgesToSuperviewEdges() + wrapper.addCircleBadge(color: UIColor.Signal.red) + barButtonView = wrapper } else { barButtonView = contextButton } diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index b44d1853e2..57847cc7ba 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -4297,6 +4297,9 @@ /* Title for the conversation list's 'archive' mode. */ "HOME_VIEW_TITLE_ARCHIVE" = "Archive"; +/* Title for the conversation list's backup storage full context menu action. */ +"HOME_VIEW_TITLE_BACKUP_OUT_OF_STORAGE_QUOTA" = "Backup Storage Full"; + /* Title for the conversation list's failed to backup context menu action. */ "HOME_VIEW_TITLE_FAILED_TO_BACKUP" = "Failed to Backup";