mastodon-ios/MastodonSDK/Sources/MastodonUI/Scene/ComposeContent/Toolbar/LanguagePicker.swift

115 lines
4.5 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import MastodonLocalization
import SwiftUI
import MastodonAsset
public typealias OnLanguageSelected = (String) -> Void
struct LanguagePickerNavigationView: View {
public init(selectedLanguage: String, onSelect: @escaping OnLanguageSelected) {
self._selectedLanguage = State(initialValue: selectedLanguage)
self.onSelect = onSelect
}
@Environment(\.dismiss) private var dismiss
@State private var selectedLanguage: String
private let onSelect: OnLanguageSelected
var body: some View {
NavigationView {
LanguagePicker(selectedLanguage: selectedLanguage) { onSelect($0) }
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button(L10n.Common.Controls.Actions.cancel) {
dismiss()
}
}
}
.navigationTitle(L10n.Scene.Compose.Language.title)
.navigationBarTitleDisplayMode(.inline)
}.navigationViewStyle(.stack)
}
}
public struct LanguagePicker: View {
public init(selectedLanguage: String, onSelect: @escaping OnLanguageSelected) {
self._selectedLanguage = State(initialValue: selectedLanguage)
self.onSelect = onSelect
}
@State private var selectedLanguage: String
private let onSelect: OnLanguageSelected
@Environment(\.dynamicTypeSize) private var dynamicTypeSize
@State private var query = ""
@State private var languages: [Language] = availableLanguages()
public static func availableLanguages() -> [Language] {
let locales = Locale.availableIdentifiers.map(Locale.init(identifier:))
var languages: [String: Language] = [:]
for locale in locales {
if let code = locale.language.languageCode?.identifier,
let endonym = locale.localizedString(forLanguageCode: code),
let exonym = Locale.current.localizedString(forLanguageCode: code) {
// dont overwrite the base language
if let lang = languages[code], !(lang.localeId ?? "").contains("_") { continue }
languages[code] = Language(endonym: endonym, exonym: exonym, id: code, localeId: locale.identifier)
}
}
return languages.values.sorted(using: KeyPathComparator(\.id))
}
public var body: some View {
ScrollViewReader { proxy in
let filteredLanguages = query.isEmpty ? languages : languages.filter { $0.contains(query) }
List(filteredLanguages) { lang in
let endonym = Text(lang.endonym)
let exonym: Text = {
if lang.exonymIsDifferent {
return Text("(\(lang.exonym))").foregroundColor(.secondary)
}
return Text("")
}()
Button(action: {
selectedLanguage = lang.id
onSelect(lang.id)
}) {
HStack {
ViewThatFits(in: .horizontal) {
HStack(spacing: 0) { endonym; Text(" "); exonym }
VStack(alignment: .leading) { endonym; exonym }
}
if lang.id == selectedLanguage {
Spacer()
Image(systemName: "checkmark")
.foregroundStyle(Asset.Colors.Brand.blurple.swiftUIColor)
}
}
}
.tint(.primary)
.accessibilityLabel(Text(lang.label))
.id(lang.id)
}
.listStyle(.plain)
.searchable(text: $query, placement: .navigationBarDrawer(displayMode: .always))
.onAppear {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(200)) { // when scrolling to quickly it'll overlap with other drawcycles and mess up the position :-(
if let selectedIndex = filteredLanguages.first(where: { $0.id == selectedLanguage }) {
proxy.scrollTo(selectedIndex.id, anchor: .center)
}
}
}
}
}
}
struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
LanguagePicker(selectedLanguage: "en", onSelect: { _ in })
}
}