From d57abfcc93a787fc52e6e332cc01ee9bb573d4ef Mon Sep 17 00:00:00 2001 From: Arturs Krumins Date: Wed, 16 Oct 2024 21:48:13 +0300 Subject: [PATCH] ios: fix theme import file picker (#5048) * ios: fix theme import file picker * minor --- .../Views/Helpers/ThemeModeEditor.swift | 64 +++++++------- .../UserSettings/AppearanceSettings.swift | 84 +++++++++++-------- 2 files changed, 83 insertions(+), 65 deletions(-) diff --git a/apps/ios/Shared/Views/Helpers/ThemeModeEditor.swift b/apps/ios/Shared/Views/Helpers/ThemeModeEditor.swift index ae94b4685c..9d5ae2e289 100644 --- a/apps/ios/Shared/Views/Helpers/ThemeModeEditor.swift +++ b/apps/ios/Shared/Views/Helpers/ThemeModeEditor.swift @@ -16,6 +16,7 @@ struct UserWallpaperEditor: View { @State var themeModeOverride: ThemeModeOverride @State var applyToMode: DefaultThemeMode? @State var showMore: Bool = false + @State var showFileImporter: Bool = false @Binding var globalThemeUsed: Bool var save: (DefaultThemeMode?, ThemeModeOverride?) async -> Void @@ -125,24 +126,27 @@ struct UserWallpaperEditor: View { CustomizeThemeColorsSection(editColor: { name in editColor(name, theme) }) - ImportExportThemeSection(perChat: nil, perUser: ChatModel.shared.currentUser?.uiThemes) { imported in - let importedFromString = imported.wallpaper?.importFromString() - let importedType = importedFromString?.toAppWallpaper().type - let currentTheme = ThemeManager.currentColors(nil, nil, nil, themeOverridesDefault.get()) - let type: WallpaperType? = if importedType?.sameType(currentTheme.wallpaper.type) == true { nil } else { importedType } - let colors = ThemeManager.currentThemeOverridesForExport(type, nil, nil).colors - let res = ThemeModeOverride(mode: imported.base.mode, colors: imported.colors, wallpaper: importedFromString).removeSameColors(imported.base, colorsToCompare: colors) - Task { - await MainActor.run { - themeModeOverride = res - } - await save(applyToMode, res) - } - } + ImportExportThemeSection(showFileImporter: $showFileImporter, perChat: nil, perUser: ChatModel.shared.currentUser?.uiThemes) } else { AdvancedSettingsButton(theme.colors.primary) { showMore = true } } } + .modifier( + ThemeImporter(isPresented: $showFileImporter) { imported in + let importedFromString = imported.wallpaper?.importFromString() + let importedType = importedFromString?.toAppWallpaper().type + let currentTheme = ThemeManager.currentColors(nil, nil, nil, themeOverridesDefault.get()) + let type: WallpaperType? = if importedType?.sameType(currentTheme.wallpaper.type) == true { nil } else { importedType } + let colors = ThemeManager.currentThemeOverridesForExport(type, nil, nil).colors + let res = ThemeModeOverride(mode: imported.base.mode, colors: imported.colors, wallpaper: importedFromString).removeSameColors(imported.base, colorsToCompare: colors) + Task { + await MainActor.run { + themeModeOverride = res + } + await save(applyToMode, res) + } + } + ) } private func onTypeCopyFromSameTheme(_ type: WallpaperType?) -> Bool { @@ -216,6 +220,7 @@ struct ChatWallpaperEditor: View { @State var themeModeOverride: ThemeModeOverride @State var applyToMode: DefaultThemeMode? @State var showMore: Bool = false + @State var showFileImporter: Bool = false @Binding var globalThemeUsed: Bool var save: (DefaultThemeMode?, ThemeModeOverride?) async -> Void @@ -328,24 +333,27 @@ struct ChatWallpaperEditor: View { CustomizeThemeColorsSection(editColor: editColor) - ImportExportThemeSection(perChat: themeModeOverride, perUser: ChatModel.shared.currentUser?.uiThemes) { imported in - let importedFromString = imported.wallpaper?.importFromString() - let importedType = importedFromString?.toAppWallpaper().type - let currentTheme = ThemeManager.currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get()) - let type: WallpaperType? = if importedType?.sameType(currentTheme.wallpaper.type) == true { nil } else { importedType } - let colors = ThemeManager.currentThemeOverridesForExport(type, nil, ChatModel.shared.currentUser?.uiThemes).colors - let res = ThemeModeOverride(mode: imported.base.mode, colors: imported.colors, wallpaper: importedFromString).removeSameColors(imported.base, colorsToCompare: colors) - Task { - await MainActor.run { - themeModeOverride = res - } - await save(applyToMode, res) - } - } + ImportExportThemeSection(showFileImporter: $showFileImporter, perChat: themeModeOverride, perUser: ChatModel.shared.currentUser?.uiThemes) } else { AdvancedSettingsButton(theme.colors.primary) { showMore = true } } } + .modifier( + ThemeImporter(isPresented: $showFileImporter) { imported in + let importedFromString = imported.wallpaper?.importFromString() + let importedType = importedFromString?.toAppWallpaper().type + let currentTheme = ThemeManager.currentColors(nil, nil, ChatModel.shared.currentUser?.uiThemes, themeOverridesDefault.get()) + let type: WallpaperType? = if importedType?.sameType(currentTheme.wallpaper.type) == true { nil } else { importedType } + let colors = ThemeManager.currentThemeOverridesForExport(type, nil, ChatModel.shared.currentUser?.uiThemes).colors + let res = ThemeModeOverride(mode: imported.base.mode, colors: imported.colors, wallpaper: importedFromString).removeSameColors(imported.base, colorsToCompare: colors) + Task { + await MainActor.run { + themeModeOverride = res + } + await save(applyToMode, res) + } + } + ) } private func onTypeCopyFromSameTheme(_ type: WallpaperType?) -> Bool { diff --git a/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift b/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift index 50f0a3a7b6..4c61d592ac 100644 --- a/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift +++ b/apps/ios/Shared/Views/UserSettings/AppearanceSettings.swift @@ -583,11 +583,14 @@ struct CustomizeThemeView: View { } } - ImportExportThemeSection(perChat: nil, perUser: nil, save: { theme in + ImportExportThemeSection(showFileImporter: $showFileImporter, perChat: nil, perUser: nil) + } + .modifier( + ThemeImporter(isPresented: $showFileImporter) { theme in ThemeManager.saveAndApplyThemeOverrides(theme) saveThemeToDatabase(nil) - }) - } + } + ) /// When changing app theme, user overrides are hidden. User overrides will be returned back after closing Appearance screen, see ThemeDestinationPicker() .interactiveDismissDisabled(true) } @@ -595,10 +598,9 @@ struct CustomizeThemeView: View { struct ImportExportThemeSection: View { @EnvironmentObject var theme: AppTheme + @Binding var showFileImporter: Bool var perChat: ThemeModeOverride? var perUser: ThemeModeOverrides? - var save: (ThemeOverrides) -> Void - @State private var showFileImporter = false var body: some View { Section { @@ -626,39 +628,47 @@ struct ImportExportThemeSection: View { } label: { Text("Import theme").foregroundColor(theme.colors.primary) } - .fileImporter( - isPresented: $showFileImporter, - allowedContentTypes: [.data/*.plainText*/], - allowsMultipleSelection: false - ) { result in - if case let .success(files) = result, let fileURL = files.first { - do { - var fileSize: Int? = nil - if fileURL.startAccessingSecurityScopedResource() { - let resourceValues = try fileURL.resourceValues(forKeys: [.fileSizeKey]) - fileSize = resourceValues.fileSize - } - if let fileSize = fileSize, - // Same as Android/desktop - fileSize <= 5_500_000 { - if let string = try? String(contentsOf: fileURL, encoding: .utf8), let theme: ThemeOverrides = decodeYAML("themeId: \(UUID().uuidString)\n" + string) { - save(theme) - logger.error("Saved theme from file") - } else { - logger.error("Error decoding theme file") - } - fileURL.stopAccessingSecurityScopedResource() - } else { - fileURL.stopAccessingSecurityScopedResource() - let prettyMaxFileSize = ByteCountFormatter.string(fromByteCount: 5_500_000, countStyle: .binary) - AlertManager.shared.showAlertMsg( - title: "Large file!", - message: "Currently maximum supported file size is \(prettyMaxFileSize)." - ) - } - } catch { - logger.error("Appearance fileImporter error \(error.localizedDescription)") + } + } +} + +struct ThemeImporter: ViewModifier { + @Binding var isPresented: Bool + var save: (ThemeOverrides) -> Void + + func body(content: Content) -> some View { + content.fileImporter( + isPresented: $isPresented, + allowedContentTypes: [.data/*.plainText*/], + allowsMultipleSelection: false + ) { result in + if case let .success(files) = result, let fileURL = files.first { + do { + var fileSize: Int? = nil + if fileURL.startAccessingSecurityScopedResource() { + let resourceValues = try fileURL.resourceValues(forKeys: [.fileSizeKey]) + fileSize = resourceValues.fileSize } + if let fileSize = fileSize, + // Same as Android/desktop + fileSize <= 5_500_000 { + if let string = try? String(contentsOf: fileURL, encoding: .utf8), let theme: ThemeOverrides = decodeYAML("themeId: \(UUID().uuidString)\n" + string) { + save(theme) + logger.error("Saved theme from file") + } else { + logger.error("Error decoding theme file") + } + fileURL.stopAccessingSecurityScopedResource() + } else { + fileURL.stopAccessingSecurityScopedResource() + let prettyMaxFileSize = ByteCountFormatter.string(fromByteCount: 5_500_000, countStyle: .binary) + AlertManager.shared.showAlertMsg( + title: "Large file!", + message: "Currently maximum supported file size is \(prettyMaxFileSize)." + ) + } + } catch { + logger.error("Appearance fileImporter error \(error.localizedDescription)") } } }