diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp.xcodeproj/project.pbxproj b/solutions/devsprint-pedro-alvarez-2/FinanceApp.xcodeproj/project.pbxproj index 5569968..dea56f0 100644 --- a/solutions/devsprint-pedro-alvarez-2/FinanceApp.xcodeproj/project.pbxproj +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 1DBC0432294176F6000501FA /* TabBarController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DBC0431294176F6000501FA /* TabBarController.swift */; }; + 7EFE570B2947C06900CEB30C /* ActivityDetailsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EFE570A2947C06900CEB30C /* ActivityDetailsViewModel.swift */; }; 98584A6D277E32C30028DBEA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98584A6C277E32C30028DBEA /* AppDelegate.swift */; }; 98584A6F277E32C30028DBEA /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98584A6E277E32C30028DBEA /* SceneDelegate.swift */; }; 98584A76277E32C50028DBEA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 98584A75277E32C50028DBEA /* Assets.xcassets */; }; @@ -51,6 +52,8 @@ 98C8A4E327C819DE00A630ED /* Contact.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C8A4E227C819DE00A630ED /* Contact.swift */; }; 98C8A4E527C81A3F00A630ED /* TransferResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C8A4E427C81A3F00A630ED /* TransferResult.swift */; }; 98C8A4E727C81A9C00A630ED /* UserProfile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98C8A4E627C81A9C00A630ED /* UserProfile.swift */; }; + FBB56216294777360060278D /* BaseViewHierarchy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB56215294777360060278D /* BaseViewHierarchy.swift */; }; + FBB56219294778320060278D /* BaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBB56218294778320060278D /* BaseView.swift */; }; CCDA8BF12947F08A00E5410D /* SnapshotTesting in Frameworks */ = {isa = PBXBuildFile; productRef = CCDA8BF02947F08A00E5410D /* SnapshotTesting */; }; /* End PBXBuildFile section */ @@ -73,6 +76,7 @@ /* Begin PBXFileReference section */ 1DBC0431294176F6000501FA /* TabBarController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabBarController.swift; sourceTree = ""; }; + 7EFE570A2947C06900CEB30C /* ActivityDetailsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityDetailsViewModel.swift; sourceTree = ""; }; 98584A69277E32C30028DBEA /* FinanceApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FinanceApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; 98584A6C277E32C30028DBEA /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 98584A6E277E32C30028DBEA /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; @@ -120,6 +124,8 @@ 98C8A4E227C819DE00A630ED /* Contact.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contact.swift; sourceTree = ""; }; 98C8A4E427C81A3F00A630ED /* TransferResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransferResult.swift; sourceTree = ""; }; 98C8A4E627C81A9C00A630ED /* UserProfile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfile.swift; sourceTree = ""; }; + FBB56215294777360060278D /* BaseViewHierarchy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewHierarchy.swift; sourceTree = ""; }; + FBB56218294778320060278D /* BaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseView.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -276,6 +282,7 @@ 98C8A4E227C819DE00A630ED /* Contact.swift */, 98C8A4E427C81A3F00A630ED /* TransferResult.swift */, 98C8A4E627C81A9C00A630ED /* UserProfile.swift */, + FBB56215294777360060278D /* BaseViewHierarchy.swift */, ); path = Models; sourceTree = ""; @@ -312,6 +319,7 @@ children = ( 98584B0E277E605F0028DBEA /* ActivityDetailsView.swift */, 98584B0A277E605F0028DBEA /* ActivityDetailsViewController.swift */, + 7EFE570A2947C06900CEB30C /* ActivityDetailsViewModel.swift */, ); path = ActivityDetails; sourceTree = ""; @@ -328,6 +336,7 @@ 98906BEC29392209001D1975 /* Components */ = { isa = PBXGroup; children = ( + FBB56217294778170060278D /* Base */, 98906BED2939221B001D1975 /* AccountSummaryView.swift */, 98906BEF2939223C001D1975 /* ActivityCellView.swift */, 98906BF129392248001D1975 /* ActivityListView.swift */, @@ -354,6 +363,14 @@ path = Extensions; sourceTree = ""; }; + FBB56217294778170060278D /* Base */ = { + isa = PBXGroup; + children = ( + FBB56218294778320060278D /* BaseView.swift */, + ); + path = Base; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -503,6 +520,7 @@ 98C8A4E327C819DE00A630ED /* Contact.swift in Sources */, 98C8A4E527C81A3F00A630ED /* TransferResult.swift in Sources */, 98584AE8277E50430028DBEA /* TransfersViewController.swift in Sources */, + FBB56216294777360060278D /* BaseViewHierarchy.swift in Sources */, 98906BF42939225B001D1975 /* ContactCellView.swift in Sources */, 98584B14277E605F0028DBEA /* ActivityDetailsView.swift in Sources */, 98584AE7277E50430028DBEA /* TransfersView.swift in Sources */, @@ -519,7 +537,9 @@ 989627E027ADC2F60009A07F /* DebugViewController.swift in Sources */, 98584AA5277E35E90028DBEA /* HomeViewController.swift in Sources */, 98906BF229392248001D1975 /* ActivityListView.swift in Sources */, + FBB56219294778320060278D /* BaseView.swift in Sources */, 98584AED277E50430028DBEA /* UserProfileView.swift in Sources */, + 7EFE570B2947C06900CEB30C /* ActivityDetailsViewModel.swift in Sources */, 98C8A4E127C8196100A630ED /* ActivityDetails.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Models/BaseViewHierarchy.swift b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Models/BaseViewHierarchy.swift new file mode 100644 index 0000000..324b561 --- /dev/null +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Models/BaseViewHierarchy.swift @@ -0,0 +1,30 @@ +// +// BaseViewHierarchy.swift +// FinanceApp +// +// Created by Kleiton Mendes on 12/12/22. +// + +import UIKit + +struct BaseViewHierarchy { + let parentView: UIView + let subViews: [UIView] + + init(parentView: UIView, subViews: [UIView]) { + self.parentView = parentView + self.subViews = subViews + } + + func makeHierarchy() { + if let stackView = parentView as? UIStackView { + for view in subViews { + stackView.addArrangedSubview(view) + } + } else { + for view in subViews { + parentView.addSubview(view) + } + } + } +} diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Resources/Assets.xcassets/mall.imageset/Contents.json b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Resources/Assets.xcassets/mall.imageset/Contents.json new file mode 100644 index 0000000..fbe6609 --- /dev/null +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Resources/Assets.xcassets/mall.imageset/Contents.json @@ -0,0 +1,15 @@ +{ + "images" : [ + { + "filename" : "mall.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "preserves-vector-representation" : true + } +} diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Resources/Assets.xcassets/mall.imageset/mall.pdf b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Resources/Assets.xcassets/mall.imageset/mall.pdf new file mode 100644 index 0000000..d4780fc Binary files /dev/null and b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Resources/Assets.xcassets/mall.imageset/mall.pdf differ diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsView.swift b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsView.swift index a1656e1..47fc3cd 100644 --- a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsView.swift +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsView.swift @@ -1,12 +1,135 @@ -// -// ActivityDetailsView.swift -// FinanceApp -// -// Created by Rodrigo Borges on 30/12/21. -// - import UIKit -class ActivityDetailsView: UIView { - +final class ActivityDetailsView: BaseView { + + // MARK: - Private Properties UI + + private lazy var mainStack: UIStackView = { + let stack = UIStackView() + stack.axis = .vertical + stack.distribution = .fillEqually + stack.translatesAutoresizingMaskIntoConstraints = false + + return stack + }() + + private lazy var productView: UIView = { + let view = UIView() + + return view + }() + + private lazy var productValueView: UIView = { + let view = UIView() + + return view + }() + + private lazy var productImage: UIImageView = { + let imageView = UIImageView() + imageView.translatesAutoresizingMaskIntoConstraints = false + + return imageView + }() + + private lazy var productNameLabel: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.font = UIFont.boldSystemFont(ofSize: 17) + label.translatesAutoresizingMaskIntoConstraints = false + + return label + }() + + private lazy var categoryNameLabel: UILabel = { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + + return label + }() + + private lazy var productValue: UILabel = { + let label = UILabel() + label.font = UIFont.boldSystemFont(ofSize: 34) + label.translatesAutoresizingMaskIntoConstraints = false + + return label + }() + + private lazy var purchaseTime: UILabel = { + let label = UILabel() + label.textAlignment = .center + label.translatesAutoresizingMaskIntoConstraints = false + + return label + }() + + private lazy var reportButton: UIButton = { + let button = UIButton() + button.layer.cornerRadius = 14 + button.backgroundColor = .systemBlue + button.setTitle("Report a issue", for: .normal) + button.translatesAutoresizingMaskIntoConstraints = false + + return button + }() + + override var hierarchies: [BaseViewHierarchy] { + return [BaseViewHierarchy.init(parentView: self, subViews: [mainStack, reportButton]), + BaseViewHierarchy.init(parentView: mainStack, subViews: [productView, productValueView]), + BaseViewHierarchy.init(parentView: productView, subViews: [productImage, productNameLabel,categoryNameLabel]), + BaseViewHierarchy.init(parentView: productValueView, subViews: [productValue, purchaseTime])] + } + + override var constraints: [NSLayoutConstraint] { + [ + mainStack.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor), + mainStack.leadingAnchor.constraint(equalTo: leadingAnchor), + mainStack.trailingAnchor.constraint(equalTo: trailingAnchor), + mainStack.bottomAnchor.constraint(equalTo: reportButton.topAnchor, constant: -50), + + productImage.centerXAnchor.constraint(equalTo: centerXAnchor), + + productNameLabel.centerXAnchor.constraint(equalTo: centerXAnchor), + productNameLabel.topAnchor.constraint(equalTo: productImage.bottomAnchor, constant: 8), + + categoryNameLabel.centerXAnchor.constraint(equalTo: centerXAnchor), + categoryNameLabel.topAnchor.constraint(equalTo: productNameLabel.bottomAnchor, constant: 8), + + productValue.centerXAnchor.constraint(equalTo: centerXAnchor), + purchaseTime.centerXAnchor.constraint(equalTo: centerXAnchor), + purchaseTime.topAnchor.constraint(equalTo: productValue.bottomAnchor, constant: 8), + + reportButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20), + reportButton.bottomAnchor.constraint(equalTo: safeAreaLayoutGuide.bottomAnchor, constant: -15), + reportButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -20), + reportButton.heightAnchor.constraint(equalToConstant: 56) + ] + } + + private let viewModel: ActivityDetailsViewModel + + // MARK: - Init + + init(viewModel: ActivityDetailsViewModel) { + self.viewModel = viewModel + super.init(frame: .zero) + setupExtra() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // MARK: - Private Methods + + private func setupExtra() { + backgroundColor = .systemBackground + productImage.image = viewModel.image + productNameLabel.text = viewModel.name + categoryNameLabel.text = viewModel.category + productValue.text = viewModel.value + purchaseTime.text = viewModel.purchaseTime + } } diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewController.swift b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewController.swift index 1ba1558..3ebebce 100644 --- a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewController.swift +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewController.swift @@ -1,15 +1,14 @@ -// -// ActivityDetailsViewController.swift -// FinanceApp -// -// Created by Rodrigo Borges on 30/12/21. -// - import UIKit -class ActivityDetailsViewController: UIViewController { +final class ActivityDetailsViewController: UIViewController { + // MARK: - Life Cycle + override func loadView() { - self.view = ActivityDetailsView() + view = ActivityDetailsView(viewModel: ActivityDetailsViewModel(image: UIImage(named: "mall"), + name: "Mall", + category: "Shopping", + value: "$1000.0", + purchaseTime: "8:40")) } } diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewModel.swift b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewModel.swift new file mode 100644 index 0000000..32e3aa6 --- /dev/null +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/ActivityDetails/ActivityDetailsViewModel.swift @@ -0,0 +1,9 @@ +import UIKit + +struct ActivityDetailsViewModel { + let image: UIImage? + let name: String + let category: String + let value: String + let purchaseTime: String +} diff --git a/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/Components/Base/BaseView.swift b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/Components/Base/BaseView.swift new file mode 100644 index 0000000..366b6b5 --- /dev/null +++ b/solutions/devsprint-pedro-alvarez-2/FinanceApp/Screens/Components/Base/BaseView.swift @@ -0,0 +1,32 @@ +// +// BaseView.swift +// FinanceApp +// +// Created by Kleiton Mendes on 12/12/22. +// + +import UIKit + +class BaseView: UIView { + open var hierarchies: [BaseViewHierarchy] { [] } + + override init(frame: CGRect) { + super.init(frame: frame) + setupView() + setupConstraints() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupConstraints() { + NSLayoutConstraint.activate(constraints) + } + + private func setupView() { + for relation in hierarchies { + relation.makeHierarchy() + } + } +}