A bit better timeline UI

This commit is contained in:
Thomas Ricouard 2022-12-16 13:16:48 +01:00
parent b7ce9648d5
commit eb4dc011b6
4 changed files with 118 additions and 22 deletions

View file

@ -1,7 +1,7 @@
import HTML2Markdown
import Foundation
extension Status {
extension AnyStatus {
private static var createdAtDateFormatter: DateFormatter {
let dateFormatter = DateFormatter()
dateFormatter.calendar = .init(identifier: .iso8601)
@ -16,6 +16,12 @@ extension Status {
return dateFormatter
}
private static var createdAtShortDateFormatted: DateFormatter {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .medium
return dateFormatter
}
public var contentAsMarkdown: String {
do {
let dom = try HTMLParser().parse(html: content)
@ -30,6 +36,21 @@ extension Status {
}
public var createdAtFormatted: String {
Self.createdAtRelativeFormatter.localizedString(for: createdAtDate, relativeTo: Date())
let calendar = Calendar(identifier: .gregorian)
if calendar.numberOfDaysBetween(createdAtDate, and: Date()) > 1 {
return Self.createdAtShortDateFormatted.string(from: createdAtDate)
} else {
return Self.createdAtRelativeFormatter.localizedString(for: createdAtDate, relativeTo: Date())
}
}
}
extension Calendar {
func numberOfDaysBetween(_ from: Date, and to: Date) -> Int {
let fromDate = startOfDay(for: from)
let toDate = startOfDay(for: to)
let numberOfDays = dateComponents([.day], from: fromDate, to: toDate)
return numberOfDays.day!
}
}

View file

@ -1,6 +1,21 @@
import Foundation
public struct Status: Codable, Identifiable {
public protocol AnyStatus {
var id: String { get }
var content: String { get }
var account: Account { get }
var createdAt: String { get }
}
public struct Status: AnyStatus, Codable, Identifiable {
public let id: String
public let content: String
public let account: Account
public let createdAt: String
public let reblog: ReblogStatus?
}
public struct ReblogStatus: AnyStatus, Codable, Identifiable {
public let id: String
public let content: String
public let account: Account

View file

@ -0,0 +1,35 @@
import SwiftUI
import Models
import Routeur
struct StatusActionsView: View {
let status: Status
var body: some View {
HStack {
Button {
} label: {
Image(systemName: "bubble.right")
}
Spacer()
Button {
} label: {
Image(systemName: "arrow.left.arrow.right.circle")
}
Spacer()
Button {
} label: {
Image(systemName: "star")
}
Spacer()
Button {
} label: {
Image(systemName: "square.and.arrow.up")
}
}
}
}

View file

@ -9,26 +9,45 @@ struct StatusRowView: View {
var body: some View {
VStack(alignment: .leading) {
HStack(alignment: .top) {
reblogView
statusView
StatusActionsView(status: status)
.padding(.vertical, 8)
}
}
@ViewBuilder
private var reblogView: some View {
if status.reblog != nil {
HStack(spacing: 2) {
Image(systemName:"arrow.left.arrow.right.circle")
Text("\(status.account.displayName) reblogged")
}
.font(.footnote)
.foregroundColor(.gray)
.fontWeight(.semibold)
}
}
@ViewBuilder
private var statusView: some View {
if let status: AnyStatus = status.reblog ?? status {
Button {
routeurPath.navigate(to: .accountDetail(id: status.account.id))
} label: {
accountView
makeAccountView(status: status)
}.buttonStyle(.plain)
Spacer()
Text(status.createdAtFormatted)
.font(.footnote)
.foregroundColor(.gray)
}
NavigationLink(value: RouteurDestinations.statusDetail(id: status.id)) {
Text(try! AttributedString(markdown: status.contentAsMarkdown))
.font(.body)
.onTapGesture {
routeurPath.navigate(to: .statusDetail(id: status.id))
}
}
}
@ViewBuilder
private var accountView: some View {
private func makeAccountView(status: AnyStatus) -> some View {
AsyncImage(
url: status.account.avatar,
content: { image in
@ -45,9 +64,15 @@ struct StatusRowView: View {
VStack(alignment: .leading) {
Text(status.account.displayName)
.font(.headline)
HStack {
Text("@\(status.account.acct)")
.font(.footnote)
.foregroundColor(.gray)
Spacer()
Text(status.createdAtFormatted)
.font(.footnote)
.foregroundColor(.gray)
}
}
}
}