implment task panner app with SwiftUI

  • first step is create taskPlanner project with xcode
  • add custom fonts image.png add costom properties for fonts image.png image.png Ubuntu.swift
import SwiftUI
/// MARK :custom font extension
enum Ubuntu{
case light
case bold
case medium
case regular
var weight:Font.Weight{
switch self{
case .light:
return .light
case .bold:
return .bold
case .medium:
return .medium
case .regular:
return .regular
}
}
}
extension View{
func Ubuntu(_ size:CGFloat,_ weight:Ubuntu)->some View{
self.font(.custom("ubuntu", size: size))
.fontWeight(weight.weight)
}
}

Task.swift

import SwiftUI
//MARK:Task model
struct Task:Identifiable{
var id:UUID = UUID()
var dateadded:Date
var taskName:String
var taskDescription:String
var taskCategory:Category
}
enum Category:String, CaseIterable{
case bug="bug"
case general="general"
case idea="idea"
case challenge="challenge"
case coding="coding"
case modifiers="modifiers"


var color:Color{
switch self{
case .bug:
return Color.green
case .general:
return Color.gray
case .idea:
return Color.pink
case .challenge:
return Color.purple
case .coding:
return Color.brown
case .modifiers:
return Color.clear
}
}
}
var sampleTasks:[Task] = [
.init(dateadded: Date(timeIntervalSince1970:1672948935), taskName: "Learn Swift", taskDescription: "", taskCategory: .coding),
.init(dateadded: Date(timeIntervalSince1970:1672946935), taskName: "Learn Swift", taskDescription: "", taskCategory: .coding),
.init(dateadded: Date(timeIntervalSince1970:1672946935), taskName: "Learn Swift", taskDescription: "", taskCategory: .coding),
.init(dateadded: Date(timeIntervalSince1970:1672936935), taskName: "Learn Swift", taskDescription: "", taskCategory: .coding),
.init(dateadded: Date(timeIntervalSince1970:1672946935), taskName: "Learn Swift", taskDescription: "", taskCategory: .coding)
]

Home.swift

