Skip to content

Commit

Permalink
feat: activity attribue를 state로 변경
Browse files Browse the repository at this point in the history
  • Loading branch information
mooyoung2309 committed May 29, 2023
1 parent c1a2d1f commit 07ad220
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 46 deletions.
25 changes: 12 additions & 13 deletions taskfolio/DynamicWidget/DynamicWidgetLiveActivity.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@ import SwiftUI
struct DynamicWidgetAttributes: ActivityAttributes {
public struct ContentState: Codable, Hashable {
// Dynamic stateful properties about your activity go here!
var time: Int
var title: String
var colorType: Int16
var time: Int32
var isTimerActive: Bool = true
}

// Fixed non-changing properties about your activity go here!
var id: UUID
var title: String
var colorType: Int16
}

struct DynamicWidgetLiveActivity: Widget {
Expand All @@ -29,9 +28,9 @@ struct DynamicWidgetLiveActivity: Widget {
HStack {
Divider()
.frame(width: 3, height: 15)
.overlay(ColorType.toDomain(int16: context.attributes.colorType).color)
.overlay(ColorType.toDomain(int16: context.state.colorType).color)

Text(context.attributes.title)
Text(context.state.title)
.font(.title2)

Spacer()
Expand All @@ -40,7 +39,7 @@ struct DynamicWidgetLiveActivity: Widget {
Image(systemName: context.state.isTimerActive ? "pause.circle" : "play.circle")
.font(.title2)

Text(TimeManager.shared.toString(second: context.state.time))
Text(TimeManager.shared.toString(second: Int(context.state.time)))
.font(.caption)
}
}
Expand All @@ -56,13 +55,13 @@ struct DynamicWidgetLiveActivity: Widget {
HStack {
Divider()
.frame(width: 3, height: 15)
.overlay(ColorType.toDomain(int16: context.attributes.colorType).color)
.overlay(ColorType.toDomain(int16: context.state.colorType).color)

Text(context.attributes.title)
Text(context.state.title)
}
}
DynamicIslandExpandedRegion(.trailing) {
Text(TimeManager.shared.toString(second: context.state.time))
Text(TimeManager.shared.toString(second: Int(context.state.time)))
}
DynamicIslandExpandedRegion(.bottom) {

Expand All @@ -71,12 +70,12 @@ struct DynamicWidgetLiveActivity: Widget {
HStack {
Divider()
.frame(width: 3, height: 15)
.overlay(ColorType.toDomain(int16: context.attributes.colorType).color)
.overlay(ColorType.toDomain(int16: context.state.colorType).color)

Text(context.attributes.title)
Text(context.state.title)
}
} compactTrailing: {
Text(TimeManager.shared.toString(second: context.state.time))
Text(TimeManager.shared.toString(second: Int(context.state.time)))
.font(.caption)
} minimal: {
VStack(alignment: .center) {
Expand Down
Binary file not shown.
74 changes: 42 additions & 32 deletions taskfolio/taskfolio/Feature/Home/HomeStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ struct HomeStore: ReducerProtocol {
var taskListCells: IdentifiedArrayOf<TaskCellStore.State> = []
var filteredTaskListCells: IdentifiedArrayOf<TaskCellStore.State> = []
var editTask: EditTaskStore.State?
var setting: SettingStore.State?

//MARK: ActivityKit
var activity : Activity<DynamicWidgetAttributes>?
var activityContent: ActivityContent<DynamicWidgetAttributes.ContentState>?
}

enum Action: BindableAction, Equatable {
Expand All @@ -55,6 +55,7 @@ struct HomeStore: ReducerProtocol {
case addButtonTapped
case leftButtonTapped
case rightButtonTapped
case settingButtonTapped
case dateChanged(Date)
case delete(IndexSet)
case setSheet(isPresented: Bool)
Expand All @@ -73,10 +74,11 @@ struct HomeStore: ReducerProtocol {
//MARK: Child Action
case taskListCell(id: TaskCellStore.State.ID, action: TaskCellStore.Action)
case editTask(EditTaskStore.Action)
case setting(SettingStore.Action)

//MARK: ActivityKit
case activityRequest(id: UUID, title: String, colorType: Int16)
case activityUpdateRequest(time: Int, isTimerActive: Bool)
case activityRequest
case activityUpdateRequest(title: String, colorType: Int16, time: Int32, isTimerActive: Bool)
case activityUpdateResponse
}

Expand All @@ -93,31 +95,6 @@ struct HomeStore: ReducerProtocol {
case .binding:
return .none

case let .activityRequest(id, title, colorType):
if state.activity?.attributes.id == id { return .none }

let initialContentState = DynamicWidgetAttributes.ContentState(time: 0)
let activityAttributes = DynamicWidgetAttributes(id: id, title: title, colorType: colorType)

let content = ActivityContent(state: initialContentState, staleDate: Calendar.current.date(byAdding: .hour, value: 7, to: Date())!)
do {
state.activity = try Activity.request(attributes: activityAttributes, content: content)
} catch {
print(error)
}
return .none

case let .activityUpdateRequest(time, isTimerActive):
let content = ActivityContent<DynamicWidgetAttributes.ContentState>.init(state: .init(time: time, isTimerActive: isTimerActive), staleDate: nil)
guard let activity = state.activity else { return .none }
return .task { [activity = activity] in
await activity.update(content)
return .activityUpdateResponse
}

case .activityUpdateResponse:
return .none

case .addButtonTapped:
let newTask = taskClient.newTask()
newTask.title = "untitled"
Expand All @@ -134,14 +111,19 @@ struct HomeStore: ReducerProtocol {
case .rightButtonTapped:
return .send(.dateChanged(state.currentDate.add(byAdding: .day, value: 7)))

case .settingButtonTapped:
state.path.append(.setting)
state.setting = .init()
return .none

case let .dateChanged(date):
state.currentDate = date
state.currentWeekDates = date.weekDates()
return .send(.fetchFilteredTaskListCellsRequest(state.taskListCells, state.currentDate))

case let .delete(indexSet):
for index in indexSet {
let id = state.taskListCells[index].task.objectID
let id = state.filteredTaskListCells[index].task.objectID
taskClient.delete(id)
}
return .send(.refresh)
Expand All @@ -168,7 +150,7 @@ struct HomeStore: ReducerProtocol {
return .init(id: $0.id, task: $0.task, isTimerActive: $0.isTimerActive)
}
})))),
.send(.activityUpdateRequest(time: Int(task?.time ?? 0), isTimerActive: state.isTimerActive))
.send(.activityUpdateRequest(title: task?.title ?? "", colorType: task?.colorType ?? 0, time: task?.time ?? 0, isTimerActive: state.isTimerActive))
])

case .refresh:
Expand Down Expand Up @@ -213,7 +195,7 @@ struct HomeStore: ReducerProtocol {
state.isTimerActive = false
let task = state.taskListCells.first(where: { $0.id == id })?.task
return .concatenate([
.send(.activityRequest(id: id, title: task?.title ?? "Task", colorType: task?.colorType ?? 0)),
.send(.activityRequest),
.send(.updateTaskListCells(.init(uniqueElements: state.taskListCells.map({
let isTimerActive = $0.isTimerActive ? false : (id == $0.id)
state.timerTaskCellID = isTimerActive ? id : state.timerTaskCellID
Expand All @@ -227,11 +209,39 @@ struct HomeStore: ReducerProtocol {
}
}
.cancellable(id: TimerID.self, cancelInFlight: true),
.send(.activityUpdateRequest(time: Int(task?.time ?? 0), isTimerActive: state.isTimerActive))
.send(.activityUpdateRequest(title: task?.title ?? "", colorType: task?.colorType ?? 0, time: task?.time ?? 0, isTimerActive: state.isTimerActive))
])
}
case .editTask:
return .none

case .setting:
return .none

case .activityRequest:
if state.activity != nil { return .none }

let initialContentState = DynamicWidgetAttributes.ContentState(title: "Task", colorType: 0, time: 0)
let activityAttributes = DynamicWidgetAttributes()

let content = ActivityContent(state: initialContentState, staleDate: Calendar.current.date(byAdding: .hour, value: 7, to: Date())!)
do {
state.activity = try Activity.request(attributes: activityAttributes, content: content)
} catch {
print(error)
}
return .none

case let .activityUpdateRequest(title, colorType, time, isTimerActive):
let content = ActivityContent<DynamicWidgetAttributes.ContentState>.init(state: .init(title: title, colorType: colorType, time: time, isTimerActive: isTimerActive), staleDate: nil)
guard let activity = state.activity else { return .none }
return .task { [activity = activity] in
await activity.update(content)
return .activityUpdateResponse
}

case .activityUpdateResponse:
return .none
}
}
.forEach(\.filteredTaskListCells, action: /Action.taskListCell(id:action:)) {
Expand Down
6 changes: 6 additions & 0 deletions taskfolio/taskfolio/Feature/Home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ struct HomeView: View {
EditButton()

Button(action:{
viewStore.send(.settingButtonTapped)
}) {
Image(systemName: "gearshape")
.imageScale(.medium)
Expand All @@ -134,6 +135,11 @@ struct HomeView: View {
)
.navigationDestination(for: HomeScene.self) { scene in
switch scene {
case .setting:
IfLetStore(self.store.scope(state: \.setting, action: { .setting($0) })) {
SettingView(store: $0)
}

default:
EmptyView()
}
Expand Down
23 changes: 23 additions & 0 deletions taskfolio/taskfolio/Feature/Setting/SettingStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,26 @@
//

import Foundation

import ComposableArchitecture

struct SettingStore: ReducerProtocol {
struct State: Equatable {
init() { }
}

enum Action: BindableAction, Equatable {
case binding(BindingAction<State>)
}

var body: some ReducerProtocol<State, Action> {
BindingReducer()

Reduce<State, Action> { state, action in
switch action {
case .binding:
return .none
}
}
}
}
37 changes: 36 additions & 1 deletion taskfolio/taskfolio/Feature/Setting/SettingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,39 @@
// Created by 송영모 on 2023/05/25.
//

import Foundation
import SwiftUI

import ComposableArchitecture

struct SettingView: View {
public let store: StoreOf<SettingStore>

public var body: some View {
WithViewStore(self.store, observe: { $0 }) { viewStore in
VStack(spacing: .zero) {
Form {
Text("iCloud를 허용 해주시면. iPad, WatchOS(지원예정), MacOS(지원 예정) 에서 사용가능 합니다.")

Section {
DisclosureGroup("TMI") {
Text("다이나믹 아일랜드를 사용한 타이머가 필요하다고 생각했습니다. 하지만 너무 복잡할 필요는 없어요. 걱정마세요. 이 이상으로 복잡해지지 않습니다.")
.font(.subheadline)
}

DisclosureGroup("Update Note") {
Text("다음 업데이트 예정 사항입니다.")
.font(.subheadline)
}
}
}
}
.navigationTitle("Setting")
}
}
}

struct SettingView_Previews: PreviewProvider {
static var previews: some View {
SettingView(store: .init(initialState: .init(), reducer: SettingStore()._printChanges()))
}
}
1 change: 1 addition & 0 deletions taskfolio/taskfolio/Feature/TaskList/TaskCellView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ struct TaskCellView: View {
.font(.caption)
}
}
.contentShape(Rectangle())
.onTapGesture {
viewStore.send(.tapped)
}
Expand Down

0 comments on commit 07ad220

Please sign in to comment.