iOS: drop demo HomeFeedView (replaced by ContactsView)

This commit is contained in:
efir369999 2026-05-05 17:16:59 +03:00
parent b5b36f93cd
commit 42311bcb74

View File

@ -1,222 +0,0 @@
import SwiftUI
import Combine
struct FeedPost: Identifiable, Hashable {
let id = UUID()
let author: String
let handle: String
let timeAgo: String
let body: String
let replies: Int
let reposts: Int
let likes: Int
}
@MainActor
final class FeedStore: ObservableObject {
static let shared = FeedStore()
@Published var posts: [FeedPost] = [
FeedPost(author: "Алик Монтана", handle: "@alik", timeAgo: "",
body: "Запустили генезис в трёх городах: мос, фра, зел. Время идёт честно.",
replies: 12, reposts: 4, likes: 87),
FeedPost(author: "Юнона", handle: "@junona", timeAgo: "18м",
body: "Никто не читает твои сообщения. Никто не знает, кто ты. Это нормально.",
replies: 3, reposts: 22, likes: 154),
FeedPost(author: "Frankfurt Node", handle: "@fra", timeAgo: "",
body: "Окно 2891844 закрыто. VDF подтверждён. Якорь установлен.",
replies: 0, reposts: 1, likes: 9),
FeedPost(author: "Helsinki Node", handle: "@zel", timeAgo: "",
body: "Reality маска работает. Трафик неотличим от обычного TLS.",
replies: 5, reposts: 11, likes: 42),
FeedPost(author: "Moscow Node", handle: "@mos", timeAgo: "",
body: "efir.org перешёл на :8443 — :443 теперь у Xray. Всё стабильно.",
replies: 2, reposts: 3, likes: 18),
]
func publish(_ text: String) {
let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty else { return }
posts.insert(FeedPost(author: "Алик Монтана", handle: "@alik", timeAgo: "сейчас",
body: trimmed, replies: 0, reposts: 0, likes: 0), at: 0)
}
}
struct HomeFeedView: View {
@StateObject private var store = FeedStore.shared
@State private var composing = false
var body: some View {
NavigationStack {
ZStack(alignment: .bottomTrailing) {
ScrollView {
LazyVStack(spacing: 0) {
FeedHeader().padding(.top, ClaudeTheme.Spacing.sm)
ForEach(store.posts) { post in
PostRow(post: post)
Rectangle()
.fill(ClaudeTheme.Palette.divider)
.frame(height: 0.5)
.padding(.leading, 76)
}
}
}
.claudeBackground()
Button { composing = true } label: {
Image(systemName: "square.and.pencil")
.font(.system(size: 22, weight: .medium))
.foregroundStyle(ClaudeTheme.Palette.bubbleOutText)
.frame(width: 56, height: 56)
.background(Circle().fill(ClaudeTheme.Palette.goldGradient))
.overlay(Circle().strokeBorder(ClaudeTheme.Palette.goldBright.opacity(0.5), lineWidth: 0.5))
.shadow(color: ClaudeTheme.Palette.gold.opacity(0.45), radius: 16, y: 4)
}
.padding(.trailing, ClaudeTheme.Spacing.lg)
.padding(.bottom, ClaudeTheme.Spacing.lg)
}
.navigationTitle("Эфир")
.navigationBarTitleDisplayMode(.inline)
.sheet(isPresented: $composing) {
ComposePostView { text in
store.publish(text)
}
}
}
}
}
private struct FeedHeader: View {
var body: some View {
HStack(spacing: 12) {
Text("Эфир")
.font(.system(size: 32, weight: .bold, design: .serif))
.foregroundStyle(ClaudeTheme.Palette.goldGradient)
Spacer()
Image(systemName: "sparkles")
.font(.system(size: 18))
.foregroundStyle(ClaudeTheme.Palette.gold.opacity(0.6))
}
.padding(.horizontal, ClaudeTheme.Spacing.lg)
.padding(.bottom, 4)
}
}
private struct PostRow: View {
let post: FeedPost
var body: some View {
HStack(alignment: .top, spacing: ClaudeTheme.Spacing.md) {
AvatarView(name: post.author, size: 44)
VStack(alignment: .leading, spacing: 6) {
HStack(spacing: 6) {
Text(post.author)
.font(ClaudeTheme.Typography.headline)
.foregroundStyle(ClaudeTheme.Palette.textPrimary)
Text(post.handle)
.font(ClaudeTheme.Typography.caption)
.foregroundStyle(ClaudeTheme.Palette.textTertiary)
Text("·").foregroundStyle(ClaudeTheme.Palette.textTertiary)
Text(post.timeAgo)
.font(ClaudeTheme.Typography.caption)
.foregroundStyle(ClaudeTheme.Palette.textTertiary)
Spacer()
}
Text(post.body)
.font(ClaudeTheme.Typography.body)
.foregroundStyle(ClaudeTheme.Palette.textPrimary)
.fixedSize(horizontal: false, vertical: true)
HStack(spacing: ClaudeTheme.Spacing.xl) {
PostAction(icon: "bubble.left", count: post.replies)
PostAction(icon: "arrow.2.squarepath", count: post.reposts)
PostAction(icon: "heart", count: post.likes)
Spacer()
Image(systemName: "square.and.arrow.up")
.font(.system(size: 14))
.foregroundStyle(ClaudeTheme.Palette.textTertiary)
}
.padding(.top, 4)
}
}
.padding(.horizontal, ClaudeTheme.Spacing.lg)
.padding(.vertical, ClaudeTheme.Spacing.md)
}
}
private struct PostAction: View {
let icon: String
let count: Int
var body: some View {
HStack(spacing: 4) {
Image(systemName: icon).font(.system(size: 14))
if count > 0 { Text("\(count)").font(ClaudeTheme.Typography.caption) }
}
.foregroundStyle(ClaudeTheme.Palette.textTertiary)
}
}
private struct ComposePostView: View {
@Environment(\.dismiss) private var dismiss
let onPublish: (String) -> Void
@State private var text: String = ""
@FocusState private var focused: Bool
var body: some View {
NavigationStack {
VStack(alignment: .leading, spacing: 0) {
HStack(alignment: .top, spacing: 12) {
AvatarView(name: "Алик Монтана", size: 44)
TextEditor(text: $text)
.font(ClaudeTheme.Typography.body)
.foregroundStyle(ClaudeTheme.Palette.textPrimary)
.scrollContentBackground(.hidden)
.focused($focused)
.overlay(alignment: .topLeading) {
if text.isEmpty {
Text("Что происходит в эфире?")
.font(ClaudeTheme.Typography.body)
.foregroundStyle(ClaudeTheme.Palette.textTertiary)
.padding(.top, 8)
.padding(.leading, 4)
.allowsHitTesting(false)
}
}
}
.padding(ClaudeTheme.Spacing.lg)
Spacer()
}
.claudeBackground()
.navigationTitle("Новый пост")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Отмена") { dismiss() }
.foregroundStyle(ClaudeTheme.Palette.textSecondary)
}
ToolbarItem(placement: .topBarTrailing) {
Button {
onPublish(text)
dismiss()
} label: {
Text("Опубликовать")
.font(.system(size: 14, weight: .semibold))
.foregroundStyle(text.isEmpty
? ClaudeTheme.Palette.textTertiary
: ClaudeTheme.Palette.bubbleOutText)
.padding(.horizontal, 14)
.padding(.vertical, 6)
.background(
Capsule().fill(text.isEmpty
? AnyShapeStyle(ClaudeTheme.Palette.surface)
: AnyShapeStyle(ClaudeTheme.Palette.goldGradient))
)
}
.disabled(text.isEmpty)
}
}
.onAppear { focused = true }
}
}
}