import SwiftUI
struct Home: View {
/// View propertyes
@State private var currentDay:Date = .init()
@State private var tasks:[Task] = sampleTasks
@State private var addNewTask:Bool = false
var body: some View {
ScrollView(.vertical,showsIndicators: false){
TimelineView().padding(15)
}.safeAreaInset(edge: .top,spacing: 0){
HeaderView()

}.fullScreenCover(isPresented: $addNewTask){
AddNewView()
}
}
/// - Time Line View
@ViewBuilder
func TimelineView()->some View{
VStack{
let hovers = Calendar.current.hovers
ForEach(hovers,id:\.self){hover in
TimelineViewRow(hover)
}
}

}
@ViewBuilder
func TimelineViewRow(_ date:Date)->some View{
HStack(alignment: .top){
Text(date.toString("h a")).Ubuntu(14, .regular).frame(width: 45,alignment: .leading)

///Filtring taks
let calendar = Calendar.current
let filteredTasks =  tasks.filter{
if let hour = calendar.dateComponents([.hour], from:date ).hour,
let taskHour = calendar.dateComponents([.hour], from: $0.dateadded).hour,
hour==taskHour && calendar.isDate($0.dateadded, inSameDayAs: currentDay){
return true
}
return false
}
if filteredTasks.isEmpty{
Rectangle().stroke(.gray.opacity(0.5),style: StrokeStyle(lineWidth: 0.5,lineCap: .butt,lineJoin: .bevel,dash: [5],dashPhase: 5))
.frame(height: 0.5)
.offset(y:10)
}else{
VStack(spacing: 10){
ForEach(filteredTasks){task in
TaskRow(task)

}
}
}

}.hAlign(.leading)
.padding(.vertical,15)
}
@ViewBuilder
func TaskRow(_ task:Task)->some View{
VStack(alignment: .leading,spacing: 8){
Text(task.taskName.uppercased()).Ubuntu(16, .regular).foregroundColor(task.taskCategory.color)
if task.taskDescription != ""{
Text(task.taskDescription).Ubuntu(14, .light)
.foregroundColor(task.taskCategory.color.opacity(0.8))
}
}.hAlign(.leading)
.padding(12)
.background{
ZStack(alignment: .leading){
Rectangle().fill(task.taskCategory.color).frame(width: 4)
Rectangle().fill(task.taskCategory.color.opacity(0.25 ))
}
}

}
/// - Header View
@ViewBuilder
func HeaderView()->some View{
VStack{
HStack{
VStack(alignment: .leading,spacing: 6){
Text("今天").Ubuntu(30, .regular)

Text("欢迎使用日历计划App").Ubuntu(14, .light)
}.hAlign(.leading)
Button{
addNewTask.toggle()
}label: {
HStack(spacing: 10){
Image(systemName: "plus")
Text("添加任务").Ubuntu(15, .regular)
}
}.padding(.vertical,10).padding(.horizontal,15).background{
Capsule().fill(Color.blue.gradient)
}.foregroundColor(.white)
}

/// Today date in string
Text(Date().toString("MMM YYYY")).Ubuntu(16, .medium).hAlign(.leading)
.padding(.top,15)


//Week row
WeekRowView()

}.padding(15)
.background{
VStack(spacing: 0){
Color.white
Rectangle().fill(.linearGradient(colors: [.white,.clear], startPoint: .top, endPoint: .bottom))
.frame(height: 20)
}.ignoresSafeArea()
}
}
/// - Week Row View
@ViewBuilder
func WeekRowView()->some View{
HStack(spacing: 0){
ForEach(Calendar.current.currentWeek){ weekDay in
let staus = Calendar.current.isDate(weekDay.date, inSameDayAs: currentDay)
VStack{
Text(weekDay.string.prefix(3))
.Ubuntu(13, .medium)
Text(weekDay.date.toString("dd"))
.Ubuntu(16, .regular)
}
.foregroundColor(staus ? Color.blue:Color.gray)
.hAlign(.center)
.contentShape(Rectangle())
.onTapGesture {
withAnimation(.easeInOut(duration: 0.3)){
currentDay = weekDay.date
}
}
}
}.padding(.horizontal,-15)
}


}
struct Home_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}
///MARK:View extensions
extension View{
func hAlign(_ alignment:Alignment)->some View{
self.frame(maxWidth: .infinity,alignment: alignment)
}
func vAlign(_ alignment:Alignment)->some View{
self.frame(maxHeight: .infinity,alignment: alignment)
}
}
///MARK:Date extension
extension Date{
func toString(_ format:String)->String{
let formatter = DateFormatter()
formatter.dateFormat = format
return formatter.string(from: self)
}

}
///MARK:Calendar extension
extension Calendar{
///return 24 hover in a day
var hovers:[Date]{
let startOfDay = self.startOfDay(for: Date())
var hovers:[Date] = []
for index in 0..<24{
if let date = self.date(byAdding: .hour, value: index, to: startOfDay){
hovers.append(date)
}
}
return hovers
}

/// return current week in Array format
var currentWeek:[WeekDay]{
guard let firstWeekDay = self.dateInterval(of: .weekOfMonth, for: Date())?.start else{
return []
}
var week:[WeekDay] = []
for index in 0..<7{
if let day = self.date(byAdding: .day, value: index, to: firstWeekDay){
let weekDaySymbol:String = day.toString("EEEE")
let isToday = self.isDateInToday(day)
week.append(.init(string: weekDaySymbol, date: day,isToday: isToday))
}
}
return week
}
struct WeekDay:Identifiable{
var id:UUID = .init()
var string:String
var date:Date
var isToday:Bool = false
}
}

ContentView.swift

import SwiftUI
struct ContentView: View {
var body: some View {
VStack {


}
.padding()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Home()
}
}

TaskPlannerApp.swift

import SwiftUI
@main
struct TaskPlannerApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}