224 lines
11 KiB
Swift
224 lines
11 KiB
Swift
//
|
|
// TextFormattingSettings.swift
|
|
// damus
|
|
//
|
|
// Created by William Casarin on 2023-04-05.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
struct ResizedEventPreview: View {
|
|
let damus_state: DamusState
|
|
@ObservedObject var settings: UserSettingsStore
|
|
|
|
var body: some View {
|
|
EventView(damus: damus_state, event: test_note, pubkey: test_note.pubkey, options: [.wide, .no_action_bar])
|
|
}
|
|
}
|
|
|
|
/// Preview component showing sample text with the current line height setting applied
|
|
struct LineHeightPreview: View {
|
|
let lineHeight: Double
|
|
let sepiaEnabled: Bool
|
|
@Environment(\.colorScheme) var colorScheme
|
|
|
|
private let sampleText = NSLocalizedString(
|
|
"The quick brown fox jumps over the lazy dog. This preview shows how your line spacing will appear in longform articles.",
|
|
comment: "Sample text for line height preview in settings"
|
|
)
|
|
|
|
var body: some View {
|
|
let font = Font.body
|
|
// Use Dynamic Type: get actual body font size from system preferences
|
|
let baseFontSize = UIFont.preferredFont(forTextStyle: .body).pointSize
|
|
let spacing = baseFontSize * (lineHeight - 1.0)
|
|
|
|
Text(sampleText)
|
|
.font(font)
|
|
.lineSpacing(spacing)
|
|
.padding()
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.background(sepiaEnabled ? DamusColors.sepiaBackground(for: colorScheme) : Color(UIColor.secondarySystemBackground))
|
|
.foregroundStyle(sepiaEnabled ? DamusColors.sepiaText(for: colorScheme) : Color.primary)
|
|
.cornerRadius(8)
|
|
.padding(.top, 8)
|
|
}
|
|
}
|
|
|
|
struct AppearanceSettingsView: View {
|
|
let damus_state: DamusState
|
|
@ObservedObject var settings: UserSettingsStore
|
|
@Environment(\.dismiss) var dismiss
|
|
|
|
@State var showing_enable_animation_alert: Bool = false
|
|
@State var enable_animation_toggle_is_user_initiated: Bool = true
|
|
|
|
var max_hashtags_binding: Binding<Double> {
|
|
Binding<Double>(get: {
|
|
return Double(settings.max_hashtags)
|
|
}, set: {
|
|
settings.max_hashtags = Int($0)
|
|
})
|
|
}
|
|
|
|
var FontSize: some View {
|
|
VStack(alignment: .leading) {
|
|
Slider(value: $settings.font_size, in: 0.5...2.0, step: 0.1)
|
|
.padding()
|
|
|
|
// Sample text to show how the font size would look
|
|
ResizedEventPreview(damus_state: damus_state, settings: settings)
|
|
|
|
}
|
|
}
|
|
|
|
var body: some View {
|
|
Form {
|
|
Section(NSLocalizedString("Font Size", comment: "Section label for font size settings.")) {
|
|
FontSize
|
|
}
|
|
|
|
// MARK: - Reading
|
|
Section(header: Text("Reading", comment: "Section header for reading appearance settings")) {
|
|
Toggle(NSLocalizedString("Sepia mode for longform articles", comment: "Setting to enable sepia reading mode for longform articles"), isOn: $settings.longform_sepia_mode)
|
|
.toggleStyle(.switch)
|
|
|
|
VStack(alignment: .leading) {
|
|
Text(verbatim: "\(String(format: NSLocalizedString("Line height: %.1fx", comment: "Label showing current line height multiplier setting"), settings.longform_line_height))")
|
|
Slider(value: $settings.longform_line_height, in: 1.2...1.8, step: 0.1)
|
|
|
|
// Preview of line height
|
|
LineHeightPreview(lineHeight: settings.longform_line_height, sepiaEnabled: settings.longform_sepia_mode)
|
|
}
|
|
}
|
|
|
|
// MARK: - Text Truncation
|
|
Section(header: Text("Text Truncation", comment: "Section header for damus text truncation user configuration")) {
|
|
Toggle(NSLocalizedString("Truncate timeline text", comment: "Setting to truncate text in timeline"), isOn: $settings.truncate_timeline_text)
|
|
.toggleStyle(.switch)
|
|
Toggle(NSLocalizedString("Truncate notification mention text", comment: "Setting to truncate text in mention notifications"), isOn: $settings.truncate_mention_text)
|
|
.toggleStyle(.switch)
|
|
}
|
|
|
|
Section(header: Text("User Statuses", comment: "Section header for user profile status settings.")) {
|
|
Toggle(NSLocalizedString("Show general statuses", comment: "Settings toggle for enabling general user statuses"), isOn: $settings.show_general_statuses)
|
|
.toggleStyle(.switch)
|
|
|
|
Toggle(NSLocalizedString("Show music statuses", comment: "Settings toggle for enabling now playing music statuses"), isOn: $settings.show_music_statuses)
|
|
.toggleStyle(.switch)
|
|
}
|
|
|
|
// MARK: - Accessibility
|
|
Section(header: Text("Accessibility", comment: "Section header for accessibility settings")) {
|
|
Toggle(NSLocalizedString("Left Handed", comment: "Moves the post button to the left side of the screen"), isOn: $settings.left_handed)
|
|
.toggleStyle(.switch)
|
|
}
|
|
|
|
// MARK: - Images
|
|
Section(NSLocalizedString("Images", comment: "Section title for images configuration.")) {
|
|
self.EnableAnimationsToggle
|
|
Toggle(NSLocalizedString("Blur images", comment: "Setting to blur images"), isOn: $settings.blur_images)
|
|
.toggleStyle(.switch)
|
|
|
|
Toggle(NSLocalizedString("Media previews", comment: "Setting to show media"), isOn: $settings.media_previews)
|
|
.toggleStyle(.switch)
|
|
|
|
Picker(NSLocalizedString("Image uploader", comment: "Prompt selection of user's image uploader"),
|
|
selection: $settings.default_media_uploader) {
|
|
ForEach(MediaUploader.allCases, id: \.self) { uploader in
|
|
Text(uploader.model.displayName)
|
|
.tag(uploader.model.tag)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - GIFs
|
|
if damus_state.settings.enable_gifs_feature {
|
|
Section(NSLocalizedString("GIFs", comment: "Section title for GIFs configuration.")) {
|
|
SecureField(NSLocalizedString("Tenor API Key (optional)", comment: "Prompt for optional entry of API Key to use with Tenor."), text: $settings.tenor_api_key)
|
|
.disableAutocorrection(true)
|
|
.autocapitalization(UITextAutocapitalizationType.none)
|
|
}
|
|
}
|
|
|
|
// MARK: - Content filters and moderation
|
|
Section(
|
|
header: Text("Content filters", comment: "Section title for content filtering/moderation configuration."),
|
|
footer: Text("Notes with the #nsfw tag usually contains adult content or other \"Not safe for work\" content", comment: "Section footer clarifying what #nsfw (not safe for work) tags mean")
|
|
) {
|
|
Toggle(NSLocalizedString("Show replies from your trusted network first", comment: "Setting to show replies in threads from the current user's trusted network first."), isOn: $settings.show_trusted_replies_first)
|
|
.toggleStyle(.switch)
|
|
Toggle(NSLocalizedString("Hide notes with #nsfw tags", comment: "Setting to hide notes with the #nsfw (not safe for work) tags"), isOn: $settings.hide_nsfw_tagged_content)
|
|
.toggleStyle(.switch)
|
|
Toggle(NSLocalizedString("Hide posts with too many hashtags", comment: "Setting to hide notes that contain too many hashtags (spam)"), isOn: $settings.hide_hashtag_spam)
|
|
.toggleStyle(.switch)
|
|
if settings.hide_hashtag_spam {
|
|
VStack(alignment: .leading) {
|
|
Text("\(String(format: NSLocalizedString("Maximum hashtags: %d", comment: "Label showing the maximum number of hashtags allowed before a post is hidden"), settings.max_hashtags))")
|
|
Slider(value: max_hashtags_binding, in: 1...20, step: 1)
|
|
}
|
|
}
|
|
}
|
|
|
|
Section(header: Text("Privacy", comment: "Section header for privacy related settings")) {
|
|
Toggle(NSLocalizedString("Share Damus client tag", comment: "Setting to publish a client tag indicating Damus posted the note"), isOn: $settings.publish_client_tag)
|
|
.toggleStyle(.switch)
|
|
Text("Client tags can help other apps understand new kinds of events. Turn this off if you prefer not to identify Damus when posting.", comment: "Description for the client tag privacy toggle.")
|
|
.font(.footnote)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
|
|
// MARK: - Profiles
|
|
Section(
|
|
header: Text("Profiles", comment: "Section title for profile view configuration."),
|
|
footer: Text("Profile action sheets allow you to follow, zap, or DM profiles more quickly without having to view their full profile", comment: "Section footer clarifying what the profile action sheet feature does")
|
|
.padding(.bottom, tabHeight + getSafeAreaBottom())
|
|
) {
|
|
Toggle(NSLocalizedString("Show profile action sheets", comment: "Setting to show profile action sheets when clicking on a user's profile picture"), isOn: $settings.show_profile_action_sheet_on_pfp_click)
|
|
.toggleStyle(.switch)
|
|
}
|
|
|
|
|
|
}
|
|
.navigationTitle(NSLocalizedString("Appearance", comment: "Navigation title for text and appearance settings."))
|
|
.onReceive(handle_notify(.switched_timeline)) { _ in
|
|
dismiss()
|
|
}
|
|
}
|
|
|
|
var EnableAnimationsToggle: some View {
|
|
Toggle(NSLocalizedString("Animations", comment: "Toggle to enable or disable image animation"), isOn: $settings.enable_animation)
|
|
.toggleStyle(.switch)
|
|
.onChange(of: settings.enable_animation) { _ in
|
|
if self.enable_animation_toggle_is_user_initiated {
|
|
self.showing_enable_animation_alert = true
|
|
}
|
|
else {
|
|
self.enable_animation_toggle_is_user_initiated = true
|
|
}
|
|
}
|
|
.alert(isPresented: $showing_enable_animation_alert) {
|
|
Alert(title: Text("Confirmation", comment: "Confirmation dialog title"),
|
|
message: Text("Changing this setting will cause the cache to be cleared. This will free space, but images may take longer to load again. Are you sure you want to proceed?", comment: "Message explaining consequences of changing the 'enable animation' setting"),
|
|
primaryButton: .default(Text("OK", comment: "Button label indicating user wants to proceed.")) {
|
|
Task.detached(priority: .utility, operation: {
|
|
await DamusCacheManager.shared.clear_cache(damus_state: self.damus_state, completion: {})
|
|
})
|
|
},
|
|
secondaryButton: .cancel() {
|
|
// Toggle back if user cancels action
|
|
self.enable_animation_toggle_is_user_initiated = false
|
|
settings.enable_animation.toggle()
|
|
}
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
struct TextFormattingSettings_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
AppearanceSettingsView(damus_state: test_damus_state, settings: UserSettingsStore())
|
|
}
|
|
}
|