@@ -19,6 +19,9 @@ final class PushNotificationViewModel: Store {
1919 var toastType : ToastType ?
2020 var isLoading : Bool = false
2121 var pendingTask : ( PushNotification , Int ) ?
22+ var sortOption : SortOption
23+ var timeFilter : TimeFilter
24+ var showUnreadOnly : Bool
2225 }
2326
2427 enum Action {
@@ -31,6 +34,10 @@ final class PushNotificationViewModel: Store {
3134 case setToast( isPresented: Bool , type: ToastType ? = nil )
3235 case setLoading( Bool )
3336 case setNotifications( [ PushNotification ] )
37+ case toggleSortOption
38+ case setTimeFilter( TimeFilter )
39+ case toggleUnreadOnly
40+ case resetFilters
3441 }
3542
3643 enum SideEffect {
@@ -47,19 +54,125 @@ final class PushNotificationViewModel: Store {
4754 case delete
4855 }
4956
50- @Published private( set) var state : State = . init( )
57+ enum SortOption : CaseIterable {
58+ case latest
59+ case oldest
60+
61+ var title : String {
62+ switch self {
63+ case . latest: return " 최신순 "
64+ case . oldest: return " 예전순 "
65+ }
66+ }
67+ }
68+
69+ enum TimeFilter : Equatable {
70+ case none
71+ case hours( Int )
72+ case days( Int )
73+
74+ var id : String {
75+ switch self {
76+ case . none: return " none "
77+ case . hours( let value) : return " hours- \( value) "
78+ case . days( let value) : return " days- \( value) "
79+ }
80+ }
81+
82+ var title : String {
83+ switch self {
84+ case . none:
85+ return " 전체 "
86+ case . hours( let value) :
87+ return " 최근 \( value) 시간 "
88+ case . days( let value) :
89+ return " 최근 \( value) 일 "
90+ }
91+ }
92+
93+ static var availableOptions : [ TimeFilter ] { [
94+ . none,
95+ . hours( 1 ) ,
96+ . hours( 6 ) ,
97+ . hours( 24 ) ,
98+ . days( 3 ) ,
99+ . days( 7 )
100+ ]
101+ }
102+
103+ init ( id: String ) {
104+ if id == " none " {
105+ self = . none
106+ } else if id. hasPrefix ( " hours- " ) {
107+ let value = Int ( id. replacingOccurrences ( of: " hours- " , with: " " ) ) ?? 0
108+ self = value > 0 ? . hours( value) : . none
109+ } else if id. hasPrefix ( " days- " ) {
110+ let value = Int ( id. replacingOccurrences ( of: " days- " , with: " " ) ) ?? 0
111+ self = value > 0 ? . days( value) : . none
112+ } else {
113+ self = . none
114+ }
115+ }
116+ }
117+
118+ @Published private( set) var state : State
51119 private let fetchUseCase : FetchPushNotificationsUseCase
52120 private let deleteUseCase : DeletePushNotificationUseCase
53121 private let toggleReadUseCase : TogglePushNotificationReadUseCase
122+ private let userDefaults : UserDefaults
123+
124+ private enum DefaultsKey {
125+ static let sortOption = " PushNotification.sortOption "
126+ static let timeFilter = " PushNotification.timeFilter "
127+ static let showUnreadOnly = " PushNotification.showUnreadOnly "
128+ }
54129
55130 init (
56131 fetchUseCase: FetchPushNotificationsUseCase ,
57132 deleteUseCase: DeletePushNotificationUseCase ,
58- toggleReadUseCase: TogglePushNotificationReadUseCase
133+ toggleReadUseCase: TogglePushNotificationReadUseCase ,
134+ userDefaults: UserDefaults = . standard
59135 ) {
60136 self . fetchUseCase = fetchUseCase
61137 self . deleteUseCase = deleteUseCase
62138 self . toggleReadUseCase = toggleReadUseCase
139+ self . userDefaults = userDefaults
140+ self . state = State (
141+ sortOption: Self . loadSortOption ( userDefaults: userDefaults) ,
142+ timeFilter: Self . loadTimeFilter ( userDefaults: userDefaults) ,
143+ showUnreadOnly: userDefaults. bool ( forKey: DefaultsKey . showUnreadOnly)
144+ )
145+ }
146+
147+ var displayedNotifications : [ PushNotification ] {
148+ var items = state. notifications
149+
150+ if state. showUnreadOnly {
151+ items = items. filter { $0. isRead == false }
152+ }
153+
154+ if case let . hours( value) = state. timeFilter {
155+ let threshold = Date ( ) . addingTimeInterval ( - Double( value) * 3600.0 )
156+ items = items. filter { $0. receivedAt >= threshold }
157+ } else if case let . days( value) = state. timeFilter {
158+ let threshold = Date ( ) . addingTimeInterval ( - Double( value) * 86400.0 )
159+ items = items. filter { $0. receivedAt >= threshold }
160+ }
161+
162+ switch state. sortOption {
163+ case . latest:
164+ return items. sorted { $0. receivedAt > $1. receivedAt }
165+ case . oldest:
166+ return items. sorted { $0. receivedAt < $1. receivedAt }
167+ }
168+ }
169+
170+ var appliedFilterCount : Int {
171+ var count = 0
172+ if state. sortOption != . latest { count += 1 }
173+ if state. timeFilter != . none { count += 1 }
174+ if state. showUnreadOnly { count += 1 }
175+ return count
63176 }
64177
65178 func reduce( with action: Action ) -> [ SideEffect ] {
@@ -96,6 +209,22 @@ final class PushNotificationViewModel: Store {
96209 state. isLoading = value
97210 case . setNotifications( let notifications) :
98211 state. notifications = notifications
212+ case . toggleSortOption:
213+ state. sortOption = state. sortOption == . latest ? . oldest : . latest
214+ saveSortOption ( state. sortOption)
215+ case . setTimeFilter( let filter) :
216+ state. timeFilter = filter
217+ saveTimeFilter ( filter)
218+ case . toggleUnreadOnly:
219+ state. showUnreadOnly. toggle ( )
220+ userDefaults. set ( state. showUnreadOnly, forKey: DefaultsKey . showUnreadOnly)
221+ case . resetFilters:
222+ state. sortOption = . latest
223+ state. timeFilter = . none
224+ state. showUnreadOnly = false
225+ saveSortOption ( . latest)
226+ saveTimeFilter ( . none)
227+ userDefaults. set ( false , forKey: DefaultsKey . showUnreadOnly)
99228 }
100229
101230 self . state = state
@@ -166,4 +295,25 @@ private extension PushNotificationViewModel {
166295 }
167296 state. showToast = isPresented
168297 }
298+
299+ static func loadSortOption( userDefaults: UserDefaults ) -> SortOption {
300+ guard let rawValue = userDefaults. string ( forKey: DefaultsKey . sortOption) else {
301+ return . latest
302+ }
303+ return rawValue == " oldest " ? . oldest : . latest
304+ }
305+
306+ static func loadTimeFilter( userDefaults: UserDefaults ) -> TimeFilter {
307+ let id = userDefaults. string ( forKey: DefaultsKey . timeFilter) ?? " none "
308+ return TimeFilter ( id: id)
309+ }
310+
311+ func saveSortOption( _ option: SortOption ) {
312+ let value = option == . oldest ? " oldest " : " latest "
313+ userDefaults. set ( value, forKey: DefaultsKey . sortOption)
314+ }
315+
316+ func saveTimeFilter( _ filter: TimeFilter ) {
317+ userDefaults. set ( filter. id, forKey: DefaultsKey . timeFilter)
318+ }
169319}
0 commit comments