Improve user manual

This commit is contained in:
Leon Böttger committed 2026-06-02 21:30:44 +02:00
1 parent 28e0ede409
commit b5de24d926
5 files changed
+1361 -105

No files matched your search

+15 -2
View File
@@ -27,6 +27,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
private var errorAlertHandler = ErrorAlertHandler.shared
private var receiveModel: ReceiveModel?
private let welcomeNavigationState = WelcomeScreenNavigationState()
var showsFirewallAlert = false
var visibleItem: NSMenuItem? = nil
@@ -233,7 +234,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
// MARK: - Button Actions
@objc private func visibleMenuItemSelected() {}
@objc private func visibleMenuItemSelected() {
showMainWindow(selectedTab: .settings)
}
@objc func sendClipboard() {
@@ -252,6 +255,15 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
@objc func openMainWindow() {
showMainWindow()
}
private func showMainWindow(selectedTab: Tab? = nil) {
if let selectedTab {
welcomeNavigationState.select(selectedTab)
}
defer {
if let welcomeWindow, !Settings.sharedInstance.appLaunchedBefore {
runAfter(seconds: 0.2) {
@@ -278,7 +290,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCenterDele
openPlusScreen: openPlusScreen,
openAppAdvertisementView: { self.openSheetView(type: .downloadAndroidApp) },
openCableTransmissionView: { self.openSheetView(type: .downloadCableConnectionApp) },
checkForNetworkIssues: performDeviceToDeviceCheck
checkForNetworkIssues: performDeviceToDeviceCheck,
navigationState: welcomeNavigationState
)
welcomeWindow = NSWindow(
File diff suppressed because it is too large. Load diff
+55 -11
View File
@@ -11,10 +11,14 @@ import LUI
struct SettingsView: View {
let openPlus: () -> Void
@ObservedObject var settings = Settings.sharedInstance
@ObservedObject var connectionManager = NearbyConnectionManager.shared
@ObservedObject var iapManager = IAPManager.sharedInstance
@State private var isChangeDeviceNameAlertPresented = false
@State private var licenseWindow: NSWindow?
var body: some View {
@@ -68,17 +72,33 @@ struct SettingsView: View {
Divider()
.padding(.vertical, 10)
Button {
openTrustedDevicesWindow()
} label: {
Text("ManageTrustedDevices")
.underline()
.font(.subheadline)
.opacity(0.5)
.frame(maxWidth: .infinity)
.padding(.vertical, 15)
HStack(spacing: 30) {
SettingsFooterButton("ManageTrustedDevices") {
openTrustedDevicesWindow()
}
SettingsFooterButton("Acknowledgements") {
licenseWindow = openLicenseWindow()
}
#if !GITHUB
if !iapManager.plusVersionState {
SettingsFooterButton("SupportQuickDrop") {
openPlus()
}
}
#endif
#if DEBUG
SettingsFooterButton("ResetAllSettings") {
IAPManager.sharedInstance.plusVersionState = false
Settings.sharedInstance.deleteAllUserDefaults()
}
#endif
}
.buttonStyle(PlainButtonStyle())
.minimumScaleFactor(0.7)
.frame(maxWidth: .infinity)
.padding(.vertical, 15)
}
}
}
@@ -194,7 +214,31 @@ struct SettingsView: View {
struct SettingsView_Previews: PreviewProvider {
static var previews: some View {
SettingsView()
SettingsView(openPlus: {})
.frame(width: 800, height: 500)
}
}
private struct SettingsFooterButton: View {
let title: String
let action: () -> Void
init(_ title: String, action: @escaping () -> Void) {
self.title = title
self.action = action
}
var body: some View {
Button {
action()
} label: {
Text(title.localized())
.underline()
.font(.subheadline)
.lineLimit(1)
.opacity(0.5)
}
.buttonStyle(.plain)
}
}
+27 -45
View File
@@ -12,12 +12,8 @@ import SwiftUI
struct TutorialView: View {
let tab: Tab
let openPlus: () -> Void
let openAppAdvertisementView: () -> Void
@State private var licenseWindow: NSWindow?
@ObservedObject var iapManager = IAPManager.sharedInstance
var body: some View {
LargeAppIconView(title: tab.title) {
@@ -35,7 +31,7 @@ struct TutorialView: View {
.padding(.top)
}
else {
Text(tab.text.localized())
Text(tab.text)
.multilineTextAlignment(.leading)
.fixedSize(horizontal: false, vertical: true)
.padding()
@@ -44,51 +40,22 @@ struct TutorialView: View {
.frame(width: 550)
if tab == .receive {
HStack(spacing: 30) {
Button {
licenseWindow = openLicenseWindow()
} label: {
Text("Acknowledgements")
.underline()
.font(.footnote)
.opacity(0.5)
}
.buttonStyle(.plain)
#if !GITHUB
if !iapManager.plusVersionState {
Button {
openPlus()
} label: {
Text("SupportQuickDrop")
.underline()
.font(.footnote)
.opacity(0.5)
}
.buttonStyle(.plain)
}
#endif
#if DEBUG
Button {
IAPManager.sharedInstance.plusVersionState = false
Settings.sharedInstance.deleteAllUserDefaults()
} label: {
Text("ResetAllSettings")
.underline()
.font(.footnote)
.opacity(0.5)
}
.buttonStyle(.plain)
#endif
Button {
showSamsungOneUI85Alert()
} label: {
Text("SamsungOneUI85HelpLink".localized())
.underline()
.font(.footnote)
.multilineTextAlignment(.center)
.opacity(0.7)
}
.buttonStyle(.plain)
.padding()
}
else if tab == .send {
EnableExtensionView()
}
else if tab == .notificationSync {
else if tab == .notificationSync || tab == .clipboardSync {
Button {
openAppAdvertisementView()
} label: {
@@ -100,6 +67,21 @@ struct TutorialView: View {
}
}
}
private func showSamsungOneUI85Alert() {
let alert = NSAlert()
alert.alertStyle = .informational
alert.messageText = "SamsungOneUI85AlertTitle".localized()
alert.informativeText = "SamsungOneUI85AlertMessage".localized()
alert.addButton(withTitle: "CloseAlert".localized())
if let window = NSApp.mainWindow ?? NSApp.keyWindow {
alert.beginSheetModal(for: window) { _ in }
}
else {
alert.runModal()
}
}
}
@@ -198,5 +180,5 @@ private struct SharingPickerPresenter: NSViewRepresentable {
#Preview {
WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, openCableTransmissionView: {}, checkForNetworkIssues: {})
WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, openCableTransmissionView: {}, checkForNetworkIssues: {}, navigationState: WelcomeScreenNavigationState())
}
+60 -8
View File
@@ -9,6 +9,25 @@ import SwiftUI
import UniformTypeIdentifiers
import LUI
struct WelcomeScreenNavigationRequest {
let tab: Tab
let id = UUID()
}
final class WelcomeScreenNavigationState: ObservableObject {
@Published private(set) var request: WelcomeScreenNavigationRequest
init(selection: Tab = .receive) {
self.request = WelcomeScreenNavigationRequest(tab: selection)
}
func select(_ tab: Tab) {
request = WelcomeScreenNavigationRequest(tab: tab)
}
}
struct WelcomeScreen: View {
static let width: CGFloat = 1000
@@ -21,7 +40,23 @@ struct WelcomeScreen: View {
let openCableTransmissionView: () -> Void
let checkForNetworkIssues: () -> Void
@State private var selection: Tab = Tab.receive
@ObservedObject var navigationState: WelcomeScreenNavigationState
@State private var selection: Tab
init(
openPlusScreen: @escaping () -> Void,
openAppAdvertisementView: @escaping () -> Void,
openCableTransmissionView: @escaping () -> Void,
checkForNetworkIssues: @escaping () -> Void,
navigationState: WelcomeScreenNavigationState
) {
self.openPlusScreen = openPlusScreen
self.openAppAdvertisementView = openAppAdvertisementView
self.openCableTransmissionView = openCableTransmissionView
self.checkForNetworkIssues = checkForNetworkIssues
self.navigationState = navigationState
_selection = State(initialValue: navigationState.request.tab)
}
var body: some View {
@@ -35,7 +70,7 @@ struct WelcomeScreen: View {
)
List(selection: listBinding) {
ForEach(Tab.allCases.filter({$0 != .settings }), id: \.self) { tab in
ForEach([Tab.receive, .send, .notificationSync, .clipboardSync], id: \.self) { tab in
Label(tab.sidebarTitle, systemImage: tab.systemImage)
.tag(tab)
.frame(height: 30)
@@ -43,6 +78,12 @@ struct WelcomeScreen: View {
Divider()
Label(Tab.troubleshooting.sidebarTitle, systemImage: Tab.troubleshooting.systemImage)
.tag(Tab.troubleshooting)
.frame(height: 30)
Divider()
ExternalLinkLabel(label: "GetSupport", icon: "questionmark.circle") {
LogExportPresenter.showUploadLogsAlert(openSupportMailWhenNotUploading: true)
}
@@ -76,12 +117,11 @@ struct WelcomeScreen: View {
Color.defaultBackground.edgesIgnoringSafeArea(.vertical)
if selection == .settings {
SettingsView()
SettingsView(openPlus: openPlusScreen)
}
else {
TutorialView(
tab: selection,
openPlus: openPlusScreen,
openAppAdvertisementView: openAppAdvertisementView
)
.onAppear {
@@ -92,6 +132,11 @@ struct WelcomeScreen: View {
}
}
}
.onReceive(navigationState.$request) { request in
if selection != request.tab {
selection = request.tab
}
}
.onDrop(of: [.fileURL], isTargeted: nil) { providers in
handleDrop(providers: providers)
return true
@@ -182,6 +227,7 @@ enum Tab: CaseIterable {
case receive
case send
case notificationSync
case clipboardSync
case troubleshooting
case settings
@@ -193,6 +239,8 @@ enum Tab: CaseIterable {
return "SendFiles".localized()
case .notificationSync:
return "NotificationSyncSidebar".localized()
case .clipboardSync:
return "ClipboardSyncSidebar".localized()
case .troubleshooting:
return "TroubleshootingAndFaq".localized()
case .settings:
@@ -210,11 +258,13 @@ enum Tab: CaseIterable {
var text: String {
switch self {
case .receive:
"UserManualDescription"
"UserManualDescription".localized()
case .send:
"SendFilesDescription"
"SendFilesDescription".localized()
case .notificationSync:
"NotificationSyncManualDescription"
"NotificationSyncManualDescription".localized()
case .clipboardSync:
"ClipboardSyncManualDescription".localized()
default:
""
}
@@ -228,6 +278,8 @@ enum Tab: CaseIterable {
return "tray.and.arrow.up"
case .notificationSync:
return "bell"
case .clipboardSync:
return "clipboard"
case .troubleshooting:
return "exclamationmark.triangle"
case .settings:
@@ -238,5 +290,5 @@ enum Tab: CaseIterable {
#Preview {
WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, openCableTransmissionView: {}, checkForNetworkIssues: {})
WelcomeScreen(openPlusScreen: {}, openAppAdvertisementView: {}, openCableTransmissionView: {}, checkForNetworkIssues: {}, navigationState: WelcomeScreenNavigationState())
}