refresh home page

This commit is contained in:
cheykrym 2025-07-16 07:44:16 +03:00
parent bb8c9a2b91
commit 8fd955d3cb
3 changed files with 96 additions and 5 deletions

View File

@ -0,0 +1,71 @@
import SwiftUI
import UIKit
struct RefreshableScrollView<Content: View>: UIViewRepresentable {
var content: Content
var onRefresh: (UIRefreshControl) -> Void
var isRefreshing: Binding<Bool>
init(isRefreshing: Binding<Bool>, onRefresh: @escaping (UIRefreshControl) -> Void, @ViewBuilder content: () -> Content) {
self.content = content()
self.onRefresh = onRefresh
self.isRefreshing = isRefreshing
}
func makeUIView(context: Context) -> UIScrollView {
let scrollView = UIScrollView()
// Создаем UIRefreshControl и добавляем его
let refreshControl = UIRefreshControl()
refreshControl.addTarget(context.coordinator, action: #selector(Coordinator.handleRefresh), for: .valueChanged)
scrollView.refreshControl = refreshControl
// Создаем хостинг для нашего SwiftUI контента
let hostingController = UIHostingController(rootView: content)
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(hostingController.view)
// Настраиваем Auto Layout
NSLayoutConstraint.activate([
hostingController.view.leadingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: scrollView.contentLayoutGuide.trailingAnchor),
hostingController.view.topAnchor.constraint(equalTo: scrollView.contentLayoutGuide.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: scrollView.contentLayoutGuide.bottomAnchor),
hostingController.view.widthAnchor.constraint(equalTo: scrollView.frameLayoutGuide.widthAnchor)
])
context.coordinator.hostingController = hostingController
return scrollView
}
func updateUIView(_ uiView: UIScrollView, context: Context) {
// Обновляем состояние индикатора
if isRefreshing.wrappedValue {
uiView.refreshControl?.beginRefreshing()
} else {
uiView.refreshControl?.endRefreshing()
}
// Обновляем SwiftUI View, если нужно
context.coordinator.hostingController?.rootView = content
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject {
var parent: RefreshableScrollView
var hostingController: UIHostingController<Content>?
init(_ parent: RefreshableScrollView) {
self.parent = parent
}
@objc func handleRefresh(_ sender: UIRefreshControl) {
parent.isRefreshing.wrappedValue = true
parent.onRefresh(sender)
}
}
}

View File

@ -3,6 +3,7 @@ import SwiftUI
struct HomeTab: View { struct HomeTab: View {
@State private var posts: [Post] = [] @State private var posts: [Post] = []
@State private var isLoading = true @State private var isLoading = true
@State private var isRefreshing = false
var body: some View { var body: some View {
NavigationView { NavigationView {
@ -10,7 +11,9 @@ struct HomeTab: View {
if isLoading { if isLoading {
ProgressView("Загрузка ленты...") ProgressView("Загрузка ленты...")
} else { } else {
ScrollView { RefreshableScrollView(isRefreshing: $isRefreshing, onRefresh: { _ in
fetchData()
}) {
LazyVStack(spacing: 24) { LazyVStack(spacing: 24) {
ForEach(posts) { post in ForEach(posts) { post in
PostDetailView(post: post) PostDetailView(post: post)
@ -22,12 +25,25 @@ struct HomeTab: View {
.navigationTitle("Лента") .navigationTitle("Лента")
.onAppear { .onAppear {
if posts.isEmpty { if posts.isEmpty {
PostService.shared.fetchAllPosts { fetchedPosts in fetchData(isInitialLoad: true)
self.posts = fetchedPosts
self.isLoading = false
}
} }
} }
} }
} }
private func fetchData(isInitialLoad: Bool = false) {
if isInitialLoad {
isLoading = true
}
PostService.shared.fetchAllPosts { fetchedPosts in
self.posts = fetchedPosts
if isInitialLoad {
print("content updated")
self.isLoading = false
}
self.isRefreshing = false
}
}
} }

View File

@ -38,6 +38,7 @@
1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; }; 1ACE61192E22FF1400B37AC5 /* Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61182E22FF1400B37AC5 /* Post.swift */; };
1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */; }; 1ACE61212E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */; };
1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */; }; 1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */; };
1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */; };
1AE587052E23264800254F06 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587042E23264800254F06 /* PostService.swift */; }; 1AE587052E23264800254F06 /* PostService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587042E23264800254F06 /* PostService.swift */; };
1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; }; 1AE587252E23337000254F06 /* ProfileContentGrid.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AE587242E23337000254F06 /* ProfileContentGrid.swift */; };
1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; }; 1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */; };
@ -81,6 +82,7 @@
1ACE61182E22FF1400B37AC5 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; }; 1ACE61182E22FF1400B37AC5 /* Post.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Post.swift; sourceTree = "<group>"; };
1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentTabbedGrid.swift; sourceTree = "<group>"; }; 1ACE61202E22FFD000B37AC5 /* ProfileContentTabbedGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentTabbedGrid.swift; sourceTree = "<group>"; };
1AD757CC2E27608C0069C1FD /* PostFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostFeedView.swift; sourceTree = "<group>"; }; 1AD757CC2E27608C0069C1FD /* PostFeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostFeedView.swift; sourceTree = "<group>"; };
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RefreshableScrollView.swift; path = Components/RefreshableScrollView.swift; sourceTree = "<group>"; };
1AE587042E23264800254F06 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; }; 1AE587042E23264800254F06 /* PostService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostService.swift; sourceTree = "<group>"; };
1AE587242E23337000254F06 /* ProfileContentGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentGrid.swift; sourceTree = "<group>"; }; 1AE587242E23337000254F06 /* ProfileContentGrid.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileContentGrid.swift; sourceTree = "<group>"; };
1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; }; 1AEE5EAA2E21A83200A3DCA3 /* HomeTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTab.swift; sourceTree = "<group>"; };
@ -119,6 +121,7 @@
1A7940792DF77BC2002569DA /* Shared */ = { 1A7940792DF77BC2002569DA /* Shared */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1AD757D02E27640F0069C1FD /* RefreshableScrollView.swift */,
1A7940FA2DF7B898002569DA /* Resources */, 1A7940FA2DF7B898002569DA /* Resources */,
1A7940E52DF7B341002569DA /* Services */, 1A7940E52DF7B341002569DA /* Services */,
1A7940A02DF77DCD002569DA /* Network */, 1A7940A02DF77DCD002569DA /* Network */,
@ -402,6 +405,7 @@
1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */, 1A7940AA2DF77E05002569DA /* LoginViewModel.swift in Sources */,
1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */, 1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */,
1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */, 1A79408D2DF77BC3002569DA /* yobbleApp.swift in Sources */,
1AD757D12E27640F0069C1FD /* RefreshableScrollView.swift in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };