Skip to content

Commit c510c33

Browse files
committed
Сделал вьюмодель для экрана с диалогами
1 parent 3cfaf34 commit c510c33

File tree

4 files changed

+79
-69
lines changed

4 files changed

+79
-69
lines changed

SwiftUI-WorkoutApp.xcodeproj/project.pbxproj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
67627750283A3A54009C203F /* JournalsListScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6762774F283A3A54009C203F /* JournalsListScreen.swift */; };
3737
67627755283A4C77009C203F /* JournalEntriesScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67627754283A4C77009C203F /* JournalEntriesScreen.swift */; };
3838
6762775B283A87AD009C203F /* JournalCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6762775A283A87AD009C203F /* JournalCell.swift */; };
39-
6764D6382D52009F00699007 /* UnreadCountService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6764D6372D52009F00699007 /* UnreadCountService.swift */; };
39+
6764D6382D52009F00699007 /* DialogsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6764D6372D52009F00699007 /* DialogsViewModel.swift */; };
4040
6765B2562D451771006164AB /* UIImage+toMediaFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6765B2552D451771006164AB /* UIImage+toMediaFile.swift */; };
4141
6765B2582D4544C8006164AB /* MainUserProfileScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6765B2572D4544C8006164AB /* MainUserProfileScreen.swift */; };
4242
6765B25B2D455D5C006164AB /* ProfileViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6765B25A2D455D5C006164AB /* ProfileViews.swift */; };
@@ -124,7 +124,7 @@
124124
6762774F283A3A54009C203F /* JournalsListScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JournalsListScreen.swift; sourceTree = "<group>"; };
125125
67627754283A4C77009C203F /* JournalEntriesScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JournalEntriesScreen.swift; sourceTree = "<group>"; };
126126
6762775A283A87AD009C203F /* JournalCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JournalCell.swift; sourceTree = "<group>"; };
127-
6764D6372D52009F00699007 /* UnreadCountService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnreadCountService.swift; sourceTree = "<group>"; };
127+
6764D6372D52009F00699007 /* DialogsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DialogsViewModel.swift; sourceTree = "<group>"; };
128128
6765B2552D451771006164AB /* UIImage+toMediaFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+toMediaFile.swift"; sourceTree = "<group>"; };
129129
6765B2572D4544C8006164AB /* MainUserProfileScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainUserProfileScreen.swift; sourceTree = "<group>"; };
130130
6765B25A2D455D5C006164AB /* ProfileViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViews.swift; sourceTree = "<group>"; };
@@ -229,6 +229,7 @@
229229
67419AD5282E8E7C004F5339 /* Messages */ = {
230230
isa = PBXGroup;
231231
children = (
232+
6764D6372D52009F00699007 /* DialogsViewModel.swift */,
232233
67D916802838E2460098D3CB /* DialogsListScreen.swift */,
233234
67D916852838F0DD0098D3CB /* DialogScreen.swift */,
234235
);
@@ -393,7 +394,6 @@
393394
67551C352AEC338600084A35 /* SWAddress.swift */,
394395
67A4710C2AEED8F8004D341D /* PastEventStorage.swift */,
395396
67BD2D002AF7D21B00F44064 /* ParksManager.swift */,
396-
6764D6372D52009F00699007 /* UnreadCountService.swift */,
397397
);
398398
path = Services;
399399
sourceTree = "<group>";
@@ -649,7 +649,7 @@
649649
6798AA84280C0F7D00DB76F1 /* EditProfileScreen.swift in Sources */,
650650
6798AA73280B43FE00DB76F1 /* LoginScreen.swift in Sources */,
651651
67D9169628396C1E0098D3CB /* SendMessageScreen.swift in Sources */,
652-
6764D6382D52009F00699007 /* UnreadCountService.swift in Sources */,
652+
6764D6382D52009F00699007 /* DialogsViewModel.swift in Sources */,
653653
6747575928128603002F0A24 /* ParkDetailScreen.swift in Sources */,
654654
675EC6572815433600C2E229 /* UsersListScreen.swift in Sources */,
655655
675EC65F2815532800C2E229 /* EventFormScreen.swift in Sources */,

SwiftUI-WorkoutApp/Screens/Messages/DialogsListScreen.swift

