diff --git a/SimpleScanner.xcodeproj/project.pbxproj b/SimpleScanner.xcodeproj/project.pbxproj index ddab5b6..221d10a 100644 --- a/SimpleScanner.xcodeproj/project.pbxproj +++ b/SimpleScanner.xcodeproj/project.pbxproj @@ -15,7 +15,10 @@ 9E04B2B124FBCD83AC383B9F /* Text.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04BF36B80CD96B067CC262 /* Text.swift */; }; 9E04B3D8FB6196F3A7040BB1 /* AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04B94C89CFCEB2536DAF75 /* AppStore.swift */; }; 9E04B43A3E35CAAE6AA0188D /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04B0FD31D5EBEE2548788A /* AppState.swift */; }; + 9E04B63EC45E8A9CDB7EA576 /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04BE3B98EE1903F8109383 /* HomeViewModel.swift */; }; + 9E04B6CCC1F5BB2142CC81C3 /* NewScanController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04B3CBA9AD2F2805B61AA8 /* NewScanController.swift */; }; 9E04B7379326CC3F426DEC11 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04B33BC071885CC1FC11FC /* View.swift */; }; + 9E04B7BD98B7D676C19371B6 /* NewScanView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04BC479B0A06D4C7085624 /* NewScanView.swift */; }; 9E04B87E33C1BFE1D2CCEC89 /* HomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04B2D900256F50CB23B4D8 /* HomeView.swift */; }; 9E04BB22843A1193CEE08A9A /* TextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04BF9490C73C86266D98EF /* TextButton.swift */; }; 9E04BC526BBA4D17234DBD8E /* HomeController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E04BD62F1EF9A07F421A937 /* HomeController.swift */; }; @@ -34,9 +37,12 @@ 9E04B2D900256F50CB23B4D8 /* HomeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeView.swift; sourceTree = ""; }; 9E04B33BC071885CC1FC11FC /* View.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; 9E04B34FB0867314FA274D65 /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; + 9E04B3CBA9AD2F2805B61AA8 /* NewScanController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewScanController.swift; sourceTree = ""; }; 9E04B94C89CFCEB2536DAF75 /* AppStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppStore.swift; sourceTree = ""; }; 9E04BB0CB53C787C4A107133 /* TypeAlias.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypeAlias.swift; sourceTree = ""; }; + 9E04BC479B0A06D4C7085624 /* NewScanView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewScanView.swift; sourceTree = ""; }; 9E04BD62F1EF9A07F421A937 /* HomeController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeController.swift; sourceTree = ""; }; + 9E04BE3B98EE1903F8109383 /* HomeViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = ""; }; 9E04BF36B80CD96B067CC262 /* Text.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Text.swift; sourceTree = ""; }; 9E04BF9490C73C86266D98EF /* TextButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextButton.swift; sourceTree = ""; }; A845416816E72C69C0F486A3 /* Pods-SimpleScanner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SimpleScanner.debug.xcconfig"; path = "Target Support Files/Pods-SimpleScanner/Pods-SimpleScanner.debug.xcconfig"; sourceTree = ""; }; @@ -127,15 +133,26 @@ isa = PBXGroup; children = ( 9E04BDA7442AB61AA499D301 /* Home */, + 9E04B9D79202784DB4104DE4 /* NewScan */, ); path = Screen; sourceTree = ""; }; + 9E04B9D79202784DB4104DE4 /* NewScan */ = { + isa = PBXGroup; + children = ( + 9E04B3CBA9AD2F2805B61AA8 /* NewScanController.swift */, + 9E04BC479B0A06D4C7085624 /* NewScanView.swift */, + ); + path = NewScan; + sourceTree = ""; + }; 9E04BDA7442AB61AA499D301 /* Home */ = { isa = PBXGroup; children = ( 9E04BD62F1EF9A07F421A937 /* HomeController.swift */, 9E04B2D900256F50CB23B4D8 /* HomeView.swift */, + 9E04BE3B98EE1903F8109383 /* HomeViewModel.swift */, ); path = Home; sourceTree = ""; @@ -297,6 +314,9 @@ 9E04BFB9572504855D8AF039 /* TypeAlias.swift in Sources */, 9E04B7379326CC3F426DEC11 /* View.swift in Sources */, 9E04B23DA14A575521803572 /* Color.swift in Sources */, + 9E04B6CCC1F5BB2142CC81C3 /* NewScanController.swift in Sources */, + 9E04B7BD98B7D676C19371B6 /* NewScanView.swift in Sources */, + 9E04B63EC45E8A9CDB7EA576 /* HomeViewModel.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/SimpleScanner/Constant/Color.swift b/SimpleScanner/Constant/Color.swift index 3eca057..a2118c9 100644 --- a/SimpleScanner/Constant/Color.swift +++ b/SimpleScanner/Constant/Color.swift @@ -9,6 +9,8 @@ class Color { static let Primary = UIColor(red: 0, green: 120.0 / 255, blue: 200.0 / 255, alpha: 1.0) static let BodyBackground = UIColor.white + static let BodyBackgroundContrast = UIColor.gray + static let Border = UIColor.gray static let Button = Primary } diff --git a/SimpleScanner/Constant/Text.swift b/SimpleScanner/Constant/Text.swift index 1b17847..3c076c8 100644 --- a/SimpleScanner/Constant/Text.swift +++ b/SimpleScanner/Constant/Text.swift @@ -8,7 +8,11 @@ import Foundation class Text { // Home Page - static let HomeViewTitle = "SimpleScanner" + static let HomeViewTitle = "Documents" static let NewScanButton = "New Scan" + static let PastScansHeader = "Past Scans" + + // New Scan Page + static let NewScanTitle = "New Scan" } diff --git a/SimpleScanner/Constant/View.swift b/SimpleScanner/Constant/View.swift index 8e0e99f..650291b 100644 --- a/SimpleScanner/Constant/View.swift +++ b/SimpleScanner/Constant/View.swift @@ -10,6 +10,10 @@ class View { // General static let ViewPadding: CGFloat = 16 static let SectionVerticalMargin: CGFloat = 24 + static let SubSectionVerticalMargin: CGFloat = 8 + + // Divider + static let DividerHeight: CGFloat = 1 // Buttons static let ButtonHorizontalInset: CGFloat = 64 @@ -18,6 +22,21 @@ class View { static let ButtonHeight: CGFloat = 50 // Fonts + static let NormalFont: UIFont = .systemFont(ofSize: 16) static let ButtonFont: UIFont = .systemFont(ofSize: 20) + static let HeaderFont: UIFont = .systemFont(ofSize: 36) + + // Collection View + static let CollectionViewItemsPerRow: CGFloat = 2 + static let CollectionViewSectionInsets = UIEdgeInsets(top: SectionVerticalMargin, left: ViewPadding, bottom: SectionVerticalMargin, right: ViewPadding) + static let CollectionViewSize: CGSize = { + get { + let paddingSpace = sectionInsets.left * (itemsPerRow + 1) + let availableWidth = view.frame.width - paddingSpace + let widthPerItem = availableWidth / itemsPerRow + + return CGSize(width: widthPerItem, height: widthPerItem) + } + } } diff --git a/SimpleScanner/Info.plist b/SimpleScanner/Info.plist index 0405e82..6d3934f 100644 --- a/SimpleScanner/Info.plist +++ b/SimpleScanner/Info.plist @@ -2,6 +2,8 @@ + NSCameraUsageDescription + The camera is required to scan new documents CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName diff --git a/SimpleScanner/Screen/Home/HomeController.swift b/SimpleScanner/Screen/Home/HomeController.swift index 03bc685..73bf3c2 100644 --- a/SimpleScanner/Screen/Home/HomeController.swift +++ b/SimpleScanner/Screen/Home/HomeController.swift @@ -25,7 +25,7 @@ class HomeController: UIViewController { override func loadView() { self.title = Text.HomeViewTitle - homeView = HomeView() + homeView = HomeView(viewModel: HomeViewModel(test: ["Item 1", "Item 2"]), newScanTapped: newScanTapped) self.view = homeView } @@ -34,5 +34,9 @@ class HomeController: UIViewController { // Do any additional setup after loading the view. } + private func newScanTapped() { + navigationController?.pushViewController(NewScanController(), animated: true) + } + } diff --git a/SimpleScanner/Screen/Home/HomeView.swift b/SimpleScanner/Screen/Home/HomeView.swift index 074b21e..665ae69 100644 --- a/SimpleScanner/Screen/Home/HomeView.swift +++ b/SimpleScanner/Screen/Home/HomeView.swift @@ -8,10 +8,20 @@ import SnapKit class HomeView: UIView { - private var mainScrollView: UIScrollView! + private var vm: HomeViewModel + + // UI private var newScanButton: TextButton! + private var bottomBar: UIView! + private var documentCollectionView: UICollectionView! + + // Callbacks + private let newScanTapped: VoidCallback + - init() { + init(viewModel: HomeViewModel, newScanTapped: @escaping VoidCallback) { + self.vm = viewModel + self.newScanTapped = newScanTapped super.init(frame: CGRect.zero) initSubviews() } @@ -20,27 +30,74 @@ class HomeView: UIView { fatalError("init(coder:) has not been implemented") } +} + +// Initialization +extension HomeView { + + // Main initialization block private func initSubviews() { backgroundColor = Color.BodyBackground + initBottomBar() + initDocumentCollectionView() + } - // Main Scroll View - mainScrollView = UIScrollView() - addSubview(mainScrollView) - mainScrollView.snp.makeConstraints { (make) in - make.edges.equalTo(safeAreaLayoutGuide.snp.edges).inset(View.ViewPadding) - } - - // New scan button - newScanButton = TextButton(text: Text.NewScanButton) { - print("Tapped") - } - mainScrollView.addSubview(newScanButton) + private func initBottomBar() { + // Bottom Bar View With Add Button + bottomBar = UIView() + bottomBar.backgroundColor = Color.BodyBackgroundContrast + // New Scan Button + newScanButton = TextButton(text: Text.NewScanButton, onTap: newScanTapped) + bottomBar.addSubview(newScanButton) + addSubview(bottomBar) newScanButton.snp.makeConstraints { (make) in - make.top.equalTo(safeAreaLayoutGuide.snp.top).offset(View.SectionVerticalMargin) + make.top.equalToSuperview().inset(View.SectionVerticalMargin) + make.bottom.equalTo(safeAreaLayoutGuide.snp.bottom).inset(View.SectionVerticalMargin) + make.left.greaterThanOrEqualToSuperview().inset(View.ViewPadding) + make.right.lessThanOrEqualToSuperview().inset(View.ViewPadding) make.centerX.equalToSuperview() - make.left.greaterThanOrEqualToSuperview() - make.right.lessThanOrEqualToSuperview() + } + bottomBar.sizeToFit() + bottomBar.snp.makeConstraints { (make) in + make.left.equalToSuperview() + make.right.equalToSuperview() + make.bottom.equalToSuperview() } } -} \ No newline at end of file + private func initDocumentCollectionView() { + let flowLayout = UICollectionViewFlowLayout() + flowLayout.sectionInset = View.CollectionViewSectionInsets + documentCollectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) + documentCollectionView.backgroundColor = Color.BodyBackground + documentCollectionView.delegate = self + documentCollectionView.dataSource = self + documentCollectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "MyCell") + addSubview(documentCollectionView) + documentCollectionView.snp.makeConstraints { (make) in + make.right.equalToSuperview() + make.left.equalToSuperview() + make.bottom.equalTo(bottomBar.snp.top) + make.top.equalToSuperview() + } + flowLayout.itemSize = View.CollectionItemSize + } +} + +// UICollectionView Delegate +extension HomeView: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return vm.test.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "MyCell", for: indexPath) + myCell.backgroundColor = UIColor.blue + return myCell + } + + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + print("Tap at \(indexPath.row)") + } +} diff --git a/SimpleScanner/Screen/Home/HomeViewModel.swift b/SimpleScanner/Screen/Home/HomeViewModel.swift new file mode 100644 index 0000000..c330b9b --- /dev/null +++ b/SimpleScanner/Screen/Home/HomeViewModel.swift @@ -0,0 +1,16 @@ +// +// Created by Frank Jia on 2019-05-29. +// Copyright (c) 2019 Frank Jia. All rights reserved. +// + +import UIKit + +class HomeViewModel { + + let test: [String] + + init(test: [String]) { + self.test = test + } + +} diff --git a/SimpleScanner/Screen/NewScan/NewScanController.swift b/SimpleScanner/Screen/NewScan/NewScanController.swift new file mode 100644 index 0000000..0c1c1d3 --- /dev/null +++ b/SimpleScanner/Screen/NewScan/NewScanController.swift @@ -0,0 +1,68 @@ +// +// Created by Frank Jia on 2019-05-28. +// Copyright (c) 2019 Frank Jia. All rights reserved. +// + +import UIKit +import WeScan + +class NewScanController: UIViewController { + + private let store: AppStore + private var newScanView: NewScanView! + + public init(store: AppStore = appStore) { + self.store = store + super.init(nibName: nil, bundle: nil) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + self.title = Text.NewScanTitle + newScanView = NewScanView(newPageTapped: newPageTapped) + self.view = newScanView + } + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + private func newPageTapped() { + // Create and launch a WeScan controller + let scannerVC = ImageScannerController() + scannerVC.navigationBar.backgroundColor = .white + scannerVC.imageScannerDelegate = self + present(scannerVC, animated: true) + } + +} + +// Extension for WeScan +extension NewScanController: ImageScannerControllerDelegate { + + func imageScannerController(_ scanner: ImageScannerController, didFailWithError error: Error) { + // You are responsible for carefully handling the error + print(error) + } + + func imageScannerController(_ scanner: ImageScannerController, didFinishScanningWithResults results: ImageScannerResults) { + // The user successfully scanned an image, which is available in the ImageScannerResults + // You are responsible for dismissing the ImageScannerController + newScanView.tempImageView.image = results.scannedImage + if (results.doesUserPreferEnhancedImage), let enhancedImage = results.enhancedImage { + newScanView.tempImageView.image = enhancedImage + } + scanner.dismiss(animated: true) + } + + func imageScannerControllerDidCancel(_ scanner: ImageScannerController) { + // The user tapped 'Cancel' on the scanner + // You are responsible for dismissing the ImageScannerController + scanner.dismiss(animated: true) + } + +} diff --git a/SimpleScanner/Screen/NewScan/NewScanView.swift b/SimpleScanner/Screen/NewScan/NewScanView.swift new file mode 100644 index 0000000..750714f --- /dev/null +++ b/SimpleScanner/Screen/NewScan/NewScanView.swift @@ -0,0 +1,48 @@ +// +// Created by Frank Jia on 2019-05-28. +// Copyright (c) 2019 Frank Jia. All rights reserved. +// + +import UIKit +import SnapKit +import WeScan + +class NewScanView: UIView { + + private let newPageTapped: VoidCallback + + // Temp + let tempImageView: UIImageView! + + init(newPageTapped: @escaping VoidCallback) { + self.newPageTapped = newPageTapped + self.tempImageView = UIImageView() + super.init(frame: CGRect.zero) + + backgroundColor = Color.BodyBackground + + let tempButton = TextButton(text: "Add Page", onTap: newPageTapped) + addSubview(tempButton) + + tempButton.snp.makeConstraints { (make) in + make.top.equalTo(safeAreaLayoutGuide.snp.top) + make.left.equalToSuperview() + make.right.equalToSuperview() + } + + addSubview(tempImageView) + tempImageView.contentMode = .scaleAspectFit + tempImageView.snp.makeConstraints { (make) in + make.top.equalTo(tempButton.snp.bottom) + make.bottom.equalToSuperview() + make.left.equalToSuperview() + make.right.equalToSuperview() + } + + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +}