Tap area improvements + live status in profile tab

This commit is contained in:
Thomas Ricouard 2022-12-26 08:47:41 +01:00
parent bda77571b6
commit 48ed60b095
7 changed files with 78 additions and 29 deletions

View file

@ -8,6 +8,8 @@ import Env
public struct AccountDetailView: View { public struct AccountDetailView: View {
@Environment(\.redactionReasons) private var reasons @Environment(\.redactionReasons) private var reasons
@EnvironmentObject private var watcher: StreamWatcher
@EnvironmentObject private var currentAccount: CurrentAccount
@EnvironmentObject private var theme: Theme @EnvironmentObject private var theme: Theme
@EnvironmentObject private var client: Client @EnvironmentObject private var client: Client
@EnvironmentObject private var routeurPath: RouterPath @EnvironmentObject private var routeurPath: RouterPath
@ -77,6 +79,12 @@ public struct AccountDetailView: View {
await viewModel.fetchStatuses() await viewModel.fetchStatuses()
} }
} }
.onChange(of: watcher.latestEvent?.id) { id in
if let latestEvent = watcher.latestEvent,
viewModel.accountId == currentAccount.account?.id {
viewModel.handleEvent(event: latestEvent, currentAccount: currentAccount)
}
}
.edgesIgnoringSafeArea(.top) .edgesIgnoringSafeArea(.top)
.navigationTitle(Text(scrollOffset < -200 ? viewModel.title : "")) .navigationTitle(Text(scrollOffset < -200 ? viewModel.title : ""))
} }

View file

@ -2,6 +2,7 @@ import SwiftUI
import Network import Network
import Models import Models
import Status import Status
import Env
@MainActor @MainActor
class AccountDetailViewModel: ObservableObject, StatusesFetcher { class AccountDetailViewModel: ObservableObject, StatusesFetcher {
@ -170,4 +171,21 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
tabState = .followedTags(tags: followedTags) tabState = .followedTags(tags: followedTags)
} }
} }
func handleEvent(event: any StreamEvent, currentAccount: CurrentAccount) {
if let event = event as? StreamEventUpdate {
if event.status.account.id == currentAccount.account?.id {
statuses.insert(event.status, at: 0)
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
}
} else if let event = event as? StreamEventDelete {
statuses.removeAll(where: { $0.id == event.status })
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
} else if let event = event as? StreamEventStatusUpdate {
if let originalIndex = statuses.firstIndex(where: { $0.id == event.status.id }) {
statuses[originalIndex] = event.status
statusesState = .display(statuses: statuses, nextPageState: .hasNextPage)
}
}
}
} }

View file

@ -51,6 +51,7 @@ public struct AccountsListRow: View {
.onAppear { .onAppear {
viewModel.client = client viewModel.client = client
} }
.contentShape(Rectangle())
.onTapGesture { .onTapGesture {
routeurPath.navigate(to: .accountDetailWithAccount(account: viewModel.account)) routeurPath.navigate(to: .accountDetailWithAccount(account: viewModel.account))
} }

View file

@ -22,6 +22,7 @@ public struct TagRowView: View {
} }
Spacer() Spacer()
} }
.contentShape(Rectangle())
.onTapGesture { .onTapGesture {
routeurPath.navigate(to: .hashTag(tag: tag.name, account: nil)) routeurPath.navigate(to: .hashTag(tag: tag.name, account: nil))
} }

View file

