// MARK: Swiftgram import SGLogging import SGSimpleSettings import SGStrings import SGAPIToken #if canImport(SGDeletedMessages) import SGDeletedMessages #endif import SGItemListUI import Foundation import UIKit import Display import SwiftSignalKit import Postbox import TelegramCore import MtProtoKit import MessageUI import TelegramPresentationData import TelegramUIPreferences import ItemListUI import PresentationDataUtils import OverlayStatusController import AccountContext import AppBundle import WebKit import PeerNameColorScreen import UndoUI private enum SGControllerSection: Int32, SGItemListSection { case search case trending case content case tabs case folders case chatList case profiles case stories case translation case voiceMessages case calls case photo case stickers case videoNotes case contextMenu case accountColors case ghostMode case other } enum SGBoolSetting: String { case hidePhoneInSettings case showTabNames case showContactsTab case showCallsTab case wideTabBar case foldersAtBottom case startTelescopeWithRearCam case hideStories case uploadSpeedBoost case showProfileId case warnOnStoriesOpen case sendWithReturnKey case rememberLastFolder case sendLargePhotos case storyStealthMode case disableSwipeToRecordStory case disableDeleteChatSwipeOption case quickTranslateButton case showRepostToStory case contextShowSelectFromUser case contextShowSaveToCloud case contextShowHideForwardName case contextShowRestrict case contextShowReport case contextShowReply case contextShowPin case contextShowSaveMedia case contextShowMessageReplies case contextShowJson case disableScrollToNextChannel case disableScrollToNextTopic case disableChatSwipeOptions case disableGalleryCamera case disableGalleryCameraPreview case disableSendAsButton case disableSnapDeletionEffect case stickerTimestamp case hideRecordingButton case hideTabBar case showDC case showCreationDate case showRegDate case compactChatList case compactFolderNames case allChatsHidden case defaultEmojisFirst case messageDoubleTapActionOutgoingEdit case wideChannelPosts case forceEmojiTab case forceBuiltInMic case secondsInMessages case hideChannelBottomButton case confirmCalls case swipeForVideoPIP case enableVoipTcp case nyStyleSnow case nyStyleLightning case tabBarSearchEnabled case hideReactions case compactMessagePreview case showDeletedMessages case saveDeletedMessagesMedia case saveDeletedMessagesReactions case saveDeletedMessagesForBots case saveEditHistory case enableLocalMessageEditing // used in GLEGramSettingsController // Ghost Mode settings case disableOnlineStatus case disableTypingStatus case disableRecordingVideoStatus case disableUploadingVideoStatus case disableVCMessageRecordingStatus case disableVCMessageUploadingStatus case disableUploadingPhotoStatus case disableUploadingFileStatus case disableChoosingLocationStatus case disableChoosingContactStatus case disablePlayingGameStatus case disableRecordingRoundVideoStatus case disableUploadingRoundVideoStatus case disableSpeakingInGroupCallStatus case disableChoosingStickerStatus case disableEmojiInteractionStatus case disableEmojiAcknowledgementStatus case disableMessageReadReceipt case disableStoryReadReceipt case disableAllAds case hideProxySponsor case enableSavingProtectedContent case sensitiveContentEnabled case disableScreenshotDetection case enableSavingSelfDestructingMessages case disableSecretChatBlurOnScreenshot case enableLocalPremium case scrollToTopButtonEnabled case fakeLocationEnabled case keepRemovedChannels case enableVideoToCircleOrVoice case enableTelescope case enableFontReplacement case disableCompactNumbers case disableZalgoText case unlimitedFavoriteStickers case enableOnlineStatusRecording case addMusicFromDeviceToProfile case pluginSystemEnabled case chatExportEnabled case emojiDownloaderEnabled case feelRichEnabled case giftIdEnabled case fakeProfileEnabled } private enum SGOneFromManySetting: String { case nyStyle case bottomTabStyle case downloadSpeedBoost case allChatsTitleLengthOverride // case allChatsFolderPositionOverride case translationBackend case transcriptionBackend } private enum SGSliderSetting: String { case accountColorsSaturation case outgoingPhotoQuality case stickerSize } private enum SGDisclosureLink: String { case contentSettings case languageSettings } private struct PeerNameColorScreenState: Equatable { var updatedNameColor: PeerNameColor? var updatedBackgroundEmojiId: Int64? } private struct SGSettingsControllerState: Equatable { var searchQuery: String? } private typealias SGControllerEntry = SGItemListUIEntry private func SGControllerEntries(presentationData: PresentationData, callListSettings: CallListSettings, experimentalUISettings: ExperimentalUISettings, SGSettings: SGUISettings, appConfiguration: AppConfiguration, nameColors: PeerNameColors, state: SGSettingsControllerState) -> [SGControllerEntry] { let lang = presentationData.strings.baseLanguageCode let strings = presentationData.strings let newStr = strings.Settings_New var entries: [SGControllerEntry] = [] let id = SGItemListCounter() entries.append(.searchInput(id: id.count, section: .search, title: NSAttributedString(string: "🔍"), text: state.searchQuery ?? "", placeholder: strings.Common_Search)) if SGSimpleSettings.shared.canUseNY { entries.append(.header(id: id.count, section: .trending, text: i18n("Settings.NY.Header", lang), badge: newStr)) entries.append(.toggle(id: id.count, section: .trending, settingName: .nyStyleSnow, value: SGSimpleSettings.shared.nyStyle == SGSimpleSettings.NYStyle.snow.rawValue, text: i18n("Settings.NY.Style.snow", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .trending, settingName: .nyStyleLightning, value: SGSimpleSettings.shared.nyStyle == SGSimpleSettings.NYStyle.lightning.rawValue, text: i18n("Settings.NY.Style.lightning", lang), enabled: true)) // entries.append(.oneFromManySelector(id: id.count, section: .trending, settingName: .nyStyle, text: i18n("Settings.NY.Style", lang), value: i18n("Settings.NY.Style.\(SGSimpleSettings.shared.nyStyle)", lang), enabled: true)) entries.append(.notice(id: id.count, section: .trending, text: i18n("Settings.NY.Notice", lang))) } else { id.increment(3) } if appConfiguration.sgWebSettings.global.canEditSettings { entries.append(.disclosure(id: id.count, section: .content, link: .contentSettings, text: i18n("Settings.ContentSettings", lang))) } else { id.increment(1) } entries.append(.header(id: id.count, section: .tabs, text: i18n("Settings.Tabs.Header", lang), badge: nil)) entries.append(.toggle(id: id.count, section: .tabs, settingName: .hideTabBar, value: SGSimpleSettings.shared.hideTabBar, text: i18n("Settings.Tabs.HideTabBar", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .tabs, settingName: .showContactsTab, value: callListSettings.showContactsTab, text: i18n("Settings.Tabs.ShowContacts", lang), enabled: !SGSimpleSettings.shared.hideTabBar)) entries.append(.toggle(id: id.count, section: .tabs, settingName: .showCallsTab, value: callListSettings.showTab, text: strings.CallSettings_TabIcon, enabled: !SGSimpleSettings.shared.hideTabBar)) entries.append(.toggle(id: id.count, section: .tabs, settingName: .showTabNames, value: SGSimpleSettings.shared.showTabNames, text: i18n("Settings.Tabs.ShowNames", lang), enabled: !SGSimpleSettings.shared.hideTabBar)) entries.append(.toggle(id: id.count, section: .tabs, settingName: .tabBarSearchEnabled, value: SGSimpleSettings.shared.tabBarSearchEnabled, text: i18n("Settings.Tabs.SearchButton", lang), enabled: !SGSimpleSettings.shared.hideTabBar)) entries.append(.toggle(id: id.count, section: .tabs, settingName: .wideTabBar, value: SGSimpleSettings.shared.wideTabBar, text: i18n("Settings.Tabs.WideTabBar", lang), enabled: !SGSimpleSettings.shared.hideTabBar)) entries.append(.notice(id: id.count, section: .tabs, text: i18n("Settings.Tabs.WideTabBar.Notice", lang))) entries.append(.header(id: id.count, section: .folders, text: strings.Settings_ChatFolders.uppercased(), badge: nil)) entries.append(.toggle(id: id.count, section: .folders, settingName: .foldersAtBottom, value: experimentalUISettings.foldersTabAtBottom, text: i18n("Settings.Folders.BottomTab", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .folders, settingName: .allChatsHidden, value: SGSimpleSettings.shared.allChatsHidden, text: i18n("Settings.Folders.AllChatsHidden", lang, strings.ChatList_Tabs_AllChats), enabled: true)) #if DEBUG // entries.append(.oneFromManySelector(id: id.count, section: .folders, settingName: .allChatsFolderPositionOverride, text: i18n("Settings.Folders.AllChatsPlacement", lang), value: i18n("Settings.Folders.AllChatsPlacement.\(SGSimpleSettings.shared.allChatsFolderPositionOverride)", lang), enabled: true)) #endif entries.append(.toggle(id: id.count, section: .folders, settingName: .compactFolderNames, value: SGSimpleSettings.shared.compactFolderNames, text: i18n("Settings.Folders.CompactNames", lang), enabled: true)) entries.append(.oneFromManySelector(id: id.count, section: .folders, settingName: .allChatsTitleLengthOverride, text: i18n("Settings.Folders.AllChatsTitle", lang), value: i18n("Settings.Folders.AllChatsTitle.\(SGSimpleSettings.shared.allChatsTitleLengthOverride)", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .folders, settingName: .rememberLastFolder, value: SGSimpleSettings.shared.rememberLastFolder, text: i18n("Settings.Folders.RememberLast", lang), enabled: true)) entries.append(.notice(id: id.count, section: .folders, text: i18n("Settings.Folders.RememberLast.Notice", lang))) entries.append(.header(id: id.count, section: .chatList, text: i18n("Settings.ChatList.Header", lang), badge: nil)) entries.append(.toggle(id: id.count, section: .chatList, settingName: .compactChatList, value: SGSimpleSettings.shared.compactChatList, text: i18n("Settings.CompactChatList", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .chatList, settingName: .compactMessagePreview, value: SGSimpleSettings.shared.chatListLines != SGSimpleSettings.ChatListLines.three.rawValue, text: i18n("Settings.CompactMessagePreview", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .chatList, settingName: .disableChatSwipeOptions, value: !SGSimpleSettings.shared.disableChatSwipeOptions, text: i18n("Settings.ChatSwipeOptions", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .chatList, settingName: .disableDeleteChatSwipeOption, value: !SGSimpleSettings.shared.disableDeleteChatSwipeOption, text: i18n("Settings.DeleteChatSwipeOption", lang), enabled: !SGSimpleSettings.shared.disableChatSwipeOptions)) entries.append(.header(id: id.count, section: .profiles, text: i18n("Settings.Profiles.Header", lang), badge: nil)) entries.append(.toggle(id: id.count, section: .profiles, settingName: .showProfileId, value: SGSimpleSettings.shared.showProfileId, text: i18n("Settings.ShowProfileID", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .profiles, settingName: .showDC, value: SGSimpleSettings.shared.showDC, text: i18n("Settings.ShowDC", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .profiles, settingName: .showRegDate, value: SGSimpleSettings.shared.showRegDate, text: i18n("Settings.ShowRegDate", lang), enabled: true)) entries.append(.notice(id: id.count, section: .profiles, text: i18n("Settings.ShowRegDate.Notice", lang))) entries.append(.toggle(id: id.count, section: .profiles, settingName: .showCreationDate, value: SGSimpleSettings.shared.showCreationDate, text: i18n("Settings.ShowCreationDate", lang), enabled: true)) entries.append(.notice(id: id.count, section: .profiles, text: i18n("Settings.ShowCreationDate.Notice", lang))) entries.append(.toggle(id: id.count, section: .profiles, settingName: .confirmCalls, value: SGSimpleSettings.shared.confirmCalls, text: i18n("Settings.CallConfirmation", lang), enabled: true)) entries.append(.notice(id: id.count, section: .profiles, text: i18n("Settings.CallConfirmation.Notice", lang))) entries.append(.header(id: id.count, section: .stories, text: strings.AutoDownloadSettings_Stories.uppercased(), badge: nil)) entries.append(.toggle(id: id.count, section: .stories, settingName: .hideStories, value: SGSimpleSettings.shared.hideStories, text: i18n("Settings.Stories.Hide", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .stories, settingName: .disableSwipeToRecordStory, value: SGSimpleSettings.shared.disableSwipeToRecordStory, text: i18n("Settings.Stories.DisableSwipeToRecord", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .stories, settingName: .warnOnStoriesOpen, value: SGSettings.warnOnStoriesOpen, text: i18n("Settings.Stories.WarnBeforeView", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .stories, settingName: .showRepostToStory, value: SGSimpleSettings.shared.showRepostToStoryV2, text: strings.Share_RepostToStory.replacingOccurrences(of: "\n", with: " "), enabled: true)) if SGSimpleSettings.shared.canUseStealthMode { entries.append(.toggle(id: id.count, section: .stories, settingName: .storyStealthMode, value: SGSimpleSettings.shared.storyStealthMode, text: strings.Story_StealthMode_Title, enabled: true)) entries.append(.notice(id: id.count, section: .stories, text: strings.Story_StealthMode_ControlText)) } else { id.increment(2) } entries.append(.header(id: id.count, section: .translation, text: strings.Localization_TranslateMessages.uppercased(), badge: nil)) entries.append(.oneFromManySelector(id: id.count, section: .translation, settingName: .translationBackend, text: i18n("Settings.Translation.Backend", lang), value: i18n("Settings.Translation.Backend.\(SGSimpleSettings.shared.translationBackend)", lang), enabled: true)) if SGSimpleSettings.shared.translationBackendEnum != .gtranslate { entries.append(.notice(id: id.count, section: .translation, text: i18n("Settings.Translation.Backend.Notice", lang, "Settings.Translation.Backend.\(SGSimpleSettings.TranslationBackend.gtranslate.rawValue)".i18n(lang)))) } else { id.increment(1) } entries.append(.toggle(id: id.count, section: .translation, settingName: .quickTranslateButton, value: SGSimpleSettings.shared.quickTranslateButton, text: i18n("Settings.Translation.QuickTranslateButton", lang), enabled: true)) entries.append(.disclosure(id: id.count, section: .translation, link: .languageSettings, text: strings.Localization_TranslateEntireChat)) entries.append(.notice(id: id.count, section: .translation, text: i18n("Common.NoTelegramPremiumNeeded", lang, strings.Settings_Premium))) entries.append(.header(id: id.count, section: .voiceMessages, text: "Settings.Transcription.Header".i18n(lang), badge: nil)) entries.append(.oneFromManySelector(id: id.count, section: .voiceMessages, settingName: .transcriptionBackend, text: i18n("Settings.Transcription.Backend", lang), value: i18n("Settings.Transcription.Backend.\(SGSimpleSettings.shared.transcriptionBackend)", lang), enabled: true)) if SGSimpleSettings.shared.transcriptionBackendEnum != .apple { entries.append(.notice(id: id.count, section: .voiceMessages, text: i18n("Settings.Transcription.Backend.Notice", lang, "Settings.Transcription.Backend.\(SGSimpleSettings.TranscriptionBackend.apple.rawValue)".i18n(lang)))) } else { id.increment(1) } entries.append(.header(id: id.count, section: .voiceMessages, text: strings.Privacy_VoiceMessages.uppercased(), badge: nil)) entries.append(.toggle(id: id.count, section: .voiceMessages, settingName: .forceBuiltInMic, value: SGSimpleSettings.shared.forceBuiltInMic, text: i18n("Settings.forceBuiltInMic", lang), enabled: true)) entries.append(.notice(id: id.count, section: .voiceMessages, text: i18n("Settings.forceBuiltInMic.Notice", lang))) entries.append(.header(id: id.count, section: .calls, text: strings.Calls_TabTitle.uppercased(), badge: nil)) entries.append(.toggle(id: id.count, section: .calls, settingName: .enableVoipTcp, value: experimentalUISettings.enableVoipTcp, text: "Force TCP", enabled: true)) entries.append(.notice(id: id.count, section: .calls, text: "Common.KnowWhatYouDo".i18n(lang))) entries.append(.header(id: id.count, section: .photo, text: strings.NetworkUsageSettings_MediaImageDataSection, badge: nil)) entries.append(.header(id: id.count, section: .photo, text: strings.PhotoEditor_QualityTool.uppercased(), badge: nil)) entries.append(.percentageSlider(id: id.count, section: .photo, settingName: .outgoingPhotoQuality, value: SGSimpleSettings.shared.outgoingPhotoQuality)) entries.append(.notice(id: id.count, section: .photo, text: i18n("Settings.Photo.Quality.Notice", lang))) entries.append(.toggle(id: id.count, section: .photo, settingName: .sendLargePhotos, value: SGSimpleSettings.shared.sendLargePhotos, text: i18n("Settings.Photo.SendLarge", lang), enabled: true)) entries.append(.notice(id: id.count, section: .photo, text: i18n("Settings.Photo.SendLarge.Notice", lang))) entries.append(.header(id: id.count, section: .stickers, text: strings.StickerPacksSettings_Title.uppercased(), badge: nil)) entries.append(.header(id: id.count, section: .stickers, text: i18n("Settings.Stickers.Size", lang), badge: nil)) entries.append(.percentageSlider(id: id.count, section: .stickers, settingName: .stickerSize, value: SGSimpleSettings.shared.stickerSize)) entries.append(.toggle(id: id.count, section: .stickers, settingName: .stickerTimestamp, value: SGSimpleSettings.shared.stickerTimestamp, text: i18n("Settings.Stickers.Timestamp", lang), enabled: true)) entries.append(.header(id: id.count, section: .videoNotes, text: i18n("Settings.VideoNotes.Header", lang), badge: nil)) entries.append(.toggle(id: id.count, section: .videoNotes, settingName: .startTelescopeWithRearCam, value: SGSimpleSettings.shared.startTelescopeWithRearCam, text: i18n("Settings.VideoNotes.StartWithRearCam", lang), enabled: true)) entries.append(.header(id: id.count, section: .contextMenu, text: i18n("Settings.ContextMenu", lang), badge: nil)) entries.append(.notice(id: id.count, section: .contextMenu, text: i18n("Settings.ContextMenu.Notice", lang))) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowSaveToCloud, value: SGSimpleSettings.shared.contextShowSaveToCloud, text: i18n("ContextMenu.SaveToCloud", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowHideForwardName, value: SGSimpleSettings.shared.contextShowHideForwardName, text: strings.Conversation_ForwardOptions_HideSendersNames, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowSelectFromUser, value: SGSimpleSettings.shared.contextShowSelectFromUser, text: i18n("ContextMenu.SelectFromUser", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowRestrict, value: SGSimpleSettings.shared.contextShowRestrict, text: strings.Conversation_ContextMenuBan, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowReport, value: SGSimpleSettings.shared.contextShowReport, text: strings.Conversation_ContextMenuReport, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowReply, value: SGSimpleSettings.shared.contextShowReply, text: strings.Conversation_ContextMenuReply, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowPin, value: SGSimpleSettings.shared.contextShowPin, text: strings.Conversation_Pin, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowSaveMedia, value: SGSimpleSettings.shared.contextShowSaveMedia, text: strings.Conversation_SaveToFiles, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowMessageReplies, value: SGSimpleSettings.shared.contextShowMessageReplies, text: strings.Conversation_ContextViewThread, enabled: true)) entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowJson, value: SGSimpleSettings.shared.contextShowJson, text: "JSON", enabled: true)) /* entries.append(.toggle(id: id.count, section: .contextMenu, settingName: .contextShowRestrict, value: SGSimpleSettings.shared.contextShowRestrict, text: strings.Conversation_ContextMenuBan)) */ entries.append(.header(id: id.count, section: .accountColors, text: i18n("Settings.CustomColors.Header", lang), badge: nil)) entries.append(.header(id: id.count, section: .accountColors, text: i18n("Settings.CustomColors.Saturation", lang), badge: nil)) let accountColorSaturation = SGSimpleSettings.shared.accountColorsSaturation entries.append(.percentageSlider(id: id.count, section: .accountColors, settingName: .accountColorsSaturation, value: accountColorSaturation)) // let nameColor: PeerNameColor // if let updatedNameColor = state.updatedNameColor { // nameColor = updatedNameColor // } else { // nameColor = .blue // } // let _ = nameColors.get(nameColor, dark: presentationData.theme.overallDarkAppearance) // entries.append(.peerColorPicker(id: entries.count, section: .other, // colors: nameColors, // currentColor: nameColor, // TODO: PeerNameColor(rawValue: <#T##Int32#>) // currentSaturation: accountColorSaturation // )) if accountColorSaturation == 0 { id.increment(100) entries.append(.peerColorDisclosurePreview(id: id.count, section: .accountColors, name: "\(strings.UserInfo_FirstNamePlaceholder) \(strings.UserInfo_LastNamePlaceholder)", color: presentationData.theme.chat.message.incoming.accentTextColor)) } else { id.increment(200) for index in nameColors.displayOrder.prefix(3) { let color: PeerNameColor = PeerNameColor(rawValue: index) let colors = nameColors.get(color, dark: presentationData.theme.overallDarkAppearance) entries.append(.peerColorDisclosurePreview(id: id.count, section: .accountColors, name: "\(strings.UserInfo_FirstNamePlaceholder) \(strings.UserInfo_LastNamePlaceholder)", color: colors.main)) } } entries.append(.notice(id: id.count, section: .accountColors, text: i18n("Settings.CustomColors.Saturation.Notice", lang))) id.increment(10000) entries.append(.header(id: id.count, section: .other, text: strings.Appearance_Other.uppercased(), badge: nil)) entries.append(.toggle(id: id.count, section: .other, settingName: .swipeForVideoPIP, value: SGSimpleSettings.shared.videoPIPSwipeDirection == SGSimpleSettings.VideoPIPSwipeDirection.up.rawValue, text: i18n("Settings.swipeForVideoPIP", lang), enabled: true)) entries.append(.notice(id: id.count, section: .other, text: i18n("Settings.swipeForVideoPIP.Notice", lang))) entries.append(.toggle(id: id.count, section: .other, settingName: .hideChannelBottomButton, value: !SGSimpleSettings.shared.hideChannelBottomButton, text: i18n("Settings.showChannelBottomButton", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .wideChannelPosts, value: SGSimpleSettings.shared.wideChannelPosts, text: i18n("Settings.wideChannelPosts", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .secondsInMessages, value: SGSimpleSettings.shared.secondsInMessages, text: i18n("Settings.secondsInMessages", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .messageDoubleTapActionOutgoingEdit, value: SGSimpleSettings.shared.messageDoubleTapActionOutgoing == SGSimpleSettings.MessageDoubleTapAction.edit.rawValue, text: i18n("Settings.messageDoubleTapActionOutgoingEdit", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .hideRecordingButton, value: !SGSimpleSettings.shared.hideRecordingButton, text: i18n("Settings.RecordingButton", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .disableSnapDeletionEffect, value: !SGSimpleSettings.shared.disableSnapDeletionEffect, text: i18n("Settings.SnapDeletionEffect", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .disableSendAsButton, value: !SGSimpleSettings.shared.disableSendAsButton, text: i18n("Settings.SendAsButton", lang, strings.Conversation_SendMesageAs), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .disableGalleryCamera, value: !SGSimpleSettings.shared.disableGalleryCamera, text: i18n("Settings.GalleryCamera", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .disableGalleryCameraPreview, value: !SGSimpleSettings.shared.disableGalleryCameraPreview, text: i18n("Settings.GalleryCameraPreview", lang), enabled: !SGSimpleSettings.shared.disableGalleryCamera)) entries.append(.toggle(id: id.count, section: .other, settingName: .disableScrollToNextChannel, value: !SGSimpleSettings.shared.disableScrollToNextChannel, text: i18n("Settings.PullToNextChannel", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .disableScrollToNextTopic, value: !SGSimpleSettings.shared.disableScrollToNextTopic, text: i18n("Settings.PullToNextTopic", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .hideReactions, value: SGSimpleSettings.shared.hideReactions, text: i18n("Settings.HideReactions", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .uploadSpeedBoost, value: SGSimpleSettings.shared.uploadSpeedBoost, text: i18n("Settings.UploadsBoost", lang), enabled: true)) entries.append(.oneFromManySelector(id: id.count, section: .other, settingName: .downloadSpeedBoost, text: i18n("Settings.DownloadsBoost", lang), value: i18n("Settings.DownloadsBoost.\(SGSimpleSettings.shared.downloadSpeedBoost)", lang), enabled: true)) entries.append(.notice(id: id.count, section: .other, text: i18n("Settings.DownloadsBoost.Notice", lang))) entries.append(.toggle(id: id.count, section: .other, settingName: .sendWithReturnKey, value: SGSettings.sendWithReturnKey, text: i18n("Settings.SendWithReturnKey", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .forceEmojiTab, value: SGSimpleSettings.shared.forceEmojiTab, text: i18n("Settings.ForceEmojiTab", lang), enabled: true)) entries.append(.toggle(id: id.count, section: .other, settingName: .defaultEmojisFirst, value: SGSimpleSettings.shared.defaultEmojisFirst, text: i18n("Settings.DefaultEmojisFirst", lang), enabled: true)) entries.append(.notice(id: id.count, section: .other, text: i18n("Settings.DefaultEmojisFirst.Notice", lang))) entries.append(.toggle(id: id.count, section: .other, settingName: .hidePhoneInSettings, value: SGSimpleSettings.shared.hidePhoneInSettings, text: i18n("Settings.HidePhoneInSettingsUI", lang), enabled: true)) entries.append(.notice(id: id.count, section: .other, text: i18n("Settings.HidePhoneInSettingsUI.Notice", lang))) // NOTE: Swiftgram-specific privacy/content toggles were moved to GLEGram. return filterSGItemListUIEntrires(entries: entries, by: state.searchQuery) } public func sgSettingsController(context: AccountContext/*, focusOnItemTag: Int? = nil*/) -> ViewController { var presentControllerImpl: ((ViewController, ViewControllerPresentationArguments?) -> Void)? var pushControllerImpl: ((ViewController) -> Void)? // var getRootControllerImpl: (() -> UIViewController?)? // var getNavigationControllerImpl: (() -> NavigationController?)? var askForRestart: (() -> Void)? let initialState = SGSettingsControllerState() let statePromise = ValuePromise(initialState, ignoreRepeated: true) let stateValue = Atomic(value: initialState) let updateState: ((SGSettingsControllerState) -> SGSettingsControllerState) -> Void = { f in statePromise.set(stateValue.modify { f($0) }) } // let sliderPromise = ValuePromise(SGSimpleSettings.shared.accountColorsSaturation, ignoreRepeated: true) // let sliderStateValue = Atomic(value: SGSimpleSettings.shared.accountColorsSaturation) // let _: ((Int32) -> Int32) -> Void = { f in // sliderPromise.set(sliderStateValue.modify( {f($0)})) // } let simplePromise = ValuePromise(true, ignoreRepeated: false) let arguments = SGItemListArguments( context: context, /*updatePeerColor: { color in updateState { state in var updatedState = state updatedState.updatedNameColor = color return updatedState } },*/ setBoolValue: { setting, value in switch setting { case .hidePhoneInSettings: SGSimpleSettings.shared.hidePhoneInSettings = value askForRestart?() case .showTabNames: SGSimpleSettings.shared.showTabNames = value askForRestart?() case .showContactsTab: let _ = ( updateCallListSettingsInteractively( accountManager: context.sharedContext.accountManager, { $0.withUpdatedShowContactsTab(value) } ) ).start() case .showCallsTab: let _ = ( updateCallListSettingsInteractively( accountManager: context.sharedContext.accountManager, { $0.withUpdatedShowTab(value) } ) ).start() case .tabBarSearchEnabled: SGSimpleSettings.shared.tabBarSearchEnabled = value case .wideTabBar: SGSimpleSettings.shared.wideTabBar = value askForRestart?() case .foldersAtBottom: let _ = ( updateExperimentalUISettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in var settings = settings settings.foldersTabAtBottom = value return settings } ) ).start() case .startTelescopeWithRearCam: SGSimpleSettings.shared.startTelescopeWithRearCam = value case .hideStories: let _ = ( updateSGUISettings(engine: context.engine, { settings in var settings = settings settings.hideStories = value return settings }) ).start() case .showProfileId: let _ = ( updateSGUISettings(engine: context.engine, { settings in var settings = settings settings.showProfileId = value return settings }) ).start() case .warnOnStoriesOpen: let _ = ( updateSGUISettings(engine: context.engine, { settings in var settings = settings settings.warnOnStoriesOpen = value return settings }) ).start() case .sendWithReturnKey: let _ = ( updateSGUISettings(engine: context.engine, { settings in var settings = settings settings.sendWithReturnKey = value return settings }) ).start() case .rememberLastFolder: SGSimpleSettings.shared.rememberLastFolder = value case .sendLargePhotos: SGSimpleSettings.shared.sendLargePhotos = value case .storyStealthMode: SGSimpleSettings.shared.storyStealthMode = value case .disableSwipeToRecordStory: SGSimpleSettings.shared.disableSwipeToRecordStory = value case .quickTranslateButton: SGSimpleSettings.shared.quickTranslateButton = value case .uploadSpeedBoost: SGSimpleSettings.shared.uploadSpeedBoost = value case .unlimitedFavoriteStickers: SGSimpleSettings.shared.unlimitedFavoriteStickers = value case .enableOnlineStatusRecording: SGSimpleSettings.shared.enableOnlineStatusRecording = value case .showRepostToStory: SGSimpleSettings.shared.showRepostToStoryV2 = value case .contextShowSelectFromUser: SGSimpleSettings.shared.contextShowSelectFromUser = value case .contextShowSaveToCloud: SGSimpleSettings.shared.contextShowSaveToCloud = value case .contextShowRestrict: SGSimpleSettings.shared.contextShowRestrict = value case .contextShowHideForwardName: SGSimpleSettings.shared.contextShowHideForwardName = value case .addMusicFromDeviceToProfile: SGSimpleSettings.shared.addMusicFromDeviceToProfile = value case .hideReactions: SGSimpleSettings.shared.hideReactions = value case .pluginSystemEnabled: SGSimpleSettings.shared.pluginSystemEnabled = value askForRestart?() case .chatExportEnabled: SGSimpleSettings.shared.chatExportEnabled = value case .disableScrollToNextChannel: SGSimpleSettings.shared.disableScrollToNextChannel = !value case .disableScrollToNextTopic: SGSimpleSettings.shared.disableScrollToNextTopic = !value case .disableChatSwipeOptions: SGSimpleSettings.shared.disableChatSwipeOptions = !value simplePromise.set(true) // Trigger update for 'enabled' field of other toggles askForRestart?() case .disableDeleteChatSwipeOption: SGSimpleSettings.shared.disableDeleteChatSwipeOption = !value askForRestart?() case .disableGalleryCamera: SGSimpleSettings.shared.disableGalleryCamera = !value simplePromise.set(true) case .disableGalleryCameraPreview: SGSimpleSettings.shared.disableGalleryCameraPreview = !value case .disableSendAsButton: SGSimpleSettings.shared.disableSendAsButton = !value case .disableSnapDeletionEffect: SGSimpleSettings.shared.disableSnapDeletionEffect = !value case .contextShowReport: SGSimpleSettings.shared.contextShowReport = value case .contextShowReply: SGSimpleSettings.shared.contextShowReply = value case .contextShowPin: SGSimpleSettings.shared.contextShowPin = value case .contextShowSaveMedia: SGSimpleSettings.shared.contextShowSaveMedia = value case .contextShowMessageReplies: SGSimpleSettings.shared.contextShowMessageReplies = value case .stickerTimestamp: SGSimpleSettings.shared.stickerTimestamp = value case .contextShowJson: SGSimpleSettings.shared.contextShowJson = value case .hideRecordingButton: SGSimpleSettings.shared.hideRecordingButton = !value case .hideTabBar: SGSimpleSettings.shared.hideTabBar = value simplePromise.set(true) // Trigger update for 'enabled' field of other toggles askForRestart?() case .showDC: SGSimpleSettings.shared.showDC = value case .showCreationDate: SGSimpleSettings.shared.showCreationDate = value case .showRegDate: SGSimpleSettings.shared.showRegDate = value case .compactChatList: SGSimpleSettings.shared.compactChatList = value askForRestart?() case .compactMessagePreview: SGSimpleSettings.shared.chatListLines = value ? SGSimpleSettings.ChatListLines.one.rawValue : SGSimpleSettings.ChatListLines.three.rawValue askForRestart?() case .compactFolderNames: SGSimpleSettings.shared.compactFolderNames = value askForRestart?() case .allChatsHidden: SGSimpleSettings.shared.allChatsHidden = value askForRestart?() case .defaultEmojisFirst: SGSimpleSettings.shared.defaultEmojisFirst = value case .messageDoubleTapActionOutgoingEdit: SGSimpleSettings.shared.messageDoubleTapActionOutgoing = value ? SGSimpleSettings.MessageDoubleTapAction.edit.rawValue : SGSimpleSettings.MessageDoubleTapAction.default.rawValue case .wideChannelPosts: SGSimpleSettings.shared.wideChannelPosts = value case .forceEmojiTab: SGSimpleSettings.shared.forceEmojiTab = value case .forceBuiltInMic: SGSimpleSettings.shared.forceBuiltInMic = value case .hideChannelBottomButton: SGSimpleSettings.shared.hideChannelBottomButton = !value case .secondsInMessages: SGSimpleSettings.shared.secondsInMessages = value case .confirmCalls: SGSimpleSettings.shared.confirmCalls = value case .swipeForVideoPIP: SGSimpleSettings.shared.videoPIPSwipeDirection = value ? SGSimpleSettings.VideoPIPSwipeDirection.up.rawValue : SGSimpleSettings.VideoPIPSwipeDirection.none.rawValue case .enableVoipTcp: let _ = ( updateExperimentalUISettingsInteractively(accountManager: context.sharedContext.accountManager, { settings in var settings = settings settings.enableVoipTcp = value return settings } ) ).start() case .nyStyleSnow: SGSimpleSettings.shared.nyStyle = value ? SGSimpleSettings.NYStyle.snow.rawValue : SGSimpleSettings.NYStyle.default.rawValue simplePromise.set(true) // Trigger update for 'enabled' field of other toggles case .nyStyleLightning: SGSimpleSettings.shared.nyStyle = value ? SGSimpleSettings.NYStyle.lightning.rawValue : SGSimpleSettings.NYStyle.default.rawValue simplePromise.set(true) // Trigger update for 'enabled' field of other toggles case .showDeletedMessages: SGSimpleSettings.shared.showDeletedMessages = value case .saveDeletedMessagesMedia: SGSimpleSettings.shared.saveDeletedMessagesMedia = value case .saveDeletedMessagesReactions: SGSimpleSettings.shared.saveDeletedMessagesReactions = value case .saveDeletedMessagesForBots: SGSimpleSettings.shared.saveDeletedMessagesForBots = value case .saveEditHistory: SGSimpleSettings.shared.saveEditHistory = value case .enableLocalMessageEditing: SGSimpleSettings.shared.enableLocalMessageEditing = value case .enableFontReplacement: SGSimpleSettings.shared.enableFontReplacement = value case .disableCompactNumbers: SGSimpleSettings.shared.disableCompactNumbers = value case .disableZalgoText: SGSimpleSettings.shared.disableZalgoText = value // Ghost Mode settings case .disableOnlineStatus: SGSimpleSettings.shared.disableOnlineStatus = value case .disableTypingStatus: SGSimpleSettings.shared.disableTypingStatus = value case .disableRecordingVideoStatus: SGSimpleSettings.shared.disableRecordingVideoStatus = value case .disableUploadingVideoStatus: SGSimpleSettings.shared.disableUploadingVideoStatus = value case .disableVCMessageRecordingStatus: SGSimpleSettings.shared.disableVCMessageRecordingStatus = value case .disableVCMessageUploadingStatus: SGSimpleSettings.shared.disableVCMessageUploadingStatus = value case .disableUploadingPhotoStatus: SGSimpleSettings.shared.disableUploadingPhotoStatus = value case .disableUploadingFileStatus: SGSimpleSettings.shared.disableUploadingFileStatus = value case .disableChoosingLocationStatus: SGSimpleSettings.shared.disableChoosingLocationStatus = value case .disableChoosingContactStatus: SGSimpleSettings.shared.disableChoosingContactStatus = value case .disablePlayingGameStatus: SGSimpleSettings.shared.disablePlayingGameStatus = value case .disableRecordingRoundVideoStatus: SGSimpleSettings.shared.disableRecordingRoundVideoStatus = value case .disableUploadingRoundVideoStatus: SGSimpleSettings.shared.disableUploadingRoundVideoStatus = value case .disableSpeakingInGroupCallStatus: SGSimpleSettings.shared.disableSpeakingInGroupCallStatus = value case .disableChoosingStickerStatus: SGSimpleSettings.shared.disableChoosingStickerStatus = value case .disableEmojiInteractionStatus: SGSimpleSettings.shared.disableEmojiInteractionStatus = value case .disableEmojiAcknowledgementStatus: SGSimpleSettings.shared.disableEmojiAcknowledgementStatus = value case .disableMessageReadReceipt: SGSimpleSettings.shared.disableMessageReadReceipt = value case .disableStoryReadReceipt: SGSimpleSettings.shared.disableStoryReadReceipt = value case .disableAllAds: SGSimpleSettings.shared.disableAllAds = value case .hideProxySponsor: SGSimpleSettings.shared.hideProxySponsor = value NotificationCenter.default.post(name: .sgHideProxySponsorDidChange, object: nil) case .enableSavingProtectedContent: SGSimpleSettings.shared.enableSavingProtectedContent = value case .disableScreenshotDetection: SGSimpleSettings.shared.disableScreenshotDetection = value case .enableSavingSelfDestructingMessages: SGSimpleSettings.shared.enableSavingSelfDestructingMessages = value case .disableSecretChatBlurOnScreenshot: SGSimpleSettings.shared.disableSecretChatBlurOnScreenshot = value case .enableLocalPremium: SGSimpleSettings.shared.enableLocalPremium = value case .sensitiveContentEnabled: // Intentionally not handled here. // This setting lives in GLEGram and is applied via Telegram server-side content settings. break case .scrollToTopButtonEnabled: SGSimpleSettings.shared.scrollToTopButtonEnabled = value case .fakeLocationEnabled: SGSimpleSettings.shared.fakeLocationEnabled = value case .keepRemovedChannels: SGSimpleSettings.shared.keepRemovedChannels = value case .enableVideoToCircleOrVoice: SGSimpleSettings.shared.enableVideoToCircleOrVoice = value case .enableTelescope: SGSimpleSettings.shared.enableTelescope = value case .emojiDownloaderEnabled: SGSimpleSettings.shared.emojiDownloaderEnabled = value case .feelRichEnabled: SGSimpleSettings.shared.feelRichEnabled = value case .giftIdEnabled: SGSimpleSettings.shared.giftIdEnabled = value case .fakeProfileEnabled: SGSimpleSettings.shared.fakeProfileEnabled = value } }, updateSliderValue: { setting, value in switch (setting) { case .accountColorsSaturation: if SGSimpleSettings.shared.accountColorsSaturation != value { SGSimpleSettings.shared.accountColorsSaturation = value simplePromise.set(true) } case .outgoingPhotoQuality: if SGSimpleSettings.shared.outgoingPhotoQuality != value { SGSimpleSettings.shared.outgoingPhotoQuality = value simplePromise.set(true) } case .stickerSize: if SGSimpleSettings.shared.stickerSize != value { SGSimpleSettings.shared.stickerSize = value simplePromise.set(true) } } }, setOneFromManyValue: { setting in let presentationData = context.sharedContext.currentPresentationData.with { $0 } let actionSheet = ActionSheetController(presentationData: presentationData) var items: [ActionSheetItem] = [] switch (setting) { case .downloadSpeedBoost: let setAction: (String) -> Void = { value in SGSimpleSettings.shared.downloadSpeedBoost = value let enableDownloadX: Bool switch (value) { case SGSimpleSettings.DownloadSpeedBoostValues.none.rawValue: enableDownloadX = false default: enableDownloadX = true } // Updating controller simplePromise.set(true) let _ = updateNetworkSettingsInteractively(postbox: context.account.postbox, network: context.account.network, { settings in var settings = settings settings.useExperimentalDownload = enableDownloadX return settings }).start(completed: { Queue.mainQueue().async { askForRestart?() } }) } for value in SGSimpleSettings.DownloadSpeedBoostValues.allCases { items.append(ActionSheetButtonItem(title: i18n("Settings.DownloadsBoost.\(value.rawValue)", presentationData.strings.baseLanguageCode), color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() setAction(value.rawValue) })) } case .bottomTabStyle: let setAction: (String) -> Void = { value in SGSimpleSettings.shared.bottomTabStyle = value simplePromise.set(true) } for value in SGSimpleSettings.BottomTabStyleValues.allCases { items.append(ActionSheetButtonItem(title: i18n("Settings.Folders.BottomTabStyle.\(value.rawValue)", presentationData.strings.baseLanguageCode), color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() setAction(value.rawValue) })) } case .allChatsTitleLengthOverride: let setAction: (String) -> Void = { value in SGSimpleSettings.shared.allChatsTitleLengthOverride = value simplePromise.set(true) } for value in SGSimpleSettings.AllChatsTitleLengthOverride.allCases { let title: String switch (value) { case SGSimpleSettings.AllChatsTitleLengthOverride.short: title = "\"\(presentationData.strings.ChatList_Tabs_All)\"" case SGSimpleSettings.AllChatsTitleLengthOverride.long: title = "\"\(presentationData.strings.ChatList_Tabs_AllChats)\"" default: title = i18n("Settings.Folders.AllChatsTitle.none", presentationData.strings.baseLanguageCode) } items.append(ActionSheetButtonItem(title: title, color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() setAction(value.rawValue) })) } // case .allChatsFolderPositionOverride: // let setAction: (String) -> Void = { value in // SGSimpleSettings.shared.allChatsFolderPositionOverride = value // simplePromise.set(true) // } // // for value in SGSimpleSettings.AllChatsFolderPositionOverride.allCases { // items.append(ActionSheetButtonItem(title: i18n("Settings.Folders.AllChatsTitle.\(value)", presentationData.strings.baseLanguageCode), color: .accent, action: { [weak actionSheet] in // actionSheet?.dismissAnimated() // setAction(value.rawValue) // })) // } case .translationBackend: let setAction: (String) -> Void = { value in SGSimpleSettings.shared.translationBackend = value simplePromise.set(true) } for value in SGSimpleSettings.TranslationBackend.allCases { if value == .system { if #available(iOS 18.0, *) { } else { continue // System translation is not available on iOS 17 and below } } items.append(ActionSheetButtonItem(title: i18n("Settings.Translation.Backend.\(value.rawValue)", presentationData.strings.baseLanguageCode), color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() setAction(value.rawValue) })) } case .transcriptionBackend: let setAction: (String) -> Void = { value in SGSimpleSettings.shared.transcriptionBackend = value simplePromise.set(true) } for value in SGSimpleSettings.TranscriptionBackend.allCases { if #available(iOS 13.0, *) { } else { if value == .apple { continue // Apple recognition is not available on iOS 12 } } items.append(ActionSheetButtonItem(title: i18n("Settings.Transcription.Backend.\(value.rawValue)", presentationData.strings.baseLanguageCode), color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() setAction(value.rawValue) })) } case .nyStyle: let setAction: (String) -> Void = { value in SGSimpleSettings.shared.nyStyle = value simplePromise.set(true) } for value in SGSimpleSettings.NYStyle.allCases { items.append(ActionSheetButtonItem(title: i18n("Settings.NY.Style.\(value.rawValue)", presentationData.strings.baseLanguageCode), color: .accent, action: { [weak actionSheet] in actionSheet?.dismissAnimated() setAction(value.rawValue) })) } } actionSheet.setItemGroups([ActionSheetItemGroup(items: items), ActionSheetItemGroup(items: [ ActionSheetButtonItem(title: presentationData.strings.Common_Cancel, color: .accent, font: .bold, action: { [weak actionSheet] in actionSheet?.dismissAnimated() }) ])]) presentControllerImpl?(actionSheet, ViewControllerPresentationArguments(presentationAnimation: .modalSheet)) }, openDisclosureLink: { link in switch (link) { case .languageSettings: pushControllerImpl?(context.sharedContext.makeLocalizationListController(context: context)) case .contentSettings: let _ = (getSGSettingsURL(context: context) |> deliverOnMainQueue).start(next: { [weak context] url in guard let strongContext = context else { return } strongContext.sharedContext.applicationBindings.openUrl(url) }) } }, action: { actionType in #if canImport(SGDeletedMessages) if let actionString = actionType as? String, actionString == "clearDeletedMessages" { let presentationData = context.sharedContext.currentPresentationData.with { $0 } let alertController = textAlertController( context: context, title: presentationData.strings.baseLanguageCode == "ru" ? "Очистить все сохраненные удаленные сообщения?" : "Clear All Saved Deleted Messages?", text: presentationData.strings.baseLanguageCode == "ru" ? "Это действие удалит все сообщения, которые были помечены как удаленные. Это действие нельзя отменить." : "This action will permanently delete all messages that were marked as deleted. This action cannot be undone.", actions: [ TextAlertAction(type: .destructiveAction, title: presentationData.strings.Common_Delete, action: { let statusController = OverlayStatusController(theme: presentationData.theme, type: .loading(cancelled: nil)) presentControllerImpl?(statusController, nil) let _ = (SGDeletedMessages.clearAllDeletedMessages(postbox: context.account.postbox) |> deliverOnMainQueue).start(completed: { statusController.dismiss() let presentationData = context.sharedContext.currentPresentationData.with { $0 } presentControllerImpl?(OverlayStatusController(theme: presentationData.theme, type: .success), nil) }) }), TextAlertAction(type: .defaultAction, title: presentationData.strings.Common_Cancel, action: {}) ] ) presentControllerImpl?(alertController, nil) } #endif }, searchInput: { searchQuery in updateState { state in var updatedState = state updatedState.searchQuery = searchQuery return updatedState } }) let sharedData = context.sharedContext.accountManager.sharedData(keys: [ApplicationSpecificSharedDataKeys.callListSettings, ApplicationSpecificSharedDataKeys.experimentalUISettings]) let preferences = context.account.postbox.preferencesView(keys: [ApplicationSpecificPreferencesKeys.SGUISettings, PreferencesKeys.appConfiguration]) let updatedContentSettingsConfiguration = contentSettingsConfiguration(network: context.account.network) |> map(Optional.init) let contentSettingsConfiguration = Promise() contentSettingsConfiguration.set(.single(nil) |> then(updatedContentSettingsConfiguration)) let signal = combineLatest(simplePromise.get(), /*sliderPromise.get(),*/ statePromise.get(), context.sharedContext.presentationData, sharedData, preferences, contentSettingsConfiguration.get(), context.engine.accountData.observeAvailableColorOptions(scope: .replies), context.engine.accountData.observeAvailableColorOptions(scope: .profile) ) |> map { _, /*sliderValue,*/ state, presentationData, sharedData, view, contentSettingsConfiguration, availableReplyColors, availableProfileColors -> (ItemListControllerState, (ItemListNodeState, Any)) in let sgUISettings: SGUISettings = view.values[ApplicationSpecificPreferencesKeys.SGUISettings]?.get(SGUISettings.self) ?? SGUISettings.default let appConfiguration: AppConfiguration = view.values[PreferencesKeys.appConfiguration]?.get(AppConfiguration.self) ?? AppConfiguration.defaultValue let callListSettings: CallListSettings = sharedData.entries[ApplicationSpecificSharedDataKeys.callListSettings]?.get(CallListSettings.self) ?? CallListSettings.defaultSettings let experimentalUISettings: ExperimentalUISettings = sharedData.entries[ApplicationSpecificSharedDataKeys.experimentalUISettings]?.get(ExperimentalUISettings.self) ?? ExperimentalUISettings.defaultSettings let entries = SGControllerEntries(presentationData: presentationData, callListSettings: callListSettings, experimentalUISettings: experimentalUISettings, SGSettings: sgUISettings, appConfiguration: appConfiguration, nameColors: PeerNameColors.with(availableReplyColors: availableReplyColors, availableProfileColors: availableProfileColors), state: state) let controllerState = ItemListControllerState(presentationData: ItemListPresentationData(presentationData), title: .text("Swiftgram"), leftNavigationButton: nil, rightNavigationButton: nil, backNavigationButton: ItemListBackButton(title: presentationData.strings.Common_Back)) // TODO(swiftgram): focusOnItemTag support /* var index = 0 var scrollToItem: ListViewScrollToItem? if let focusOnItemTag = focusOnItemTag { for entry in entries { if entry.tag?.isEqual(to: focusOnItemTag) ?? false { scrollToItem = ListViewScrollToItem(index: index, position: .top(0.0), animated: false, curve: .Default(duration: 0.0), directionHint: .Up) } index += 1 } } */ let listState = ItemListNodeState(presentationData: ItemListPresentationData(presentationData), entries: entries, style: .blocks, ensureVisibleItemTag: /*focusOnItemTag*/ nil, initialScrollToItem: nil /* scrollToItem*/ ) return (controllerState, (listState, arguments)) } let controller = ItemListController(context: context, state: signal) presentControllerImpl = { [weak controller] c, a in controller?.present(c, in: .window(.root), with: a) } pushControllerImpl = { [weak controller] c in (controller?.navigationController as? NavigationController)?.pushViewController(c) } // getRootControllerImpl = { [weak controller] in // return controller?.view.window?.rootViewController // } // getNavigationControllerImpl = { [weak controller] in // return controller?.navigationController as? NavigationController // } askForRestart = { [weak context] in guard let context = context else { return } let presentationData = context.sharedContext.currentPresentationData.with { $0 } presentControllerImpl?( UndoOverlayController( presentationData: presentationData, content: .info(title: nil, // i18n("Common.RestartRequired", presentationData.strings.baseLanguageCode), text: i18n("Common.RestartRequired", presentationData.strings.baseLanguageCode), timeout: nil, customUndoText: i18n("Common.RestartNow", presentationData.strings.baseLanguageCode) //presentationData.strings.Common_Yes ), elevatedLayout: false, action: { action in if action == .undo { exit(0) }; return true } ), nil ) } return controller }