ios, android: show progress indicator on joining group (#3281)

This commit is contained in:
spaced4ndy
2023-10-26 10:32:11 +04:00
committed by GitHub
parent 4a8da196ad
commit 4a5fdd3e0e
8 changed files with 252 additions and 103 deletions

View File

@@ -17,34 +17,45 @@ struct CIGroupInvitationView: View {
var memberRole: GroupMemberRole
var chatIncognito: Bool = false
@State private var frameWidth: CGFloat = 0
@State private var inProgress = false
@State private var progressByTimeout = false
var body: some View {
let action = !chatItem.chatDir.sent && groupInvitation.status == .pending
let v = ZStack(alignment: .bottomTrailing) {
VStack(alignment: .leading) {
groupInfoView(action)
.padding(.horizontal, 2)
.padding(.top, 8)
.padding(.bottom, 6)
.overlay(DetermineWidth())
ZStack {
VStack(alignment: .leading) {
groupInfoView(action)
.padding(.horizontal, 2)
.padding(.top, 8)
.padding(.bottom, 6)
.overlay(DetermineWidth())
Divider().frame(width: frameWidth)
Divider().frame(width: frameWidth)
if action {
groupInvitationText()
.overlay(DetermineWidth())
Text(chatIncognito ? "Tap to join incognito" : "Tap to join")
.foregroundColor(chatIncognito ? .indigo : .accentColor)
.font(.callout)
.padding(.trailing, 60)
.overlay(DetermineWidth())
} else {
groupInvitationText()
.padding(.trailing, 60)
.overlay(DetermineWidth())
if action {
VStack(alignment: .leading, spacing: 2) {
groupInvitationText()
.overlay(DetermineWidth())
Text(chatIncognito ? "Tap to join incognito" : "Tap to join")
.foregroundColor(inProgress ? .secondary : chatIncognito ? .indigo : .accentColor)
.font(.callout)
.padding(.trailing, 60)
.overlay(DetermineWidth())
}
} else {
groupInvitationText()
.padding(.trailing, 60)
.overlay(DetermineWidth())
}
}
.padding(.bottom, 2)
if progressByTimeout {
ProgressView().scaleEffect(2)
}
}
.padding(.bottom, 2)
chatItem.timestampText
.font(.caption)
.foregroundColor(.secondary)
@@ -55,11 +66,24 @@ struct CIGroupInvitationView: View {
.cornerRadius(18)
.textSelection(.disabled)
.onPreferenceChange(DetermineWidth.Key.self) { frameWidth = $0 }
.onChange(of: inProgress) { inProgress in
if inProgress {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
progressByTimeout = inProgress
}
} else {
progressByTimeout = false
}
}
if action {
v.onTapGesture {
joinGroup(groupInvitation.groupId)
inProgress = true
joinGroup(groupInvitation.groupId) {
await MainActor.run { inProgress = false }
}
}
.disabled(inProgress)
} else {
v
}
@@ -67,7 +91,7 @@ struct CIGroupInvitationView: View {
private func groupInfoView(_ action: Bool) -> some View {
var color: Color
if action {
if action && !inProgress {
color = chatIncognito ? .indigo : .accentColor
} else {
color = Color(uiColor: .tertiaryLabel)

View File

@@ -33,19 +33,32 @@ struct ChatListNavLink: View {
@State private var showContactConnectionInfo = false
@State private var showInvalidJSON = false
@State private var showDeleteContactActionSheet = false
@State private var inProgress = false
@State private var progressByTimeout = false
var body: some View {
switch chat.chatInfo {
case let .direct(contact):
contactNavLink(contact)
case let .group(groupInfo):
groupNavLink(groupInfo)
case let .contactRequest(cReq):
contactRequestNavLink(cReq)
case let .contactConnection(cConn):
contactConnectionNavLink(cConn)
case let .invalidJSON(json):
invalidJSONPreview(json)
Group {
switch chat.chatInfo {
case let .direct(contact):
contactNavLink(contact)
case let .group(groupInfo):
groupNavLink(groupInfo)
case let .contactRequest(cReq):
contactRequestNavLink(cReq)
case let .contactConnection(cConn):
contactConnectionNavLink(cConn)
case let .invalidJSON(json):
invalidJSONPreview(json)
}
}
.onChange(of: inProgress) { inProgress in
if inProgress {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
progressByTimeout = inProgress
}
} else {
progressByTimeout = false
}
}
}
@@ -53,7 +66,7 @@ struct ChatListNavLink: View {
NavLinkPlain(
tag: chat.chatInfo.id,
selection: $chatModel.chatId,
label: { ChatPreviewView(chat: chat) }
label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) }
)
.swipeActions(edge: .leading, allowsFullSwipe: true) {
markReadButton()
@@ -101,7 +114,7 @@ struct ChatListNavLink: View {
@ViewBuilder private func groupNavLink(_ groupInfo: GroupInfo) -> some View {
switch (groupInfo.membership.memberStatus) {
case .memInvited:
ChatPreviewView(chat: chat)
ChatPreviewView(chat: chat, progressByTimeout: $progressByTimeout)
.frame(height: rowHeights[dynamicTypeSize])
.swipeActions(edge: .trailing, allowsFullSwipe: true) {
joinGroupButton()
@@ -112,12 +125,16 @@ struct ChatListNavLink: View {
.onTapGesture { showJoinGroupDialog = true }
.confirmationDialog("Group invitation", isPresented: $showJoinGroupDialog, titleVisibility: .visible) {
Button(chat.chatInfo.incognito ? "Join incognito" : "Join group") {
joinGroup(groupInfo.groupId)
inProgress = true
joinGroup(groupInfo.groupId) {
await MainActor.run { inProgress = false }
}
}
Button("Delete invitation", role: .destructive) { Task { await deleteChat(chat) } }
}
.disabled(inProgress)
case .memAccepted:
ChatPreviewView(chat: chat)
ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false))
.frame(height: rowHeights[dynamicTypeSize])
.onTapGesture {
AlertManager.shared.showAlert(groupInvitationAcceptedAlert())
@@ -134,7 +151,7 @@ struct ChatListNavLink: View {
NavLinkPlain(
tag: chat.chatInfo.id,
selection: $chatModel.chatId,
label: { ChatPreviewView(chat: chat) },
label: { ChatPreviewView(chat: chat, progressByTimeout: Binding.constant(false)) },
disabled: !groupInfo.ready
)
.frame(height: rowHeights[dynamicTypeSize])
@@ -159,7 +176,10 @@ struct ChatListNavLink: View {
private func joinGroupButton() -> some View {
Button {
joinGroup(chat.chatInfo.apiId)
inProgress = true
joinGroup(chat.chatInfo.apiId) {
await MainActor.run { inProgress = false }
}
} label: {
Label("Join", systemImage: chat.chatInfo.incognito ? "theatermasks" : "ipad.and.arrow.forward")
}
@@ -419,7 +439,7 @@ func deleteContactConnectionAlert(_ contactConnection: PendingContactConnection,
)
}
func joinGroup(_ groupId: Int64) {
func joinGroup(_ groupId: Int64, _ onComplete: @escaping () async -> Void) {
Task {
logger.debug("joinGroup")
do {
@@ -434,7 +454,9 @@ func joinGroup(_ groupId: Int64) {
AlertManager.shared.showAlertMsg(title: "No group!", message: "This group no longer exists.")
await deleteGroup()
}
await onComplete()
} catch let error {
await onComplete()
let a = getErrorAlert(error, "Error joining group")
AlertManager.shared.showAlertMsg(title: a.title, message: a.message)
}

View File

@@ -12,6 +12,7 @@ import SimpleXChat
struct ChatPreviewView: View {
@EnvironmentObject var chatModel: ChatModel
@ObservedObject var chat: Chat
@Binding var progressByTimeout: Bool
@Environment(\.colorScheme) var colorScheme
var darkGreen = Color(red: 0, green: 0.5, blue: 0)
@@ -252,6 +253,12 @@ struct ChatPreviewView: View {
} else {
incognitoIcon(chat.chatInfo.incognito)
}
case .group:
if progressByTimeout {
ProgressView()
} else {
incognitoIcon(chat.chatInfo.incognito)
}
default:
incognitoIcon(chat.chatInfo.incognito)
}
@@ -280,30 +287,30 @@ struct ChatPreviewView_Previews: PreviewProvider {
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: []
))
), progressByTimeout: Binding.constant(false))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete))]
))
), progressByTimeout: Binding.constant(false))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete))],
chatStats: ChatStats(unreadCount: 11, minUnreadItemId: 0)
))
), progressByTimeout: Binding.constant(false))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete), itemDeleted: .deleted(deletedTs: .now))]
))
), progressByTimeout: Binding.constant(false))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.direct,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "hello", .sndSent(sndProgress: .complete))],
chatStats: ChatStats(unreadCount: 3, minUnreadItemId: 0)
))
), progressByTimeout: Binding.constant(false))
ChatPreviewView(chat: Chat(
chatInfo: ChatInfo.sampleData.group,
chatItems: [ChatItem.getSample(1, .directSnd, .now, "Lorem ipsum dolor sit amet, d. consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")],
chatStats: ChatStats(unreadCount: 11, minUnreadItemId: 0)
))
), progressByTimeout: Binding.constant(false))
}
.previewLayout(.fixed(width: 360, height: 78))
}