From 891418e90fe29515364a236a2bb9c81e2a37ff65 Mon Sep 17 00:00:00 2001 From: Vitaly Takmazov Date: Wed, 15 May 2024 09:50:08 +0300 Subject: Refactor & reorganize project * LoadableState -> Result --- Juick.xcodeproj/project.pbxproj | 14 ++++---- JuickNext/FeedView.swift | 60 ---------------------------------- JuickNext/Helpers/Errors.swift | 20 ++++++++++++ JuickNext/LoadableImageView.swift | 29 ---------------- JuickNext/LoadableState.swift | 25 -------------- JuickNext/MessageFetcher.swift | 12 +++---- JuickNext/MessageView.swift | 43 ------------------------ JuickNext/View/FeedView.swift | 57 ++++++++++++++++++++++++++++++++ JuickNext/View/LoadableImageView.swift | 29 ++++++++++++++++ JuickNext/View/MessageView.swift | 43 ++++++++++++++++++++++++ 10 files changed, 162 insertions(+), 170 deletions(-) delete mode 100644 JuickNext/FeedView.swift create mode 100644 JuickNext/Helpers/Errors.swift delete mode 100644 JuickNext/LoadableImageView.swift delete mode 100644 JuickNext/LoadableState.swift delete mode 100644 JuickNext/MessageView.swift create mode 100644 JuickNext/View/FeedView.swift create mode 100644 JuickNext/View/LoadableImageView.swift create mode 100644 JuickNext/View/MessageView.swift diff --git a/Juick.xcodeproj/project.pbxproj b/Juick.xcodeproj/project.pbxproj index 68ca4a4..2c548fc 100644 --- a/Juick.xcodeproj/project.pbxproj +++ b/Juick.xcodeproj/project.pbxproj @@ -61,7 +61,7 @@ 77AA76482BF48818007A0FA8 /* Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA76402BF48818007A0FA8 /* Models.swift */; }; 77AA764A2BF48818007A0FA8 /* FeedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA76422BF48818007A0FA8 /* FeedView.swift */; }; 77AA764B2BF48818007A0FA8 /* MessageFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA76432BF48818007A0FA8 /* MessageFetcher.swift */; }; - 77AA764C2BF48818007A0FA8 /* LoadableState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA76442BF48818007A0FA8 /* LoadableState.swift */; }; + 77AA764C2BF48818007A0FA8 /* Errors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA76442BF48818007A0FA8 /* Errors.swift */; }; 77AA764D2BF48818007A0FA8 /* ImageFetcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA76452BF48818007A0FA8 /* ImageFetcher.swift */; }; 77AA76502BF488A9007A0FA8 /* Image+Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 77AA764F2BF488A9007A0FA8 /* Image+Data.swift */; }; 77B09994189D0B9900A84F59 /* UIImage+Utils.m in Sources */ = {isa = PBXBuildFile; fileRef = 77B09993189D0B9900A84F59 /* UIImage+Utils.m */; }; @@ -195,7 +195,7 @@ 77AA76402BF48818007A0FA8 /* Models.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Models.swift; sourceTree = ""; }; 77AA76422BF48818007A0FA8 /* FeedView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedView.swift; sourceTree = ""; }; 77AA76432BF48818007A0FA8 /* MessageFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageFetcher.swift; sourceTree = ""; }; - 77AA76442BF48818007A0FA8 /* LoadableState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadableState.swift; sourceTree = ""; }; + 77AA76442BF48818007A0FA8 /* Errors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Errors.swift; sourceTree = ""; }; 77AA76452BF48818007A0FA8 /* ImageFetcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageFetcher.swift; sourceTree = ""; }; 77AA764F2BF488A9007A0FA8 /* Image+Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Image+Data.swift"; sourceTree = ""; }; 77B09992189D0B9900A84F59 /* UIImage+Utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+Utils.h"; sourceTree = ""; }; @@ -279,6 +279,9 @@ 77163AC82A1051DE009BEE0E /* View */ = { isa = PBXGroup; children = ( + 77AA763E2BF48818007A0FA8 /* LoadableImageView.swift */, + 77AA763F2BF48818007A0FA8 /* MessageView.swift */, + 77AA76422BF48818007A0FA8 /* FeedView.swift */, 77163AB52A104786009BEE0E /* ContentView.swift */, ); path = View; @@ -455,12 +458,8 @@ isa = PBXGroup; children = ( 77AA764E2BF48890007A0FA8 /* Helpers */, - 77AA76422BF48818007A0FA8 /* FeedView.swift */, 77AA76452BF48818007A0FA8 /* ImageFetcher.swift */, - 77AA763E2BF48818007A0FA8 /* LoadableImageView.swift */, - 77AA76442BF48818007A0FA8 /* LoadableState.swift */, 77AA76432BF48818007A0FA8 /* MessageFetcher.swift */, - 77AA763F2BF48818007A0FA8 /* MessageView.swift */, 77AA76402BF48818007A0FA8 /* Models.swift */, 77163AC82A1051DE009BEE0E /* View */, 77163AB32A104786009BEE0E /* JuickApp.swift */, @@ -473,6 +472,7 @@ 77AA764E2BF48890007A0FA8 /* Helpers */ = { isa = PBXGroup; children = ( + 77AA76442BF48818007A0FA8 /* Errors.swift */, 77AA764F2BF488A9007A0FA8 /* Image+Data.swift */, ); path = Helpers; @@ -702,7 +702,7 @@ files = ( 77AA76472BF48818007A0FA8 /* MessageView.swift in Sources */, 77AA764B2BF48818007A0FA8 /* MessageFetcher.swift in Sources */, - 77AA764C2BF48818007A0FA8 /* LoadableState.swift in Sources */, + 77AA764C2BF48818007A0FA8 /* Errors.swift in Sources */, 77AA76502BF488A9007A0FA8 /* Image+Data.swift in Sources */, 77AA764A2BF48818007A0FA8 /* FeedView.swift in Sources */, 77163AB62A104786009BEE0E /* ContentView.swift in Sources */, diff --git a/JuickNext/FeedView.swift b/JuickNext/FeedView.swift deleted file mode 100644 index 7e293bd..0000000 --- a/JuickNext/FeedView.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// FeedView.swift -// tst -// -// Created by Vitaly Takmazov on 10.12.2019. -// Copyright © 2019 com.juick. All rights reserved. -// - -import SwiftUI - -struct FeedView: View { - @ObservedObject var messageFetcher : MessageFetcher - - let title: String - - init(_ title: String, url: String) { - self.title = title - messageFetcher = MessageFetcher(url: url) - } - - private var stateContent: AnyView { - switch messageFetcher.state { - case .loading: - return AnyView( - ProgressView() - ) - case .fetched(let result): - switch result { - case .failure(let error): - return AnyView( - Text(error.localizedDescription) - ) - case .success(let root): - return AnyView( - List(root) { (message: Message) in - MessageView(message: message) - } - ) - } - } - } - - var body: some View { - NavigationView { - VStack { - stateContent - }.toolbar { - ToolbarItem(placement: .principal) { - Text(title) - } - } - } - } -} - -struct FeedView_Previews: PreviewProvider { - static var previews: some View { - FeedView("Discover", url: "https://api.juick.com/messages") - } -} diff --git a/JuickNext/Helpers/Errors.swift b/JuickNext/Helpers/Errors.swift new file mode 100644 index 0000000..5c47a70 --- /dev/null +++ b/JuickNext/Helpers/Errors.swift @@ -0,0 +1,20 @@ +// +// Errors.swift +// JuickNext +// +// Created by Vitaly Takmazov on 10.12.2019. +// Copyright © 2019 com.juick. All rights reserved. +// + +import Foundation + +enum FetchError: Error { + case error(String) + + var localizedDescription: String { + switch self { + case .error(let message): + return message + } + } +} diff --git a/JuickNext/LoadableImageView.swift b/JuickNext/LoadableImageView.swift deleted file mode 100644 index 6a41dc2..0000000 --- a/JuickNext/LoadableImageView.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// LoadableImageView.swift -// tst -// -// Created by Vitaly Takmazov on 10.12.2019. -// Copyright © 2019 com.juick. All rights reserved. -// - -import SwiftUI - -struct LoadableImageView: View { - @ObservedObject var imageFetcher: ImageFetcher - - init(with urlString: String) { - imageFetcher = ImageFetcher(url: urlString) - } - - var body: some View { - if let image = Image(data: imageFetcher.data) { - return AnyView( - image.resizable() - ) - } else { - return AnyView( - ProgressView() - ) - } - } -} diff --git a/JuickNext/LoadableState.swift b/JuickNext/LoadableState.swift deleted file mode 100644 index a45edb2..0000000 --- a/JuickNext/LoadableState.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// LoadableState.swift -// tst -// -// Created by Vitaly Takmazov on 10.12.2019. -// Copyright © 2019 com.juick. All rights reserved. -// - -import Foundation - -enum LoadableState { - case loading - case fetched(Result) -} - -enum FetchError: Error { - case error(String) - - var localizedDescription: String { - switch self { - case .error(let message): - return message - } - } -} diff --git a/JuickNext/MessageFetcher.swift b/JuickNext/MessageFetcher.swift index 565cca0..8a150b8 100644 --- a/JuickNext/MessageFetcher.swift +++ b/JuickNext/MessageFetcher.swift @@ -1,6 +1,6 @@ // // MessageFetcher.swift -// tst +// JuickNext // // Created by Vitaly Takmazov on 10.12.2019. // Copyright © 2019 com.juick. All rights reserved. @@ -11,28 +11,28 @@ import Combine class MessageFetcher: ObservableObject { - @Published var state: LoadableState = .loading + @Published var state: Result? = nil init(url: String) { guard let apiUrl = URL(string: url) else { - state = .fetched(.failure(.error("Malformed API URL."))) + state = .failure(.error("Malformed API URL.")) return } URLSession.shared.dataTask(with: apiUrl) { [weak self] (data, _, error) in if let error = error { - self?.state = .fetched(.failure(.error(error.localizedDescription))) + self?.state = .failure(.error(error.localizedDescription)) return } guard let data = data else { - self?.state = .fetched(.failure(.error("Malformed response data"))) + self?.state = .failure(.error("Malformed response data")) return } let root = try! JSONDecoder().decode(Root.self, from: data) DispatchQueue.main.async { [weak self] in - self?.state = .fetched(.success(root)) + self?.state = .success(root) } }.resume() } diff --git a/JuickNext/MessageView.swift b/JuickNext/MessageView.swift deleted file mode 100644 index 398978b..0000000 --- a/JuickNext/MessageView.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// MessageView.swift -// tst -// -// Created by Vitaly Takmazov on 10.12.2019. -// Copyright © 2019 com.juick. All rights reserved. -// - -import SwiftUI - -struct MessageView: View { - var message: Message - var body: some View { - VStack(alignment: .leading) { - HStack { - LoadableImageView(with: message.user.avatar ?? "") - .frame(width: 48, height: 48, alignment: .center) - Text(message.user.name) - .font(.headline) - .foregroundColor(.accentColor) - } - message.tags.map { - Text($0.joined(separator: ", ")) - .font(.subheadline) - .italic() - .foregroundColor(.secondary) - } - Text(message.text ?? "") - .font(.body) - .padding() - message.attachment.map { - LoadableImageView(with: $0.url).scaledToFit() - } - } - } -} - -struct MessageView_Previews: PreviewProvider { - static let msg = Message(id: 0, user: User(id: 0, name: "ugnich"), text: "Lorem ipsum") - static var previews: some View { - MessageView(message: msg) - } -} diff --git a/JuickNext/View/FeedView.swift b/JuickNext/View/FeedView.swift new file mode 100644 index 0000000..3a612e8 --- /dev/null +++ b/JuickNext/View/FeedView.swift @@ -0,0 +1,57 @@ +// +// FeedView.swift +// tst +// +// Created by Vitaly Takmazov on 10.12.2019. +// Copyright © 2019 com.juick. All rights reserved. +// + +import SwiftUI + +struct FeedView: View { + @ObservedObject var messageFetcher : MessageFetcher + + let title: String + + init(_ title: String, url: String) { + self.title = title + messageFetcher = MessageFetcher(url: url) + } + + private var stateContent: AnyView { + switch messageFetcher.state { + case nil: + return AnyView( + ProgressView() + ) + case .failure(let error): + return AnyView( + Text(error.localizedDescription) + ) + case .success(let root): + return AnyView( + List(root) { (message: Message) in + MessageView(message: message) + } + ) + } + } + + var body: some View { + NavigationView { + VStack { + stateContent + }.toolbar { + ToolbarItem(placement: .principal) { + Text(title) + } + } + } + } +} + +struct FeedView_Previews: PreviewProvider { + static var previews: some View { + FeedView("Discover", url: "https://api.juick.com/messages") + } +} diff --git a/JuickNext/View/LoadableImageView.swift b/JuickNext/View/LoadableImageView.swift new file mode 100644 index 0000000..6a41dc2 --- /dev/null +++ b/JuickNext/View/LoadableImageView.swift @@ -0,0 +1,29 @@ +// +// LoadableImageView.swift +// tst +// +// Created by Vitaly Takmazov on 10.12.2019. +// Copyright © 2019 com.juick. All rights reserved. +// + +import SwiftUI + +struct LoadableImageView: View { + @ObservedObject var imageFetcher: ImageFetcher + + init(with urlString: String) { + imageFetcher = ImageFetcher(url: urlString) + } + + var body: some View { + if let image = Image(data: imageFetcher.data) { + return AnyView( + image.resizable() + ) + } else { + return AnyView( + ProgressView() + ) + } + } +} diff --git a/JuickNext/View/MessageView.swift b/JuickNext/View/MessageView.swift new file mode 100644 index 0000000..398978b --- /dev/null +++ b/JuickNext/View/MessageView.swift @@ -0,0 +1,43 @@ +// +// MessageView.swift +// tst +// +// Created by Vitaly Takmazov on 10.12.2019. +// Copyright © 2019 com.juick. All rights reserved. +// + +import SwiftUI + +struct MessageView: View { + var message: Message + var body: some View { + VStack(alignment: .leading) { + HStack { + LoadableImageView(with: message.user.avatar ?? "") + .frame(width: 48, height: 48, alignment: .center) + Text(message.user.name) + .font(.headline) + .foregroundColor(.accentColor) + } + message.tags.map { + Text($0.joined(separator: ", ")) + .font(.subheadline) + .italic() + .foregroundColor(.secondary) + } + Text(message.text ?? "") + .font(.body) + .padding() + message.attachment.map { + LoadableImageView(with: $0.url).scaledToFit() + } + } + } +} + +struct MessageView_Previews: PreviewProvider { + static let msg = Message(id: 0, user: User(id: 0, name: "ugnich"), text: "Lorem ipsum") + static var previews: some View { + MessageView(message: msg) + } +} -- cgit v1.2.3