load from api
This commit is contained in:
		
							parent
							
								
									efc7773c04
								
							
						
					
					
						commit
						a02fa53902
					
				
							
								
								
									
										58
									
								
								Shared/Components/RemoteImageView.swift
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								Shared/Components/RemoteImageView.swift
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
			
		||||
import SwiftUI
 | 
			
		||||
import Combine
 | 
			
		||||
 | 
			
		||||
// 1. Класс для загрузки изображения
 | 
			
		||||
class ImageLoader: ObservableObject {
 | 
			
		||||
    @Published var image: UIImage?
 | 
			
		||||
    private var cancellable: AnyCancellable?
 | 
			
		||||
    private let url: URL
 | 
			
		||||
    
 | 
			
		||||
    init(url: URL) {
 | 
			
		||||
        self.url = url
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    deinit {
 | 
			
		||||
        cancellable?.cancel()
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func load() {
 | 
			
		||||
        cancellable = URLSession.shared.dataTaskPublisher(for: url)
 | 
			
		||||
            .map { UIImage(data: $0.data) }
 | 
			
		||||
            .replaceError(with: nil)
 | 
			
		||||
            .receive(on: DispatchQueue.main)
 | 
			
		||||
            .assign(to: \.image, on: self)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    func cancel() {
 | 
			
		||||
        cancellable?.cancel()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 2. View для отображения удаленного изображения
 | 
			
		||||
struct RemoteImageView: View {
 | 
			
		||||
    @StateObject private var loader: ImageLoader
 | 
			
		||||
    private let placeholder: Image
 | 
			
		||||
    
 | 
			
		||||
    init(url: URL, placeholder: Image = Image("placeholderPhoto")) {
 | 
			
		||||
        _loader = StateObject(wrappedValue: ImageLoader(url: url))
 | 
			
		||||
        self.placeholder = placeholder
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        content
 | 
			
		||||
            .onAppear(perform: loader.load)
 | 
			
		||||
            .onDisappear(perform: loader.cancel)
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private var content: some View {
 | 
			
		||||
        Group {
 | 
			
		||||
            if let image = loader.image {
 | 
			
		||||
                Image(uiImage: image)
 | 
			
		||||
                    .resizable()
 | 
			
		||||
            } else {
 | 
			
		||||
                placeholder
 | 
			
		||||
                    .resizable()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -50,15 +50,24 @@ struct PostGridItem: View {
 | 
			
		||||
    let post: Post
 | 
			
		||||
    let width: CGFloat // Ширина элемента
 | 
			
		||||
    
 | 
			
		||||
    // Формируем URL для загрузки изображения
 | 
			
		||||
    private var imageURL: URL? {
 | 
			
		||||
        // Используем picsum.photos для получения уникального изображения для каждого поста
 | 
			
		||||
        URL(string: "https://picsum.photos/seed/\(post.id.uuidString)/400/400")
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    var body: some View {
 | 
			
		||||
        VStack(alignment: .leading, spacing: 0) { // Убираем отступ между картинкой и текстом
 | 
			
		||||
            // 1. Медиа контент
 | 
			
		||||
            if let _ = post.media.first {
 | 
			
		||||
                Image("placeholderPhoto")
 | 
			
		||||
                    .resizable()
 | 
			
		||||
                    .scaledToFill() // Заполняем кадр, сохраняя пропорции
 | 
			
		||||
                    .frame(width: width, height: width) // Устанавливаем жесткий размер
 | 
			
		||||
                    .clipped() // Обрезаем лишнее
 | 
			
		||||
            if let url = imageURL {
 | 
			
		||||
                // Создаем контейнер с четкими границами, чтобы избежать перекрытия
 | 
			
		||||
                Color.clear
 | 
			
		||||
                    .frame(width: width, height: width)
 | 
			
		||||
                    .background(
 | 
			
		||||
                        RemoteImageView(url: url)
 | 
			
		||||
                            .scaledToFill()
 | 
			
		||||
                    )
 | 
			
		||||
                    .clipped()
 | 
			
		||||
            }
 | 
			
		||||
            
 | 
			
		||||
            // Контейнер для текста, который создает эффект "расширения"
 | 
			
		||||
 | 
			
		||||
@ -37,6 +37,7 @@
 | 
			
		||||
		1A9B016E2E4BFB9000887E0B /* NewHomeTabViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */; };
 | 
			
		||||
		1A9B017C2E4C087F00887E0B /* SideMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9B017B2E4C087F00887E0B /* SideMenuView.swift */; };
 | 
			
		||||
		1A9E4FB32E4D6A67002249D6 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */; };
 | 
			
		||||
		1A9E4FD72E4E47EF002249D6 /* RemoteImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A9E4FD62E4E47EF002249D6 /* RemoteImageView.swift */; };
 | 
			
		||||
		1AB4F8CD2E22E341002B6E40 /* AccountShareSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */; };
 | 
			
		||||
		1AB4F8F32E22EC9F002B6E40 /* FollowersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */; };
 | 
			
		||||
		1AB4F8F72E22ECAC002B6E40 /* FollowingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */; };
 | 
			
		||||
@ -92,6 +93,7 @@
 | 
			
		||||
		1A9B016D2E4BFB9000887E0B /* NewHomeTabViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewHomeTabViewModel.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A9B017B2E4C087F00887E0B /* SideMenuView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SideMenuView.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A9E4FB22E4D6A67002249D6 /* ThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1A9E4FD62E4E47EF002249D6 /* RemoteImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteImageView.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1AB4F8CC2E22E341002B6E40 /* AccountShareSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountShareSheet.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1AB4F8F22E22EC9F002B6E40 /* FollowersView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowersView.swift; sourceTree = "<group>"; };
 | 
			
		||||
		1AB4F8F62E22ECAC002B6E40 /* FollowingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowingView.swift; sourceTree = "<group>"; };
 | 
			
		||||
@ -257,6 +259,7 @@
 | 
			
		||||
		1AB7F5132E32EBF1003756F3 /* Components */ = {
 | 
			
		||||
			isa = PBXGroup;
 | 
			
		||||
			children = (
 | 
			
		||||
				1A9E4FD62E4E47EF002249D6 /* RemoteImageView.swift */,
 | 
			
		||||
				1AB7F5142E32EC1C003756F3 /* RefreshableScrollView.swift */,
 | 
			
		||||
				1AB7F5152E32EC1C003756F3 /* TopBarView.swift */,
 | 
			
		||||
			);
 | 
			
		||||
@ -429,6 +432,7 @@
 | 
			
		||||
				1AEE5EAB2E21A83200A3DCA3 /* HomeTab.swift in Sources */,
 | 
			
		||||
				1ACE60F82E22F3DC00B37AC5 /* SettingsView.swift in Sources */,
 | 
			
		||||
				1AD757CD2E27608C0069C1FD /* PostFeedView.swift in Sources */,
 | 
			
		||||
				1A9E4FD72E4E47EF002249D6 /* RemoteImageView.swift in Sources */,
 | 
			
		||||
				1A9B017C2E4C087F00887E0B /* SideMenuView.swift in Sources */,
 | 
			
		||||
				1A7940C62DF7A98E002569DA /* ContactsTab.swift in Sources */,
 | 
			
		||||
				1ACE61092E22F57100B37AC5 /* AppPreferencesView.swift in Sources */,
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user