Add iOS chat list status indicators
This commit is contained in:
@@ -17,13 +17,19 @@ public struct RootView: View {
|
|||||||
Group {
|
Group {
|
||||||
switch store.authState {
|
switch store.authState {
|
||||||
case .ready:
|
case .ready:
|
||||||
ChatListView(viewModel: chatListViewModel, bridge: store.bridge)
|
ChatListView(
|
||||||
|
viewModel: chatListViewModel,
|
||||||
|
bridge: store.bridge,
|
||||||
|
networkState: store.networkState,
|
||||||
|
typingState: store.typingState
|
||||||
|
)
|
||||||
default:
|
default:
|
||||||
AuthView(state: store.authState, viewModel: authViewModel)
|
AuthView(state: store.authState, viewModel: authViewModel)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.task {
|
.task {
|
||||||
await store.refreshAuthState()
|
await store.refreshAuthState()
|
||||||
|
await store.refreshNetworkState()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -118,22 +124,34 @@ public struct AuthView: View {
|
|||||||
public struct ChatListView: View {
|
public struct ChatListView: View {
|
||||||
@ObservedObject public var viewModel: ChatListViewModel
|
@ObservedObject public var viewModel: ChatListViewModel
|
||||||
public let bridge: SessionBridge
|
public let bridge: SessionBridge
|
||||||
|
public var networkState: NetworkState
|
||||||
|
public var typingState: TypingState
|
||||||
@State private var selectedChat: ChatSummary?
|
@State private var selectedChat: ChatSummary?
|
||||||
@State private var showsAccountSwitcher = false
|
@State private var showsAccountSwitcher = false
|
||||||
|
|
||||||
public init(viewModel: ChatListViewModel, bridge: SessionBridge) {
|
public init(
|
||||||
|
viewModel: ChatListViewModel,
|
||||||
|
bridge: SessionBridge,
|
||||||
|
networkState: NetworkState = .ready,
|
||||||
|
typingState: TypingState = .idle
|
||||||
|
) {
|
||||||
self.viewModel = viewModel
|
self.viewModel = viewModel
|
||||||
self.bridge = bridge
|
self.bridge = bridge
|
||||||
|
self.networkState = networkState
|
||||||
|
self.typingState = typingState
|
||||||
}
|
}
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
NavigationSplitView {
|
NavigationSplitView {
|
||||||
List(selection: $selectedChat) {
|
VStack(spacing: 0) {
|
||||||
ForEach(viewModel.filteredChats) { chat in
|
List(selection: $selectedChat) {
|
||||||
NavigationLink(value: chat) {
|
ForEach(viewModel.filteredChats) { chat in
|
||||||
ChatRow(chat: chat)
|
NavigationLink(value: chat) {
|
||||||
|
ChatRow(chat: chat)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ChatListStatusBar(networkState: networkState, typingState: typingState)
|
||||||
}
|
}
|
||||||
.navigationTitle("Chats")
|
.navigationTitle("Chats")
|
||||||
.searchable(text: $viewModel.searchText)
|
.searchable(text: $viewModel.searchText)
|
||||||
@@ -178,6 +196,71 @@ public struct ChatListView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public struct ChatListStatusBar: View {
|
||||||
|
public var networkState: NetworkState
|
||||||
|
public var typingState: TypingState
|
||||||
|
|
||||||
|
public init(networkState: NetworkState, typingState: TypingState) {
|
||||||
|
self.networkState = networkState
|
||||||
|
self.typingState = typingState
|
||||||
|
}
|
||||||
|
|
||||||
|
public var body: some View {
|
||||||
|
HStack(spacing: 8) {
|
||||||
|
Image(systemName: networkIconName)
|
||||||
|
.foregroundStyle(networkState == .ready ? .green : .orange)
|
||||||
|
Text(statusText)
|
||||||
|
.font(.footnote)
|
||||||
|
.lineLimit(1)
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
.padding(.horizontal, 12)
|
||||||
|
.padding(.vertical, 8)
|
||||||
|
.background(.bar)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var networkIconName: String {
|
||||||
|
switch networkState {
|
||||||
|
case .ready:
|
||||||
|
"checkmark.circle.fill"
|
||||||
|
case .waitingForNetwork:
|
||||||
|
"wifi.slash"
|
||||||
|
case .connectingToProxy:
|
||||||
|
"shield.lefthalf.filled"
|
||||||
|
case .connecting:
|
||||||
|
"antenna.radiowaves.left.and.right"
|
||||||
|
case .updating:
|
||||||
|
"arrow.triangle.2.circlepath"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var statusText: String {
|
||||||
|
switch typingState {
|
||||||
|
case let .typing(_, _, text) where !text.isEmpty:
|
||||||
|
text
|
||||||
|
case .typing:
|
||||||
|
"Typing"
|
||||||
|
case .idle:
|
||||||
|
networkText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var networkText: String {
|
||||||
|
switch networkState {
|
||||||
|
case .ready:
|
||||||
|
"Online"
|
||||||
|
case .waitingForNetwork:
|
||||||
|
"Waiting for network"
|
||||||
|
case .connectingToProxy:
|
||||||
|
"Connecting to proxy"
|
||||||
|
case .connecting:
|
||||||
|
"Connecting"
|
||||||
|
case .updating:
|
||||||
|
"Updating"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public struct ChatRow: View {
|
public struct ChatRow: View {
|
||||||
public var chat: ChatSummary
|
public var chat: ChatSummary
|
||||||
|
|
||||||
@@ -195,7 +278,20 @@ public struct ChatRow: View {
|
|||||||
Image(systemName: "pin.fill")
|
Image(systemName: "pin.fill")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
}
|
}
|
||||||
|
if chat.isMuted {
|
||||||
|
Image(systemName: "bell.slash")
|
||||||
|
.font(.caption)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
Spacer()
|
Spacer()
|
||||||
|
if chat.unreadMentionCount > 0 {
|
||||||
|
Text("@\(chat.unreadMentionCount)")
|
||||||
|
.font(.caption)
|
||||||
|
.padding(.horizontal, 7)
|
||||||
|
.padding(.vertical, 3)
|
||||||
|
.background(.orange, in: Capsule())
|
||||||
|
.foregroundStyle(.white)
|
||||||
|
}
|
||||||
if chat.unreadCount > 0 {
|
if chat.unreadCount > 0 {
|
||||||
Text("\(chat.unreadCount)")
|
Text("\(chat.unreadCount)")
|
||||||
.font(.caption)
|
.font(.caption)
|
||||||
@@ -205,7 +301,13 @@ public struct ChatRow: View {
|
|||||||
.foregroundStyle(.white)
|
.foregroundStyle(.white)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Text(chat.draft?.text ?? chat.lastMessage)
|
HStack(spacing: 4) {
|
||||||
|
if chat.draft != nil {
|
||||||
|
Text("Draft")
|
||||||
|
.fontWeight(.semibold)
|
||||||
|
}
|
||||||
|
Text(chat.draft?.text ?? chat.lastMessage)
|
||||||
|
}
|
||||||
.font(.subheadline)
|
.font(.subheadline)
|
||||||
.foregroundStyle(chat.draft == nil ? Color.secondary : Color.red)
|
.foregroundStyle(chat.draft == nil ? Color.secondary : Color.red)
|
||||||
.lineLimit(2)
|
.lineLimit(2)
|
||||||
|
|||||||
Reference in New Issue
Block a user