You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-ios/Session/Settings/SettingsViewModel.swift

676 lines
30 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import Combine
import GRDB
import YYImage
import DifferenceKit
import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
import SignalUtilitiesKit
class SettingsViewModel: SessionTableViewModel, NavigationItemSource, NavigatableStateHolder, EditableStateHolder, ObservableTableSource {
public let dependencies: Dependencies
public let navigatableState: NavigatableState = NavigatableState()
public let editableState: EditableState<TableItem> = EditableState()
public let state: TableDataState<Section, TableItem> = TableDataState()
public let observableState: ObservableTableSourceState<Section, TableItem> = ObservableTableSourceState()
private let userSessionId: String
private lazy var imagePickerHandler: ImagePickerHandler = ImagePickerHandler(
onTransition: { [weak self] in self?.transitionToScreen($0, transitionType: $1) },
onImageDataPicked: { [weak self] resultImageData in
guard let oldDisplayName: String = self?.oldDisplayName else { return }
self?.updatedProfilePictureSelected(
name: oldDisplayName,
avatarUpdate: .uploadImageData(resultImageData)
)
}
)
fileprivate var oldDisplayName: String
private var editedDisplayName: String?
private var editProfilePictureModal: ConfirmationModal?
private var editProfilePictureModalInfo: ConfirmationModal.Info?
// MARK: - Initialization
init(using dependencies: Dependencies = Dependencies()) {
self.dependencies = dependencies
self.userSessionId = getUserHexEncodedPublicKey(using: dependencies)
self.oldDisplayName = Profile.fetchOrCreateCurrentUser(using: dependencies).name
}
// MARK: - Config
enum NavState {
case standard
case editing
}
enum NavItem: Equatable {
case close
case qrCode
case cancel
case done
}
public enum Section: SessionTableSection {
case profileInfo
case sessionId
case menus
case footer
var title: String? {
switch self {
case .sessionId: return "your_session_id".localized()
default: return nil
}
}
var style: SessionTableSectionStyle {
switch self {
case .sessionId: return .titleSeparator
case .menus: return .padding
default: return .none
}
}
}
public enum TableItem: Differentiable {
case avatar
case profileName
case sessionId
case idActions
case path
case privacy
case notifications
case conversations
case messageRequests
case appearance
case inviteAFriend
case recoveryPhrase
case help
case clearData
}
// MARK: - Navigation
lazy var navState: AnyPublisher<NavState, Never> = {
Publishers
.CombineLatest(
isEditing,
textChanged
.handleEvents(
receiveOutput: { [weak self] value, _ in
self?.editedDisplayName = value
}
)
.filter { _ in false }
.prepend((nil, .profileName))
)
.map { isEditing, _ -> NavState in (isEditing ? .editing : .standard) }
.removeDuplicates()
.prepend(.standard) // Initial value
.shareReplay(1)
.eraseToAnyPublisher()
}()
lazy var leftNavItems: AnyPublisher<[SessionNavItem<NavItem>], Never> = navState
.map { navState -> [SessionNavItem<NavItem>] in
switch navState {
case .standard:
return [
SessionNavItem(
id: .close,
image: UIImage(named: "X")?
.withRenderingMode(.alwaysTemplate),
style: .plain,
accessibilityIdentifier: "Close button"
) { [weak self] in self?.dismissScreen() }
]
case .editing:
return [
SessionNavItem(
id: .cancel,
systemItem: .cancel,
accessibilityIdentifier: "Cancel button"
) { [weak self] in
self?.setIsEditing(false)
self?.editedDisplayName = self?.oldDisplayName
}
]
}
}
.eraseToAnyPublisher()
lazy var rightNavItems: AnyPublisher<[SessionNavItem<NavItem>], Never> = navState
.map { [weak self] navState -> [SessionNavItem<NavItem>] in
switch navState {
case .standard:
return [
SessionNavItem(
id: .qrCode,
image: UIImage(named: "QRCode")?
.withRenderingMode(.alwaysTemplate),
style: .plain,
accessibilityIdentifier: "Show QR code button",
action: { [weak self] in
self?.transitionToScreen(QRCodeVC())
}
)
]
case .editing:
return [
SessionNavItem(
id: .done,
systemItem: .done,
accessibilityIdentifier: "Done"
) { [weak self] in
let updatedNickname: String = (self?.editedDisplayName ?? "")
.trimmingCharacters(in: .whitespacesAndNewlines)
guard !updatedNickname.isEmpty else {
self?.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
title: "vc_settings_display_name_missing_error".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text
)
),
transitionType: .present
)
return
}
guard !ProfileManager.isToLong(profileName: updatedNickname) else {
self?.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
title: "vc_settings_display_name_too_long_error".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text
)
),
transitionType: .present
)
return
}
self?.setIsEditing(false)
self?.oldDisplayName = updatedNickname
self?.updateProfile(
name: updatedNickname,
avatarUpdate: .none
)
}
]
}
}
.eraseToAnyPublisher()
// MARK: - Content
let title: String = "vc_settings_title".localized()
lazy var observation: TargetObservation = ObservationBuilder
.databaseObservation(self) { [weak self, dependencies] db -> Profile in
Profile.fetchOrCreateCurrentUser(db, using: dependencies)
}
.map { [weak self] profile -> [SectionModel] in
return [
SectionModel(
model: .profileInfo,
elements: [
SessionCell.Info(
id: .avatar,
accessory: .profile(
id: profile.id,
size: .hero,
profile: profile
),
styling: SessionCell.StyleInfo(
alignment: .centerHugging,
customPadding: SessionCell.Padding(bottom: Values.smallSpacing),
backgroundStyle: .noBackground
),
accessibility: Accessibility(
label: "Profile picture"
),
onTap: {
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
self?.updateProfilePicture(currentFileName: profile.profilePictureFileName)
}
),
SessionCell.Info(
id: .profileName,
title: SessionCell.TextInfo(
profile.displayName(),
font: .titleLarge,
alignment: .center,
interaction: .editable
),
styling: SessionCell.StyleInfo(
alignment: .centerHugging,
customPadding: SessionCell.Padding(top: Values.smallSpacing),
backgroundStyle: .noBackground
),
accessibility: Accessibility(
identifier: "Username",
label: profile.displayName()
),
onTap: { self?.setIsEditing(true) }
)
]
),
SectionModel(
model: .sessionId,
elements: [
SessionCell.Info(
id: .sessionId,
title: SessionCell.TextInfo(
profile.id,
font: .monoLarge,
alignment: .center,
interaction: .copy
),
styling: SessionCell.StyleInfo(
customPadding: SessionCell.Padding(bottom: Values.smallSpacing),
backgroundStyle: .noBackground
),
accessibility: Accessibility(
identifier: "Session ID",
label: profile.id
)
),
SessionCell.Info(
id: .idActions,
leftAccessory: .button(
style: .bordered,
title: "copy".localized(),
run: { button in
self?.copySessionId(profile.id, button: button)
}
),
rightAccessory: .button(
style: .bordered,
title: "share".localized(),
run: { _ in
self?.shareSessionId(profile.id)
}
),
styling: SessionCell.StyleInfo(
customPadding: SessionCell.Padding(
top: Values.smallSpacing,
leading: 0,
trailing: 0
),
backgroundStyle: .noBackground
)
)
]
),
SectionModel(
model: .menus,
elements: [
SessionCell.Info(
id: .path,
leftAccessory: .customView(hashValue: "PathStatusView") { // stringlint:disable
// Need to ensure this view is the same size as the icons so
// wrap it in a larger view
let result: UIView = UIView()
let pathView: PathStatusView = PathStatusView(size: .large)
result.addSubview(pathView)
result.set(.width, to: IconSize.medium.size)
result.set(.height, to: IconSize.medium.size)
pathView.center(in: result)
return result
},
title: "vc_path_title".localized(),
onTap: { self?.transitionToScreen(PathVC()) }
),
SessionCell.Info(
id: .privacy,
leftAccessory: .icon(
UIImage(named: "icon_privacy")?
.withRenderingMode(.alwaysTemplate)
),
title: "vc_settings_privacy_button_title".localized(),
onTap: {
self?.transitionToScreen(
SessionTableViewController(viewModel: PrivacySettingsViewModel())
)
}
),
SessionCell.Info(
id: .notifications,
leftAccessory: .icon(
UIImage(named: "icon_speaker")?
.withRenderingMode(.alwaysTemplate)
),
title: "vc_settings_notifications_button_title".localized(),
onTap: {
self?.transitionToScreen(
SessionTableViewController(viewModel: NotificationSettingsViewModel())
)
}
),
SessionCell.Info(
id: .conversations,
leftAccessory: .icon(
UIImage(named: "icon_msg")?
.withRenderingMode(.alwaysTemplate)
),
title: "CONVERSATION_SETTINGS_TITLE".localized(),
onTap: {
self?.transitionToScreen(
SessionTableViewController(viewModel: ConversationSettingsViewModel())
)
}
),
SessionCell.Info(
id: .messageRequests,
leftAccessory: .icon(
UIImage(named: "icon_msg_req")?
.withRenderingMode(.alwaysTemplate)
),
title: "MESSAGE_REQUESTS_TITLE".localized(),
onTap: {
self?.transitionToScreen(
SessionTableViewController(viewModel: MessageRequestsViewModel())
)
}
),
SessionCell.Info(
id: .appearance,
leftAccessory: .icon(
UIImage(named: "icon_apperance")?
.withRenderingMode(.alwaysTemplate)
),
title: "APPEARANCE_TITLE".localized(),
onTap: {
self?.transitionToScreen(AppearanceViewController())
}
),
SessionCell.Info(
id: .inviteAFriend,
leftAccessory: .icon(
UIImage(named: "icon_invite")?
.withRenderingMode(.alwaysTemplate)
),
title: "vc_settings_invite_a_friend_button_title".localized(),
onTap: {
let invitation: String = "Hey, I've been using Session to chat with complete privacy and security. Come join me! Download it at https://getsession.org/. My Session ID is \(profile.id) !"
self?.transitionToScreen(
UIActivityViewController(
activityItems: [ invitation ],
applicationActivities: nil
),
transitionType: .present
)
}
),
SessionCell.Info(
id: .recoveryPhrase,
leftAccessory: .icon(
UIImage(named: "icon_recovery")?
.withRenderingMode(.alwaysTemplate)
),
title: "vc_settings_recovery_phrase_button_title".localized(),
onTap: {
let targetViewController: UIViewController = {
if let modal: SeedModal = try? SeedModal() {
return modal
}
return ConfirmationModal(
info: ConfirmationModal.Info(
title: "ALERT_ERROR_TITLE".localized(),
body: .text("LOAD_RECOVERY_PASSWORD_ERROR".localized()),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text
)
)
}()
self?.transitionToScreen(targetViewController, transitionType: .present)
}
),
SessionCell.Info(
id: .help,
leftAccessory: .icon(
UIImage(named: "icon_help")?
.withRenderingMode(.alwaysTemplate)
),
title: "HELP_TITLE".localized(),
onTap: {
self?.transitionToScreen(
SessionTableViewController(viewModel: HelpViewModel())
)
}
),
SessionCell.Info(
id: .clearData,
leftAccessory: .icon(
UIImage(named: "icon_bin")?
.withRenderingMode(.alwaysTemplate)
),
title: "vc_settings_clear_all_data_button_title".localized(),
styling: SessionCell.StyleInfo(tintColor: .danger),
onTap: {
self?.transitionToScreen(NukeDataModal(), transitionType: .present)
}
)
]
)
]
}
public let footerView: AnyPublisher<UIView?, Never> = Just(VersionFooterView()).eraseToAnyPublisher()
// MARK: - Functions
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
private func updateProfilePicture(currentFileName: String?) {
let existingDisplayName: String = self.oldDisplayName
let existingImageData: Data? = ProfileManager
.profileAvatar(id: self.userSessionId)
let editProfilePictureModalInfo: ConfirmationModal.Info = ConfirmationModal.Info(
title: "update_profile_modal_title".localized(),
body: .image(
placeholderData: UIImage(named: "profile_placeholder")?.pngData(),
valueData: existingImageData,
icon: .rightPlus,
style: .circular,
accessibility: Accessibility(
identifier: "Image picker",
label: "Image picker"
),
onClick: { [weak self] in self?.showPhotoLibraryForAvatar() }
),
confirmTitle: "update_profile_modal_save".localized(),
confirmEnabled: false,
cancelTitle: "update_profile_modal_remove".localized(),
cancelEnabled: (existingImageData != nil),
hasCloseButton: true,
dismissOnConfirm: false,
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
onConfirm: { modal in modal.close() },
onCancel: { [weak self] modal in
self?.updateProfile(
name: existingDisplayName,
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
avatarUpdate: .remove,
onComplete: { [weak modal] in modal?.close() }
)
},
afterClosed: { [weak self] in
self?.editProfilePictureModal = nil
self?.editProfilePictureModalInfo = nil
}
)
let modal: ConfirmationModal = ConfirmationModal(info: editProfilePictureModalInfo)
self.editProfilePictureModalInfo = editProfilePictureModalInfo
self.editProfilePictureModal = modal
self.transitionToScreen(modal, transitionType: .present)
}
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
fileprivate func updatedProfilePictureSelected(name: String, avatarUpdate: ProfileManager.AvatarUpdate) {
guard let info: ConfirmationModal.Info = self.editProfilePictureModalInfo else { return }
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
self.editProfilePictureModal?.updateContent(
with: info.with(
body: .image(
placeholderData: UIImage(named: "profile_placeholder")?.pngData(),
valueData: {
switch avatarUpdate {
case .uploadImageData(let imageData): return imageData
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
default: return nil
}
}(),
icon: .rightPlus,
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
style: .circular,
accessibility: Accessibility(
identifier: "Image picker",
label: "Image picker"
),
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
onClick: { [weak self] in self?.showPhotoLibraryForAvatar() }
),
confirmEnabled: true,
onConfirm: { [weak self] modal in
self?.updateProfile(
name: name,
avatarUpdate: avatarUpdate,
onComplete: { [weak modal] in modal?.close() }
)
}
)
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
)
}
private func showPhotoLibraryForAvatar() {
Permissions.requestLibraryPermissionIfNeeded { [weak self] in
DispatchQueue.main.async {
let picker: UIImagePickerController = UIImagePickerController()
picker.sourceType = .photoLibrary
picker.mediaTypes = [ "public.image" ] // stringlint:disable
picker.delegate = self?.imagePickerHandler
self?.transitionToScreen(picker, transitionType: .present)
}
}
}
fileprivate func updateProfile(
name: String,
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
avatarUpdate: ProfileManager.AvatarUpdate,
onComplete: (() -> ())? = nil
) {
let viewController = ModalActivityIndicatorViewController(canCancel: false) { [weak self] modalActivityIndicator in
ProfileManager.updateLocal(
Fixed a number of issues found during internal testing Added copy for an unrecoverable startup case Added some additional logs to better debug ValueObservation query errors Increased the pageSize to 20 on iPad devices (to prevent it immediately loading a second page) Cleaned up a bunch of threading logic (try to avoid overriding subscribe/receive threads specified at subscription) Consolidated the 'sendMessage' and 'sendAttachments' functions Updated the various frameworks to use 'DAWRF with DSYM' to allow for better debugging during debug mode (at the cost of a longer build time) Updated the logic to optimistically insert messages when sending to avoid any database write delays Updated the logic to avoid sending notifications for messages which are already marked as read by the config Fixed an issue where multiple paths could incorrectly get built at the same time in some cases Fixed an issue where other job queues could be started before the blockingQueue finishes Fixed a potential bug with the snode version comparison (was just a string comparison which would fail when getting to double-digit values) Fixed a bug where you couldn't remove the last reaction on a message Fixed the broken media message zoom animations Fixed a bug where the last message read in a conversation wouldn't be correctly detected as already read Fixed a bug where the QuoteView had no line limits (resulting in the '@You' mention background highlight being incorrectly positioned in the quote preview) Fixed a bug where a large number of configSyncJobs could be scheduled (only one would run at a time but this could result in performance impacts)
2 years ago
queue: .global(qos: .default),
profileName: name,
avatarUpdate: avatarUpdate,
success: { db in
// Wait for the database transaction to complete before updating the UI
db.afterNextTransactionNested { _ in
DispatchQueue.main.async {
modalActivityIndicator.dismiss(completion: {
onComplete?()
})
}
}
},
failure: { [weak self] error in
DispatchQueue.main.async {
modalActivityIndicator.dismiss {
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
let title: String = {
switch (avatarUpdate, error) {
case (.remove, _): return "update_profile_modal_remove_error_title".localized()
case (_, .avatarUploadMaxFileSizeExceeded):
return "update_profile_modal_max_size_error_title".localized()
default: return "update_profile_modal_error_title".localized()
}
}()
let message: String? = {
switch (avatarUpdate, error) {
case (.remove, _): return nil
case (_, .avatarUploadMaxFileSizeExceeded):
return "update_profile_modal_max_size_error_message".localized()
default: return "update_profile_modal_error_message".localized()
}
}()
self?.transitionToScreen(
ConfirmationModal(
info: ConfirmationModal.Info(
Merge remote-tracking branch 'upstream/dev' into feature/updated-user-config-handling # Conflicts: # Session/Closed Groups/NewClosedGroupVC.swift # Session/Conversations/ConversationVC+Interaction.swift # Session/Conversations/ConversationVC.swift # Session/Conversations/ConversationViewModel.swift # Session/Conversations/Settings/ThreadSettingsViewModel.swift # Session/Home/GlobalSearch/GlobalSearchViewController.swift # Session/Home/HomeVC.swift # Session/Home/New Conversation/NewDMVC.swift # Session/Media Viewing & Editing/GIFs/GifPickerViewController.swift # Session/Meta/Translations/de.lproj/Localizable.strings # Session/Meta/Translations/en.lproj/Localizable.strings # Session/Meta/Translations/es.lproj/Localizable.strings # Session/Meta/Translations/fa.lproj/Localizable.strings # Session/Meta/Translations/fi.lproj/Localizable.strings # Session/Meta/Translations/fr.lproj/Localizable.strings # Session/Meta/Translations/hi.lproj/Localizable.strings # Session/Meta/Translations/hr.lproj/Localizable.strings # Session/Meta/Translations/id-ID.lproj/Localizable.strings # Session/Meta/Translations/it.lproj/Localizable.strings # Session/Meta/Translations/ja.lproj/Localizable.strings # Session/Meta/Translations/nl.lproj/Localizable.strings # Session/Meta/Translations/pl.lproj/Localizable.strings # Session/Meta/Translations/pt_BR.lproj/Localizable.strings # Session/Meta/Translations/ru.lproj/Localizable.strings # Session/Meta/Translations/si.lproj/Localizable.strings # Session/Meta/Translations/sk.lproj/Localizable.strings # Session/Meta/Translations/sv.lproj/Localizable.strings # Session/Meta/Translations/th.lproj/Localizable.strings # Session/Meta/Translations/vi-VN.lproj/Localizable.strings # Session/Meta/Translations/zh-Hant.lproj/Localizable.strings # Session/Meta/Translations/zh_CN.lproj/Localizable.strings # Session/Settings/BlockedContactsViewController.swift # Session/Settings/NukeDataModal.swift # Session/Settings/SettingsViewModel.swift # SessionMessagingKit/Shared Models/SessionThreadViewModel.swift # SessionUIKit/Components/ConfirmationModal.swift
2 years ago
title: title,
body: (message.map { .text($0) } ?? .none),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text,
dismissType: .single
)
),
transitionType: .present
)
}
}
}
)
}
self.transitionToScreen(viewController, transitionType: .present)
}
private func copySessionId(_ sessionId: String, button: SessionButton?) {
UIPasteboard.general.string = sessionId
guard let button: SessionButton = button else { return }
// Ensure we are on the main thread just in case
DispatchQueue.main.async {
button.isUserInteractionEnabled = false
UIView.transition(
with: button,
duration: 0.25,
options: .transitionCrossDissolve,
animations: {
button.setTitle("copied".localized(), for: .normal)
},
completion: { _ in
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4)) {
button.isUserInteractionEnabled = true
UIView.transition(
with: button,
duration: 0.25,
options: .transitionCrossDissolve,
animations: {
button.setTitle("copy".localized(), for: .normal)
},
completion: nil
)
}
}
)
}
}
private func shareSessionId(_ sessionId: String) {
let shareVC = UIActivityViewController(
activityItems: [ sessionId ],
applicationActivities: nil
)
self.transitionToScreen(shareVC, transitionType: .present)
}
}