From 3c433bf72eb9a3d4499d8271ebbd99e82870aa97 Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Fri, 16 Dec 2022 01:47:44 +0100 Subject: [PATCH] Implemented the DocumentView view for the Browse module. --- .../Browse/UI/Views/DocumentView.swift | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 Modules/Sources/Browse/UI/Views/DocumentView.swift diff --git a/Modules/Sources/Browse/UI/Views/DocumentView.swift b/Modules/Sources/Browse/UI/Views/DocumentView.swift new file mode 100644 index 0000000..740247a --- /dev/null +++ b/Modules/Sources/Browse/UI/Views/DocumentView.swift @@ -0,0 +1,152 @@ +// +// DocumentView.swift +// Browse +// +// Created by Javier Cicchelli on 16/12/2022. +// Copyright © 2022 Röck+Cöde. All rights reserved. +// + +import DataModels +import KeychainStorage +import SwiftUI + +struct DocumentView: View { + + // MARK: Environments + + @Environment(\.dismiss) private var dismiss + + // MARK: Storages + + @KeychainStorage(key: .KeychainStorage.account) private var account: Account? + + // MARK: States + + @State private var status: ViewStatus = .loading + @State private var loadedData: Data? + + private let getData = GetDataUseCase() + + // MARK: Properties + + let document: Document + let login: ActionClosure + + // MARK: Body + + var body: some View { + content + .navigationTitle(document.name) + .navigationBarTitleDisplayMode(.inline) + .task { + await loadDataIfPossible() + } + } + +} + +// MARK: - UI + +private extension DocumentView { + @ViewBuilder var content: some View { + switch status { + case .noCredentials: + MessageView( + type: .noCredentials, + action: login + ) + case .notSupported: + MessageView(type: .notSupported) { + dismiss() + } + case .loading: + LoadingView() + case .loaded: + Image(uiImage: imageFromData) + .resizable() + .scaledToFit() + case .empty: + EmptyView() + case .error: + MessageView(type: .error) { + Task { + await loadDataIfPossible() + } + } + } + } +} + +// MARK: - Helpers + +private extension DocumentView { + + // MARK: Computed + + var imageFromData: UIImage { + guard + let loadedData, + let image = UIImage(data: loadedData) + else { + return .init() + } + + return image + } + + // MARK: Functions + + func loadDataIfPossible() async { + guard document.contentType == .Constants.supportedContentType else { + status = .notSupported + return + } + guard let account else { + status = .noCredentials + return + } + + do { + status = .loading + + let data = try await getData( + id: document.id, + username: account.username, + password: account.password + ) + + if data.isEmpty { + status = .error + } else { + loadedData = data + status = .loaded + } + } catch { + status = .error + } + } +} + +// MARK: - String+Constants + +private extension String { + enum Constants { + static let supportedContentType = "image/jpeg" + } +} + +// MARK: - Previews + +struct DocumentView_Previews: PreviewProvider { + static var previews: some View { + DocumentView(document: .init( + id: "1234567890", + name: "Some document name goes in here...", + contentType: "some content type", + size: .random(in: 1 ... 100), + lastModifiedAt: .now + )) { + // login closure. + } + } +}