Lines changed: 18 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import SWUtils
88
struct DialogsListScreen: View {
99
@Environment(\.isNetworkConnected) private var isNetworkConnected
1010
@EnvironmentObject private var defaults: DefaultsService
11-
@State private var dialogs = [DialogResponse]()
11+
@EnvironmentObject private var viewModel: DialogsViewModel
1212
@State private var selectedDialog: DialogResponse?
13-
@State private var isLoading = false
1413
@State private var indexToDelete: Int?
1514
@State private var openFriendList = false
1615
@State private var showDeleteConfirmation = false
@@ -42,7 +41,7 @@ private extension DialogsListScreen {
4241
var authorizedContentView: some View {
4342
dialogList
4443
.overlay { emptyContentView }
45-
.loadingOverlay(if: isLoading)
44+
.loadingOverlay(if: viewModel.isLoading)
4645
.background(Color.swBackground)
4746
.confirmationDialog(
4847
.init(Constants.Alert.deleteDialog),
@@ -58,9 +57,6 @@ private extension DialogsListScreen {
5857
friendListButton
5958
}
6059
}
61-
.onDisappear {
62-
[refreshTask, deleteDialogTask].forEach { $0?.cancel() }
63-
}
6460
}
6561

6662
var refreshButton: some View {
@@ -71,8 +67,8 @@ private extension DialogsListScreen {
7167
} label: {
7268
Icons.Regular.refresh.view
7369
}
74-
.opacity(showEmptyView || !DeviceOSVersionChecker.iOS16Available ? 1 : 0)
75-
.disabled(isLoading)
70+
.opacity(viewModel.showRefreshButton ? 1 : 0)
71+
.disabled(viewModel.isLoading)
7672
}
7773

7874
var friendListButton: some View {
@@ -86,28 +82,24 @@ private extension DialogsListScreen {
8682
Icons.Regular.plus.view
8783
.symbolVariant(.circle)
8884
}
89-
.opacity(hasFriends || !dialogs.isEmpty ? 1 : 0)
85+
.opacity(hasFriends || viewModel.hasDialogs ? 1 : 0)
9086
.disabled(!isNetworkConnected)
9187
}
9288

9389
var emptyContentView: some View {
9490
EmptyContentView(
9591
mode: .dialogs,
96-
action: emptyViewAction
92+
action: { openFriendList.toggle() }
9793
)
98-
.opacity(showEmptyView ? 1 : 0)
99-
}
100-
101-
var showEmptyView: Bool {
102-
dialogs.isEmpty && !isLoading
94+
.opacity(viewModel.showEmptyView ? 1 : 0)
10395
}
10496

10597
@ViewBuilder
10698
var dialogList: some View {
10799
ZStack {
108100
Color.swBackground
109101
List {
110-
ForEach(dialogs) { model in
102+
ForEach(viewModel.dialogs) { model in
111103
dialogListItem(model)
112104
.listRowInsets(.init(top: 12, leading: 16, bottom: 12, trailing: 16))
113105
.listRowBackground(Color.swBackground)
@@ -116,9 +108,9 @@ private extension DialogsListScreen {
116108
.onDelete { initiateDeletion(at: $0) }
117109
}
118110
.listStyle(.plain)
119-
.opacity(dialogs.isEmpty ? 0 : 1)
111+
.opacity(viewModel.hasDialogs ? 1 : 0)
120112
}
121-
.animation(.default, value: dialogs.count)
113+
.animation(.default, value: viewModel.dialogs.count)
122114
.background(
123115
NavigationLink(
124116
destination: lazyDestination,
@@ -130,7 +122,12 @@ private extension DialogsListScreen {
130122
@ViewBuilder
131123
var lazyDestination: some View {
132124
if let selectedDialog {
133-
DialogScreen(dialog: selectedDialog) { markAsRead($0) }
125+
DialogScreen(
126+
dialog: selectedDialog,
127+
markedAsReadClbk: { dialog in
128+
viewModel.markAsRead(dialog, defaults: defaults)
129+
}
130+
)
134131
}
135132
}
136133

@@ -162,39 +159,12 @@ private extension DialogsListScreen {
162159
defaults.hasFriends
163160
}
164161

165-
func emptyViewAction() {
166-
openFriendList.toggle()
167-
}
168-
169-
func markAsRead(_ dialog: DialogResponse) {
170-
dialogs = dialogs.map { item in
171-
if item.id == dialog.id {
172-
var updatedDialog = dialog
173-
updatedDialog.unreadMessagesCount = 0
174-
return updatedDialog
175-
} else {
176-
return item
177-
}
178-
}
179-
guard dialog.unreadMessagesCount > 0,
180-
defaults.unreadMessagesCount >= dialog.unreadMessagesCount
181-
else { return }
182-
let newValue = defaults.unreadMessagesCount - dialog.unreadMessagesCount
183-
defaults.saveUnreadMessagesCount(newValue)
184-
}
185-
186162
func askForDialogs(refresh: Bool = false) async {
187-
guard defaults.isAuthorized else { return }
188-
if isLoading || (!dialogs.isEmpty && !refresh) { return }
189-
if !refresh { isLoading = true }
190163
do {
191-
dialogs = try await client.getDialogs()
192-
let unreadMessagesCount = dialogs.map(\.unreadMessagesCount).reduce(0, +)
193-
defaults.saveUnreadMessagesCount(unreadMessagesCount)
164+
try await viewModel.askForDialogs(refresh: refresh, defaults: defaults)
194165
} catch {
195166
SWAlert.shared.presentDefaultUIKit(message: error.localizedDescription)
196167
}
197-
isLoading = false
198168
}
199169

200170
func initiateDeletion(at indexSet: IndexSet) {
@@ -204,17 +174,11 @@ private extension DialogsListScreen {
204174

205175
func deleteAction(at index: Int?) {
206176
deleteDialogTask = Task {
207-
guard let index, !isLoading else { return }
208-
isLoading = true
209177
do {
210-
let dialogID = dialogs[index].id
211-
if try await client.deleteDialog(dialogID) {
212-
dialogs.remove(at: index)
213-
}
178+
try await viewModel.deleteDialog(at: index, defaults: defaults)
214179
} catch {
215180
SWAlert.shared.presentDefaultUIKit(message: error.localizedDescription)
216181
}
217-
isLoading = false
218182
}
219183
}
220184
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import Foundation
2+
import SWModels
3+
import SWNetworkClient
4+
import SWUtils
5+
6+
final class DialogsViewModel: ObservableObject {
7+
@Published private(set) var dialogs = [DialogResponse]()
8+
@Published private(set) var isLoading = false
9+
var hasDialogs: Bool { !dialogs.isEmpty }
10+
var showEmptyView: Bool { !hasDialogs && !isLoading }
11+
var showRefreshButton: Bool {
12+
showEmptyView || !DeviceOSVersionChecker.iOS16Available
13+
}
14+
15+
@MainActor
16+
func askForDialogs(
17+
refresh: Bool = false,
18+
defaults: DefaultsService
19+
) async throws {
20+
guard defaults.isAuthorized else { return }
21+
if isLoading || (!dialogs.isEmpty && !refresh) { return }
22+
if !refresh || dialogs.isEmpty { isLoading = true }
23+
dialogs = try await SWClient(with: defaults).getDialogs()
24+
let unreadMessagesCount = dialogs.map(\.unreadMessagesCount).reduce(0, +)
25+
defaults.saveUnreadMessagesCount(unreadMessagesCount)
26+
isLoading = false
27+
}
28+
29+
@MainActor
30+
func deleteDialog(at index: Int?, defaults: DefaultsService) async throws {
31+
guard let index, !isLoading else { return }
32+
isLoading = true
33+
let dialogID = dialogs[index].id
34+
if try await SWClient(with: defaults).deleteDialog(dialogID) {
35+
dialogs.remove(at: index)
36+
}
37+
isLoading = false
38+
}
39+
40+
@MainActor
41+
func markAsRead(_ dialog: DialogResponse, defaults: DefaultsService) {
42+
dialogs = dialogs.map { item in
43+
if item.id == dialog.id {
44+
var updatedDialog = dialog
45+
updatedDialog.unreadMessagesCount = 0
46+
return updatedDialog
47+
} else {
48+
return item
49+
}
50+
}
51+
guard dialog.unreadMessagesCount > 0,
52+
defaults.unreadMessagesCount >= dialog.unreadMessagesCount
53+
else { return }
54+
let newValue = defaults.unreadMessagesCount - dialog.unreadMessagesCount
55+
defaults.saveUnreadMessagesCount(newValue)
56+
}
57+
}

SwiftUI-WorkoutApp/Services/UnreadCountService.swift

Lines changed: 0 additions & 11 deletions
This file was deleted.

0 commit comments

Comments
 (0)