mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00

* Implement Settings->General->"Ask Before" and add "Ask Before Posting Without Alt Text" IOS-166 * Implement Alt Missing Alert for Status Edits (IOS-166) * Fix status edit composes duplicate message * Show (or don't) the "Really delete post?" Alert based on the User's preference (IOS-166) * Implement alert for boost/unboost (IOS-166) * Begin implementing "Default Post Language"-Setting (IOS-166) * Show "Unfollow @user?" Alert (IOS-166) * Merge conflict fixes for IOS-166 * Implement default post language setting (IOS-166) * Fix follow button state not updated correctly (IOS-166) * Add PR feedback (IOS-166) * Improve default language cell style (IOS-166) * Fix language filter broken (IOS-166)
115 lines
4.5 KiB
Swift
115 lines
4.5 KiB
Swift
// 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) {
|
||
// don’t 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 })
|
||
}
|
||
}
|