mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-12-01 20:51:25 +00:00
Improve the display of replies (#1672)
Threads/replies are now shown more clearly. Each reply has an indentation level (and therefore the number of vertical lines) one more than its direct parent. This leads to siblings having the same indentation level. It makes understanding somewhat complex thread structures way easier. Previously, a reply was only indented if it came directly after its parent. If a toot had more than one reply, the structure was nearly indecipherable, as it wasn't clear which the parent post of the second (or later) toot was. An example is "https://mastodon.social/@mhoye/110452462852364819" and all of its replies. Signed-off-by: Paul Schuetz <pa.schuetz@web.de>
This commit is contained in:
parent
4b74532048
commit
59e5eba860
4 changed files with 31 additions and 31 deletions
|
@ -25,8 +25,8 @@ private struct IsStatusFocused: EnvironmentKey {
|
||||||
static let defaultValue: Bool = false
|
static let defaultValue: Bool = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct IsStatusReplyToPrevious: EnvironmentKey {
|
private struct IndentationLevel: EnvironmentKey {
|
||||||
static let defaultValue: Bool = false
|
static let defaultValue: UInt = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
public extension EnvironmentValues {
|
public extension EnvironmentValues {
|
||||||
|
@ -60,8 +60,8 @@ public extension EnvironmentValues {
|
||||||
set { self[IsStatusFocused.self] = newValue }
|
set { self[IsStatusFocused.self] = newValue }
|
||||||
}
|
}
|
||||||
|
|
||||||
var isStatusReplyToPrevious: Bool {
|
var indentationLevel: UInt {
|
||||||
get { self[IsStatusReplyToPrevious.self] }
|
get { self[IndentationLevel.self] }
|
||||||
set { self[IsStatusReplyToPrevious.self] = newValue }
|
set { self[IndentationLevel.self] = newValue }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,15 +103,15 @@ public struct StatusDetailView: View {
|
||||||
|
|
||||||
private func makeStatusesListView(statuses: [Status]) -> some View {
|
private func makeStatusesListView(statuses: [Status]) -> some View {
|
||||||
ForEach(statuses) { status in
|
ForEach(statuses) { status in
|
||||||
let isReplyToPrevious = viewModel.isReplyToPreviousCache[status.id] ?? false
|
let indentationLevel = viewModel.getIndentationLevel(id: status.id)
|
||||||
let viewModel: StatusRowViewModel = .init(status: status,
|
let viewModel: StatusRowViewModel = .init(status: status,
|
||||||
client: client,
|
client: client,
|
||||||
routerPath: routerPath)
|
routerPath: routerPath)
|
||||||
let isFocused = self.viewModel.statusId == status.id
|
let isFocused = self.viewModel.statusId == status.id
|
||||||
|
|
||||||
StatusRowView(viewModel: viewModel)
|
StatusRowView(viewModel: viewModel)
|
||||||
.environment(\.extraLeadingInset, isReplyToPrevious ? 10 : 0)
|
.environment(\.extraLeadingInset, (indentationLevel > 0) ? 10 : 0)
|
||||||
.environment(\.isStatusReplyToPrevious, isReplyToPrevious)
|
.environment(\.indentationLevel, indentationLevel)
|
||||||
.environment(\.isStatusFocused, isFocused)
|
.environment(\.isStatusFocused, isFocused)
|
||||||
.overlay {
|
.overlay {
|
||||||
if isFocused {
|
if isFocused {
|
||||||
|
|
|
@ -19,9 +19,10 @@ import SwiftUI
|
||||||
var state: State = .loading
|
var state: State = .loading
|
||||||
var title: LocalizedStringKey = ""
|
var title: LocalizedStringKey = ""
|
||||||
var scrollToId: String?
|
var scrollToId: String?
|
||||||
|
static var maxIndent = UInt(7)
|
||||||
|
|
||||||
@ObservationIgnored
|
@ObservationIgnored
|
||||||
var isReplyToPreviousCache: [String: Bool] = [:]
|
var indentationLevelPreviousCache: [String: UInt] = [:]
|
||||||
|
|
||||||
init(statusId: String) {
|
init(statusId: String) {
|
||||||
state = .loading
|
state = .loading
|
||||||
|
@ -35,7 +36,7 @@ import SwiftUI
|
||||||
statusId = status.id
|
statusId = status.id
|
||||||
remoteStatusURL = nil
|
remoteStatusURL = nil
|
||||||
if status.inReplyToId != nil {
|
if status.inReplyToId != nil {
|
||||||
isReplyToPreviousCache[status.id] = true
|
indentationLevelPreviousCache[status.id] = 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,24 +112,15 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
|
|
||||||
private func cacheReplyTopPrevious(statuses: [Status]) {
|
private func cacheReplyTopPrevious(statuses: [Status]) {
|
||||||
isReplyToPreviousCache = [:]
|
indentationLevelPreviousCache = [:]
|
||||||
for status in statuses {
|
for status in statuses {
|
||||||
var isReplyToPrevious: Bool = false
|
if let inReplyToId = status.inReplyToId,
|
||||||
if let index = statuses.firstIndex(where: { $0.id == status.id }),
|
let prevIndent = indentationLevelPreviousCache[inReplyToId] {
|
||||||
index > 0,
|
indentationLevelPreviousCache[status.id] = prevIndent + 1
|
||||||
statuses[index - 1].id == status.inReplyToId
|
|
||||||
{
|
|
||||||
if index == 1, statuses.count > 2 {
|
|
||||||
let nextStatus = statuses[2]
|
|
||||||
isReplyToPrevious = nextStatus.inReplyToId == status.id
|
|
||||||
} else if statuses.count == 2 {
|
|
||||||
isReplyToPrevious = false
|
|
||||||
} else {
|
} else {
|
||||||
isReplyToPrevious = true
|
indentationLevelPreviousCache[status.id] = 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isReplyToPreviousCache[status.id] = isReplyToPrevious
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleEvent(event: any StreamEvent, currentAccount: Account?) {
|
func handleEvent(event: any StreamEvent, currentAccount: Account?) {
|
||||||
|
@ -146,4 +138,8 @@ import SwiftUI
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getIndentationLevel(id: String) -> UInt {
|
||||||
|
min(indentationLevelPreviousCache[id] ?? 0, Self.maxIndent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ public struct StatusRowView: View {
|
||||||
@Environment(\.isCompact) private var isCompact: Bool
|
@Environment(\.isCompact) private var isCompact: Bool
|
||||||
@Environment(\.accessibilityVoiceOverEnabled) private var accessibilityVoiceOverEnabled
|
@Environment(\.accessibilityVoiceOverEnabled) private var accessibilityVoiceOverEnabled
|
||||||
@Environment(\.isStatusFocused) private var isFocused
|
@Environment(\.isStatusFocused) private var isFocused
|
||||||
@Environment(\.isStatusReplyToPrevious) private var isStatusReplyToPrevious
|
@Environment(\.indentationLevel) private var indentationLevel
|
||||||
|
|
||||||
@Environment(QuickLook.self) private var quickLook
|
@Environment(QuickLook.self) private var quickLook
|
||||||
@Environment(Theme.self) private var theme
|
@Environment(Theme.self) private var theme
|
||||||
|
@ -32,11 +32,15 @@ public struct StatusRowView: View {
|
||||||
|
|
||||||
public var body: some View {
|
public var body: some View {
|
||||||
HStack(spacing: 0) {
|
HStack(spacing: 0) {
|
||||||
if isStatusReplyToPrevious {
|
HStack(spacing: 3) {
|
||||||
|
ForEach(0..<indentationLevel, id: \.self) {_ in
|
||||||
Rectangle()
|
Rectangle()
|
||||||
.fill(theme.tintColor)
|
.fill(theme.tintColor)
|
||||||
.frame(width: 2)
|
.frame(width: 2)
|
||||||
.accessibilityHidden(true)
|
.accessibilityHidden(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if indentationLevel > 0 {
|
||||||
Spacer(minLength: 8)
|
Spacer(minLength: 8)
|
||||||
}
|
}
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
|
|
Loading…
Reference in a new issue