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