Skip to content

Commit 30de381

Browse files
authored
Доработал бейджи и загрузку диалогов/друзей (#284)
* Доработал обновление диалогов и профиля * Обновляем список друзей после изменения списка * Добавил бейдж для профиля Показываем количество заявок в друзья * Доработал бейджи - Показываем бейдж на табе с профилем, если есть заявки в друзья - Показываем бейдж на иконке приложения с суммарным количеством уведомлений (сообщения + заявки) * Мелкий рефактор
1 parent ee334e8 commit 30de381

File tree

10 files changed

+71
-34
lines changed

10 files changed

+71
-34
lines changed

SwiftUI-WorkoutApp.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -876,7 +876,7 @@
876876
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
877877
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
878878
CODE_SIGN_STYLE = Automatic;
879-
CURRENT_PROJECT_VERSION = 15;
879+
CURRENT_PROJECT_VERSION = 16;
880880
DEVELOPMENT_ASSET_PATHS = "SwiftUI-WorkoutApp/Preview\\ Content/PreviewContent.swift SwiftUI-WorkoutApp/Preview\\ Content";
881881
DEVELOPMENT_TEAM = CR68PP2Z3F;
882882
ENABLE_PREVIEWS = YES;
@@ -928,7 +928,7 @@
928928
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
929929
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
930930
CODE_SIGN_STYLE = Automatic;
931-
CURRENT_PROJECT_VERSION = 15;
931+
CURRENT_PROJECT_VERSION = 16;
932932
DEVELOPMENT_ASSET_PATHS = "SwiftUI-WorkoutApp/Preview\\ Content/PreviewContent.swift SwiftUI-WorkoutApp/Preview\\ Content";
933933
DEVELOPMENT_TEAM = CR68PP2Z3F;
934934
ENABLE_PREVIEWS = YES;

SwiftUI-WorkoutApp/Libraries/SWModels/Sources/SWModels/DeviceOSVersionChecker.swift

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import Foundation
22

3-
@available(
4-
iOS,
5-
introduced: 15,
6-
deprecated: 16,
7-
message: "refreshable работает в ScrollView на iOS 16, можно убрать неактуальную кнопку обновления"
8-
)
3+
@available(iOS, deprecated: 16, message: "refreshable работает в ScrollView на iOS 16, можно убрать неактуальную кнопку обновления")
94
public enum DeviceOSVersionChecker {
105
/// Установлена ли iOS 16 на девайсе
116
///

SwiftUI-WorkoutApp/Screens/Messages/DialogsListScreen.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ struct DialogsListScreen: View {
99
@Environment(\.scenePhase) private var scenePhase
1010
@Environment(\.isNetworkConnected) private var isNetworkConnected
1111
@EnvironmentObject private var defaults: DefaultsService
12-
@StateObject private var viewModel = DialogsViewModel()
12+
@EnvironmentObject private var viewModel: DialogsViewModel
1313
@State private var selectedDialog: DialogResponse?
1414
@State private var indexToDelete: Int?
1515
@State private var openFriendList = false
@@ -32,15 +32,14 @@ struct DialogsListScreen: View {
3232
.background(Color.swBackground)
3333
.navigationTitle("Сообщения")
3434
}
35-
.navigationViewStyle(.stack)
36-
.onChange(of: defaults.isAuthorized, perform: viewModel.clearDialogsOnLogout)
3735
.onChange(of: scenePhase) { phase in
3836
if case .active = phase {
39-
guard refreshTask == nil else { return }
40-
refreshTask = Task { await askForDialogs(refresh: true) }
37+
refreshTask = Task {
38+
try? await viewModel.getDialogs(refresh: true, defaults: defaults)
39+
}
4140
}
4241
}
43-
.task(id: defaults.isAuthorized) { await askForDialogs() }
42+
.navigationViewStyle(.stack)
4443
}
4544
}
4645

@@ -168,7 +167,7 @@ private extension DialogsListScreen {
168167

169168
func askForDialogs(refresh: Bool = false) async {
170169
do {
171-
try await viewModel.askForDialogs(refresh: refresh, defaults: defaults)
170+
try await viewModel.getDialogs(refresh: refresh, defaults: defaults)
172171
} catch {
173172
SWAlert.shared.presentDefaultUIKit(error)
174173
}
@@ -189,5 +188,6 @@ private extension DialogsListScreen {
189188
#Preview {
190189
DialogsListScreen()
191190
.environmentObject(DefaultsService())
191+
.environmentObject(DialogsViewModel())
192192
}
193193
#endif

SwiftUI-WorkoutApp/Screens/Messages/DialogsViewModel.swift

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ final class DialogsViewModel: ObservableObject {
1010
var hasDialogs: Bool { !dialogs.isEmpty }
1111
var showEmptyView: Bool { !hasDialogs && !isLoading }
1212

13-
func askForDialogs(
13+
func getDialogs(
1414
refresh: Bool = false,
1515
defaults: DefaultsService
1616
) async throws {
17-
guard defaults.isAuthorized else { return }
17+
guard defaults.isAuthorized else {
18+
if !dialogs.isEmpty {
19+
dialogs.removeAll()
20+
}
21+
return
22+
}
1823
guard !isLoading else { return }
1924
guard dialogs.isEmpty || refresh else { return }
2025
if !refresh || dialogs.isEmpty { isLoading = true }
@@ -51,11 +56,6 @@ final class DialogsViewModel: ObservableObject {
5156
defaults.saveUnreadMessagesCount(newValue)
5257
}
5358

54-
func clearDialogsOnLogout(isAuthorized: Bool) {
55-
guard !isAuthorized else { return }
56-
dialogs.removeAll()
57-
}
58-
5959
private func updateUnreadMessagesCount(with defaults: DefaultsService) {
6060
let unreadMessagesCount = dialogs.map(\.unreadMessagesCount).reduce(0, +)
6161
defaults.saveUnreadMessagesCount(unreadMessagesCount)

SwiftUI-WorkoutApp/Screens/Profile/MainUserFriendsListScreen.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ private extension MainUserFriendsListScreen {
7474

7575
func askForUsers(refresh: Bool = false) async {
7676
guard !isLoading else { return }
77+
let needUpdate = defaults.needUpdateUser
7778
let isEmpty = [friends, friendRequests].allSatisfy(\.isEmpty)
78-
guard isEmpty || refresh else { return }
79+
guard isEmpty || refresh || needUpdate else { return }
7980
do {
80-
if !refresh { isLoading = true }
81+
if !refresh || needUpdate { isLoading = true }
8182
try await getFriendsAndRequests()
8283
} catch {
8384
SWAlert.shared.presentDefaultUIKit(error)

SwiftUI-WorkoutApp/Screens/Profile/MainUserProfileScreen.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ struct MainUserProfileScreen: View {
3434
.task { await askForUserInfo() }
3535
.onChange(of: scenePhase) { phase in
3636
if case .active = phase {
37-
guard refreshTask == nil else { return }
3837
refreshTask = Task { await askForUserInfo(refresh: true) }
3938
}
4039
}
@@ -155,7 +154,7 @@ private extension MainUserProfileScreen {
155154
func askForUserInfo(refresh: Bool = false) async {
156155
guard let userId = defaults.mainUserInfo?.id else { return }
157156
guard !isLoading else { return }
158-
if !refresh { isLoading = true }
157+
if !refresh || defaults.needUpdateUser { isLoading = true }
159158
if refresh || defaults.needUpdateUser {
160159
do {
161160
let result = try await client.getSocialUpdates(userID: userId)

SwiftUI-WorkoutApp/Screens/Profile/UserDetailsScreen.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ private extension UserDetailsScreen {
133133
case .removeFriend:
134134
socialActions.friend = .sendFriendRequest
135135
}
136+
defaults.setUserNeedUpdate(true)
136137
}
137138
} catch {
138139
SWAlert.shared.presentDefaultUIKit(error)

SwiftUI-WorkoutApp/Screens/Root/RootScreen.swift

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,45 @@ import SwiftUI
44
struct RootScreen: View {
55
@Binding var selectedTab: TabViewModel.Tab
66
let unreadCount: Int
7+
let friendRequestsCount: Int
78

89
var body: some View {
910
TabView(selection: $selectedTab) {
1011
ForEach(TabViewModel.Tab.allCases, id: \.rawValue) { tab in
1112
tab.screen
1213
.tabItem { tab.tabItemLabel }
1314
.tag(tab)
14-
.badge(tab == .messages ? unreadCount : 0)
15+
.badge(makeBadgeCount(for: tab))
1516
}
1617
}
1718
.navigationViewStyle(.stack)
1819
}
20+
21+
private func makeBadgeCount(for tab: TabViewModel.Tab) -> Int {
22+
switch tab {
23+
case .messages: unreadCount
24+
case .profile: friendRequestsCount
25+
default: 0
26+
}
27+
}
1928
}
2029

2130
#if DEBUG
22-
#Preview("Есть бейдж для чатов") {
31+
#Preview("Есть бейджи") {
2332
RootScreen(
2433
selectedTab: .constant(.map),
25-
unreadCount: 1
34+
unreadCount: 1,
35+
friendRequestsCount: 1
2636
)
2737
.environmentObject(ParksManager())
2838
.environmentObject(DefaultsService())
2939
}
3040

31-
#Preview("Нет бейджа") {
41+
#Preview("Нет бейджей") {
3242
RootScreen(
3343
selectedTab: .constant(.map),
34-
unreadCount: 0
44+
unreadCount: 0,
45+
friendRequestsCount: 0
3546
)
3647
.environmentObject(ParksManager())
3748
.environmentObject(DefaultsService())

SwiftUI-WorkoutApp/Services/DefaultsService.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import SWUtils
55
@MainActor
66
final class DefaultsService: ObservableObject, DefaultsProtocol {
77
var authToken: String? { try? basicAuthInfo().token }
8+
var appIconBadgeCount: Int {
9+
unreadMessagesCount + friendRequestsList.count
10+
}
811

912
@AppStorage(Key.needUpdateUser.rawValue)
1013
private(set) var needUpdateUser = false

SwiftUI-WorkoutApp/SwiftUI_WorkoutAppApp.swift

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ struct SwiftUI_WorkoutAppApp: App {
1111
@StateObject private var defaults = DefaultsService()
1212
@StateObject private var network = NetworkStatus()
1313
@StateObject private var parksManager = ParksManager()
14+
@StateObject private var dialogsViewModel = DialogsViewModel()
1415
@State private var countriesUpdateTask: Task<Void, Never>?
1516
private let countriesStorage = SWAddress()
1617
private var client: SWClient { SWClient(with: defaults) }
@@ -31,20 +32,26 @@ struct SwiftUI_WorkoutAppApp: App {
3132
WindowGroup {
3233
RootScreen(
3334
selectedTab: $tabViewModel.selectedTab,
34-
unreadCount: defaults.unreadMessagesCount
35+
unreadCount: defaults.unreadMessagesCount,
36+
friendRequestsCount: defaults.friendRequestsList.count
3537
)
3638
.environmentObject(tabViewModel)
3739
.environmentObject(defaults)
3840
.environmentObject(parksManager)
41+
.environmentObject(dialogsViewModel)
3942
.preferredColorScheme(colorScheme)
4043
.environment(\.isNetworkConnected, network.isConnected)
4144
.environment(\.userFlags, defaults.userFlags)
45+
.task(id: defaults.isAuthorized) {
46+
try? await dialogsViewModel.getDialogs(defaults: defaults)
47+
}
4248
}
4349
.onChange(of: scenePhase) { phase in
4450
switch phase {
4551
case .active:
4652
updateCountriesIfNeeded()
4753
default:
54+
updateAppIconBadge()
4855
defaults.setUserNeedUpdate(true)
4956
}
5057
}
@@ -61,6 +68,28 @@ struct SwiftUI_WorkoutAppApp: App {
6168
}
6269
}
6370
}
71+
72+
@available(iOS, deprecated: 16, message: "Заменить на async-вариант")
73+
private func updateAppIconBadge() {
74+
func setupAppIconBadge() {
75+
DispatchQueue.main.async {
76+
UIApplication.shared.applicationIconBadgeNumber = defaults.appIconBadgeCount
77+
}
78+
}
79+
let center = UNUserNotificationCenter.current()
80+
center.getNotificationSettings { settings in
81+
switch settings.authorizationStatus {
82+
case .notDetermined:
83+
center.requestAuthorization(options: [.badge]) { granted, _ in
84+
guard granted else { return }
85+
setupAppIconBadge()
86+
}
87+
case .authorized, .provisional:
88+
setupAppIconBadge()
89+
default: break
90+
}
91+
}
92+
}
6493
}
6594

6695
private extension SwiftUI_WorkoutAppApp {
@@ -100,8 +129,6 @@ private extension SwiftUI_WorkoutAppApp {
100129
let tabBarItemAppearance = UITabBarItemAppearance()
101130
tabBarItemAppearance.normal.iconColor = .init(.swSmallElements)
102131
tabBarItemAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor(.swSmallElements)]
103-
tabBarItemAppearance.normal.badgeBackgroundColor = .accent
104-
tabBarItemAppearance.normal.badgeTextAttributes = [.foregroundColor: UIColor(.swBackground)]
105132
return tabBarItemAppearance
106133
}
107134

0 commit comments

Comments
 (0)