はじめに
Qiita初投稿です。
勉強中のSwiftUIで自分の為にAPPを作りたい!
そんな感じです。
何を作ったの?
TODOリストにタイマーをくっつけたもの。
初めてだから無理せずシンプルに!
開発環境
Swift version 5.3.1
Xcode Version 12.5.1
code
import SwiftUI
struct TodoModel: Codable, Identifiable {
var id = UUID()
let todo: String
var imcomplete: Bool
init(todo: String, imcomplete: Bool) {
self.todo = todo
self.imcomplete = imcomplete
}
}
class TimerModel: ObservableObject {
@Published var deadLine : Date {
didSet {
UserDefaults.standard.set(deadLine, forKey: "deadLine")
}
}
init() {
deadLine = UserDefaults.standard.object(forKey: "deadLine") as? Date ?? Date()
}
}
struct ContentView: View {
init() {
UITableView.appearance().backgroundColor = UIColor.clear
}
@State private var newTodo = ""
@State private var allTodos: [TodoModel] = []
@EnvironmentObject var timerModel: TimerModel
@State var nowDate: Date = Date()
var timer: Timer {
Timer.scheduledTimer(withTimeInterval: 1, repeats: true) {_ in
self.nowDate = Date()
}
}
var body: some View {
NavigationView {
VStack {
VStack {
HStack {
DatePicker("", selection: $timerModel.deadLine, in: Date()...).labelsHidden()
}
Text("期限まであと")
.frame(maxWidth: .infinity, alignment: .center)
let timerFunc = TimerFunc(self.timerModel.deadLine)
HStack {
if timerFunc.day <= 0,
timerFunc.hour <= 0,
timerFunc.minute <= 0,
timerFunc.second <= 0 {
Text("Time Up!")
.fontWeight(.bold)
} else if timerFunc.day <= 0,
timerFunc.hour <= 0,
timerFunc.minute <= 0 {
Text("\(timerFunc.second)")
.fontWeight(.bold)
} else if timerFunc.day <= 0,
timerFunc.hour <= 0 {
Text("\(timerFunc.minute):")
.fontWeight(.bold)
Text("\(timerFunc.second)")
.fontWeight(.bold)
} else if timerFunc.day <= 0 {
Text("\(timerFunc.hour):")
.fontWeight(.bold)
Text("\(timerFunc.minute):")
.fontWeight(.bold)
Text("\(timerFunc.second)")
.fontWeight(.bold)
} else {
VStack {
Text("\(timerFunc.day) day")
.font(.largeTitle)
.fontWeight(.bold)
HStack {
Text("\(timerFunc.hour):")
.fontWeight(.bold)
Text("\(timerFunc.minute):")
.fontWeight(.bold)
Text("\(timerFunc.second)")
.fontWeight(.bold)
}
}
}
}.onAppear(perform: {_ = self.timer}).font(.title)
}
List {
ForEach (0..<allTodos.count, id: \.self) { index in
HStack {
Image(systemName: allTodos[index].imcomplete ? "square" : "checkmark.square.fill")
.foregroundColor(.blue)
Text(self.allTodos[index].todo)
Spacer()
if allTodos[index].imcomplete {
Text("")
} else {
Text("complete!")
.foregroundColor(.blue)
}
}.onTapGesture {
allTodos[index].imcomplete.toggle()
self.saveTodos()
}
}.onDelete(perform: deleteTodos)
HStack {
TextField("Add todo", text: $newTodo)
Button(action: {
guard !self.newTodo.isEmpty else { return }
self.allTodos.append(TodoModel(todo: self.newTodo, imcomplete: true))
self.newTodo = ""
self.saveTodos()
}) {
Image(systemName: "plus")
.foregroundColor(.blue)
}
}
}
}
}
.onAppear(perform: loadTodos)
}
func TimerFunc(_ date:Date) -> (day: Int, hour: Int, minute: Int, second: Int) {
let cal = Calendar(identifier: .japanese)
let timeVal = cal.dateComponents([.day, .hour, .minute, .second], from: nowDate, to: timerModel.deadLine)
return (Int(timeVal.day ?? 0),
Int(timeVal.hour ?? 0),
Int(timeVal.minute ?? 0),
Int(timeVal.second ?? 0))
}
private func saveTodos() {
UserDefaults.standard.set(try? PropertyListEncoder().encode(self.allTodos), forKey: "todosKey")
}
private func loadTodos() {
if let todosData = UserDefaults.standard.value(forKey: "todosKey") as? Data {
if let todosList = try? PropertyListDecoder().decode(Array<TodoModel>.self, from: todosData) {
self.allTodos = todosList
}
}
}
private func deleteTodos(at offsets: IndexSet) {
self.allTodos.remove(atOffsets: offsets)
saveTodos()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
.environmentObject(TimerModel())
}
}
つまずいた!
① userdefaltsに保存できない
いろいろ調べた結果、構造体及びタプル型は保存出来ないらしいのでCodableを使って処理
https://ichi.pro/swiftui-chu-toriaru-saisho-no-ios-apuri-o-sakuseisuru-212038845663015
② チェックボックスの動きと処理
.onTapGestureで解決
③ タイマーの処理と表示
参考にしたページを真似すると「0day0:0:1」とかになり「0」が邪魔なので改造した。
しかしながら、それが原因で冗長に……
https://betterprogramming.pub/make-a-simple-countdown-with-timer-and-swiftui-3ce355b54986
https://qiita.com/yuujioka/items/53f555ccba5e97bedb59
https://mt312.com/785
今後はどうするの?
せっかくなので元グラフィックデザイナーを生かして見た目もイケてるものにupdateしていこうと思う。
機能的には十分だが、タイマーを複数個別に走らせて複数のタスクリストをもてるようにしたいかな〜