mirror of
https://github.com/dscyrescotti/Memola.git
synced 2026-03-22 09:29:26 +01:00
feat: add setting view
This commit is contained in:
@@ -32,6 +32,8 @@
|
||||
EC2002ED2C417B68002EBD5F /* AppScene.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2002EC2C417B68002EBD5F /* AppScene.swift */; };
|
||||
EC2002F02C417BF1002EBD5F /* ActiveSceneKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2002EF2C417BF1002EBD5F /* ActiveSceneKey.swift */; };
|
||||
EC2106AD2C10C2A700FBE27C /* AnyStroke.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2106AC2C10C2A700FBE27C /* AnyStroke.swift */; };
|
||||
EC2117632C47FA30005B32A1 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2117622C47FA30005B32A1 /* SettingsView.swift */; };
|
||||
EC2117662C4802C0005B32A1 /* AppWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2117652C4802C0005B32A1 /* AppWindow.swift */; };
|
||||
EC2BEBF42C0F5FF7005DB0AF /* RTree.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2BEBF32C0F5FF7005DB0AF /* RTree.swift */; };
|
||||
EC2BEBF62C0F600D005DB0AF /* Box.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2BEBF52C0F600D005DB0AF /* Box.swift */; };
|
||||
EC2BEBF82C0F601A005DB0AF /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = EC2BEBF72C0F601A005DB0AF /* Node.swift */; };
|
||||
@@ -169,6 +171,8 @@
|
||||
EC2002EC2C417B68002EBD5F /* AppScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppScene.swift; sourceTree = "<group>"; };
|
||||
EC2002EF2C417BF1002EBD5F /* ActiveSceneKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSceneKey.swift; sourceTree = "<group>"; };
|
||||
EC2106AC2C10C2A700FBE27C /* AnyStroke.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyStroke.swift; sourceTree = "<group>"; };
|
||||
EC2117622C47FA30005B32A1 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
|
||||
EC2117652C4802C0005B32A1 /* AppWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppWindow.swift; sourceTree = "<group>"; };
|
||||
EC2BEBF32C0F5FF7005DB0AF /* RTree.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RTree.swift; sourceTree = "<group>"; };
|
||||
EC2BEBF52C0F600D005DB0AF /* Box.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Box.swift; sourceTree = "<group>"; };
|
||||
EC2BEBF72C0F601A005DB0AF /* Node.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Node.swift; sourceTree = "<group>"; };
|
||||
@@ -439,6 +443,30 @@
|
||||
path = AppScene;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EC2117602C47FA14005B32A1 /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EC2117612C47FA29005B32A1 /* Settings */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EC2117612C47FA29005B32A1 /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EC2117622C47FA30005B32A1 /* SettingsView.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EC2117642C4802B4005B32A1 /* AppWindow */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EC2117652C4802C0005B32A1 /* AppWindow.swift */,
|
||||
);
|
||||
path = AppWindow;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
EC2BEBF22C0F5FE1005DB0AF /* RTree */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -607,6 +635,7 @@
|
||||
children = (
|
||||
EC01511A2C305ABB008A115E /* Dashboard */,
|
||||
ECA7387B2BE5EF3500A4542E /* Memo */,
|
||||
EC2117602C47FA14005B32A1 /* Settings */,
|
||||
);
|
||||
path = Features;
|
||||
sourceTree = "<group>";
|
||||
@@ -996,6 +1025,7 @@
|
||||
ECF7B2E52C391DFA004D2C57 /* Utilies */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EC2117642C4802B4005B32A1 /* AppWindow */,
|
||||
EC6E3BDD2C43D5A500DD20F3 /* SidebarVisibility */,
|
||||
EC2002EE2C417BBF002EBD5F /* AppScene */,
|
||||
ECF7B2CF2C39169C004D2C57 /* Extensions */,
|
||||
@@ -1134,6 +1164,7 @@
|
||||
EC2002DD2C4163E8002EBD5F /* AppCommands.swift in Sources */,
|
||||
EC1815082C2D980B00541369 /* Sort.swift in Sources */,
|
||||
EC6E3BD92C43C6C000DD20F3 /* OnDismissSearchViewModifier.swift in Sources */,
|
||||
EC2117662C4802C0005B32A1 /* AppWindow.swift in Sources */,
|
||||
ECA7387D2BE5EF4B00A4542E /* MemoView.swift in Sources */,
|
||||
ECDDD40D2C366B3B00DF9D5E /* PreviewRenderPass.swift in Sources */,
|
||||
ECF7B2E12C39169C004D2C57 /* View++.swift in Sources */,
|
||||
@@ -1159,6 +1190,7 @@
|
||||
EC8C9DCE2C39882500A8F3C4 /* NSSyncScrollView.swift in Sources */,
|
||||
ECF7B2D72C39169C004D2C57 /* Color++.swift in Sources */,
|
||||
EC01512C2C306BEF008A115E /* MemoCard.swift in Sources */,
|
||||
EC2117632C47FA30005B32A1 /* SettingsView.swift in Sources */,
|
||||
ECA738D42BE60F9100A4542E /* StrokeGenerator.swift in Sources */,
|
||||
ECF7B2D52C39169C004D2C57 /* CGSize++.swift in Sources */,
|
||||
ECA739082BE623F300A4542E /* PenDock.swift in Sources */,
|
||||
|
||||
@@ -54,6 +54,17 @@ extension Application: NSApplicationDelegate {
|
||||
NSWindow.allowsAutomaticWindowTabbing = false
|
||||
UserDefaults.standard.register(defaults: ["NSQuitAlwaysKeepsWindows": false])
|
||||
}
|
||||
|
||||
func openWindow(for appWindow: AppWindow) {
|
||||
let window = NSApplication.shared.windows.first { window in
|
||||
window.identifier?.rawValue.contains(appWindow.id) == true
|
||||
}
|
||||
if window == nil, let url = appWindow.url {
|
||||
NSWorkspace.shared.open(url)
|
||||
} else {
|
||||
window?.makeKeyAndOrderFront(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
extension Application: UIApplicationDelegate {
|
||||
|
||||
@@ -16,7 +16,7 @@ struct MemolaApp: App {
|
||||
#endif
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
WindowGroup(id: AppWindow.dashboard.id) {
|
||||
DashboardView()
|
||||
.persistence(\.viewContext)
|
||||
.onReceive(NotificationCenter.default.publisher(for: Platform.Application.willTerminateNotification)) { _ in
|
||||
@@ -36,13 +36,38 @@ struct MemolaApp: App {
|
||||
.defaultPosition(.center)
|
||||
.windowResizability(.contentSize)
|
||||
.defaultSize(width: 1200, height: 800)
|
||||
.windowToolbarStyle(.unifiedCompact)
|
||||
.windowToolbarStyle(.unified)
|
||||
.handlesExternalEvents(matching: [AppWindow.dashboard.id])
|
||||
#endif
|
||||
.commands {
|
||||
AppCommands()
|
||||
FileCommands()
|
||||
#if os(macOS)
|
||||
AppCommands(application: application)
|
||||
#endif
|
||||
FileCommands(application: application)
|
||||
EditCommands()
|
||||
ViewCommands(application: application)
|
||||
}
|
||||
#if os(macOS)
|
||||
WindowGroup(id: AppWindow.settings.id) {
|
||||
SettingsView()
|
||||
.onReceive(NotificationCenter.default.publisher(for: Platform.Application.willTerminateNotification)) { _ in
|
||||
withPersistenceSync(\.viewContext) { context in
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
withPersistenceSync(\.backgroundContext) { context in
|
||||
try context.saveIfNeeded()
|
||||
}
|
||||
}
|
||||
#if os(macOS)
|
||||
.frame(minWidth: 700, minHeight: 500)
|
||||
#endif
|
||||
.environmentObject(application)
|
||||
}
|
||||
.defaultPosition(.center)
|
||||
.windowResizability(.contentSize)
|
||||
.defaultSize(width: 800, height: 400)
|
||||
.windowToolbarStyle(.unifiedCompact)
|
||||
.handlesExternalEvents(matching: [AppWindow.settings.id])
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,30 +2,37 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Memola requires access to the camera to capture photos.</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict/>
|
||||
</dict>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>$(MARKETING_VERSION)</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
<array>
|
||||
<dict>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Editor</string>
|
||||
<key>CFBundleURLSchemes</key>
|
||||
<array>
|
||||
<string>memola</string>
|
||||
</array>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Memola requires access to the camera to capture photos.</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
<dict>
|
||||
<key>UIApplicationSupportsMultipleScenes</key>
|
||||
@@ -35,19 +42,23 @@
|
||||
</dict>
|
||||
<key>UIApplicationSupportsIndirectInputEvents</key>
|
||||
<true/>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict>
|
||||
<key>UILaunchScreen</key>
|
||||
<dict/>
|
||||
</dict>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~iphone</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationPortrait</string>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -52,7 +52,7 @@ struct DashboardView: View {
|
||||
}
|
||||
.animation(.easeIn, value: application.memoObject)
|
||||
.toolbar(application.memoObject == nil ? .visible : .hidden, for: .windowToolbar)
|
||||
.toolbarBackground(Color(nsColor: .windowBackgroundColor), for: .windowToolbar)
|
||||
.toolbarBackground(Color(nsColor: .unemphasizedSelectedContentBackgroundColor), for: .windowToolbar)
|
||||
.onChange(of: columnVisibility) { oldValue, newValue in
|
||||
application.changeSidebarVisibility(newValue == .all ? .shown : .hidden)
|
||||
}
|
||||
|
||||
@@ -9,35 +9,91 @@ import SwiftUI
|
||||
|
||||
struct Sidebar: View {
|
||||
private let sidebarItems: [SidebarItem] = [.memos, .trash]
|
||||
@Binding private var sidebarItem: SidebarItem?
|
||||
|
||||
private let horizontalSizeClass: UserInterfaceSizeClass?
|
||||
|
||||
@Binding private var sidebarItem: SidebarItem?
|
||||
|
||||
@State private var presentsSettings: Bool = false
|
||||
|
||||
#if os(macOS)
|
||||
@EnvironmentObject private var application: Application
|
||||
#endif
|
||||
|
||||
init(sidebarItem: Binding<SidebarItem?>, horizontalSizeClass: UserInterfaceSizeClass?) {
|
||||
self._sidebarItem = sidebarItem
|
||||
self.horizontalSizeClass = horizontalSizeClass
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
#if os(macOS)
|
||||
regularList
|
||||
#else
|
||||
Group {
|
||||
if horizontalSizeClass == .compact {
|
||||
compactList
|
||||
} else {
|
||||
regularList
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $presentsSettings) {
|
||||
SettingsView()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private var regularList: some View {
|
||||
VStack(spacing: 10) {
|
||||
list
|
||||
Divider()
|
||||
settingsButton
|
||||
.buttonStyle(.unselected)
|
||||
.padding(.horizontal, 10)
|
||||
}
|
||||
#if os(macOS)
|
||||
.padding(.bottom, 10)
|
||||
.background(Color(color: .windowBackgroundColor))
|
||||
#else
|
||||
.background(Color(color: .secondarySystemBackground))
|
||||
#endif
|
||||
.navigationSplitViewColumnWidth(min: 250, ideal: 250, max: 250)
|
||||
}
|
||||
|
||||
private var compactList: some View {
|
||||
list
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .topBarTrailing) {
|
||||
settingsButton
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var list: some View {
|
||||
List(selection: $sidebarItem) {
|
||||
ForEach(sidebarItems) { item in
|
||||
if horizontalSizeClass == .compact {
|
||||
Button {
|
||||
sidebarItem = item
|
||||
} label: {
|
||||
Label(item.title, systemImage: item.icon)
|
||||
.foregroundColor(.primary)
|
||||
Group {
|
||||
if horizontalSizeClass == .compact {
|
||||
Button {
|
||||
sidebarItem = item
|
||||
} label: {
|
||||
Label(item.title, systemImage: item.icon)
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
} else {
|
||||
Button {
|
||||
sidebarItem = item
|
||||
} label: {
|
||||
Label(item.title, systemImage: item.icon)
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
.buttonStyle(sidebarItem == item ? .selected : .unselected)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
}
|
||||
} else {
|
||||
Button {
|
||||
sidebarItem = item
|
||||
} label: {
|
||||
Label(item.title, systemImage: item.icon)
|
||||
.foregroundColor(.primary)
|
||||
}
|
||||
.buttonStyle(sidebarItem == item ? .selected : .unselected)
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0))
|
||||
}
|
||||
#if os(macOS)
|
||||
.padding(.top, item == .memos ? 20 : 0)
|
||||
#else
|
||||
.padding(.top, horizontalSizeClass == .regular ? (item == .memos ? 20 : 0) : 0)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
@@ -48,11 +104,22 @@ struct Sidebar: View {
|
||||
#else
|
||||
.background(Color(color: .secondarySystemBackground))
|
||||
#endif
|
||||
.navigationSplitViewColumnWidth(min: 250, ideal: 250, max: 250)
|
||||
#if os(iOS)
|
||||
.navigationBarTitleDisplayMode(horizontalSizeClass == .compact ? .automatic : .inline)
|
||||
#endif
|
||||
}
|
||||
|
||||
private var settingsButton: some View {
|
||||
Button {
|
||||
#if os(macOS)
|
||||
application.openWindow(for: .settings)
|
||||
#else
|
||||
presentsSettings.toggle()
|
||||
#endif
|
||||
} label: {
|
||||
Label("Settings", systemImage: "gearshape.fill")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension Sidebar {
|
||||
|
||||
19
Memola/Features/Settings/Settings/SettingsView.swift
Normal file
19
Memola/Features/Settings/Settings/SettingsView.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// SettingsView.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 7/17/24.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Text("Settings View")
|
||||
.navigationTitle("Settings")
|
||||
}
|
||||
.focusedSceneValue(\.activeSceneKey, .settings)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,20 @@
|
||||
// Created by Dscyre Scotti on 7/12/24.
|
||||
//
|
||||
|
||||
#if os(macOS)
|
||||
import SwiftUI
|
||||
|
||||
struct AppCommands: Commands {
|
||||
@ObservedObject private var application: Application
|
||||
|
||||
init(application: Application) {
|
||||
self.application = application
|
||||
}
|
||||
|
||||
var body: some Commands {
|
||||
CommandGroup(replacing: .appSettings) {
|
||||
Button {
|
||||
|
||||
application.openWindow(for: .settings)
|
||||
} label: {
|
||||
Text("Services...")
|
||||
}
|
||||
@@ -19,3 +26,4 @@ struct AppCommands: Commands {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -11,8 +11,24 @@ struct FileCommands: Commands {
|
||||
@Environment(\.shortcut) private var shortcut
|
||||
@FocusedValue(\.activeSceneKey) private var appScene
|
||||
|
||||
@ObservedObject private var application: Application
|
||||
|
||||
init(application: Application) {
|
||||
self.application = application
|
||||
}
|
||||
|
||||
var body: some Commands {
|
||||
CommandGroup(replacing: .newItem) {
|
||||
#if os(macOS)
|
||||
if appScene == nil {
|
||||
Button {
|
||||
application.openWindow(for: .dashboard)
|
||||
} label: {
|
||||
Text("Open Dashboard")
|
||||
}
|
||||
.keyboardShortcut("m", modifiers: [.command])
|
||||
}
|
||||
#endif
|
||||
if appScene == .memos {
|
||||
Button {
|
||||
shortcut.trigger(.newMemo)
|
||||
|
||||
@@ -11,4 +11,5 @@ enum AppScene {
|
||||
case memos
|
||||
case trash
|
||||
case memo
|
||||
case settings
|
||||
}
|
||||
|
||||
19
Memola/Utilies/AppWindow/AppWindow.swift
Normal file
19
Memola/Utilies/AppWindow/AppWindow.swift
Normal file
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// AppWindow.swift
|
||||
// Memola
|
||||
//
|
||||
// Created by Dscyre Scotti on 7/17/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
enum AppWindow: String, Identifiable {
|
||||
var id: String { rawValue }
|
||||
|
||||
case dashboard
|
||||
case settings
|
||||
|
||||
var url: URL? {
|
||||
URL(string: "memola:\(id)")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user