diff --git a/SodaLive/Sources/V2/Main/Chat/MainChatView.swift b/SodaLive/Sources/V2/Main/Chat/MainChatView.swift index e76bbe2d..9d563da8 100644 --- a/SodaLive/Sources/V2/Main/Chat/MainChatView.swift +++ b/SodaLive/Sources/V2/Main/Chat/MainChatView.swift @@ -54,16 +54,10 @@ struct MainChatView: View { @ViewBuilder private var chatListContent: some View { - if viewModel.isLoading && viewModel.rooms.isEmpty { - ProgressView() - .progressViewStyle(.circular) - .tint(Color.soda400) - .frame(maxWidth: .infinity, maxHeight: .infinity) + if viewModel.isLoading && !viewModel.hasLoaded { + loadingContent } else if viewModel.shouldShowEmptyState { - Text(I18n.MainChat.emptyStateMessage) - .appFont(size: 16, weight: .medium) - .foregroundColor(Color.gray500) - .frame(maxWidth: .infinity, maxHeight: .infinity) + emptyContent } else { ScrollView(showsIndicators: false) { LazyVStack(spacing: 0) { @@ -85,6 +79,39 @@ struct MainChatView: View { } .padding(.top, 0) } + .refreshable { + await viewModel.refresh() + } + } + } + + private var loadingContent: some View { + GeometryReader { geometry in + ScrollView(showsIndicators: false) { + ProgressView() + .progressViewStyle(.circular) + .tint(Color.soda400) + .frame(maxWidth: .infinity) + .frame(minHeight: geometry.size.height) + } + .refreshable { + await viewModel.refresh() + } + } + } + + private var emptyContent: some View { + GeometryReader { geometry in + ScrollView(showsIndicators: false) { + Text(I18n.MainChat.emptyStateMessage) + .appFont(size: 16, weight: .medium) + .foregroundColor(Color.gray500) + .frame(maxWidth: .infinity) + .frame(minHeight: geometry.size.height) + } + .refreshable { + await viewModel.refresh() + } } } diff --git a/SodaLive/Sources/V2/Main/Chat/MainChatViewModel.swift b/SodaLive/Sources/V2/Main/Chat/MainChatViewModel.swift index f20999c0..9d9856b9 100644 --- a/SodaLive/Sources/V2/Main/Chat/MainChatViewModel.swift +++ b/SodaLive/Sources/V2/Main/Chat/MainChatViewModel.swift @@ -31,6 +31,16 @@ final class MainChatViewModel: ObservableObject { fetchChatRooms(filter: filter, cursor: nil, isNextPage: false) } + func refresh() async { + if !isLoading { + fetchChatRooms(filter: selectedFilter, cursor: nil, isNextPage: false) + } + + for await isLoading in $isLoading.values { + if !isLoading { return } + } + } + func applyFilter(_ filter: MainChatFilter) { guard selectedFilter != filter else { return } fetchFirstPage(filter: filter) @@ -42,7 +52,11 @@ final class MainChatViewModel: ObservableObject { fetchChatRooms(filter: selectedFilter, cursor: nextCursor, isNextPage: true) } - private func fetchChatRooms(filter: MainChatFilter, cursor: String?, isNextPage: Bool) { + private func fetchChatRooms( + filter: MainChatFilter, + cursor: String?, + isNextPage: Bool + ) { latestRequestId += 1 let requestId = latestRequestId