Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions SwiftUI-WorkoutApp.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,6 @@
children = (
674E704D2B24D382008AE9D0 /* LoggerScreen.swift */,
670CA19D280E8F09003914A3 /* SettingsScreen.swift */,
6798AA72280B43FE00DB76F1 /* LoginScreen.swift */,
);
path = Settings;
sourceTree = "<group>";
Expand Down Expand Up @@ -424,6 +423,7 @@
isa = PBXGroup;
children = (
67BAF3F72836245100DB40D9 /* CommentsView.swift */,
6798AA72280B43FE00DB76F1 /* LoginScreen.swift */,
671D7DEB28210D2F0068E728 /* EmptyContentView.swift */,
67515697283FEC0B00501346 /* ImagePicker */,
6798AA65280B232F00DB76F1 /* IncognitoProfileView.swift */,
Expand Down Expand Up @@ -868,7 +868,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_ASSET_PATHS = "SwiftUI-WorkoutApp/Preview\\ Content/PreviewContent.swift SwiftUI-WorkoutApp/Preview\\ Content";
DEVELOPMENT_TEAM = CR68PP2Z3F;
ENABLE_PREVIEWS = YES;
Expand Down Expand Up @@ -919,7 +919,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CLANG_WARN_SEMICOLON_BEFORE_METHOD_BODY = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 13;
CURRENT_PROJECT_VERSION = 14;
DEVELOPMENT_ASSET_PATHS = "SwiftUI-WorkoutApp/Preview\\ Content/PreviewContent.swift SwiftUI-WorkoutApp/Preview\\ Content";
DEVELOPMENT_TEAM = CR68PP2Z3F;
ENABLE_PREVIEWS = YES;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ public struct SWClient: Sendable {
return result.userID
}

/// Запрашивает обновления списка друзей, заявок в друзья, черного списка
/// Запрашивает обновления для пользователя и его списков: друзья, заявки, черный список
///
/// - Вызывается при авторизации и при `scenePhase = active`
/// - Список чатов не обновляет
/// - Список чатов не обновляет (для этого `DialogsViewModel`)
/// - Parameter userID: Идентификатор основного пользователя
/// - Returns: Список друзей, заявок в друзья и черный список
public func getSocialUpdates(userID: Int) async -> (
public func getSocialUpdates(userID: Int) async throws -> (
user: UserResponse,
friends: [UserResponse],
friendRequests: [UserResponse],
blacklist: [UserResponse]
)? {
) {
async let user = getUserByID(userID)
async let friendsForUser = getFriendsForUser(id: userID)
async let friendRequests = getFriendRequests()
async let blacklist = getBlacklist()
return try? await (friendsForUser, friendRequests, blacklist)
return try await (user, friendsForUser, friendRequests, blacklist)
}

/// Запрашивает данные пользователя по `id`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SWUtils
/// Экран для авторизации / восстановления пароля
struct LoginScreen: View {
@EnvironmentObject private var defaults: DefaultsService
@Environment(\.dismiss) private var dismiss
@Environment(\.isNetworkConnected) private var isNetworkConnected
@State private var isLoading = false
@State private var credentials = LoginCredentials()
Expand Down Expand Up @@ -100,18 +101,21 @@ private extension LoginScreen {
func loginAction() {
guard !isLoading else { return }
focus = nil
isLoading.toggle()
isLoading = true
loginTask = Task {
do {
let token = AuthData(login: credentials.login, password: credentials.password).token
let userId = try await client.logIn(with: token)
try defaults.saveAuthData(login: credentials.login, password: credentials.password)
let userInfo = try await client.getUserByID(userId)
try defaults.saveUserInfo(userInfo)
let result = try await client.getSocialUpdates(userID: userId)
try defaults.saveFriendsIds(result.friends.map(\.id))
try defaults.saveFriendRequests(result.friendRequests)
try defaults.saveBlacklist(result.blacklist)
try defaults.saveUserInfo(result.user)
} catch {
loginErrorMessage = error.localizedDescription
}
isLoading.toggle()
isLoading = false
}
}

Expand Down
18 changes: 9 additions & 9 deletions SwiftUI-WorkoutApp/Screens/Messages/DialogsListScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import SWUtils

/// Экран со списком диалогов
struct DialogsListScreen: View {
@Environment(\.scenePhase) private var scenePhase
@Environment(\.isNetworkConnected) private var isNetworkConnected
@EnvironmentObject private var defaults: DefaultsService
@EnvironmentObject private var viewModel: DialogsViewModel
@StateObject private var viewModel = DialogsViewModel()
@State private var selectedDialog: DialogResponse?
@State private var indexToDelete: Int?
@State private var openFriendList = false
@State private var showDeleteConfirmation = false
@State private var refreshTask: Task<Void, Never>?
@State private var deleteDialogTask: Task<Void, Never>?
private var client: SWClient { SWClient(with: defaults) }
Expand All @@ -34,6 +34,11 @@ struct DialogsListScreen: View {
}
.navigationViewStyle(.stack)
.onChange(of: defaults.isAuthorized, perform: viewModel.clearDialogsOnLogout)
.onChange(of: scenePhase) { phase in
if case .active = phase {
refreshTask = Task { await askForDialogs() }
}
}
.task(id: defaults.isAuthorized) { await askForDialogs() }
}
}
Expand All @@ -46,7 +51,7 @@ private extension DialogsListScreen {
.background(Color.swBackground)
.confirmationDialog(
.init(Constants.Alert.deleteDialog),
isPresented: $showDeleteConfirmation,
isPresented: $indexToDelete.mappedToBool(),
titleVisibility: .visible
) { deleteDialogButton }
.toolbar {
Expand Down Expand Up @@ -105,7 +110,7 @@ private extension DialogsListScreen {
.listRowBackground(Color.swBackground)
.listRowSeparator(.hidden)
}
.onDelete { initiateDeletion(at: $0) }
.onDelete { indexToDelete = $0.first }
}
.listStyle(.plain)
.opacity(viewModel.hasDialogs ? 1 : 0)
Expand Down Expand Up @@ -168,11 +173,6 @@ private extension DialogsListScreen {
}
}

func initiateDeletion(at indexSet: IndexSet) {
indexToDelete = indexSet.first
showDeleteConfirmation.toggle()
}

func deleteAction(at index: Int?) {
deleteDialogTask = Task {
do {
Expand Down
3 changes: 2 additions & 1 deletion SwiftUI-WorkoutApp/Screens/Messages/DialogsViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ final class DialogsViewModel: ObservableObject {
defaults: DefaultsService
) async throws {
guard defaults.isAuthorized else { return }
if isLoading || (!dialogs.isEmpty && !refresh) { return }
guard !isLoading else { return }
guard dialogs.isEmpty || refresh else { return }
if !refresh || dialogs.isEmpty { isLoading = true }
dialogs = try await SWClient(with: defaults).getDialogs()
let unreadMessagesCount = dialogs.map(\.unreadMessagesCount).reduce(0, +)
Expand Down
5 changes: 1 addition & 4 deletions SwiftUI-WorkoutApp/Screens/Profile/BlackListScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ struct BlackListScreen: View {
.frame(maxWidth: .infinity)
.confirmationDialog(
.init(BlacklistOption.remove.dialogTitle),
isPresented: .init(
get: { userToDelete != nil },
set: { if !$0 { userToDelete = nil } }
),
isPresented: $userToDelete.mappedToBool(),
titleVisibility: .visible
) {
Button(
Expand Down
37 changes: 19 additions & 18 deletions SwiftUI-WorkoutApp/Screens/Profile/MainUserProfileScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import SWUtils

/// Экран с профилем главного пользователя
struct MainUserProfileScreen: View {
@Environment(\.scenePhase) private var scenePhase
@Environment(\.isNetworkConnected) private var isNetworkConnected
@EnvironmentObject private var defaults: DefaultsService
@State private var refreshTask: Task<Void, Never>?
@State private var isLoading = false
@State private var showLogoutDialog = false
@State private var showSearchUsersScreen = false
Expand All @@ -30,6 +32,13 @@ struct MainUserProfileScreen: View {
}
.navigationViewStyle(.stack)
.task { await askForUserInfo() }
.onChange(of: scenePhase) { phase in
if case .active = phase {
refreshTask = Task {
await askForUserInfo(refresh: true)
}
}
}
}
}

Expand Down Expand Up @@ -144,30 +153,22 @@ private extension MainUserProfileScreen {
}

func askForUserInfo(refresh: Bool = false) async {
guard defaults.isAuthorized else { return }
guard let userId = defaults.mainUserInfo?.id else { return }
guard !isLoading else { return }
if !refresh { isLoading = true }
if refresh || defaults.needUpdateUser {
await makeUserInfo()
do {
let result = try await client.getSocialUpdates(userID: userId)
try defaults.saveFriendsIds(result.friends.map(\.id))
try defaults.saveFriendRequests(result.friendRequests)
try defaults.saveBlacklist(result.blacklist)
try defaults.saveUserInfo(result.user)
} catch {
SWAlert.shared.presentDefaultUIKit(error)
}
}
isLoading = false
}

func makeUserInfo() async {
guard let mainUserId = defaults.mainUserInfo?.id else { return }
do {
// TODO: вынести обновление заявок/черного списка в отдельную логику
async let getUserInfo = client.getUserByID(mainUserId)
async let getFriendRequests = client.getFriendRequests()
async let getBlacklist = client.getBlacklist()
let (userInfo, friendRequests, blacklist) = try await (getUserInfo, getFriendRequests, getBlacklist)
try defaults.saveUserInfo(userInfo)
try defaults.saveFriendRequests(friendRequests)
try defaults.saveBlacklist(blacklist)
} catch {
SWAlert.shared.presentDefaultUIKit(error)
}
}
}

#if DEBUG
Expand Down
22 changes: 1 addition & 21 deletions SwiftUI-WorkoutApp/SwiftUI_WorkoutAppApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,7 @@ struct SwiftUI_WorkoutAppApp: App {
@StateObject private var defaults = DefaultsService()
@StateObject private var network = NetworkStatus()
@StateObject private var parksManager = ParksManager()
@StateObject private var dialogsViewModel = DialogsViewModel()
@State private var countriesUpdateTask: Task<Void, Never>?
@State private var socialUpdateTask: Task<Void, Never>?
@State private var dialogsUpdateTask: Task<Void, Never>?
private let countriesStorage = SWAddress()
private var client: SWClient { SWClient(with: defaults) }
private var colorScheme: ColorScheme? {
Expand All @@ -39,7 +36,6 @@ struct SwiftUI_WorkoutAppApp: App {
.environmentObject(tabViewModel)
.environmentObject(defaults)
.environmentObject(parksManager)
.environmentObject(dialogsViewModel)
.preferredColorScheme(colorScheme)
.environment(\.isNetworkConnected, network.isConnected)
.environment(\.userFlags, defaults.userFlags)
Expand All @@ -48,9 +44,8 @@ struct SwiftUI_WorkoutAppApp: App {
switch phase {
case .active:
updateCountriesIfNeeded()
updateSocialInfoIfNeeded()
default:
[socialUpdateTask, countriesUpdateTask].forEach { $0?.cancel() }
countriesUpdateTask?.cancel()
defaults.setUserNeedUpdate(true)
}
}
Expand All @@ -65,21 +60,6 @@ struct SwiftUI_WorkoutAppApp: App {
}
}
}

private func updateSocialInfoIfNeeded() {
guard let mainUserId = defaults.mainUserInfo?.id else { return }
socialUpdateTask = Task {
if let result = await client.getSocialUpdates(userID: mainUserId) {
try? defaults.saveFriendsIds(result.friends.map(\.id))
try? defaults.saveFriendRequests(result.friendRequests)
try? defaults.saveBlacklist(result.blacklist)
defaults.setUserNeedUpdate(false)
}
}
dialogsUpdateTask = Task {
try? await dialogsViewModel.askForDialogs(refresh: true, defaults: defaults)
}
}
}

private extension SwiftUI_WorkoutAppApp {
Expand Down
Loading