ios, android: show progress indicator on joining group (#3281)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user