forked from shadowfacts/Tusker
More preferences reorganizing
This commit is contained in:
parent
c7a56a9f61
commit
4665df228d
|
@ -169,7 +169,6 @@
|
||||||
D67C57AD21E265FC00C3118B /* LargeAccountDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57AC21E265FC00C3118B /* LargeAccountDetailView.swift */; };
|
D67C57AD21E265FC00C3118B /* LargeAccountDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57AC21E265FC00C3118B /* LargeAccountDetailView.swift */; };
|
||||||
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */; };
|
D67C57AF21E28EAD00C3118B /* Array+Uniques.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */; };
|
||||||
D68015402401A6BA00D6103B /* ComposingPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */; };
|
D68015402401A6BA00D6103B /* ComposingPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */; };
|
||||||
D68015422401A74600D6103B /* MediaPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68015412401A74600D6103B /* MediaPrefsView.swift */; };
|
|
||||||
D681E4D7246E32290053414F /* StatusActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D6246E32290053414F /* StatusActivityItemSource.swift */; };
|
D681E4D7246E32290053414F /* StatusActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D6246E32290053414F /* StatusActivityItemSource.swift */; };
|
||||||
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */; };
|
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */; };
|
||||||
D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */; };
|
D68232F72464F4FD00325FB8 /* ComposeDrawingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */; };
|
||||||
|
@ -592,7 +591,6 @@
|
||||||
D67C57AC21E265FC00C3118B /* LargeAccountDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeAccountDetailView.swift; sourceTree = "<group>"; };
|
D67C57AC21E265FC00C3118B /* LargeAccountDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeAccountDetailView.swift; sourceTree = "<group>"; };
|
||||||
D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Uniques.swift"; sourceTree = "<group>"; };
|
D67C57AE21E28EAD00C3118B /* Array+Uniques.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Uniques.swift"; sourceTree = "<group>"; };
|
||||||
D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposingPrefsView.swift; sourceTree = "<group>"; };
|
D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposingPrefsView.swift; sourceTree = "<group>"; };
|
||||||
D68015412401A74600D6103B /* MediaPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPrefsView.swift; sourceTree = "<group>"; };
|
|
||||||
D681E4D6246E32290053414F /* StatusActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityItemSource.swift; sourceTree = "<group>"; };
|
D681E4D6246E32290053414F /* StatusActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityItemSource.swift; sourceTree = "<group>"; };
|
||||||
D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountActivityItemSource.swift; sourceTree = "<group>"; };
|
D681E4D8246E346E0053414F /* AccountActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountActivityItemSource.swift; sourceTree = "<group>"; };
|
||||||
D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeDrawingViewController.swift; sourceTree = "<group>"; };
|
D68232F62464F4FD00325FB8 /* ComposeDrawingViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeDrawingViewController.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1172,12 +1170,9 @@
|
||||||
D63661BF2381C144004B9E16 /* PreferencesNavigationController.swift */,
|
D63661BF2381C144004B9E16 /* PreferencesNavigationController.swift */,
|
||||||
04586B4022B2FFB10021BD04 /* PreferencesView.swift */,
|
04586B4022B2FFB10021BD04 /* PreferencesView.swift */,
|
||||||
D64B96802BC3279D002C8990 /* PrefsAccountView.swift */,
|
D64B96802BC3279D002C8990 /* PrefsAccountView.swift */,
|
||||||
D61F75892932E1FC00C0B37F /* SwipeActionsPrefsView.swift */,
|
|
||||||
D6958F3C2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift */,
|
|
||||||
0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */,
|
0427033722B30F5F000D31B6 /* BehaviorPrefsView.swift */,
|
||||||
D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */,
|
D6B17254254F88B800128392 /* OppositeCollapseKeywordsView.swift */,
|
||||||
D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */,
|
D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */,
|
||||||
D68015412401A74600D6103B /* MediaPrefsView.swift */,
|
|
||||||
D6BC9DB2232D4C07002CA326 /* WellnessPrefsView.swift */,
|
D6BC9DB2232D4C07002CA326 /* WellnessPrefsView.swift */,
|
||||||
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */,
|
0427033922B31269000D31B6 /* AdvancedPrefsView.swift */,
|
||||||
D67895BF246870DE00D4CD9E /* LocalAccountAvatarView.swift */,
|
D67895BF246870DE00D4CD9E /* LocalAccountAvatarView.swift */,
|
||||||
|
@ -1492,6 +1487,8 @@
|
||||||
children = (
|
children = (
|
||||||
D6C4532C2BCB86AC00E26A0E /* AppearancePrefsView.swift */,
|
D6C4532C2BCB86AC00E26A0E /* AppearancePrefsView.swift */,
|
||||||
D6C4532E2BCB873400E26A0E /* MockStatusView.swift */,
|
D6C4532E2BCB873400E26A0E /* MockStatusView.swift */,
|
||||||
|
D6958F3C2AA383D90062FE52 /* WidescreenNavigationPrefsView.swift */,
|
||||||
|
D61F75892932E1FC00C0B37F /* SwipeActionsPrefsView.swift */,
|
||||||
);
|
);
|
||||||
path = Appearance;
|
path = Appearance;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -2348,7 +2345,6 @@
|
||||||
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */,
|
D61AC1D5232E9FA600C54D2D /* InstanceSelectorTableViewController.swift in Sources */,
|
||||||
D6CF5B892AC9BA6E00F15D83 /* MastodonSearchController.swift in Sources */,
|
D6CF5B892AC9BA6E00F15D83 /* MastodonSearchController.swift in Sources */,
|
||||||
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */,
|
D681E4D9246E346E0053414F /* AccountActivityItemSource.swift in Sources */,
|
||||||
D68015422401A74600D6103B /* MediaPrefsView.swift in Sources */,
|
|
||||||
D6093F9B25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift in Sources */,
|
D6093F9B25BDD4B9004811E6 /* HashtagSearchResultsViewController.swift in Sources */,
|
||||||
D6E77D09286D25FA00D8B732 /* TrendingHashtagCollectionViewCell.swift in Sources */,
|
D6E77D09286D25FA00D8B732 /* TrendingHashtagCollectionViewCell.swift in Sources */,
|
||||||
D6D79F292A0D596B00AB2315 /* StatusEditHistoryViewController.swift in Sources */,
|
D6D79F292A0D596B00AB2315 /* StatusEditHistoryViewController.swift in Sources */,
|
||||||
|
|
|
@ -7,18 +7,49 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import Combine
|
||||||
import TuskerPreferences
|
import TuskerPreferences
|
||||||
|
|
||||||
struct AppearancePrefsView: View {
|
struct AppearancePrefsView: View {
|
||||||
@ObservedObject private var preferences = Preferences.shared
|
@ObservedObject private var preferences = Preferences.shared
|
||||||
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
|
||||||
|
private var appearanceChangePublisher: some Publisher<Void, Never> {
|
||||||
|
preferences.$theme
|
||||||
|
.map { _ in () }
|
||||||
|
.merge(with: preferences.$pureBlackDarkMode.map { _ in () },
|
||||||
|
preferences.$accentColor.map { _ in () }
|
||||||
|
)
|
||||||
|
// the prefrence publishers are all willSet, but want to notify after the change, so wait one runloop iteration
|
||||||
|
.receive(on: DispatchQueue.main)
|
||||||
|
}
|
||||||
|
|
||||||
|
private static let accentColorsAndImages: [(AccentColor, UIImage?)] = AccentColor.allCases.map { color in
|
||||||
|
var image: UIImage?
|
||||||
|
if let color = color.color {
|
||||||
|
if #available(iOS 16.0, *) {
|
||||||
|
image = UIImage(systemName: "circle.fill")!.withTintColor(color, renderingMode: .alwaysTemplate).withRenderingMode(.alwaysOriginal)
|
||||||
|
} else {
|
||||||
|
image = UIGraphicsImageRenderer(size: CGSize(width: 20, height: 20)).image { context in
|
||||||
|
color.setFill()
|
||||||
|
context.cgContext.fillEllipse(in: CGRect(x: 0, y: 0, width: 20, height: 20))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (color, image)
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
Section {
|
themeSection
|
||||||
|
interfaceSection
|
||||||
|
|
||||||
|
Section("Post Preview") {
|
||||||
MockStatusView()
|
MockStatusView()
|
||||||
.padding(.top, 8)
|
.padding(.top, 8)
|
||||||
|
.padding(.horizontal, UIDevice.current.userInterfaceIdiom == .pad ? 8 : 4)
|
||||||
}
|
}
|
||||||
.appGroupedListRowBackground()
|
.listRowBackground(preferences.pureBlackDarkMode ? colorScheme == .dark ? Color.black : Color.white : Color.appBackground)
|
||||||
|
|
||||||
accountsSection
|
accountsSection
|
||||||
postsSection
|
postsSection
|
||||||
|
@ -29,6 +60,53 @@ struct AppearancePrefsView: View {
|
||||||
.navigationTitle("Appearance")
|
.navigationTitle("Appearance")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var themeSection: some View {
|
||||||
|
Section {
|
||||||
|
#if !os(visionOS)
|
||||||
|
Picker(selection: $preferences.theme, label: Text("Theme")) {
|
||||||
|
Text("Use System Theme").tag(Theme.unspecified)
|
||||||
|
Text("Light").tag(Theme.light)
|
||||||
|
Text("Dark").tag(Theme.dark)
|
||||||
|
}
|
||||||
|
|
||||||
|
// macOS system dark mode isn't pure black, so this isn't necessary
|
||||||
|
if !ProcessInfo.processInfo.isMacCatalystApp && !ProcessInfo.processInfo.isiOSAppOnMac {
|
||||||
|
Toggle(isOn: $preferences.pureBlackDarkMode) {
|
||||||
|
Text("Pure Black Dark Mode")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Picker(selection: $preferences.accentColor, label: Text("Accent Color")) {
|
||||||
|
ForEach(Self.accentColorsAndImages, id: \.0.rawValue) { (color, image) in
|
||||||
|
HStack {
|
||||||
|
Text(color.name)
|
||||||
|
if let image {
|
||||||
|
Spacer()
|
||||||
|
Image(uiImage: image)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tag(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onReceive(appearanceChangePublisher) { _ in
|
||||||
|
NotificationCenter.default.post(name: .themePreferenceChanged, object: nil)
|
||||||
|
}
|
||||||
|
.appGroupedListRowBackground()
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var interfaceSection: some View {
|
||||||
|
let visionIdiom = UIUserInterfaceIdiom(rawValue: 6)
|
||||||
|
if [visionIdiom, .pad, .mac].contains(UIDevice.current.userInterfaceIdiom) {
|
||||||
|
Section(header: Text("Interface")) {
|
||||||
|
WidescreenNavigationPrefsView()
|
||||||
|
}
|
||||||
|
.appGroupedListRowBackground()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var accountsSection: some View {
|
private var accountsSection: some View {
|
||||||
Section("Accounts") {
|
Section("Accounts") {
|
||||||
Toggle(isOn: Binding(get: {
|
Toggle(isOn: Binding(get: {
|
||||||
|
@ -65,15 +143,16 @@ struct AppearancePrefsView: View {
|
||||||
Toggle(isOn: $preferences.underlineTextLinks) {
|
Toggle(isOn: $preferences.underlineTextLinks) {
|
||||||
Text("Underline Links")
|
Text("Underline Links")
|
||||||
}
|
}
|
||||||
// NavigationLink("Leading Swipe Actions") {
|
NavigationLink("Leading Swipe Actions") {
|
||||||
// SwipeActionsPrefsView(selection: $preferences.leadingStatusSwipeActions)
|
SwipeActionsPrefsView(selection: $preferences.leadingStatusSwipeActions)
|
||||||
// .edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
// .navigationTitle("Leading Swipe Actions")
|
.navigationTitle("Leading Swipe Actions")
|
||||||
// }
|
}
|
||||||
// NavigationLink("Trailing Swipe Actions") {
|
NavigationLink("Trailing Swipe Actions") {
|
||||||
// SwipeActionsPrefsView(selection: $preferences.trailingStatusSwipeActions)
|
SwipeActionsPrefsView(selection: $preferences.trailingStatusSwipeActions)
|
||||||
// .edgesIgnoringSafeArea(.all)
|
.edgesIgnoringSafeArea(.all)
|
||||||
// .navigationTitle("Trailing Swipe Actions")
|
.navigationTitle("Trailing Swipe Actions")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.appGroupedListRowBackground()
|
.appGroupedListRowBackground()
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ private actor MockAttachmentsGenerator {
|
||||||
return attachmentURLs
|
return attachmentURLs
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = CGSize(width: 100, height: 100)
|
let size = CGSize(width: 200, height: 200)
|
||||||
let bounds = CGRect(origin: .zero, size: size)
|
let bounds = CGRect(origin: .zero, size: size)
|
||||||
let format = UIGraphicsImageRendererFormat()
|
let format = UIGraphicsImageRendererFormat()
|
||||||
format.scale = displayScale
|
format.scale = displayScale
|
||||||
|
@ -171,24 +171,24 @@ private actor MockAttachmentsGenerator {
|
||||||
UIColor(red: 0x56 / 255, green: 0x03 / 255, blue: 0xad / 255, alpha: 1).setFill()
|
UIColor(red: 0x56 / 255, green: 0x03 / 255, blue: 0xad / 255, alpha: 1).setFill()
|
||||||
ctx.fill(bounds)
|
ctx.fill(bounds)
|
||||||
ctx.cgContext.concatenate(CGAffineTransform(1, 0, -0.5, 1, 0, 0))
|
ctx.cgContext.concatenate(CGAffineTransform(1, 0, -0.5, 1, 0, 0))
|
||||||
for minX in stride(from: 0, through: 100, by: 30) {
|
for x in 0..<9 {
|
||||||
UIColor(red: 0x83 / 255, green: 0x67 / 255, blue: 0xc7 / 255, alpha: 1).setFill()
|
UIColor(red: 0x83 / 255, green: 0x67 / 255, blue: 0xc7 / 255, alpha: 1).setFill()
|
||||||
ctx.fill(CGRect(x: minX + 20, y: 0, width: 15, height: 100))
|
ctx.fill(CGRect(x: CGFloat(x) * 30 + 20, y: 0, width: 15, height: bounds.height))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let secondImage = renderer.image { ctx in
|
let secondImage = renderer.image { ctx in
|
||||||
UIColor(red: 0x00 / 255, green: 0x43 / 255, blue: 0x85 / 255, alpha: 1).setFill()
|
UIColor(red: 0x00 / 255, green: 0x43 / 255, blue: 0x85 / 255, alpha: 1).setFill()
|
||||||
ctx.fill(bounds)
|
ctx.fill(bounds)
|
||||||
UIColor(red: 0x05 / 255, green: 0xb2 / 255, blue: 0xdc / 255, alpha: 1).setFill()
|
UIColor(red: 0x05 / 255, green: 0xb2 / 255, blue: 0xdc / 255, alpha: 1).setFill()
|
||||||
for y in 0..<2 {
|
for y in 0..<4 {
|
||||||
for x in 0..<4 {
|
for x in 0..<5 {
|
||||||
let rect = CGRect(x: x * 45 - 5, y: y * 50 + 15, width: 20, height: 20)
|
let rect = CGRect(x: x * 45 - 5, y: y * 50 + 15, width: 20, height: 20)
|
||||||
ctx.cgContext.fillEllipse(in: rect)
|
ctx.cgContext.fillEllipse(in: rect)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UIColor(red: 0x08 / 255, green: 0x7c / 255, blue: 0xa7 / 255, alpha: 1).setFill()
|
UIColor(red: 0x08 / 255, green: 0x7c / 255, blue: 0xa7 / 255, alpha: 1).setFill()
|
||||||
for y in 0..<3 {
|
for y in 0..<5 {
|
||||||
for x in 0..<2 {
|
for x in 0..<4 {
|
||||||
let rect = CGRect(x: CGFloat(x) * 45 + 22.5, y: CGFloat(y) * 50 - 5, width: 10, height: 10)
|
let rect = CGRect(x: CGFloat(x) * 45 + 22.5, y: CGFloat(y) * 50 - 5, width: 10, height: 10)
|
||||||
ctx.cgContext.fillEllipse(in: rect)
|
ctx.cgContext.fillEllipse(in: rect)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,26 +12,32 @@ import TuskerPreferences
|
||||||
|
|
||||||
struct WidescreenNavigationPrefsView: View {
|
struct WidescreenNavigationPrefsView: View {
|
||||||
@ObservedObject private var preferences = Preferences.shared
|
@ObservedObject private var preferences = Preferences.shared
|
||||||
@State private var startAnimation = PassthroughSubject<Void, Never>()
|
@State private var startAnimation = CurrentValueSubject<Bool, Never>(false)
|
||||||
|
|
||||||
|
private var startAnimationSignal: some Publisher<Void, Never> {
|
||||||
|
startAnimation.filter { $0 }.removeDuplicates().map { _ in () }
|
||||||
|
}
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
HStack {
|
HStack {
|
||||||
Spacer()
|
Spacer()
|
||||||
|
|
||||||
OptionView<StackNavigationPreview>(
|
OptionView(
|
||||||
|
content: StackNavigationPreview.self,
|
||||||
value: .stack,
|
value: .stack,
|
||||||
selection: $preferences.widescreenNavigationMode,
|
selection: $preferences.widescreenNavigationMode,
|
||||||
startAnimation: startAnimation
|
startAnimation: startAnimationSignal
|
||||||
) {
|
) {
|
||||||
Text("Stack")
|
Text("Stack")
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(minLength: 32)
|
Spacer(minLength: 32)
|
||||||
|
|
||||||
OptionView<SplitNavigationPreview>(
|
OptionView(
|
||||||
|
content: SplitNavigationPreview.self,
|
||||||
value: .splitScreen,
|
value: .splitScreen,
|
||||||
selection: $preferences.widescreenNavigationMode,
|
selection: $preferences.widescreenNavigationMode,
|
||||||
startAnimation: startAnimation
|
startAnimation: startAnimationSignal
|
||||||
) {
|
) {
|
||||||
Text("Split Screen")
|
Text("Split Screen")
|
||||||
}
|
}
|
||||||
|
@ -39,10 +45,11 @@ struct WidescreenNavigationPrefsView: View {
|
||||||
if preferences.hasFeatureFlag(.iPadMultiColumn) {
|
if preferences.hasFeatureFlag(.iPadMultiColumn) {
|
||||||
Spacer(minLength: 32)
|
Spacer(minLength: 32)
|
||||||
|
|
||||||
OptionView<MultiColumnNavigationPreview>(
|
OptionView(
|
||||||
|
content: MultiColumnNavigationPreview.self,
|
||||||
value: .multiColumn,
|
value: .multiColumn,
|
||||||
selection: $preferences.widescreenNavigationMode,
|
selection: $preferences.widescreenNavigationMode,
|
||||||
startAnimation: startAnimation
|
startAnimation: startAnimationSignal
|
||||||
) {
|
) {
|
||||||
Text("Multi-Column")
|
Text("Multi-Column")
|
||||||
}
|
}
|
||||||
|
@ -53,19 +60,26 @@ struct WidescreenNavigationPrefsView: View {
|
||||||
.frame(height: 100)
|
.frame(height: 100)
|
||||||
.onAppear {
|
.onAppear {
|
||||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
|
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
|
||||||
startAnimation.send()
|
startAnimation.send(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct OptionView<Content: NavigationModePreview>: View {
|
private struct OptionView<Content: NavigationModePreview, P: Publisher<Void, Never>>: View {
|
||||||
let value: WidescreenNavigationMode
|
let value: WidescreenNavigationMode
|
||||||
@Binding var selection: WidescreenNavigationMode
|
@Binding var selection: WidescreenNavigationMode
|
||||||
let startAnimation: PassthroughSubject<Void, Never>
|
let startAnimation: P
|
||||||
@ViewBuilder let label: Text
|
let label: Text
|
||||||
@Environment(\.colorScheme) private var colorScheme
|
@Environment(\.colorScheme) private var colorScheme
|
||||||
|
|
||||||
|
init(content _: Content.Type, value: WidescreenNavigationMode, selection: Binding<WidescreenNavigationMode>, startAnimation: P, @ViewBuilder label: () -> Text) {
|
||||||
|
self.value = value
|
||||||
|
self._selection = selection
|
||||||
|
self.startAnimation = startAnimation
|
||||||
|
self.label = label()
|
||||||
|
}
|
||||||
|
|
||||||
private var selected: Bool {
|
private var selected: Bool {
|
||||||
selection == value
|
selection == value
|
||||||
}
|
}
|
||||||
|
@ -84,7 +98,7 @@ private struct OptionView<Content: NavigationModePreview>: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var preview: some View {
|
private var preview: some View {
|
||||||
NavigationModeRepresentable<Content>(startAnimation: startAnimation)
|
NavigationModeRepresentable(content: Content.self, startAnimation: startAnimation)
|
||||||
.clipShape(RoundedRectangle(cornerRadius: 12.5, style: .continuous))
|
.clipShape(RoundedRectangle(cornerRadius: 12.5, style: .continuous))
|
||||||
.overlay {
|
.overlay {
|
||||||
RoundedRectangle(cornerRadius: 12.5, style: .continuous)
|
RoundedRectangle(cornerRadius: 12.5, style: .continuous)
|
||||||
|
@ -106,11 +120,15 @@ private struct WideCapsule: Shape {
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
private protocol NavigationModePreview: UIView {
|
private protocol NavigationModePreview: UIView {
|
||||||
init(startAnimation: PassthroughSubject<Void, Never>)
|
init(startAnimation: some Publisher<Void, Never>)
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct NavigationModeRepresentable<UIViewType: NavigationModePreview>: UIViewRepresentable {
|
private struct NavigationModeRepresentable<UIViewType: NavigationModePreview, P: Publisher<Void, Never>>: UIViewRepresentable {
|
||||||
let startAnimation: PassthroughSubject<Void, Never>
|
let startAnimation: P
|
||||||
|
|
||||||
|
init(content _: UIViewType.Type, startAnimation: P) {
|
||||||
|
self.startAnimation = startAnimation
|
||||||
|
}
|
||||||
|
|
||||||
func makeUIView(context: Context) -> UIViewType {
|
func makeUIView(context: Context) -> UIViewType {
|
||||||
UIViewType(startAnimation: startAnimation)
|
UIViewType(startAnimation: startAnimation)
|
||||||
|
@ -128,7 +146,7 @@ private final class StackNavigationPreview: UIView, NavigationModePreview {
|
||||||
private let destinationView = UIView()
|
private let destinationView = UIView()
|
||||||
private var cancellable: AnyCancellable?
|
private var cancellable: AnyCancellable?
|
||||||
|
|
||||||
init(startAnimation: PassthroughSubject<Void, Never>) {
|
init(startAnimation: some Publisher<Void, Never>) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
backgroundColor = .appBackground
|
backgroundColor = .appBackground
|
||||||
|
@ -203,7 +221,7 @@ private final class SplitNavigationPreview: UIView, NavigationModePreview {
|
||||||
private var cellStackTrailingConstraint: NSLayoutConstraint!
|
private var cellStackTrailingConstraint: NSLayoutConstraint!
|
||||||
private var cancellable: AnyCancellable?
|
private var cancellable: AnyCancellable?
|
||||||
|
|
||||||
init(startAnimation: PassthroughSubject<Void, Never>) {
|
init(startAnimation: some Publisher<Void, Never>) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
backgroundColor = .appBackground
|
backgroundColor = .appBackground
|
||||||
|
@ -297,7 +315,7 @@ private final class MultiColumnNavigationPreview: UIView, NavigationModePreview
|
||||||
|
|
||||||
private var startedAnimation = false
|
private var startedAnimation = false
|
||||||
|
|
||||||
init(startAnimation: PassthroughSubject<Void, Never>) {
|
init(startAnimation: some Publisher<Void, Never>) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
|
|
||||||
backgroundColor = .appSecondaryBackground
|
backgroundColor = .appSecondaryBackground
|
|
@ -1,64 +0,0 @@
|
||||||
//
|
|
||||||
// MediaPrefsView.swift
|
|
||||||
// Tusker
|
|
||||||
//
|
|
||||||
// Created by Shadowfacts on 2/22/20.
|
|
||||||
// Copyright © 2020 Shadowfacts. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
import TuskerPreferences
|
|
||||||
|
|
||||||
struct MediaPrefsView: View {
|
|
||||||
@ObservedObject var preferences = Preferences.shared
|
|
||||||
|
|
||||||
var body: some View {
|
|
||||||
List {
|
|
||||||
viewingSection
|
|
||||||
}
|
|
||||||
.listStyle(.insetGrouped)
|
|
||||||
.appGroupedListBackground(container: PreferencesNavigationController.self)
|
|
||||||
.navigationBarTitle("Media")
|
|
||||||
}
|
|
||||||
|
|
||||||
var viewingSection: some View {
|
|
||||||
Section(header: Text("Viewing")) {
|
|
||||||
Picker(selection: $preferences.attachmentBlurMode) {
|
|
||||||
ForEach(AttachmentBlurMode.allCases, id: \.self) { mode in
|
|
||||||
Text(mode.displayName).tag(mode)
|
|
||||||
}
|
|
||||||
} label: {
|
|
||||||
Text("Blur Media")
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.blurMediaBehindContentWarning) {
|
|
||||||
Text("Blur Media Behind Content Warning")
|
|
||||||
}
|
|
||||||
.disabled(preferences.attachmentBlurMode != .useStatusSetting)
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.automaticallyPlayGifs) {
|
|
||||||
Text("Automatically Play GIFs")
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.showUncroppedMediaInline) {
|
|
||||||
Text("Show Uncropped Media Inline")
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.showAttachmentBadges) {
|
|
||||||
Text("Show GIF/\(Text("Alt").font(.body.lowercaseSmallCaps())) Badges")
|
|
||||||
}
|
|
||||||
|
|
||||||
Toggle(isOn: $preferences.attachmentAltBadgeInverted) {
|
|
||||||
Text("Show Badge when Missing \(Text("Alt").font(.body.lowercaseSmallCaps()))")
|
|
||||||
}
|
|
||||||
.disabled(!preferences.showAttachmentBadges)
|
|
||||||
}
|
|
||||||
.appGroupedListRowBackground()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct MediaPrefsView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
MediaPrefsView()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,7 +23,6 @@ struct PreferencesView: View {
|
||||||
var body: some View {
|
var body: some View {
|
||||||
List {
|
List {
|
||||||
accountsSection
|
accountsSection
|
||||||
notificationsSection
|
|
||||||
preferencesSection
|
preferencesSection
|
||||||
aboutSection
|
aboutSection
|
||||||
}
|
}
|
||||||
|
@ -92,31 +91,22 @@ struct PreferencesView: View {
|
||||||
.appGroupedListRowBackground()
|
.appGroupedListRowBackground()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var notificationsSection: some View {
|
|
||||||
Section {
|
|
||||||
NavigationLink(isActive: $navigationState.showNotificationPreferences) {
|
|
||||||
NotificationsPrefsView()
|
|
||||||
} label: {
|
|
||||||
Text("Notifications")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.appGroupedListRowBackground()
|
|
||||||
}
|
|
||||||
|
|
||||||
private var preferencesSection: some View {
|
private var preferencesSection: some View {
|
||||||
Section {
|
Section {
|
||||||
NavigationLink(destination: AppearancePrefsView()) {
|
NavigationLink(destination: AppearancePrefsView()) {
|
||||||
Text("Appearance")
|
Text("Appearance")
|
||||||
}
|
}
|
||||||
NavigationLink(destination: ComposingPrefsView()) {
|
|
||||||
Text("Composing")
|
|
||||||
}
|
|
||||||
NavigationLink(destination: MediaPrefsView()) {
|
|
||||||
Text("Media")
|
|
||||||
}
|
|
||||||
NavigationLink(destination: BehaviorPrefsView()) {
|
NavigationLink(destination: BehaviorPrefsView()) {
|
||||||
Text("Behavior")
|
Text("Behavior")
|
||||||
}
|
}
|
||||||
|
NavigationLink(isActive: $navigationState.showNotificationPreferences) {
|
||||||
|
NotificationsPrefsView()
|
||||||
|
} label: {
|
||||||
|
Text("Notifications")
|
||||||
|
}
|
||||||
|
NavigationLink(destination: ComposingPrefsView()) {
|
||||||
|
Text("Composing")
|
||||||
|
}
|
||||||
NavigationLink(destination: WellnessPrefsView()) {
|
NavigationLink(destination: WellnessPrefsView()) {
|
||||||
Text("Digital Wellness")
|
Text("Digital Wellness")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue