mirror of
https://github.com/pboulch/luto.git
synced 2025-12-19 12:52:47 +00:00
✨ Add SQLite to save tasks
This commit is contained in:
@ -17,6 +17,9 @@
|
|||||||
682D06C22A5487D600EA4745 /* LutoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06C12A5487D600EA4745 /* LutoUITests.swift */; };
|
682D06C22A5487D600EA4745 /* LutoUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06C12A5487D600EA4745 /* LutoUITests.swift */; };
|
||||||
682D06C42A5487D600EA4745 /* LutoUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06C32A5487D600EA4745 /* LutoUITestsLaunchTests.swift */; };
|
682D06C42A5487D600EA4745 /* LutoUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06C32A5487D600EA4745 /* LutoUITestsLaunchTests.swift */; };
|
||||||
6838051A2A57356700CEF29C /* TextFieldExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 683805192A57356700CEF29C /* TextFieldExtensions.swift */; };
|
6838051A2A57356700CEF29C /* TextFieldExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 683805192A57356700CEF29C /* TextFieldExtensions.swift */; };
|
||||||
|
684640A72A65569D00D5A369 /* TaskDataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 684640A62A65569D00D5A369 /* TaskDataStore.swift */; };
|
||||||
|
684640AA2A6566B300D5A369 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = 684640A92A6566B300D5A369 /* SQLite */; };
|
||||||
|
68A773762A66F9A1000887A3 /* TaskViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68A773752A66F9A1000887A3 /* TaskViewModel.swift */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -51,6 +54,8 @@
|
|||||||
682D06C12A5487D600EA4745 /* LutoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LutoUITests.swift; sourceTree = "<group>"; };
|
682D06C12A5487D600EA4745 /* LutoUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LutoUITests.swift; sourceTree = "<group>"; };
|
||||||
682D06C32A5487D600EA4745 /* LutoUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LutoUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
682D06C32A5487D600EA4745 /* LutoUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LutoUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||||
683805192A57356700CEF29C /* TextFieldExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldExtensions.swift; sourceTree = "<group>"; };
|
683805192A57356700CEF29C /* TextFieldExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldExtensions.swift; sourceTree = "<group>"; };
|
||||||
|
684640A62A65569D00D5A369 /* TaskDataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskDataStore.swift; sourceTree = "<group>"; };
|
||||||
|
68A773752A66F9A1000887A3 /* TaskViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskViewModel.swift; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -58,6 +63,7 @@
|
|||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
684640AA2A6566B300D5A369 /* SQLite in Frameworks */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -118,6 +124,8 @@
|
|||||||
682D06A42A5487D200EA4745 /* Luto */ = {
|
682D06A42A5487D200EA4745 /* Luto */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
68A773742A66F984000887A3 /* ViewModels */,
|
||||||
|
684640A52A65568A00D5A369 /* Store */,
|
||||||
680A62162A600F75004C21A4 /* Models */,
|
680A62162A600F75004C21A4 /* Models */,
|
||||||
683805182A57354900CEF29C /* UI */,
|
683805182A57354900CEF29C /* UI */,
|
||||||
682D06A52A5487D200EA4745 /* LutoApp.swift */,
|
682D06A52A5487D200EA4745 /* LutoApp.swift */,
|
||||||
@ -162,6 +170,22 @@
|
|||||||
path = UI;
|
path = UI;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
684640A52A65568A00D5A369 /* Store */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
684640A62A65569D00D5A369 /* TaskDataStore.swift */,
|
||||||
|
);
|
||||||
|
path = Store;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
68A773742A66F984000887A3 /* ViewModels */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
68A773752A66F9A1000887A3 /* TaskViewModel.swift */,
|
||||||
|
);
|
||||||
|
path = ViewModels;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -178,6 +202,9 @@
|
|||||||
dependencies = (
|
dependencies = (
|
||||||
);
|
);
|
||||||
name = Luto;
|
name = Luto;
|
||||||
|
packageProductDependencies = (
|
||||||
|
684640A92A6566B300D5A369 /* SQLite */,
|
||||||
|
);
|
||||||
productName = Luto;
|
productName = Luto;
|
||||||
productReference = 682D06A22A5487D200EA4745 /* Luto.app */;
|
productReference = 682D06A22A5487D200EA4745 /* Luto.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
@ -250,6 +277,9 @@
|
|||||||
Base,
|
Base,
|
||||||
);
|
);
|
||||||
mainGroup = 682D06992A5487D200EA4745;
|
mainGroup = 682D06992A5487D200EA4745;
|
||||||
|
packageReferences = (
|
||||||
|
684640A82A6566B300D5A369 /* XCRemoteSwiftPackageReference "SQLite.swift" */,
|
||||||
|
);
|
||||||
productRefGroup = 682D06A32A5487D200EA4745 /* Products */;
|
productRefGroup = 682D06A32A5487D200EA4745 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
@ -292,6 +322,8 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
|
684640A72A65569D00D5A369 /* TaskDataStore.swift in Sources */,
|
||||||
|
68A773762A66F9A1000887A3 /* TaskViewModel.swift in Sources */,
|
||||||
682D06A82A5487D200EA4745 /* MainView.swift in Sources */,
|
682D06A82A5487D200EA4745 /* MainView.swift in Sources */,
|
||||||
6838051A2A57356700CEF29C /* TextFieldExtensions.swift in Sources */,
|
6838051A2A57356700CEF29C /* TextFieldExtensions.swift in Sources */,
|
||||||
680A62182A600F81004C21A4 /* Task.swift in Sources */,
|
680A62182A600F81004C21A4 /* Task.swift in Sources */,
|
||||||
@ -383,7 +415,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
MACOSX_DEPLOYMENT_TARGET = 13.4;
|
||||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
ONLY_ACTIVE_ARCH = YES;
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
@ -437,7 +469,7 @@
|
|||||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
GCC_WARN_UNUSED_FUNCTION = YES;
|
GCC_WARN_UNUSED_FUNCTION = YES;
|
||||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||||
MACOSX_DEPLOYMENT_TARGET = 13.3;
|
MACOSX_DEPLOYMENT_TARGET = 13.4;
|
||||||
MTL_ENABLE_DEBUG_INFO = NO;
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
MTL_FAST_MATH = YES;
|
MTL_FAST_MATH = YES;
|
||||||
SDKROOT = macosx;
|
SDKROOT = macosx;
|
||||||
@ -460,6 +492,7 @@
|
|||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_LSUIElement = YES;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -487,6 +520,7 @@
|
|||||||
ENABLE_HARDENED_RUNTIME = YES;
|
ENABLE_HARDENED_RUNTIME = YES;
|
||||||
ENABLE_PREVIEWS = YES;
|
ENABLE_PREVIEWS = YES;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_KEY_LSUIElement = YES;
|
||||||
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
LD_RUNPATH_SEARCH_PATHS = (
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
@ -612,6 +646,25 @@
|
|||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCRemoteSwiftPackageReference section */
|
||||||
|
684640A82A6566B300D5A369 /* XCRemoteSwiftPackageReference "SQLite.swift" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/stephencelis/SQLite.swift.git";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 0.14.1;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
684640A92A6566B300D5A369 /* SQLite */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 684640A82A6566B300D5A369 /* XCRemoteSwiftPackageReference "SQLite.swift" */;
|
||||||
|
productName = SQLite;
|
||||||
|
};
|
||||||
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = 682D069A2A5487D200EA4745 /* Project object */;
|
rootObject = 682D069A2A5487D200EA4745 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"pins" : [
|
||||||
|
{
|
||||||
|
"identity" : "sqlite.swift",
|
||||||
|
"kind" : "remoteSourceControl",
|
||||||
|
"location" : "https://github.com/stephencelis/SQLite.swift.git",
|
||||||
|
"state" : {
|
||||||
|
"revision" : "7a2e3cd27de56f6d396e84f63beefd0267b55ccb",
|
||||||
|
"version" : "0.14.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version" : 2
|
||||||
|
}
|
||||||
@ -9,6 +9,27 @@
|
|||||||
<key>orderHint</key>
|
<key>orderHint</key>
|
||||||
<integer>0</integer>
|
<integer>0</integer>
|
||||||
</dict>
|
</dict>
|
||||||
|
<key>SQLite (Playground) 1.xcscheme</key>
|
||||||
|
<dict>
|
||||||
|
<key>isShown</key>
|
||||||
|
<false/>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>2</integer>
|
||||||
|
</dict>
|
||||||
|
<key>SQLite (Playground) 2.xcscheme</key>
|
||||||
|
<dict>
|
||||||
|
<key>isShown</key>
|
||||||
|
<false/>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>3</integer>
|
||||||
|
</dict>
|
||||||
|
<key>SQLite (Playground).xcscheme</key>
|
||||||
|
<dict>
|
||||||
|
<key>isShown</key>
|
||||||
|
<false/>
|
||||||
|
<key>orderHint</key>
|
||||||
|
<integer>0</integer>
|
||||||
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
|
|||||||
15
Luto/Assets.xcassets/arrow-down.imageset/Contents.json
vendored
Normal file
15
Luto/Assets.xcassets/arrow-down.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "arrow-down.svg",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
},
|
||||||
|
"properties" : {
|
||||||
|
"template-rendering-intent" : "template"
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Luto/Assets.xcassets/arrow-down.imageset/arrow-down.svg
vendored
Normal file
3
Luto/Assets.xcassets/arrow-down.imageset/arrow-down.svg
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0 4.7725C0 4.5825 0.08 4.3825 0.23 4.2325C0.53 3.9225 1.02 3.9225 1.32 4.2325L8 10.9125L14.68 4.2325C14.98 3.9325 15.47 3.9325 15.77 4.2325C16.07 4.5325 16.07 5.0225 15.77 5.3225L8.54 12.5525C8.24 12.8525 7.75 12.8525 7.45 12.5525L0.23 5.3225C0.08 5.1725 0 4.9725 0 4.7725Z" fill="black"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 403 B |
@ -14,7 +14,7 @@ struct LutoApp: App {
|
|||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup(id: "MainWindow") {
|
WindowGroup(id: "MainWindow") {
|
||||||
MainView()
|
MainView(viewModel: TaskViewModel())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -40,8 +40,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
|||||||
self.popover = NSPopover()
|
self.popover = NSPopover()
|
||||||
self.popover.contentSize = NSSize(width: 500, height: 500)
|
self.popover.contentSize = NSSize(width: 500, height: 500)
|
||||||
self.popover.behavior = .transient
|
self.popover.behavior = .transient
|
||||||
self.popover.contentViewController = NSHostingController(rootView: MainView()
|
self.popover.contentViewController = NSHostingController(rootView: MainView(viewModel: TaskViewModel()))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func togglePopover() {
|
@objc func togglePopover() {
|
||||||
|
|||||||
@ -7,7 +7,20 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
struct Task {
|
class Task {
|
||||||
|
let id: Int64
|
||||||
var title: String
|
var title: String
|
||||||
var description: String
|
var body: String
|
||||||
|
|
||||||
|
init(title: String, body: String) {
|
||||||
|
self.id = 0
|
||||||
|
self.title = title
|
||||||
|
self.body = body
|
||||||
|
}
|
||||||
|
|
||||||
|
init(id: Int64, title: String, body: String) {
|
||||||
|
self.id = id
|
||||||
|
self.title = title
|
||||||
|
self.body = body
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
138
Luto/Store/TaskDataStore.swift
Normal file
138
Luto/Store/TaskDataStore.swift
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
//
|
||||||
|
// TaskDataStore.swift
|
||||||
|
// Luto
|
||||||
|
//
|
||||||
|
// Created by Pierre Boulc'h on 17/07/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SQLite
|
||||||
|
|
||||||
|
class TaskDataStore {
|
||||||
|
|
||||||
|
static let DIR_TASK_DB = "TaskDB"
|
||||||
|
static let STORE_NAME = "task.sqlite3"
|
||||||
|
|
||||||
|
private let tasks = Table("tasks")
|
||||||
|
|
||||||
|
private let id = Expression<Int64>("id")
|
||||||
|
private let title = Expression<String>("title")
|
||||||
|
private let body = Expression<String>("body")
|
||||||
|
|
||||||
|
static let shared = TaskDataStore()
|
||||||
|
|
||||||
|
private var db: Connection? = nil
|
||||||
|
|
||||||
|
private init() {
|
||||||
|
if let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
|
||||||
|
let dirPath = docDir.appendingPathComponent(Self.DIR_TASK_DB)
|
||||||
|
|
||||||
|
do {
|
||||||
|
try FileManager.default.createDirectory(atPath: dirPath.path, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
let dbPath = dirPath.appendingPathComponent(Self.STORE_NAME).path
|
||||||
|
db = try Connection(dbPath)
|
||||||
|
createTable()
|
||||||
|
print("SQLiteDataStore init successfully at: \(dbPath) ")
|
||||||
|
} catch {
|
||||||
|
db = nil
|
||||||
|
print("SQLiteDataStore init error: \(error)")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
db = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func createTable() {
|
||||||
|
guard let database = db else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
try database.run(tasks.create { table in
|
||||||
|
table.column(id, primaryKey: .autoincrement)
|
||||||
|
table.column(title)
|
||||||
|
table.column(body)
|
||||||
|
})
|
||||||
|
print("Table Created...")
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func insert(name: String, description: String) -> Int64? {
|
||||||
|
guard let database = db else { return nil }
|
||||||
|
|
||||||
|
let insert = tasks.insert(self.title <- name,
|
||||||
|
self.body <- description)
|
||||||
|
|
||||||
|
do {
|
||||||
|
let rowID = try database.run(insert)
|
||||||
|
return rowID
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAllTasks() -> [Task] {
|
||||||
|
var tasks: [Task] = []
|
||||||
|
guard let database = db else { return [] }
|
||||||
|
|
||||||
|
do {
|
||||||
|
for task in try database.prepare(self.tasks) {
|
||||||
|
tasks.append(Task(id: task[id], title: task[title], body: task[body]))
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
return tasks
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
func findTask(taskId: Int64) -> Task? {
|
||||||
|
var task: Task = Task(id: taskId, title: "", body: "")
|
||||||
|
guard let database = db else { return nil }
|
||||||
|
|
||||||
|
let filter = self.tasks.filter(id == taskId)
|
||||||
|
do {
|
||||||
|
for t in try database.prepare(filter) {
|
||||||
|
task.title = t[title]
|
||||||
|
task.body = t[body]
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
return task
|
||||||
|
}
|
||||||
|
|
||||||
|
func update(id: Int64, name: String, date: Date = Date(), status: Bool = false) -> Bool {
|
||||||
|
guard let database = db else { return false }
|
||||||
|
|
||||||
|
let task = tasks.filter(self.id == id)
|
||||||
|
do {
|
||||||
|
let update = task.update([
|
||||||
|
title <- title,
|
||||||
|
self.body <- body,
|
||||||
|
])
|
||||||
|
if try database.run(update) > 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func delete(id: Int64) -> Bool {
|
||||||
|
guard let database = db else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
let filter = tasks.filter(self.id == id)
|
||||||
|
try database.run(filter.delete())
|
||||||
|
return true
|
||||||
|
} catch {
|
||||||
|
print(error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,9 +15,10 @@ struct MainView: View {
|
|||||||
case descriptionField
|
case descriptionField
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ObservedObject var viewModel: TaskViewModel
|
||||||
|
|
||||||
@State var taskTitle = ""
|
@State var taskTitle = ""
|
||||||
@State var taskDescription = ""
|
@State var taskDescription = ""
|
||||||
@State var listTask: [Task] = []
|
|
||||||
|
|
||||||
@State var showAdditionnalFields = false
|
@State var showAdditionnalFields = false
|
||||||
|
|
||||||
@ -28,12 +29,12 @@ struct MainView: View {
|
|||||||
Text("Mes tâches")
|
Text("Mes tâches")
|
||||||
ScrollView {
|
ScrollView {
|
||||||
LazyVStack(alignment: .leading) {
|
LazyVStack(alignment: .leading) {
|
||||||
ForEach(Array(listTask.enumerated()), id: \.offset) { index, task in
|
ForEach(Array(viewModel.allTask.enumerated()), id: \.offset) { index, task in
|
||||||
HStack {
|
HStack {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
Text("\(task.title)").font(.system(size: 16))
|
Text("\(task.title)").font(.system(size: 16))
|
||||||
if !task.description.isEmpty {
|
if !task.body.isEmpty {
|
||||||
Text("\(task.description)")
|
Text("\(task.body)")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 8))
|
.padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 8))
|
||||||
@ -60,6 +61,8 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
}.onSubmit {
|
}.onSubmit {
|
||||||
addTask()
|
addTask()
|
||||||
|
}.onAppear {
|
||||||
|
focusState = .titleField
|
||||||
}
|
}
|
||||||
Button(action: {
|
Button(action: {
|
||||||
addTask()
|
addTask()
|
||||||
@ -74,6 +77,13 @@ struct MainView: View {
|
|||||||
TextField("Description ...", text: $taskDescription).focused($focusState, equals: .descriptionField).textFieldStyle(OvalTextFieldStyle()).padding(EdgeInsets(top: 8, leading: 0, bottom: 0, trailing: 0)).onSubmit {
|
TextField("Description ...", text: $taskDescription).focused($focusState, equals: .descriptionField).textFieldStyle(OvalTextFieldStyle()).padding(EdgeInsets(top: 8, leading: 0, bottom: 0, trailing: 0)).onSubmit {
|
||||||
addTask()
|
addTask()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Button(action: {
|
||||||
|
showAdditionnalFields = true
|
||||||
|
}, label: {
|
||||||
|
Image("arrow-down").tint(Color.white)
|
||||||
|
}).buttonStyle(PlainButtonStyle())
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding()
|
.padding()
|
||||||
@ -83,7 +93,7 @@ struct MainView: View {
|
|||||||
func addTask() {
|
func addTask() {
|
||||||
if !taskTitle.isEmpty {
|
if !taskTitle.isEmpty {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
listTask.append(Task(title: taskTitle, description: taskDescription))
|
viewModel.addTask(name: taskTitle, body: taskDescription)
|
||||||
}
|
}
|
||||||
taskTitle = ""
|
taskTitle = ""
|
||||||
taskDescription = ""
|
taskDescription = ""
|
||||||
@ -93,14 +103,8 @@ struct MainView: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func removeTask(index: Int) {
|
func removeTask(index: Int) {
|
||||||
_ = withAnimation {
|
withAnimation {
|
||||||
listTask.remove(at: index)
|
viewModel.deleteTask(at: IndexSet([index]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MainView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
MainView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
39
Luto/ViewModels/TaskViewModel.swift
Normal file
39
Luto/ViewModels/TaskViewModel.swift
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
//
|
||||||
|
// TaskViewModel.swift
|
||||||
|
// Luto
|
||||||
|
//
|
||||||
|
// Created by Pierre Boulc'h on 18/07/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
class TaskViewModel: ObservableObject {
|
||||||
|
|
||||||
|
@Published var allTask: [Task] = []
|
||||||
|
|
||||||
|
init() {
|
||||||
|
getTaskList()
|
||||||
|
}
|
||||||
|
|
||||||
|
func addTask(name: String, body: String) {
|
||||||
|
let id = TaskDataStore.shared.insert(name: name, description: body)
|
||||||
|
if id != 0 {
|
||||||
|
getTaskList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func getTaskList() {
|
||||||
|
allTask = TaskDataStore.shared.getAllTasks()
|
||||||
|
}
|
||||||
|
|
||||||
|
func deleteTask(at indexSet: IndexSet) {
|
||||||
|
let id = indexSet.map { self.allTask[$0].id }.first
|
||||||
|
if let id = id {
|
||||||
|
let delete = TaskDataStore.shared.delete(id: id)
|
||||||
|
if delete {
|
||||||
|
getTaskList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user