mirror of
https://github.com/pboulch/luto.git
synced 2025-12-18 20:42:45 +00:00
🎉 first commit
This commit is contained in:
90
.gitignore
vendored
Normal file
90
.gitignore
vendored
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Xcode
|
||||||
|
#
|
||||||
|
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
|
||||||
|
|
||||||
|
## User settings
|
||||||
|
xcuserdata/
|
||||||
|
|
||||||
|
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
|
||||||
|
*.xcscmblueprint
|
||||||
|
*.xccheckout
|
||||||
|
|
||||||
|
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
|
||||||
|
build/
|
||||||
|
DerivedData/
|
||||||
|
*.moved-aside
|
||||||
|
*.pbxuser
|
||||||
|
!default.pbxuser
|
||||||
|
*.mode1v3
|
||||||
|
!default.mode1v3
|
||||||
|
*.mode2v3
|
||||||
|
!default.mode2v3
|
||||||
|
*.perspectivev3
|
||||||
|
!default.perspectivev3
|
||||||
|
|
||||||
|
## Obj-C/Swift specific
|
||||||
|
*.hmap
|
||||||
|
|
||||||
|
## App packaging
|
||||||
|
*.ipa
|
||||||
|
*.dSYM.zip
|
||||||
|
*.dSYM
|
||||||
|
|
||||||
|
## Playgrounds
|
||||||
|
timeline.xctimeline
|
||||||
|
playground.xcworkspace
|
||||||
|
|
||||||
|
# Swift Package Manager
|
||||||
|
#
|
||||||
|
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
|
||||||
|
# Packages/
|
||||||
|
# Package.pins
|
||||||
|
# Package.resolved
|
||||||
|
# *.xcodeproj
|
||||||
|
#
|
||||||
|
# Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata
|
||||||
|
# hence it is not needed unless you have added a package configuration file to your project
|
||||||
|
# .swiftpm
|
||||||
|
|
||||||
|
.build/
|
||||||
|
|
||||||
|
# CocoaPods
|
||||||
|
#
|
||||||
|
# We recommend against adding the Pods directory to your .gitignore. However
|
||||||
|
# you should judge for yourself, the pros and cons are mentioned at:
|
||||||
|
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
|
||||||
|
#
|
||||||
|
# Pods/
|
||||||
|
#
|
||||||
|
# Add this line if you want to avoid checking in source code from the Xcode workspace
|
||||||
|
# *.xcworkspace
|
||||||
|
|
||||||
|
# Carthage
|
||||||
|
#
|
||||||
|
# Add this line if you want to avoid checking in source code from Carthage dependencies.
|
||||||
|
# Carthage/Checkouts
|
||||||
|
|
||||||
|
Carthage/Build/
|
||||||
|
|
||||||
|
# Accio dependency management
|
||||||
|
Dependencies/
|
||||||
|
.accio/
|
||||||
|
|
||||||
|
# fastlane
|
||||||
|
#
|
||||||
|
# It is recommended to not store the screenshots in the git repo.
|
||||||
|
# Instead, use fastlane to re-generate the screenshots whenever they are needed.
|
||||||
|
# For more information about the recommended setup visit:
|
||||||
|
# https://docs.fastlane.tools/best-practices/source-control/#source-control
|
||||||
|
|
||||||
|
fastlane/report.xml
|
||||||
|
fastlane/Preview.html
|
||||||
|
fastlane/screenshots/**/*.png
|
||||||
|
fastlane/test_output
|
||||||
|
|
||||||
|
# Code Injection
|
||||||
|
#
|
||||||
|
# After new code Injection tools there's a generated folder /iOSInjectionProject
|
||||||
|
# https://github.com/johnno1962/injectionforxcode
|
||||||
|
|
||||||
|
iOSInjectionProject/
|
||||||
@ -7,13 +7,15 @@
|
|||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
|
680A62122A5F475D004C21A4 /* ViewExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 680A62112A5F475D004C21A4 /* ViewExtensions.swift */; };
|
||||||
682D06A62A5487D200EA4745 /* LutoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06A52A5487D200EA4745 /* LutoApp.swift */; };
|
682D06A62A5487D200EA4745 /* LutoApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06A52A5487D200EA4745 /* LutoApp.swift */; };
|
||||||
682D06A82A5487D200EA4745 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06A72A5487D200EA4745 /* ContentView.swift */; };
|
682D06A82A5487D200EA4745 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06A72A5487D200EA4745 /* MainView.swift */; };
|
||||||
682D06AA2A5487D500EA4745 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 682D06A92A5487D500EA4745 /* Assets.xcassets */; };
|
682D06AA2A5487D500EA4745 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 682D06A92A5487D500EA4745 /* Assets.xcassets */; };
|
||||||
682D06AD2A5487D500EA4745 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 682D06AC2A5487D500EA4745 /* Preview Assets.xcassets */; };
|
682D06AD2A5487D500EA4745 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 682D06AC2A5487D500EA4745 /* Preview Assets.xcassets */; };
|
||||||
682D06B82A5487D600EA4745 /* LutoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06B72A5487D600EA4745 /* LutoTests.swift */; };
|
682D06B82A5487D600EA4745 /* LutoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 682D06B72A5487D600EA4745 /* LutoTests.swift */; };
|
||||||
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 */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@ -34,9 +36,10 @@
|
|||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
|
680A62112A5F475D004C21A4 /* ViewExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewExtensions.swift; sourceTree = "<group>"; };
|
||||||
682D06A22A5487D200EA4745 /* Luto.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Luto.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
682D06A22A5487D200EA4745 /* Luto.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Luto.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
682D06A52A5487D200EA4745 /* LutoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LutoApp.swift; sourceTree = "<group>"; };
|
682D06A52A5487D200EA4745 /* LutoApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LutoApp.swift; sourceTree = "<group>"; };
|
||||||
682D06A72A5487D200EA4745 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
682D06A72A5487D200EA4745 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
|
||||||
682D06A92A5487D500EA4745 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
682D06A92A5487D500EA4745 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||||
682D06AC2A5487D500EA4745 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
682D06AC2A5487D500EA4745 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
682D06AE2A5487D500EA4745 /* Luto.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Luto.entitlements; sourceTree = "<group>"; };
|
682D06AE2A5487D500EA4745 /* Luto.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Luto.entitlements; sourceTree = "<group>"; };
|
||||||
@ -45,6 +48,7 @@
|
|||||||
682D06BD2A5487D600EA4745 /* LutoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LutoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
682D06BD2A5487D600EA4745 /* LutoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LutoUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
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>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@ -72,6 +76,15 @@
|
|||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
|
680A620F2A5F4739004C21A4 /* Utils */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
683805192A57356700CEF29C /* TextFieldExtensions.swift */,
|
||||||
|
680A62112A5F475D004C21A4 /* ViewExtensions.swift */,
|
||||||
|
);
|
||||||
|
path = Utils;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
682D06992A5487D200EA4745 = {
|
682D06992A5487D200EA4745 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -95,8 +108,8 @@
|
|||||||
682D06A42A5487D200EA4745 /* Luto */ = {
|
682D06A42A5487D200EA4745 /* Luto */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
683805182A57354900CEF29C /* UI */,
|
||||||
682D06A52A5487D200EA4745 /* LutoApp.swift */,
|
682D06A52A5487D200EA4745 /* LutoApp.swift */,
|
||||||
682D06A72A5487D200EA4745 /* ContentView.swift */,
|
|
||||||
682D06A92A5487D500EA4745 /* Assets.xcassets */,
|
682D06A92A5487D500EA4745 /* Assets.xcassets */,
|
||||||
682D06AE2A5487D500EA4745 /* Luto.entitlements */,
|
682D06AE2A5487D500EA4745 /* Luto.entitlements */,
|
||||||
682D06AB2A5487D500EA4745 /* Preview Content */,
|
682D06AB2A5487D500EA4745 /* Preview Content */,
|
||||||
@ -129,6 +142,15 @@
|
|||||||
path = LutoUITests;
|
path = LutoUITests;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
683805182A57354900CEF29C /* UI */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
682D06A72A5487D200EA4745 /* MainView.swift */,
|
||||||
|
680A620F2A5F4739004C21A4 /* Utils */,
|
||||||
|
);
|
||||||
|
path = UI;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
/* End PBXGroup section */
|
/* End PBXGroup section */
|
||||||
|
|
||||||
/* Begin PBXNativeTarget section */
|
/* Begin PBXNativeTarget section */
|
||||||
@ -259,7 +281,9 @@
|
|||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
files = (
|
files = (
|
||||||
682D06A82A5487D200EA4745 /* ContentView.swift in Sources */,
|
682D06A82A5487D200EA4745 /* MainView.swift in Sources */,
|
||||||
|
6838051A2A57356700CEF29C /* TextFieldExtensions.swift in Sources */,
|
||||||
|
680A62122A5F475D004C21A4 /* ViewExtensions.swift in Sources */,
|
||||||
682D06A62A5487D200EA4745 /* LutoApp.swift in Sources */,
|
682D06A62A5487D200EA4745 /* LutoApp.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|||||||
@ -1,6 +1,15 @@
|
|||||||
{
|
{
|
||||||
"colors" : [
|
"colors" : [
|
||||||
{
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0",
|
||||||
|
"green" : "205",
|
||||||
|
"red" : "255"
|
||||||
|
}
|
||||||
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
//
|
|
||||||
// ContentView.swift
|
|
||||||
// Luto
|
|
||||||
//
|
|
||||||
// Created by Pierre Boulc'h on 04/07/2023.
|
|
||||||
//
|
|
||||||
|
|
||||||
import SwiftUI
|
|
||||||
|
|
||||||
struct ContentView: View {
|
|
||||||
var body: some View {
|
|
||||||
VStack {
|
|
||||||
Image(systemName: "globe")
|
|
||||||
.imageScale(.large)
|
|
||||||
.foregroundColor(.accentColor)
|
|
||||||
Text("Hello, world!")
|
|
||||||
}
|
|
||||||
.padding()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ContentView_Previews: PreviewProvider {
|
|
||||||
static var previews: some View {
|
|
||||||
ContentView()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,9 +9,51 @@ import SwiftUI
|
|||||||
|
|
||||||
@main
|
@main
|
||||||
struct LutoApp: App {
|
struct LutoApp: App {
|
||||||
|
|
||||||
|
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
||||||
|
|
||||||
var body: some Scene {
|
var body: some Scene {
|
||||||
WindowGroup {
|
WindowGroup(id: "MainWindow") {
|
||||||
ContentView()
|
MainView(taskTitle: "", taskDescription: "", listTask: [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class AppDelegate: NSObject, NSApplicationDelegate, ObservableObject {
|
||||||
|
|
||||||
|
private var statusItem: NSStatusItem!
|
||||||
|
private var popover: NSPopover!
|
||||||
|
|
||||||
|
@MainActor func applicationDidFinishLaunching(_ notification: Notification) {
|
||||||
|
|
||||||
|
if let window = NSApplication.shared.windows.first {
|
||||||
|
window.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||||
|
|
||||||
|
if let statusButton = statusItem.button {
|
||||||
|
statusButton.image = NSImage(systemSymbolName: "brain", accessibilityDescription: "Chart Line")
|
||||||
|
statusButton.action = #selector(togglePopover)
|
||||||
|
}
|
||||||
|
|
||||||
|
self.popover = NSPopover()
|
||||||
|
self.popover.contentSize = NSSize(width: 500, height: 500)
|
||||||
|
self.popover.behavior = .transient
|
||||||
|
self.popover.contentViewController = NSHostingController(rootView: MainView(taskTitle: "", taskDescription: "", listTask: [])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func togglePopover() {
|
||||||
|
|
||||||
|
if let button = statusItem.button {
|
||||||
|
if popover.isShown {
|
||||||
|
self.popover.performClose(nil)
|
||||||
|
} else {
|
||||||
|
popover.show(relativeTo: button.bounds, of: button, preferredEdge: NSRectEdge.minY)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
94
Luto/UI/MainView.swift
Normal file
94
Luto/UI/MainView.swift
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
//
|
||||||
|
// ContentView.swift
|
||||||
|
// Luto
|
||||||
|
//
|
||||||
|
// Created by Pierre Boulc'h on 04/07/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import AppKit
|
||||||
|
|
||||||
|
struct MainView: View {
|
||||||
|
|
||||||
|
@State var taskTitle = ""
|
||||||
|
@State var taskDescription = ""
|
||||||
|
@State var listTask: [String] = []
|
||||||
|
|
||||||
|
@State var showAdditionnalFields = false
|
||||||
|
@FocusState private var titleFieldInFocus: Bool
|
||||||
|
@FocusState private var descriptionFieldInFocus: Bool
|
||||||
|
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
VStack {
|
||||||
|
Text("Mes tâches")
|
||||||
|
LazyVStack(alignment: .leading) {
|
||||||
|
ForEach(Array(listTask.enumerated()), id: \.offset) { index, task in
|
||||||
|
HStack {
|
||||||
|
Text("\(task)")
|
||||||
|
.padding(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 8))
|
||||||
|
Spacer()
|
||||||
|
Button(action: {
|
||||||
|
removeTask(index: index)
|
||||||
|
}, label: {
|
||||||
|
Image(systemName: "trash")
|
||||||
|
}).buttonStyle(PlainButtonStyle()).padding(12)
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
}.border(width: 5, edges: [.leading], color: .accentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
HStack {
|
||||||
|
TextField("Titre de la tâche ...", text: $taskTitle).focused($titleFieldInFocus).onChange(of: titleFieldInFocus) { isFocused in
|
||||||
|
if !isFocused {
|
||||||
|
withAnimation {
|
||||||
|
showAdditionnalFields = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.onSubmit {
|
||||||
|
addTask()
|
||||||
|
}
|
||||||
|
Button(action: {
|
||||||
|
addTask()
|
||||||
|
}, label: {
|
||||||
|
Image(systemName: "plus")
|
||||||
|
}).buttonStyle(PlainButtonStyle()).padding(12)
|
||||||
|
.background(Color.accentColor)
|
||||||
|
.foregroundColor(.black)
|
||||||
|
.cornerRadius(24)
|
||||||
|
}.textFieldStyle(OvalTextFieldStyle())
|
||||||
|
if showAdditionnalFields {
|
||||||
|
TextField("Description", text: $taskDescription).focused($descriptionFieldInFocus)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.padding()
|
||||||
|
.frame(width: 500, height: 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addTask() {
|
||||||
|
if !taskTitle.isEmpty {
|
||||||
|
withAnimation {
|
||||||
|
listTask.append(taskTitle)
|
||||||
|
}
|
||||||
|
taskTitle = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func removeTask(index: Int) {
|
||||||
|
_ = withAnimation {
|
||||||
|
listTask.remove(at: index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(taskTitle: String = "", taskDescription: String = "", listTask: [String]) {
|
||||||
|
self.taskTitle = taskTitle
|
||||||
|
self.taskDescription = taskDescription
|
||||||
|
self.listTask = listTask
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MainView_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
MainView(taskTitle: "", taskDescription: "", listTask: [])
|
||||||
|
}
|
||||||
|
}
|
||||||
32
Luto/UI/Utils/TextFieldExtensions.swift
Normal file
32
Luto/UI/Utils/TextFieldExtensions.swift
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
//
|
||||||
|
// TextFieldExtensions.swift
|
||||||
|
// Luto
|
||||||
|
//
|
||||||
|
// Created by Pierre Boulc'h on 06/07/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct OvalTextFieldStyle: TextFieldStyle {
|
||||||
|
func _body(configuration: TextField<Self._Label>) -> some View {
|
||||||
|
configuration
|
||||||
|
.textFieldStyle(.plain)
|
||||||
|
.colorMultiply(.gray)
|
||||||
|
.padding(10)
|
||||||
|
.tint(.gray)
|
||||||
|
.foregroundColor(.black)
|
||||||
|
.background(.white)
|
||||||
|
.cornerRadius(20)
|
||||||
|
.shadow(color: .accentColor, radius: 2)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension NSTextField {
|
||||||
|
open override var focusRingType: NSFocusRingType {
|
||||||
|
get { .none }
|
||||||
|
set { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
31
Luto/UI/Utils/ViewExtensions.swift
Normal file
31
Luto/UI/Utils/ViewExtensions.swift
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
//
|
||||||
|
// ViewExtensions.swift
|
||||||
|
// Luto
|
||||||
|
//
|
||||||
|
// Created by Pierre Boulc'h on 12/07/2023.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
extension View {
|
||||||
|
func border(width: CGFloat, edges: [Edge], color: Color) -> some View {
|
||||||
|
overlay(EdgeBorder(width: width, edges: edges).foregroundColor(color))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EdgeBorder: Shape {
|
||||||
|
var width: CGFloat
|
||||||
|
var edges: [Edge]
|
||||||
|
|
||||||
|
func path(in rect: CGRect) -> Path {
|
||||||
|
edges.map { edge -> Path in
|
||||||
|
switch edge {
|
||||||
|
case .top: return Path(.init(x: rect.minX, y: rect.minY, width: rect.width, height: width))
|
||||||
|
case .bottom: return Path(.init(x: rect.minX, y: rect.maxY - width, width: rect.width, height: width))
|
||||||
|
case .leading: return Path(.init(x: rect.minX, y: rect.minY, width: width, height: rect.height))
|
||||||
|
case .trailing: return Path(.init(x: rect.maxX - width, y: rect.minY, width: width, height: rect.height))
|
||||||
|
}
|
||||||
|
}.reduce(into: Path()) { $0.addPath($1) }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user