Files
org-social-ios/App/Views/Discover/DiscoverView.swift
andros cb5c631290 Add Read more for long posts, Discover pinned order, and bump to 1.1 (9)
- PostRowView: truncate posts over 500 chars with a pill-style Read more
  button; expands inline on tap and collapses on reappear (back navigation
  or scroll off-screen). Focal post in ThreadView never truncated.
- Settings: Stepper in new Timeline section to configure the character
  limit (100–2000, default 500).
- DiscoverViewModel: org-social and andros accounts always appear first;
  remaining feeds in random order; removed manual reload button.
- Version: 1.1 (9)
2026-05-12 21:22:41 +02:00

107 lines
3.9 KiB
Swift

import SwiftUI
import OrgSocialKit
struct DiscoverView: View {
@State private var viewModel = DiscoverViewModel()
var body: some View {
NavigationStack {
Group {
if viewModel.isLoading && viewModel.users.isEmpty {
VStack(spacing: 16) {
ProgressView()
Text("Loading profiles from relay...")
.font(.subheadline)
.foregroundStyle(.secondary)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else if let error = viewModel.errorMessage, viewModel.users.isEmpty {
ContentUnavailableView {
Label("Discover unavailable", systemImage: "person.slash")
} description: {
Text(error)
} actions: {
Button("Retry") { Task { await viewModel.load() } }
.buttonStyle(.bordered)
}
} else if viewModel.users.isEmpty {
ContentUnavailableView(
"No profiles found",
systemImage: "person.3",
description: Text("No other users registered on this relay.")
)
} else {
List(viewModel.users) { user in
DiscoverUserRow(user: user, viewModel: viewModel)
}
.listStyle(.plain)
.navigationDestination(for: URL.self) { ProfileView(feedURL: $0) }
}
}
.navigationTitle("Discover")
.task { await viewModel.load() }
}
}
}
private struct DiscoverUserRow: View {
let user: DiscoverViewModel.DiscoverUser
var viewModel: DiscoverViewModel
@State private var isToggling = false
var body: some View {
HStack(spacing: 12) {
NavigationLink(value: user.feedURL) {
HStack(spacing: 12) {
AvatarView(url: user.avatar, nick: user.nick, size: 44)
VStack(alignment: .leading, spacing: 3) {
if let nick = user.nick {
Text("@\(nick)")
.font(.subheadline.weight(.semibold))
}
if let desc = user.description {
Text(desc)
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(2)
} else {
Text(user.feedURL.host ?? user.feedURL.absoluteString)
.font(.caption)
.foregroundStyle(.secondary)
.lineLimit(1)
}
}
}
}
Spacer()
if isToggling {
ProgressView()
.frame(width: 72)
} else {
Button {
isToggling = true
Task {
if user.isFollowing {
await viewModel.unfollow(user: user)
} else {
await viewModel.follow(user: user)
}
isToggling = false
}
} label: {
Text(user.isFollowing ? "Unfollow" : "Follow")
.font(.subheadline)
.fontWeight(user.isFollowing ? .regular : .semibold)
.frame(width: 72)
}
.buttonStyle(.bordered)
.tint(user.isFollowing ? .secondary : .accentColor)
}
}
.padding(.vertical, 4)
}
}