🎉 first commit

This commit is contained in:
2023-07-13 11:56:17 +02:00
parent 92e03bc310
commit 3ad6ee9134
8 changed files with 328 additions and 32 deletions

View File

@ -1,6 +1,15 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0",
"green" : "205",
"red" : "255"
}
},
"idiom" : "universal"
}
],

View File

@ -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()
}
}

View File

@ -9,9 +9,51 @@ import SwiftUI
@main
struct LutoApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
WindowGroup(id: "MainWindow") {
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
View 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: [])
}
}

View 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 { }
}
}

View 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) }
}
}