135 lines
5.8 KiB
Swift
135 lines
5.8 KiB
Swift
import SwiftUI
|
||
|
||
struct NewHomeTab: View {
|
||
@ObservedObject var viewModel: NewHomeTabViewModel
|
||
|
||
// Ширина колонки теперь вычисляется в ViewModel, но нам она нужна и здесь для PostGridItem
|
||
private let columnWidth = (UIScreen.main.bounds.width - 14) / 2
|
||
|
||
var body: some View {
|
||
VStack {
|
||
if viewModel.isLoading {
|
||
ProgressView("Загрузка ленты...")
|
||
} else {
|
||
RefreshableScrollView(isRefreshing: $viewModel.isRefreshing, onRefresh: {
|
||
viewModel.refreshData()
|
||
}) {
|
||
HStack(alignment: .top, spacing: 6) {
|
||
LazyVStack(spacing: 6) {
|
||
ForEach(viewModel.column1Posts) { post in
|
||
PostGridItem(post: post, width: columnWidth)
|
||
}
|
||
}
|
||
LazyVStack(spacing: 6) {
|
||
ForEach(viewModel.column2Posts) { post in
|
||
PostGridItem(post: post, width: columnWidth)
|
||
}
|
||
}
|
||
}
|
||
.padding(.horizontal, 4)
|
||
}
|
||
}
|
||
}
|
||
.onAppear {
|
||
viewModel.fetchDataIfNeeded()
|
||
}
|
||
// .background(Color(.secondarySystemBackground)) // Фон для всей вкладки
|
||
}
|
||
}
|
||
|
||
struct PostGridItem: View {
|
||
let post: Post
|
||
let width: CGFloat // Ширина элемента
|
||
|
||
// Формируем URL для загрузки изображения
|
||
private var imageURL: URL? {
|
||
// Используем picsum.photos для получения уникального изображения для каждого поста
|
||
// Используем реальные размеры для большей вариативности
|
||
if let media = post.media.first, let w = media.width, let h = media.height {
|
||
return URL(string: "https://picsum.photos/seed/\(post.id.uuidString)/\(w)/\(h)")
|
||
}
|
||
return URL(string: "https://picsum.photos/seed/\(post.id.uuidString)/400/400")
|
||
}
|
||
|
||
// Вычисляем высоту изображения на основе данных из модели
|
||
private var imageHeight: CGFloat {
|
||
guard let media = post.media.first,
|
||
let mediaWidth = media.width,
|
||
let mediaHeight = media.height,
|
||
mediaWidth > 0 else {
|
||
return width // Возвращаем 1:1, если данных нет
|
||
}
|
||
|
||
let aspectRatio = CGFloat(mediaHeight) / CGFloat(mediaWidth)
|
||
return width * aspectRatio
|
||
}
|
||
|
||
var body: some View {
|
||
VStack(alignment: .leading, spacing: 0) { // Убираем отступ между картинкой и текстом
|
||
|
||
// 1. Медиа контент
|
||
if let url = imageURL {
|
||
// Создаем контейнер с четкими границами, чтобы избежать перекрытия
|
||
Color.clear
|
||
.frame(width: width, height: imageHeight) // Используем вычисленную высоту
|
||
.background(
|
||
RemoteImageView(url: url)
|
||
.scaledToFill()
|
||
)
|
||
.clipped()
|
||
}
|
||
|
||
// Контейнер для текста, который создает эффект "расширения"
|
||
VStack(alignment: .leading, spacing: 8) {
|
||
// 2. Название поста
|
||
if let title = post.title, !title.isEmpty {
|
||
Text(title)
|
||
.font(.subheadline)
|
||
.lineLimit(2)
|
||
}
|
||
|
||
// 3. Информация об авторе и лайки
|
||
HStack {
|
||
|
||
Button(action: {
|
||
// пока ничего не делаем
|
||
}) {
|
||
HStack(spacing: 4) {
|
||
Image(systemName: "person.circle.fill")
|
||
.resizable()
|
||
.frame(width: 20, height: 20)
|
||
.foregroundColor(.gray)
|
||
Text(post.authorUsername)
|
||
.font(.footnote)
|
||
.lineLimit(1)
|
||
.foregroundColor(.primary)
|
||
}
|
||
}
|
||
.contentShape(Rectangle())
|
||
|
||
Spacer()
|
||
|
||
Button(action: {
|
||
// пока ничего не делаем
|
||
}) {
|
||
HStack(spacing: 4) {
|
||
Image(systemName: post.isLikedByCurrentUser ? "heart.fill" : "heart")
|
||
.foregroundColor(post.isLikedByCurrentUser ? .red : .primary)
|
||
Text("\(post.likes)")
|
||
.font(.subheadline)
|
||
.foregroundColor(.primary)
|
||
}
|
||
}
|
||
.contentShape(Rectangle())
|
||
|
||
}
|
||
}
|
||
.padding(8)
|
||
.background(Color(UIColor.systemBackground)) // Фон только для текстовой части
|
||
}
|
||
.cornerRadius(6) // Закругляем всю карточку
|
||
.clipped() // Обрезаем дочерние вью по закругленной форме родителя
|
||
.shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2)
|
||
}
|
||
}
|