@ -28,9 +28,6 @@ struct NotificationRowView: View {
private func makeAvatarView(type: Models.Notification.NotificationType) -> some View { private func makeAvatarView(type: Models.Notification.NotificationType) -> some View {
ZStack(alignment: .topLeading) { ZStack(alignment: .topLeading) {
AvatarView(url: notification.account.avatar) AvatarView(url: notification.account.avatar)
.onTapGesture {
routeurPath.navigate(to: .accountDetailWithAccount(account: notification.account))
}
ZStack(alignment: .center) { ZStack(alignment: .center) {
Circle() Circle()
.strokeBorder(Color.white, lineWidth: 1) .strokeBorder(Color.white, lineWidth: 1)
@ -44,6 +41,10 @@ struct NotificationRowView: View {
} }
.offset(x: -14, y: -4) .offset(x: -14, y: -4)
} }
.contentShape(Rectangle())
.onTapGesture {
routeurPath.navigate(to: .accountDetailWithAccount(account: notification.account))
}
} }
private func makeMainLabel(type: Models.Notification.NotificationType) -> some View { private func makeMainLabel(type: Models.Notification.NotificationType) -> some View {
@ -64,6 +65,10 @@ struct NotificationRowView: View {
Spacer() Spacer()
} }
} }
.contentShape(Rectangle())
.onTapGesture {
routeurPath.navigate(to: .accountDetailWithAccount(account: notification.account))
}
} }
@ViewBuilder @ViewBuilder
@ -78,18 +83,24 @@ struct NotificationRowView: View {
) )
.padding(.top, 8) .padding(.top, 8)
} else { } else {
Text("@\(notification.account.acct)") Group {
.font(.callout) Text("@\(notification.account.acct)")
.foregroundColor(.gray)
if type == .follow {
Text(notification.account.note.asSafeAttributedString)
.lineLimit(3)
.font(.callout) .font(.callout)
.foregroundColor(.gray) .foregroundColor(.gray)
.environment(\.openURL, OpenURLAction { url in
routeurPath.handle(url: url) if type == .follow {
}) Text(notification.account.note.asSafeAttributedString)
.lineLimit(3)
.font(.callout)
.foregroundColor(.gray)
.environment(\.openURL, OpenURLAction { url in
routeurPath.handle(url: url)
})
}
}
.contentShape(Rectangle())
.onTapGesture {
routeurPath.navigate(to: .accountDetailWithAccount(account: notification.account))
} }
} }
} }

View file

@ -55,6 +55,7 @@ public struct StatusDetailView: View {
} }
} }
.padding(.horizontal, DS.Constants.layoutPadding) .padding(.horizontal, DS.Constants.layoutPadding)
.padding(.top, DS.Constants.layoutPadding)
} }
.task { .task {
guard !isLoaded else { return } guard !isLoaded else { return }

View file

@ -27,6 +27,10 @@ public struct StatusRowView: View {
StatusActionsView(viewModel: viewModel) StatusActionsView(viewModel: viewModel)
.padding(.vertical, 8) .padding(.vertical, 8)
.tint(viewModel.isFocused ? theme.tintColor : .gray) .tint(viewModel.isFocused ? theme.tintColor : .gray)
.contentShape(Rectangle())
.onTapGesture {
routeurPath.navigate(to: .statusDetail(id: viewModel.status.reblog?.id ?? viewModel.status.id))
}
} }
} }
.onAppear { .onAppear {
@ -84,25 +88,28 @@ public struct StatusRowView: View {
} }
} }
Text(status.content.asSafeAttributedString) Group {
.font(.body) Text(status.content.asSafeAttributedString)
.onTapGesture { .font(.body)
routeurPath.navigate(to: .statusDetail(id: status.id)) .environment(\.openURL, OpenURLAction { url in
routeurPath.handleStatus(status: status, url: url)
})
if !status.mediaAttachments.isEmpty {
if viewModel.isEmbed {
Image(systemName: "paperclip")
} else {
StatusMediaPreviewView(attachements: status.mediaAttachments)
.padding(.vertical, 4)
}
} }
.environment(\.openURL, OpenURLAction { url in if let card = status.card, !viewModel.isEmbed {
routeurPath.handleStatus(status: status, url: url) StatusCardView(card: card)
})
if !status.mediaAttachments.isEmpty {
if viewModel.isEmbed {
Image(systemName: "paperclip")
} else {
StatusMediaPreviewView(attachements: status.mediaAttachments)
.padding(.vertical, 4)
} }
} }
if let card = status.card, !viewModel.isEmbed { .contentShape(Rectangle())
StatusCardView(card: card) .onTapGesture {
routeurPath.navigate(to: .statusDetail(id: viewModel.status.reblog?.id ?? viewModel.status.id))
} }
} }
} }
@ -130,8 +137,10 @@ public struct StatusRowView: View {
contextMenu contextMenu
} label: { } label: {
Image(systemName: "ellipsis") Image(systemName: "ellipsis")
.frame(width: 30, height: 30)
} }
.foregroundColor(.gray) .foregroundColor(.gray)
.contentShape(Rectangle())
} }
@ViewBuilder @ViewBuilder