IceCubesApp/Packages/Status/Sources/Status/Row/StatusActionsView.swift
Thomas Ricouard 16636b12a9 Swift format
2023-01-30 07:27:06 +01:00

189 lines
5.4 KiB
Swift

import DesignSystem
import Env
import Models
import Network
import SwiftUI
struct StatusActionsView: View {
@Environment(\.openURL) private var openURL
@EnvironmentObject private var theme: Theme
@EnvironmentObject private var routerPath: RouterPath
@ObservedObject var viewModel: StatusRowViewModel
let generator = UINotificationFeedbackGenerator()
@MainActor
enum Actions: CaseIterable {
case respond, boost, favorite, bookmark, share
func iconName(viewModel: StatusRowViewModel) -> String {
switch self {
case .respond:
return "arrowshape.turn.up.left"
case .boost:
return viewModel.isReblogged ? "arrow.left.arrow.right.circle.fill" : "arrow.left.arrow.right.circle"
case .favorite:
return viewModel.isFavorited ? "star.fill" : "star"
case .bookmark:
return viewModel.isBookmarked ? "bookmark.fill" : "bookmark"
case .share:
return "square.and.arrow.up"
}
}
func count(viewModel: StatusRowViewModel, theme: Theme) -> Int? {
if theme.statusActionsDisplay == .discret {
return nil
}
switch self {
case .respond:
return viewModel.repliesCount
case .favorite:
return viewModel.favoritesCount
case .boost:
return viewModel.reblogsCount
case .share, .bookmark:
return nil
}
}
func tintColor(viewModel: StatusRowViewModel, theme: Theme) -> Color? {
switch self {
case .respond, .share:
return nil
case .favorite:
return viewModel.isFavorited ? .yellow : nil
case .bookmark:
return viewModel.isBookmarked ? .pink : nil
case .boost:
return viewModel.isReblogged ? theme.tintColor : nil
}
}
}
var body: some View {
VStack(spacing: 12) {
HStack {
ForEach(Actions.allCases, id: \.self) { action in
if action == .share {
if let url = viewModel.status.reblog?.url ?? viewModel.status.url {
ShareLink(item: url) {
Image(systemName: action.iconName(viewModel: viewModel))
}
.buttonStyle(.borderless)
}
} else {
Button {
handleAction(action: action)
} label: {
HStack(spacing: 2) {
Image(systemName: action.iconName(viewModel: viewModel))
.foregroundColor(action.tintColor(viewModel: viewModel, theme: theme))
if let count = action.count(viewModel: viewModel, theme: theme) {
Text("\(count)")
.font(.scaledFootnote)
}
}
}
.buttonStyle(.borderless)
.disabled(action == .boost &&
(viewModel.status.visibility == .direct || viewModel.status.visibility == .priv))
Spacer()
}
}
}
if viewModel.isFocused {
summaryView
}
}
}
@ViewBuilder
private var summaryView: some View {
Divider()
HStack {
Text(viewModel.status.createdAt.asDate, style: .date) +
Text("status.summary.at-time") +
Text(viewModel.status.createdAt.asDate, style: .time) +
Text(" ·")
Image(systemName: viewModel.status.visibility.iconName)
Spacer()
Text(viewModel.status.application?.name ?? "")
.underline()
.onTapGesture {
if let url = viewModel.status.application?.website {
openURL(url)
}
}
}
.font(.scaledCaption)
.foregroundColor(.gray)
if let editedAt = viewModel.status.editedAt {
Divider()
HStack {
Text("status.summary.edited-time") +
Text(editedAt.asDate, style: .date) +
Text("status.summary.at-time") +
Text(editedAt.asDate, style: .time)
Spacer()
}
.onTapGesture {
routerPath.presentedSheet = .statusEditHistory(status: viewModel.status.id)
}
.underline()
.font(.scaledCaption)
.foregroundColor(.gray)
}
if viewModel.favoritesCount > 0 {
Divider()
NavigationLink(value: RouterDestinations.favoritedBy(id: viewModel.status.id)) {
Text("status.summary.n-favorites \(viewModel.favoritesCount)")
.font(.scaledCallout)
Spacer()
Image(systemName: "chevron.right")
}
}
if viewModel.reblogsCount > 0 {
Divider()
NavigationLink(value: RouterDestinations.rebloggedBy(id: viewModel.status.id)) {
Text("status.summary.n-boosts \(viewModel.reblogsCount)")
.font(.scaledCallout)
Spacer()
Image(systemName: "chevron.right")
}
}
}
private func handleAction(action: Actions) {
Task {
generator.notificationOccurred(.success)
switch action {
case .respond:
routerPath.presentedSheet = .replyToStatusEditor(status: viewModel.status)
case .favorite:
if viewModel.isFavorited {
await viewModel.unFavorite()
} else {
await viewModel.favorite()
}
case .bookmark:
if viewModel.isBookmarked {
await viewModel.unbookmark()
} else {
await viewModel.bookmark()
}
case .boost:
if viewModel.isReblogged {
await viewModel.unReblog()
} else {
await viewModel.reblog()
}
default:
break
}
}
}
}