From 37dd669854c99fcaef85dd73aceda748c71bb49f Mon Sep 17 00:00:00 2001 From: rushadantia Date: Fri, 4 Sep 2020 17:29:12 -0400 Subject: [PATCH 01/22] init --- Grocery List.xcodeproj/project.pbxproj | 40 +- .../Table/CollapsibleTableViewHeader.swift | 72 - .../StoresTableViewController.swift | 4 +- .../Base.lproj/LaunchScreen.storyboard | 0 .../{ => Views}/Base.lproj/Main.storyboard | 14 +- Grocery List/Views/StoreListHeader.swift | 18 + Grocery List/Views/StoreListHeader.xib | 55 + Podfile | 2 +- Podfile.lock | 10 +- Pods/BulletinBoard/README.md | 87 - .../Appearance/BLTNBackgroundViewStyle.swift | 87 - .../Appearance/BLTNInterfaceBuilder.swift | 220 --- .../Appearance/BLTNItemAppearance.swift | 210 --- .../Sources/Appearance/BLTNSpacing.swift | 56 - .../Sources/Appearance/BLTNViewPosition.swift | 20 - Pods/BulletinBoard/Sources/BLTNBoard.h | 10 - .../Sources/BLTNItemManager.swift | 730 -------- Pods/BulletinBoard/Sources/Deprecations.swift | 30 - .../Sources/Models/BLTNActionItem.h | 294 ---- .../Sources/Models/BLTNActionItem.m | 174 -- Pods/BulletinBoard/Sources/Models/BLTNItem.h | 128 -- .../Sources/Models/BLTNPageItem.h | 140 -- .../Sources/Models/BLTNPageItem.m | 162 -- .../Support/Animations/AnimationChain.swift | 163 -- .../BulletinDismissAnimationController.swift | 90 - ...letinPresentationAnimationController.swift | 79 - .../BulletinSwipeInteractionController.swift | 261 --- .../Sources/Support/BLTNBoardSwiftSupport.h | 13 - .../Support/BulletinViewController.swift | 632 ------- .../Helpers/UIButton+BackgroundColor.swift | 25 - .../Support/Helpers/UIColor+Luminance.swift | 25 - .../Support/Helpers/UIView+SafeAnchors.swift | 27 - .../Views/Internal/ActivityIndicator.swift | 70 - .../Internal/BulletinBackgroundView.swift | 134 -- .../Views/Internal/BulletinCloseButton.swift | 166 -- .../ContinuousMaskLayer.swift | 81 - .../RoundedViewProtocol.swift | 45 - .../UIView+RoundedView.swift | 30 - .../Views/Internal/HighlightButton.swift | 71 - .../Support/Views/Internal/Highlighter.swift | 110 -- .../Views/Public/BLTNContainerView.swift | 47 - .../Public/BLTNHighlightButtonWrapper.swift | 42 - .../Public/BLTNTitleLabelContainer.swift | 45 - Pods/Manifest.lock | 10 +- .../LICENSE | 5 +- Pods/MultiProgressView/README.md | 156 ++ .../Sources/MultiProgressView.h | 19 + .../MultiProgressView/AlignmentType.swift | 11 + .../MultiProgressView/LayoutProvider.swift | 155 ++ .../MultiProgressView/LineCapType.swift | 5 + .../MultiProgressView/MultiProgressView.swift | 238 +++ .../ProgressViewSection.swift | 106 ++ Pods/Pods.xcodeproj/project.pbxproj | 1529 ++++++++--------- .../BulletinBoard/BulletinBoard-dummy.m | 5 - .../BulletinBoard/BulletinBoard-umbrella.h | 20 - .../BulletinBoard/BulletinBoard.modulemap | 6 - .../MultiProgressView-Info.plist} | 2 +- .../MultiProgressView-dummy.m | 5 + .../MultiProgressView-prefix.pch} | 0 .../MultiProgressView-umbrella.h | 17 + .../MultiProgressView.debug.xcconfig} | 5 +- .../MultiProgressView.modulemap | 6 + .../MultiProgressView.release.xcconfig} | 5 +- ...ods-Grocery List-acknowledgements.markdown | 51 +- .../Pods-Grocery List-acknowledgements.plist | 63 +- ...st-frameworks-Debug-input-files.xcfilelist | 4 +- ...t-frameworks-Debug-output-files.xcfilelist | 4 +- ...-frameworks-Release-input-files.xcfilelist | 4 +- ...frameworks-Release-output-files.xcfilelist | 4 +- .../Pods-Grocery List-frameworks.sh | 4 +- .../Pods-Grocery List.debug.xcconfig | 6 +- .../Pods-Grocery List.release.xcconfig | 6 +- StoreViewController.swift | 42 + 73 files changed, 1666 insertions(+), 5546 deletions(-) delete mode 100644 Grocery List/Table/CollapsibleTableViewHeader.swift rename Grocery List/{ => Views}/Base.lproj/LaunchScreen.storyboard (100%) rename Grocery List/{ => Views}/Base.lproj/Main.storyboard (98%) create mode 100644 Grocery List/Views/StoreListHeader.swift create mode 100644 Grocery List/Views/StoreListHeader.xib delete mode 100644 Pods/BulletinBoard/README.md delete mode 100644 Pods/BulletinBoard/Sources/Appearance/BLTNBackgroundViewStyle.swift delete mode 100644 Pods/BulletinBoard/Sources/Appearance/BLTNInterfaceBuilder.swift delete mode 100644 Pods/BulletinBoard/Sources/Appearance/BLTNItemAppearance.swift delete mode 100644 Pods/BulletinBoard/Sources/Appearance/BLTNSpacing.swift delete mode 100644 Pods/BulletinBoard/Sources/Appearance/BLTNViewPosition.swift delete mode 100644 Pods/BulletinBoard/Sources/BLTNBoard.h delete mode 100644 Pods/BulletinBoard/Sources/BLTNItemManager.swift delete mode 100644 Pods/BulletinBoard/Sources/Deprecations.swift delete mode 100644 Pods/BulletinBoard/Sources/Models/BLTNActionItem.h delete mode 100644 Pods/BulletinBoard/Sources/Models/BLTNActionItem.m delete mode 100644 Pods/BulletinBoard/Sources/Models/BLTNItem.h delete mode 100644 Pods/BulletinBoard/Sources/Models/BLTNPageItem.h delete mode 100644 Pods/BulletinBoard/Sources/Models/BLTNPageItem.m delete mode 100644 Pods/BulletinBoard/Sources/Support/Animations/AnimationChain.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Animations/BulletinDismissAnimationController.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Animations/BulletinPresentationAnimationController.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Animations/BulletinSwipeInteractionController.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/BLTNBoardSwiftSupport.h delete mode 100644 Pods/BulletinBoard/Sources/Support/BulletinViewController.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Helpers/UIButton+BackgroundColor.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Helpers/UIColor+Luminance.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Helpers/UIView+SafeAnchors.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/ActivityIndicator.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinBackgroundView.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinCloseButton.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/ContinuousMaskLayer.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/RoundedViewProtocol.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/UIView+RoundedView.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/HighlightButton.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Internal/Highlighter.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Public/BLTNContainerView.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Public/BLTNHighlightButtonWrapper.swift delete mode 100644 Pods/BulletinBoard/Sources/Support/Views/Public/BLTNTitleLabelContainer.swift rename Pods/{BulletinBoard => MultiProgressView}/LICENSE (92%) create mode 100644 Pods/MultiProgressView/README.md create mode 100644 Pods/MultiProgressView/Sources/MultiProgressView.h create mode 100644 Pods/MultiProgressView/Sources/MultiProgressView/AlignmentType.swift create mode 100644 Pods/MultiProgressView/Sources/MultiProgressView/LayoutProvider.swift create mode 100644 Pods/MultiProgressView/Sources/MultiProgressView/LineCapType.swift create mode 100644 Pods/MultiProgressView/Sources/MultiProgressView/MultiProgressView.swift create mode 100644 Pods/MultiProgressView/Sources/MultiProgressView/ProgressViewSection.swift delete mode 100644 Pods/Target Support Files/BulletinBoard/BulletinBoard-dummy.m delete mode 100644 Pods/Target Support Files/BulletinBoard/BulletinBoard-umbrella.h delete mode 100644 Pods/Target Support Files/BulletinBoard/BulletinBoard.modulemap rename Pods/Target Support Files/{BulletinBoard/BulletinBoard-Info.plist => MultiProgressView/MultiProgressView-Info.plist} (96%) create mode 100644 Pods/Target Support Files/MultiProgressView/MultiProgressView-dummy.m rename Pods/Target Support Files/{BulletinBoard/BulletinBoard-prefix.pch => MultiProgressView/MultiProgressView-prefix.pch} (100%) create mode 100644 Pods/Target Support Files/MultiProgressView/MultiProgressView-umbrella.h rename Pods/Target Support Files/{BulletinBoard/BulletinBoard.debug.xcconfig => MultiProgressView/MultiProgressView.debug.xcconfig} (69%) create mode 100644 Pods/Target Support Files/MultiProgressView/MultiProgressView.modulemap rename Pods/Target Support Files/{BulletinBoard/BulletinBoard.release.xcconfig => MultiProgressView/MultiProgressView.release.xcconfig} (69%) create mode 100644 StoreViewController.swift diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index b4c04d1..752e14b 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -12,6 +12,9 @@ 2418684324884B42003E7C69 /* Category.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2418684224884B42003E7C69 /* Category.swift */; }; 2418684524884B6C003E7C69 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2418684424884B6C003E7C69 /* Store.swift */; }; 2418684824885824003E7C69 /* StoresTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2418684724885824003E7C69 /* StoresTableViewController.swift */; }; + 241E7C342501730F00C06241 /* StoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241E7C332501730F00C06241 /* StoreViewController.swift */; }; + 241E7C372502E14100C06241 /* StoreListHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 241E7C362502E14100C06241 /* StoreListHeader.xib */; }; + 241E7C392502E16200C06241 /* StoreListHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241E7C382502E16200C06241 /* StoreListHeader.swift */; }; 241F0F7C24B7A35800A3F67C /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241F0F7B24B7A35800A3F67C /* ItemCell.swift */; }; 2423A01F24BB93CC0089181C /* Grocery_ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */; }; 24283BB124BD017100141807 /* InstantSearchVoiceOverlay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24283BB024BD017100141807 /* InstantSearchVoiceOverlay.framework */; }; @@ -24,9 +27,7 @@ 2461A83424882541009BE0AB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83224882541009BE0AB /* Main.storyboard */; }; 2461A83624882543009BE0AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83524882543009BE0AB /* Assets.xcassets */; }; 2461A83924882543009BE0AB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83724882543009BE0AB /* LaunchScreen.storyboard */; }; - 2461A841248829B7009BE0AB /* TableController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461A840248829B6009BE0AB /* TableController.swift */; }; 2461A84324882D1D009BE0AB /* AddItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461A84224882D1D009BE0AB /* AddItemViewController.swift */; }; - 2461A8452488347D009BE0AB /* CollapsibleTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461A8442488347D009BE0AB /* CollapsibleTableViewHeader.swift */; }; 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */; }; 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2494FFA7248C10CA00DC58E0 /* DataStore.swift */; }; 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */; }; @@ -67,6 +68,9 @@ 2418684424884B6C003E7C69 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; 2418684724885824003E7C69 /* StoresTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoresTableViewController.swift; sourceTree = ""; }; 2419C7D824B652FD004F5096 /* StrikethroughLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StrikethroughLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 241E7C332501730F00C06241 /* StoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreViewController.swift; sourceTree = SOURCE_ROOT; }; + 241E7C362502E14100C06241 /* StoreListHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StoreListHeader.xib; sourceTree = ""; }; + 241E7C382502E16200C06241 /* StoreListHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreListHeader.swift; path = "Grocery List/Views/StoreListHeader.swift"; sourceTree = SOURCE_ROOT; }; 241F0F7B24B7A35800A3F67C /* ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; 2423A01C24BB93CC0089181C /* Grocery ListTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Grocery ListTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grocery_ListTests.swift; sourceTree = ""; }; @@ -85,7 +89,6 @@ 2461A83A24882543009BE0AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 2461A840248829B6009BE0AB /* TableController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableController.swift; sourceTree = ""; }; 2461A84224882D1D009BE0AB /* AddItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddItemViewController.swift; sourceTree = ""; }; - 2461A8442488347D009BE0AB /* CollapsibleTableViewHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsibleTableViewHeader.swift; sourceTree = ""; }; 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreIconManager.swift; path = "Grocery List/View Controllers/StoreIconManager.swift"; sourceTree = SOURCE_ROOT; }; 2494FFA7248C10CA00DC58E0 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = ""; }; 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddStoreCell.swift; sourceTree = ""; }; @@ -149,8 +152,10 @@ 2418684924885827003E7C69 /* View Controllers */ = { isa = PBXGroup; children = ( - 2418684724885824003E7C69 /* StoresTableViewController.swift */, + 241E7C382502E16200C06241 /* StoreListHeader.swift */, + 241E7C332501730F00C06241 /* StoreViewController.swift */, 2461A840248829B6009BE0AB /* TableController.swift */, + 2418684724885824003E7C69 /* StoresTableViewController.swift */, 2461A84224882D1D009BE0AB /* AddItemViewController.swift */, 24E5F40024EB14D5007DA4BE /* AddStoreViewController.swift */, 24E5F3FE24EB1345007DA4BE /* ToolBarView.swift */, @@ -158,6 +163,16 @@ path = "View Controllers"; sourceTree = ""; }; + 241E7C352502E12C00C06241 /* Views */ = { + isa = PBXGroup; + children = ( + 2461A83224882541009BE0AB /* Main.storyboard */, + 2461A83724882543009BE0AB /* LaunchScreen.storyboard */, + 241E7C362502E14100C06241 /* StoreListHeader.xib */, + ); + path = Views; + sourceTree = ""; + }; 2423A01D24BB93CC0089181C /* Grocery ListTests */ = { isa = PBXGroup; children = ( @@ -194,14 +209,12 @@ children = ( 2418684624884C4F003E7C69 /* Data Models */, 2418684924885827003E7C69 /* View Controllers */, + 241E7C352502E12C00C06241 /* Views */, 24A3C98124F180B50019D23F /* Cells */, - 24C3A7B124A577C50084D49F /* Table */, 24E5F40424EB16C0007DA4BE /* Extensions */, 247E02E724DDF32600148580 /* Other */, - 2461A83224882541009BE0AB /* Main.storyboard */, 2461A82E24882541009BE0AB /* AppDelegate.swift */, 2461A83524882543009BE0AB /* Assets.xcassets */, - 2461A83724882543009BE0AB /* LaunchScreen.storyboard */, 2461A83A24882543009BE0AB /* Info.plist */, ); path = "Grocery List"; @@ -236,14 +249,6 @@ path = "Grocery ListUITests"; sourceTree = ""; }; - 24C3A7B124A577C50084D49F /* Table */ = { - isa = PBXGroup; - children = ( - 2461A8442488347D009BE0AB /* CollapsibleTableViewHeader.swift */, - ); - path = Table; - sourceTree = ""; - }; 24E5F40424EB16C0007DA4BE /* Extensions */ = { isa = PBXGroup; children = ( @@ -393,6 +398,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 241E7C372502E14100C06241 /* StoreListHeader.xib in Resources */, 2461A83924882543009BE0AB /* LaunchScreen.storyboard in Resources */, 2461A83624882543009BE0AB /* Assets.xcassets in Resources */, 2461A83424882541009BE0AB /* Main.storyboard in Resources */, @@ -463,11 +469,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 241E7C342501730F00C06241 /* StoreViewController.swift in Sources */, 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */, 24E5F40324EB16B7007DA4BE /* UIView+Separator.swift in Sources */, + 241E7C392502E16200C06241 /* StoreListHeader.swift in Sources */, 24F91AEC24F0589E0064FDBB /* CategoryCell.swift in Sources */, 241F0F7C24B7A35800A3F67C /* ItemCell.swift in Sources */, - 2461A8452488347D009BE0AB /* CollapsibleTableViewHeader.swift in Sources */, 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */, 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */, 2418684824885824003E7C69 /* StoresTableViewController.swift in Sources */, @@ -480,7 +487,6 @@ 2409D27524A7D738001FAD06 /* ImagePicker.swift in Sources */, 24390CBF24C61B6700189D75 /* StoreCell.swift in Sources */, 24A3C98324F1912F0019D23F /* UIView+DashedBorder.swift in Sources */, - 2461A841248829B7009BE0AB /* TableController.swift in Sources */, 2461A82F24882541009BE0AB /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Grocery List/Table/CollapsibleTableViewHeader.swift b/Grocery List/Table/CollapsibleTableViewHeader.swift deleted file mode 100644 index 9c20e67..0000000 --- a/Grocery List/Table/CollapsibleTableViewHeader.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// CollapsibleTableViewHeader.swift -// Grocery List -// -// Created by Rushad Antia on 6/3/20. -// Copyright © 2020 Rushad Antia. All rights reserved. -// - -import Foundation -import UIKit - -class CollapsibleTableViewHeader: UITableViewHeaderFooterView { - var delegate: CollapsibleTableViewHeaderDelegate? - var section: Int = 0 - - let titleLabel = UILabel() - let arrowLabel = UILabel() - - override init(reuseIdentifier: String?) { - super.init(reuseIdentifier: reuseIdentifier) - - contentView.addSubview(titleLabel) - contentView.addSubview(arrowLabel) - addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(CollapsibleTableViewHeader.tapHeader(_:)))) - - // header color - contentView.backgroundColor = #colorLiteral(red: 0.07841721922, green: 0.07843927294, blue: 0.07841745764, alpha: 1) - - let marginGuide = contentView.layoutMarginsGuide - - // arrow label setup - contentView.addSubview(arrowLabel) - arrowLabel.textColor = UIColor.white - arrowLabel.translatesAutoresizingMaskIntoConstraints = false - arrowLabel.widthAnchor.constraint(equalToConstant: 12).isActive = false - arrowLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true - arrowLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true - arrowLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true - - contentView.addSubview(titleLabel) - titleLabel.textColor = UIColor.white - titleLabel.translatesAutoresizingMaskIntoConstraints = false - titleLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true - titleLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true - titleLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true - titleLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = true - } - - @objc func tapHeader(_ gestureRecognizer: UITapGestureRecognizer) { - guard let cell = gestureRecognizer.view as? CollapsibleTableViewHeader else { - return - } - - delegate?.toggleSection(self, section: cell.section) - } - - func setCollapsed(_ collapsed: Bool, _ numItems: Int) { - if numItems == 0 { - arrowLabel.text = "✓" - } else { - arrowLabel.text = collapsed == false ? "\(numItems) ↓" : "\(numItems) →" - } - } - - required init?(coder _: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -protocol CollapsibleTableViewHeaderDelegate { - func toggleSection(_ header: CollapsibleTableViewHeader, section: Int) -} diff --git a/Grocery List/View Controllers/StoresTableViewController.swift b/Grocery List/View Controllers/StoresTableViewController.swift index ee8dff8..83ad45a 100644 --- a/Grocery List/View Controllers/StoresTableViewController.swift +++ b/Grocery List/View Controllers/StoresTableViewController.swift @@ -141,8 +141,8 @@ class StoresTableViewController: UITableViewController, UIAdaptivePresentationCo // setup segue movement override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - if segue.destination is TableController { - let vc = segue.destination as? TableController + if segue.destination is StoreViewController { + let vc = segue.destination as? StoreViewController let store = stores[(sender as? Int)!] vc?.store = store } else if segue.destination is AddStoreViewController { diff --git a/Grocery List/Base.lproj/LaunchScreen.storyboard b/Grocery List/Views/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from Grocery List/Base.lproj/LaunchScreen.storyboard rename to Grocery List/Views/Base.lproj/LaunchScreen.storyboard diff --git a/Grocery List/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard similarity index 98% rename from Grocery List/Base.lproj/Main.storyboard rename to Grocery List/Views/Base.lproj/Main.storyboard index 6000d75..3d00ce2 100644 --- a/Grocery List/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -49,13 +49,12 @@ - - + + - - + @@ -432,7 +431,7 @@ - + @@ -494,6 +493,11 @@ + + + + + diff --git a/Grocery List/Views/StoreListHeader.swift b/Grocery List/Views/StoreListHeader.swift new file mode 100644 index 0000000..894b389 --- /dev/null +++ b/Grocery List/Views/StoreListHeader.swift @@ -0,0 +1,18 @@ +// +// StoreListHeader.swift +// Grocery List +// +// Created by Rushad Antia on 9/4/20. +// Copyright © 2020 Rushad Antia. All rights reserved. +// + +import Foundation +import UIKit + +class StoreListHeader: UITableViewHeaderFooterView { + static let reuseIdentifier = String(describing: self) + + static var nib: UINib { + return UINib(nibName: String(describing: self), bundle: nil) + } +} diff --git a/Grocery List/Views/StoreListHeader.xib b/Grocery List/Views/StoreListHeader.xib new file mode 100644 index 0000000..f5f6fb1 --- /dev/null +++ b/Grocery List/Views/StoreListHeader.xib @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Podfile b/Podfile index 7f28062..f2423ad 100644 --- a/Podfile +++ b/Podfile @@ -6,8 +6,8 @@ target 'Grocery List' do use_frameworks! # Pods for Grocery List -pod 'BulletinBoard' pod 'Lightbox' +pod 'MultiProgressView' pod 'BEMCheckBox' pod 'InstantSearchVoiceOverlay', '~> 1.1.0' diff --git a/Podfile.lock b/Podfile.lock index 5b97978..4f328e4 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,36 +1,36 @@ PODS: - BEMCheckBox (1.4.1) - - BulletinBoard (4.1.2) - Cache (5.3.0) - Imaginary (4.3.1): - Cache (~> 5.3.0) - InstantSearchVoiceOverlay (1.1.0) - Lightbox (2.4.1): - Imaginary (~> 4.3.1) + - MultiProgressView (1.3.0) DEPENDENCIES: - BEMCheckBox - - BulletinBoard - InstantSearchVoiceOverlay (~> 1.1.0) - Lightbox + - MultiProgressView SPEC REPOS: trunk: - BEMCheckBox - - BulletinBoard - Cache - Imaginary - InstantSearchVoiceOverlay - Lightbox + - MultiProgressView SPEC CHECKSUMS: BEMCheckBox: 5ba6e37ade3d3657b36caecc35c8b75c6c2b1a4e - BulletinBoard: 1c0cb191b6c6245d08f51bd2445f1e36414ec0ed Cache: 48762993ec44e1d93483c4d4a13edd18452326f4 Imaginary: 18c5bba364229eef383b925199db442e71d175e1 InstantSearchVoiceOverlay: 8fcbd0c143c872e6b39ef9b6475f1dfeb9ebfbcf Lightbox: cede4a64f2d864da1f7e7959aa78a8659a311e7c + MultiProgressView: 65e5bb8181687099ade56d16d85d245a92fafa96 -PODFILE CHECKSUM: f3980290d04c5177b1dbe326de2cf20746993044 +PODFILE CHECKSUM: 36d6cf94c2dc4596b9853e92bb677330039c916e COCOAPODS: 1.9.1 diff --git a/Pods/BulletinBoard/README.md b/Pods/BulletinBoard/README.md deleted file mode 100644 index c032b9f..0000000 --- a/Pods/BulletinBoard/README.md +++ /dev/null @@ -1,87 +0,0 @@ -# BulletinBoard - -[![CI Status](https://dev.azure.com/alexaubry/BulletinBoard/_apis/build/status/alexaubry.BulletinBoard)](https://dev.azure.com/alexaubry/BulletinBoard/_build/latest?definitionId=3) -[![CI Status](https://travis-ci.org/alexaubry/BulletinBoard.svg?branch=master)](https://travis-ci.org/alexaubry/BulletinBoard) -[![Version](https://img.shields.io/cocoapods/v/BulletinBoard.svg?style=flat)](https://cocoapods.org/pods/BulletinBoard) -[![License](https://img.shields.io/cocoapods/l/BulletinBoard.svg?style=flat)](https://cocoapods.org/pods/BulletinBoard) -[![Platform](https://img.shields.io/cocoapods/p/BulletinBoard.svg?style=flat)](https://cocoapods.org/pods/BulletinBoard) -[![Documentation](https://img.shields.io/badge/Documentation-available-blue.svg)](https://alexaubry.github.io/BulletinBoard) -[![Contact: @_alexaubry](https://raw.githubusercontent.com/alexaubry/BulletinBoard/master/.assets/twitter_badge.svg?sanitize=true)](https://twitter.com/_alexaubry) - -BulletinBoard is an iOS library that generates and manages contextual cards displayed at the bottom of the screen. It is especially well suited for quick user interactions such as onboarding screens or configuration. - -It has an interface similar to the cards displayed by iOS for AirPods, Apple TV/HomePod configuration and NFC tag scanning. It supports both the iPhone, iPhone X and the iPad. - -It has built-in support for accessibility features such as VoiceOver and Switch Control. - -Here are some screenshots showing what you can build with BulletinBoard: - -![Demo Screenshots](https://raw.githubusercontent.com/alexaubry/BulletinBoard/master/.assets/demo_screenshots.png) - -## Requirements - -- Xcode 11 and later -- iOS 9 and later -- Swift 5.1 and later (also works with Objective-C). - -## Demo - -A demo project is included in the `BulletinBoard` workspace. It demonstrates how to: - -- integrate the library (setup, data flow) -- create standard page cards -- create custom page subclasses to add features -- create custom cards from scratch - -Two demo targets are available: - -- `BB-Swift` (demo written in Swift) -- `BB-ObjC` (demo written in Objective-C) - -Build and run the scheme for your favorite language to open the demo app. - -Here's a video showing it in action: - -[![Watch Demo on YouTube](https://raw.githubusercontent.com/alexaubry/BulletinBoard/master/.assets/demo_thumbnail.png)](https://youtu.be/f4UErY-epYY) - -## Installation - -BulletinBoard is available via CocoaPods and Carthage. - -### CocoaPods - -To install BulletinBoard using [CocoaPods](https://cocoapods.org), add this line to your `Podfile`: - -~~~ruby -pod 'BulletinBoard' -~~~ - -### Carthage - -To install BulletinBoard using [Carthage](https://github.com/Carthage/Carthage), add this line to your `Cartfile`: - -~~~ -github "alexaubry/BulletinBoard" -~~~ - -## Documentation - -- The full library documentation is available [here](https://alexaubry.github.io/BulletinBoard). -- To learn how to start using `BulletinBoard`, check out our [Getting Started](https://alexaubry.github.io/BulletinBoard/getting-started.html) guide. - -## Contributing - -Thank you for your interest in the project! Contributions are welcome and appreciated. - -Make sure to read these guides before getting started: - -- [Code of Conduct](https://github.com/alexaubry/BulletinBoard/blob/master/CODE_OF_CONDUCT.md) -- [Contribution Guidelines](https://github.com/alexaubry/BulletinBoard/blob/master/CONTRIBUTING.md) - -## Author - -Written by Alexis Aubry. You can [find me on Twitter](https://twitter.com/_alexaubry). - -## License - -BulletinBoard is available under the MIT license. See the [LICENSE](LICENSE) file for more info. diff --git a/Pods/BulletinBoard/Sources/Appearance/BLTNBackgroundViewStyle.swift b/Pods/BulletinBoard/Sources/Appearance/BLTNBackgroundViewStyle.swift deleted file mode 100644 index 36f0b8e..0000000 --- a/Pods/BulletinBoard/Sources/Appearance/BLTNBackgroundViewStyle.swift +++ /dev/null @@ -1,87 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * The types of background used to cover the content behind the bulletins. - */ - -@objc public class BLTNBackgroundViewStyle: NSObject { - - enum Style { - - case none - case dimmed - case blurred(style: UIBlurEffect.Style, isDark: Bool) - - var isDark: Bool { - - switch self { - case .none, .dimmed: return true - case .blurred(_, let isDarkBlur): return isDarkBlur - } - - } - - } - - let rawValue: Style - - init(rawValue: Style) { - self.rawValue = rawValue - } - - @available(*, unavailable, message: "Use one of the presets to create a backrgound style object.") - override init() { - fatalError("BLTNBackgroundViewStyle.init is unavailable. Use one of the presets instead.") - } - -} - -// MARK: - Presets - -extension BLTNBackgroundViewStyle { - - /** - * The background content is not covered. - */ - - @objc public static let none = BLTNBackgroundViewStyle(rawValue: .none) - - /** - * The background is covered with a semi-transparent view similar to the view displayed behind - * UIKit alerts and action sheets. - */ - - @objc public static let dimmed = BLTNBackgroundViewStyle(rawValue: .dimmed) - - /** - * The background is blurred with the specified effect. - * - * Available on iOS 10.0 and later. - * - * - parameter style: The style of blur to use to cover the background. - * - parameter isDark: Whether the blur effect is dark. - */ - - @available(iOS 10, *) - @objc public static func blurred(style: UIBlurEffect.Style, isDark: Bool) -> BLTNBackgroundViewStyle { - return BLTNBackgroundViewStyle(rawValue: .blurred(style: style, isDark: isDark)) - } - - /// The background blurred with a light style. - @available(iOS 10, *) - @objc public static let blurredLight: BLTNBackgroundViewStyle = .blurred(style: .light, isDark: false) - - /// The background blurred with an extra light style. - @available(iOS 10, *) - @objc public static let blurredExtraLight: BLTNBackgroundViewStyle = .blurred(style: .extraLight, isDark: false) - - /// The background blurred with a dark style. - @available(iOS 10, *) - @objc public static let blurredDark: BLTNBackgroundViewStyle = .blurred(style: .dark, isDark: true) - -} diff --git a/Pods/BulletinBoard/Sources/Appearance/BLTNInterfaceBuilder.swift b/Pods/BulletinBoard/Sources/Appearance/BLTNInterfaceBuilder.swift deleted file mode 100644 index e688fbc..0000000 --- a/Pods/BulletinBoard/Sources/Appearance/BLTNInterfaceBuilder.swift +++ /dev/null @@ -1,220 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * Generates interface elements for bulletins. Use this class to create custom bulletin items with - * standard components. - */ - -@objc open class BLTNInterfaceBuilder: NSObject { - - /// The item for which the interface builder was created. - @objc public weak var item: BLTNItem? - - /// The appearance to use to generate the items. - @objc public let appearance: BLTNItemAppearance - - /// Creates a new interface builder. - @objc public required init(appearance: BLTNItemAppearance, item: BLTNItem) { - self.appearance = appearance - self.item = item - } - - /** - * Creates a standard title label. - */ - - @objc open func makeTitleLabel() -> BLTNTitleLabelContainer { - - let titleLabel = UILabel() - titleLabel.textAlignment = .center - titleLabel.textColor = appearance.titleTextColor - titleLabel.accessibilityTraits.insert(.header) - titleLabel.numberOfLines = 2 - titleLabel.adjustsFontSizeToFitWidth = true - titleLabel.lineBreakMode = .byWordWrapping - - titleLabel.font = appearance.makeTitleFont() - - let needsCloseButton = item?.isDismissable == true && item?.requiresCloseButton == true - let inset: CGFloat = needsCloseButton ? 12 + 30 : 0 - - return BLTNTitleLabelContainer(label: titleLabel, horizontalInset: inset) - - } - - /** - * Creates a standard description label. - */ - - @objc open func makeDescriptionLabel() -> UILabel { - - let descriptionLabel = UILabel() - descriptionLabel.textAlignment = .center - descriptionLabel.textColor = appearance.descriptionTextColor - descriptionLabel.numberOfLines = 0 - descriptionLabel.font = appearance.makeDescriptionFont() - - return descriptionLabel - - } - - /** - * Creates a standard text field with an optional delegate. - * - * - parameter placeholder: The placeholder text. - * - parameter returnKey: The type of return key to apply to the text field. - * - parameter delegate: The delegate for the text field. - */ - - @objc open func makeTextField(placeholder: String? = nil, - returnKey: UIReturnKeyType = .default, - delegate: UITextFieldDelegate? = nil) -> UITextField { - - let textField = UITextField() - textField.delegate = delegate - textField.textAlignment = .left - textField.placeholder = placeholder - textField.borderStyle = .roundedRect - textField.returnKeyType = returnKey - - return textField - - } - - /** - * Creates a standard action (main) button. - * - * The created button will have rounded corners, a background color set to the `tintColor` and - * a title color set to `actionButtonTitleColor`. - * - * - parameter title: The title of the button. - */ - - @objc open func makeActionButton(title: String) -> BLTNHighlightButtonWrapper { - - let actionButton = HighlightButton() - actionButton.cornerRadius = appearance.actionButtonCornerRadius - - if let actionButtonImage = appearance.actionButtonImage { - actionButton.setBackgroundImage(actionButtonImage, for: .normal) - - } else { - actionButton.setBackgroundColor(appearance.actionButtonColor, forState: .normal) - } - - actionButton.setTitleColor(appearance.actionButtonTitleColor, for: .normal) - actionButton.contentHorizontalAlignment = .center - - actionButton.setTitle(title, for: .normal) - actionButton.titleLabel?.font = appearance.makeActionButtonFont() - - actionButton.clipsToBounds = true - - if let color = appearance.actionButtonBorderColor { - actionButton.layer.borderColor = color.cgColor - actionButton.layer.borderWidth = appearance.actionButtonBorderWidth - } - - let wrapper = BLTNHighlightButtonWrapper(button: actionButton) - wrapper.setContentHuggingPriority(.defaultLow, for: .horizontal) - - let heightConstraint = wrapper.heightAnchor.constraint(equalToConstant: 55) - heightConstraint.priority = .defaultHigh - heightConstraint.isActive = true - - return wrapper - - } - - /** - * Creates a standard alternative button. - * - * The created button will have no background color and a title color set to `tintColor`. - * - * - parameter title: The title of the button. - */ - - @objc open func makeAlternativeButton(title: String) -> UIButton { - - let alternativeButton = RoundedButton() - alternativeButton.cornerRadius = appearance.alternativeButtonCornerRadius - alternativeButton.setTitle(title, for: .normal) - alternativeButton.setTitleColor(appearance.alternativeButtonTitleColor, for: .normal) - alternativeButton.titleLabel?.font = appearance.makeAlternativeButtonFont() - - if let color = appearance.alternativeButtonBorderColor { - alternativeButton.clipsToBounds = true - alternativeButton.layer.borderColor = color.cgColor - alternativeButton.layer.borderWidth = appearance.alternativeButtonBorderWidth - } - - return alternativeButton - - } - - /** - * Creates a stack view to contain a group of objects. - * - * - parameter spacing: The spacing between elements. Defaults to `10`. - */ - - @objc open func makeGroupStack(spacing: CGFloat = 10) -> UIStackView { - - let buttonsStack = UIStackView() - buttonsStack.axis = .vertical - buttonsStack.alignment = .fill - buttonsStack.distribution = .fill - buttonsStack.spacing = spacing - - return buttonsStack - - } - - /** - * Wraps a view without intrinsic content size inside a view with an intrinsic content size. - * - * This method allows you to display view without an intrinsic content size, such as collection views, - * inside stack views; by using the returned `BLTNContentView` view. - * - * - parameter view: The view to wrap in the container. - * - parameter width: The width of the content. Pass `nil` if the content has a flexible width. - * - parameter height: The height of the content. Pass `nil` if the content has a flexible height. - * - parameter position: The position of `view` inside its parent. - * - * - returns: The view that contains the `view` and an intrinsic content size. You can add the returned - * view to a stack view. - */ - - @objc open func wrapView(_ view: UIView, width: NSNumber?, height: NSNumber?, position: BLTNViewPosition) -> BLTNContainerView { - - let container = BLTNContainerView() - - container.contentSize = CGSize(width: width.flatMap(CGFloat.init) ?? UIView.noIntrinsicMetric, - height: height.flatMap(CGFloat.init) ?? UIView.noIntrinsicMetric) - - container.setChildView(view) { parent, child in - - switch position { - case .centered: - child.centerXAnchor.constraint(equalTo: parent.centerXAnchor).isActive = true - child.centerYAnchor.constraint(equalTo: parent.centerYAnchor).isActive = true - - case .pinnedToEdges: - child.leadingAnchor.constraint(equalTo: parent.leadingAnchor).isActive = true - child.trailingAnchor.constraint(equalTo: parent.trailingAnchor).isActive = true - child.topAnchor.constraint(equalTo: parent.topAnchor).isActive = true - child.bottomAnchor.constraint(equalTo: parent.bottomAnchor).isActive = true - } - - } - - return container - - } - -} diff --git a/Pods/BulletinBoard/Sources/Appearance/BLTNItemAppearance.swift b/Pods/BulletinBoard/Sources/Appearance/BLTNItemAppearance.swift deleted file mode 100644 index 76c45c6..0000000 --- a/Pods/BulletinBoard/Sources/Appearance/BLTNItemAppearance.swift +++ /dev/null @@ -1,210 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * An object that defines the appearance of bulletin items. - */ - -@objc public class BLTNItemAppearance: NSObject { - - // MARK: - Color Customization - - /// The tint color to apply to the action button (default `.link` on iOS 13 and `.blue` on older systems). - @objc public var actionButtonColor: UIColor = { - if #available(iOS 13.0, *) { - return .link - } else { - return #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1) - } - }() - - /// The button image to apply to the action button - @objc public var actionButtonImage: UIImage? - - /// The title color to apply to action button (default white). - @objc public var actionButtonTitleColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) - - /// The border color to apply to action button. - @objc public var actionButtonBorderColor: UIColor? = nil - - /// The border width to apply to action button. - @objc public var actionButtonBorderWidth: CGFloat = 1.0 - - /// The title color to apply to the alternative button (default `.link` on iOS 13 and `.blue` on older systems). - @objc public var alternativeButtonTitleColor: UIColor = { - if #available(iOS 13.0, *) { - return .link - } else { - return #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1) - } - }() - - /// The border color to apply to the alternative button. - @objc public var alternativeButtonBorderColor: UIColor? = nil - - /// The border width to apply to the alternative button. - @objc public var alternativeButtonBorderWidth: CGFloat = 1.0 - - /// The tint color to apply to the imageView (if image rendered in template mode, default `.link` on iOS 13 and `.blue` on older systems). - @objc public var imageViewTintColor: UIColor = { - if #available(iOS 13.0, *) { - return .link - } else { - return #colorLiteral(red: 0, green: 0.4784313725, blue: 1, alpha: 1) - } - }() - - /// The color of title text labels (default `.secondaryLabel` on iOS 13 and light gray on older systems). - @objc public var titleTextColor: UIColor = { - if #available(iOS 13.0, *) { - return .secondaryLabel - } else { - return #colorLiteral(red: 0.568627451, green: 0.5647058824, blue: 0.5725490196, alpha: 1) - } - }() - - /// The color of description text labels (default `.label` on iOS 13 and black on older systems). - @objc public var descriptionTextColor: UIColor = { - if #available(iOS 13.0, *) { - return .label - } else { - return #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) - } - }() - - // MARK: - Corner Radius Customization - - /// The corner radius of the action button (default 12). - @objc public var actionButtonCornerRadius: CGFloat = 12 - - /// The corner radius of the alternative button (default 12). - @objc public var alternativeButtonCornerRadius: CGFloat = 12 - - // MARK: - Font Customization - - /// An optional custom font to use for the title label. Set this to nil to use the system font. - @objc public var titleFontDescriptor: UIFontDescriptor? - - /// An optional custom font to use for the description label. Set this to nil to use the system font. - @objc public var descriptionFontDescriptor: UIFontDescriptor? - - /// An optional custom font to use for the buttons. Set this to nil to use the system font. - @objc public var buttonFontDescriptor: UIFontDescriptor? - - /** - * Whether the description text should be displayed with a smaller font. - * - * You should set this to `true` if your text is long (more that two sentences). - */ - - @objc public var shouldUseCompactDescriptionText: Bool = false - - - // MARK: - Font Constants - - /// The font size of title elements (default 30). - @objc public var titleFontSize: CGFloat = 30 - - /// The font size of description labels (default 20). - @objc public var descriptionFontSize: CGFloat = 20 - - /// The font size of compact description labels (default 15). - @objc public var compactDescriptionFontSize: CGFloat = 15 - - /// The font size of action buttons (default 17). - @objc public var actionButtonFontSize: CGFloat = 17 - - /// The font size of alternative buttons (default 15). - @objc public var alternativeButtonFontSize: CGFloat = 15 - -} - -// MARK: - Font Factories - -extension BLTNItemAppearance { - - /** - * Creates the font for title labels. - */ - - @objc public func makeTitleFont() -> UIFont { - - if let titleFontDescriptor = self.titleFontDescriptor { - return UIFont(descriptor: titleFontDescriptor, size: titleFontSize) - } else { - return UIFont.systemFont(ofSize: titleFontSize, weight: .medium) - } - - } - - /** - * Creates the font for description labels. - */ - - @objc public func makeDescriptionFont() -> UIFont { - - let size = shouldUseCompactDescriptionText ? compactDescriptionFontSize : descriptionFontSize - - if let descriptionFontDescriptor = self.descriptionFontDescriptor { - return UIFont(descriptor: descriptionFontDescriptor, size: size) - } else { - return UIFont.systemFont(ofSize: size) - } - - } - - /** - * Creates the font for action buttons. - */ - - @objc public func makeActionButtonFont() -> UIFont { - - if let buttonFontDescriptor = self.buttonFontDescriptor { - return UIFont(descriptor: buttonFontDescriptor, size: actionButtonFontSize) - } else { - return UIFont.systemFont(ofSize: actionButtonFontSize, weight: .semibold) - } - - } - - /** - * Creates the font for alternative buttons. - */ - - @objc public func makeAlternativeButtonFont() -> UIFont { - - if let buttonFontDescriptor = self.buttonFontDescriptor { - return UIFont(descriptor: buttonFontDescriptor, size: alternativeButtonFontSize) - } else { - return UIFont.systemFont(ofSize: alternativeButtonFontSize, weight: .semibold) - } - - } - -} - -// MARK: - Status Bar - -/** - * Styles of status bar to use with bulletin items. - */ - -@objc public enum BLTNStatusBarAppearance: Int { - - /// The status bar is hidden. - case hidden - - /// The color of the status bar is determined automatically. This is the default style. - case automatic - - /// Style to use with dark backgrounds. - case lightContent - - /// Style to use with light backgrounds. - case darkContent - -} diff --git a/Pods/BulletinBoard/Sources/Appearance/BLTNSpacing.swift b/Pods/BulletinBoard/Sources/Appearance/BLTNSpacing.swift deleted file mode 100644 index 54e7090..0000000 --- a/Pods/BulletinBoard/Sources/Appearance/BLTNSpacing.swift +++ /dev/null @@ -1,56 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * Represents a spacing value. - */ - -@objc public class BLTNSpacing: NSObject { - - let rawValue: CGFloat - - init(rawValue: CGFloat) { - self.rawValue = rawValue - } - - /** - * A custom spacing. - * - * - parameter value: The spacing to apply. - */ - - @objc public class func custom(_ value: CGFloat) -> BLTNSpacing { - return BLTNSpacing(rawValue: value) - } - - /** - * No spacing is applied. (value: 0) - * - * If you use this padding, corner radii will be ignored. - */ - - @objc public class var none: BLTNSpacing { - return BLTNSpacing(rawValue: 0) - } - - /** - * A compact spacing. (value: 6) - */ - - @objc public class var compact: BLTNSpacing { - return BLTNSpacing(rawValue: 6) - } - - /** - * The standard spacing. (value: 12) - */ - - @objc public class var regular: BLTNSpacing { - return BLTNSpacing(rawValue: 12) - } - -} diff --git a/Pods/BulletinBoard/Sources/Appearance/BLTNViewPosition.swift b/Pods/BulletinBoard/Sources/Appearance/BLTNViewPosition.swift deleted file mode 100644 index 0c849fa..0000000 --- a/Pods/BulletinBoard/Sources/Appearance/BLTNViewPosition.swift +++ /dev/null @@ -1,20 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import Foundation - -/** - * Describes the position of a view inside of its parent container. - */ - -@objc public enum BLTNViewPosition: Int { - - /// The view is centered in its parent container. - case centered - - /// The view is pinned to the four edges of its parent container. - case pinnedToEdges - -} diff --git a/Pods/BulletinBoard/Sources/BLTNBoard.h b/Pods/BulletinBoard/Sources/BLTNBoard.h deleted file mode 100644 index b59238f..0000000 --- a/Pods/BulletinBoard/Sources/BLTNBoard.h +++ /dev/null @@ -1,10 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -@import UIKit; - -#import "BLTNItem.h" -#import "BLTNActionItem.h" -#import "BLTNPageItem.h" diff --git a/Pods/BulletinBoard/Sources/BLTNItemManager.swift b/Pods/BulletinBoard/Sources/BLTNItemManager.swift deleted file mode 100644 index 72dd2c5..0000000 --- a/Pods/BulletinBoard/Sources/BLTNItemManager.swift +++ /dev/null @@ -1,730 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * An object that manages the presentation of a bulletin. - * - * You create a bulletin manager using the `init(rootItem:)` initializer, where `rootItem` is the - * first bulletin item to display. An item represents the contents displayed on a single card. - * - * The manager works like a navigation controller. You can push new items to the stack to display them, - * and pop existing ones to go back. - * - * You must call the `prepare` method before displaying the view controller. - * - * `BLTNItemManager` must only be used from the main thread. - */ - -@objc public final class BLTNItemManager: NSObject { - - /// Bulletin view controller. - fileprivate var bulletinController: BulletinViewController! - - // MARK: - Background - - /** - * The background color of the bulletin card. Defaults to `systemBackground` on iOS 13 - * and white on older versions of the OS. - * - * Set this value before presenting the bulletin. Changing it after will have no effect. - */ - - @objc public var backgroundColor: UIColor = { - if #available(iOS 13.0, *) { - return .systemBackground - } else { - return .white - } - }() - - /** - * The style of the view covering the content. Defaults to `.dimmed`. - * - * Set this value before presenting the bulletin. Changing it after will have no effect. - */ - - @objc public var backgroundViewStyle: BLTNBackgroundViewStyle = .dimmed - - // MARK: - Status Bar - - /** - * The style of status bar to use with the bulltin. Defaults to `.automatic`. - * - * Set this value before presenting the bulletin. Changing it after will have no effect. - */ - - @objc public var statusBarAppearance: BLTNStatusBarAppearance = .automatic - - /** - * The style of status bar animation. Defaults to `.fade`. - * - * Set this value before presenting the bulletin. Changing it after will have no effect. - */ - - @objc public var statusBarAnimation: UIStatusBarAnimation = .fade - - /** - * The home indicator for iPhone X should be hidden or not. Defaults to false. - * - * Set this value before presenting the bulletin. Changing it after will have no effect. - */ - - @objc public var hidesHomeIndicator: Bool = false - - // MARK: - Card Presentation - - /** - * The spacing between the edge of the screen and the edge of the card. Defaults to regular. - * - * Set this value before presenting the bulletin. Changing it after will have no effect. - */ - - @objc public var edgeSpacing: BLTNSpacing = .regular - - /** - * The rounded corner radius of the bulletin card. Defaults to 12, and 36 on iPhone X. - * - * Set this value before calling `prepare`. Changing it after will have no effect. - */ - - @objc public var cardCornerRadius: NSNumber? - - /** - * Whether swipe to dismiss should be allowed. Defaults to true. - * - * If you set this value to true, the user will be able to drag the card, and swipe down to - * dismiss it (if allowed by the current item). - * - * If you set this value to false, no pan gesture will be recognized, and swipe to dismiss - * won't be available. - */ - - @objc public var allowsSwipeInteraction: Bool = true - - /** - * Tells us if a bulletin is currently being shown. Defaults to false - */ - - @objc public var isShowingBulletin: Bool { - return bulletinController?.presentingViewController != nil - } - - // MARK: - Private Properties - - var currentItem: BLTNItem - - fileprivate let rootItem: BLTNItem - fileprivate var itemsStack: [BLTNItem] - fileprivate var previousItem: BLTNItem? - fileprivate var presentingWindow: UIWindow? - - fileprivate var isPrepared: Bool = false - fileprivate var isPreparing: Bool = false - fileprivate var shouldDisplayActivityIndicator: Bool = false - fileprivate var lastActivityIndicatorColor: UIColor = .black - - // MARK: - Initialization - - /** - * Creates a bulletin manager and sets the first item to display.s - * - * - parameter rootItem: The first item to display. - */ - - @objc public init(rootItem: BLTNItem) { - - self.rootItem = rootItem - self.itemsStack = [] - self.currentItem = rootItem - - } - - deinit { - - tearDownItemsChain(startingAt: self.rootItem) - - for item in itemsStack { - tearDownItemsChain(startingAt: item) - } - - } - - @available(*, unavailable, message: "Use init(rootItem:) instead.") - override init() { - fatalError("BLTNItemManager.init is unavailable. Use init(rootItem:) instead.") - } - -} - -// MARK: - Interacting with the Bulletin - -extension BLTNItemManager { - - /** - * Prepares the bulletin interface and displays the root item. - * - * This method must be called before any other interaction with the bulletin. - */ - - fileprivate func prepare() { - - assertIsMainThread() - - bulletinController = BulletinViewController() - bulletinController.manager = self - - bulletinController.modalPresentationStyle = .overFullScreen - bulletinController.transitioningDelegate = bulletinController - bulletinController.loadBackgroundView() - bulletinController.setNeedsStatusBarAppearanceUpdate() - - if #available(iOS 11.0, *) { - bulletinController.setNeedsUpdateOfHomeIndicatorAutoHidden() - } - - isPrepared = true - isPreparing = true - shouldDisplayActivityIndicator = rootItem.shouldStartWithActivityIndicator - - refreshCurrentItemInterface() - isPreparing = false - - } - - /** - * Presents a view controller above the bulletin card. - * - * This is useful if you want to present an alert or a Safari view contoller in response to user - * action. - * - * - parameter viewController: The view controller to present. - * - parameter animated: Whether presentation should be animated. - * - parameter completion: An optional completion block to run after presentation - * has completed. Defaults to `nil`. - */ - - @objc(presentViewControllerAboveBulletin:animated:completion:) - public func present(_ viewController: UIViewController, animated: Bool, completion: (() -> Void)? = nil) { - assertIsPrepared() - self.bulletinController.present(viewController, animated: animated, completion: completion) - } - - /** - * Performs an operation with the bulletin content view and returns the result. - * - * Use this as an opportunity to customize the behavior of the content view (e.g. add motion effects). - * - * You must not store a reference to the view, or modify its layout (add subviews, add contraints, ...) as this - * could break the bulletin. - * - * Use this feature sparingly. - * - * - parameter transform: The code to execute with the content view. - * - warning: If you save the content view outside of the `transform` closure, an exception will be raised. - */ - - @discardableResult - public func withContentView(_ transform: (UIView) throws -> Result) rethrows -> Result { - - assertIsPrepared() - assertIsMainThread() - - let contentView = bulletinController.contentView - let initialRetainCount = CFGetRetainCount(contentView) - - let result = try transform(bulletinController.contentView) - let finalRetainCount = CFGetRetainCount(contentView) - - precondition(initialRetainCount == finalRetainCount, - "The content view was saved outside of the transform closure. This is not allowed.") - - return result - - } - - /** - * Hides the contents of the stack and displays an activity indicator view. - * - * Use this method if you need to perform a long task or fetch some data before changing the item. - * - * Displaying the loading indicator does not change the height of the page or the current item. It will disable - * dismissal by tapping and swiping to allow the task to complete and avoid resource deallocation. - * - * - parameter color: The color of the activity indicator to display. Defaults to .label on iOS 13 and .black on older systems. - * - * Displaying the loading indicator does not change the height of the page or the current item. - */ - - @objc public func displayActivityIndicator(color: UIColor? = nil) { - - assertIsPrepared() - assertIsMainThread() - - shouldDisplayActivityIndicator = true - lastActivityIndicatorColor = color ?? defaultActivityIndicatorColor - - bulletinController.displayActivityIndicator(color: lastActivityIndicatorColor) - } - - /// Provides a default color for activity indicator views. - /// Defaults to .label on iOS 13 and .black on older systems. - private var defaultActivityIndicatorColor: UIColor { - if #available(iOS 13.0, *) { - return .label - } else { - return .black - } - } - - /** - * Hides the activity indicator and displays the current item. - * - * You can also call one of `popItem`, `popToRootItem` and `pushItem` if you need to hide the activity - * indicator and change the current item. - */ - - @objc public func hideActivityIndicator() { - - assertIsPrepared() - assertIsMainThread() - - shouldDisplayActivityIndicator = false - bulletinController.swipeInteractionController?.cancelIfNeeded() - refreshCurrentItemInterface(elementsChanged: false) - - } - - /** - * Displays a new item after the current one. - * - parameter item: The item to display. - */ - - @objc public func push(item: BLTNItem) { - - assertIsPrepared() - assertIsMainThread() - - previousItem = currentItem - itemsStack.append(item) - - currentItem = item - - shouldDisplayActivityIndicator = item.shouldStartWithActivityIndicator - refreshCurrentItemInterface() - - } - - /** - * Removes the current item from the stack and displays the previous item. - */ - - @objc public func popItem() { - - assertIsPrepared() - assertIsMainThread() - - guard let previousItem = itemsStack.popLast() else { - popToRootItem() - return - } - - self.previousItem = previousItem - - guard let currentItem = itemsStack.last else { - popToRootItem() - return - } - - self.currentItem = currentItem - - shouldDisplayActivityIndicator = currentItem.shouldStartWithActivityIndicator - refreshCurrentItemInterface() - - } - - /** - * Removes items from the stack until a specific item is found. - * - parameter item: The item to seek. - * - parameter orDismiss: If true, dismiss bullein if not found. Otherwise popToRootItem() - */ - - @objc public func popTo(item: BLTNItem, orDismiss: Bool) { - - assertIsPrepared() - assertIsMainThread() - - for index in 0.. Void)? = nil) { - - self.prepare() - - let isDetached = bulletinController.presentingViewController == nil - assert(isDetached, "Attempt to present a Bulletin that is already presented.") - - assertIsPrepared() - assertIsMainThread() - bulletinController.loadView() - - let refreshActivityIndicator = shouldDisplayActivityIndicator && isDetached - - if refreshActivityIndicator { - bulletinController.displayActivityIndicator(color: lastActivityIndicatorColor) - } - - bulletinController.modalPresentationCapturesStatusBarAppearance = true - presentingVC.present(bulletinController, animated: animated, completion: completion) - - } - - /** - * Presents the bulletin on top of your application window. - * - * - parameter application: The application in which to display the bulletin. (normally: UIApplication.shared) - * - parameter animated: Whether to animate presentation. Defaults to `true`. - * - parameter completion: An optional block to execute after presentation. Default to `nil`. - */ - - @objc(showBulletinInApplication:animated:completion:) - public func showBulletin(in application: UIApplication, - animated: Bool = true, - completion: (() -> Void)? = nil) { - assert(presentingWindow == nil, "Attempt to present a Bulletin on top of another Bulletin window. Make sure to dismiss any existing bulletin before calling this method.") - presentingWindow = UIWindow(frame: UIScreen.main.bounds) - presentingWindow?.rootViewController = UIViewController() - - // set alert window above current top window - if let topWindow = application.windows.last { - presentingWindow?.windowLevel = topWindow.windowLevel + 1 - } - - presentingWindow?.makeKeyAndVisible() - - if let vc = presentingWindow?.rootViewController { - self.showBulletin(above: vc, animated: animated, completion: completion) - } - - } - - /** - * Dismisses the bulletin and clears the current page. You will have to call `prepare` before - * presenting the bulletin again. - * - * This method will call the `dismissalHandler` block of the current item if it was set. - * - * - parameter animated: Whether to animate dismissal. Defaults to `true`. - */ - - @objc(dismissBulletinAnimated:) - public func dismissBulletin(animated: Bool = true) { - - assertIsPrepared() - assertIsMainThread() - - currentItem.tearDown() - currentItem.manager = nil - - bulletinController.dismiss(animated: animated) { - self.completeDismissal() - } - - isPrepared = false - - } - - /** - * Tears down the view controller and item stack after dismissal is finished. - */ - - @nonobjc func completeDismissal() { - - currentItem.onDismiss() - - for arrangedSubview in bulletinController.contentStackView.arrangedSubviews { - bulletinController.contentStackView.removeArrangedSubview(arrangedSubview) - arrangedSubview.removeFromSuperview() - } - - presentingWindow?.isHidden = true - presentingWindow = nil - - bulletinController.backgroundView = nil - bulletinController.manager = nil - bulletinController.transitioningDelegate = nil - - bulletinController = nil - - currentItem = self.rootItem - itemsStack.removeAll() - - } - -} - -// MARK: - Transitions - -extension BLTNItemManager { - - var needsCloseButton: Bool { - return currentItem.isDismissable && currentItem.requiresCloseButton - } - - /// Refreshes the interface for the current item. - fileprivate func refreshCurrentItemInterface(elementsChanged: Bool = true) { - - bulletinController.isDismissable = false - bulletinController.swipeInteractionController?.cancelIfNeeded() - bulletinController.refreshSwipeInteractionController() - - let showActivityIndicator = self.shouldDisplayActivityIndicator - let contentAlpha: CGFloat = showActivityIndicator ? 0 : 1 - - // Tear down old item - - let oldArrangedSubviews = bulletinController.contentStackView.arrangedSubviews - let oldHideableArrangedSubviews = recursiveArrangedSubviews(in: oldArrangedSubviews) - - if elementsChanged { - previousItem?.tearDown() - previousItem?.manager = nil - previousItem = nil - } - - // Create new views - - let newArrangedSubviews = currentItem.makeArrangedSubviews() - let newHideableArrangedSubviews = recursiveArrangedSubviews(in: newArrangedSubviews) - - if elementsChanged { - - currentItem.setUp() - currentItem.manager = self - - for arrangedSubview in newHideableArrangedSubviews { - arrangedSubview.isHidden = isPreparing ? false : true - } - - for arrangedSubview in newArrangedSubviews { - bulletinController.contentStackView.addArrangedSubview(arrangedSubview) - } - - } - - // Animate transition - - let animationDuration = isPreparing ? 0 : 0.75 - let transitionAnimationChain = AnimationChain(duration: animationDuration) - - let hideSubviewsAnimationPhase = AnimationPhase(relativeDuration: 1/3, curve: .linear) - - hideSubviewsAnimationPhase.block = { - - if !showActivityIndicator { - self.bulletinController.hideActivityIndicator() - } - - for arrangedSubview in oldArrangedSubviews { - arrangedSubview.alpha = 0 - } - - for arrangedSubview in newArrangedSubviews { - arrangedSubview.alpha = 0 - } - - } - - let displayNewItemsAnimationPhase = AnimationPhase(relativeDuration: 1/3, curve: .linear) - - displayNewItemsAnimationPhase.block = { - - for arrangedSubview in oldHideableArrangedSubviews { - arrangedSubview.isHidden = true - } - - for arrangedSubview in newHideableArrangedSubviews { - arrangedSubview.isHidden = false - } - - } - - displayNewItemsAnimationPhase.completionHandler = { - self.currentItem.willDisplay() - } - - let finalAnimationPhase = AnimationPhase(relativeDuration: 1/3, curve: .linear) - - finalAnimationPhase.block = { - - let currentElements = elementsChanged ? newArrangedSubviews : oldArrangedSubviews - self.bulletinController.contentStackView.alpha = contentAlpha - self.bulletinController.updateCloseButton(isRequired: self.needsCloseButton && !showActivityIndicator) - - for arrangedSubview in currentElements { - arrangedSubview.alpha = contentAlpha - } - - } - - finalAnimationPhase.completionHandler = { - - self.bulletinController.isDismissable = self.currentItem.isDismissable && (showActivityIndicator == false) - - if elementsChanged { - - self.currentItem.onDisplay() - - for arrangedSubview in oldArrangedSubviews { - self.bulletinController.contentStackView.removeArrangedSubview(arrangedSubview) - arrangedSubview.removeFromSuperview() - } - - } - - UIAccessibility.post(notification: .screenChanged, argument: newArrangedSubviews.first) - - } - - // Perform animation - - if elementsChanged { - transitionAnimationChain.add(hideSubviewsAnimationPhase) - transitionAnimationChain.add(displayNewItemsAnimationPhase) - } else { - bulletinController.hideActivityIndicator() - } - - transitionAnimationChain.add(finalAnimationPhase) - transitionAnimationChain.start() - - } - - /// Tears down every item on the stack starting from the specified item. - fileprivate func tearDownItemsChain(startingAt item: BLTNItem) { - - item.tearDown() - item.manager = nil - - if let next = item.next { - tearDownItemsChain(startingAt: next) - item.next = nil - } - - } - - /// Returns all the arranged subviews. - private func recursiveArrangedSubviews(in views: [UIView]) -> [UIView] { - - var arrangedSubviews: [UIView] = [] - - for view in views { - - if let stack = view as? UIStackView { - arrangedSubviews.append(stack) - let recursiveViews = self.recursiveArrangedSubviews(in: stack.arrangedSubviews) - arrangedSubviews.append(contentsOf: recursiveViews) - } else { - arrangedSubviews.append(view) - } - - } - - return arrangedSubviews - - } - -} - -// MARK: - Utilities - -extension BLTNItemManager { - - fileprivate func assertIsMainThread() { - precondition(Thread.isMainThread, "BLTNItemManager must only be used from the main thread.") - } - - fileprivate func assertIsPrepared() { - precondition(isPrepared, "You must call the `prepare` function before interacting with the bulletin.") - } - -} diff --git a/Pods/BulletinBoard/Sources/Deprecations.swift b/Pods/BulletinBoard/Sources/Deprecations.swift deleted file mode 100644 index 290806c..0000000 --- a/Pods/BulletinBoard/Sources/Deprecations.swift +++ /dev/null @@ -1,30 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import Foundation - -@available(*, unavailable, renamed: "BLTNItem") -@objc public protocol BulletinItem {} - -@available(*, unavailable, renamed: "BLTNItemManager") -@objc public class BulletinManager: NSObject {} - -@available(*, unavailable, renamed: "BLTNActionItem") -@objc public class ActionBulletinItem: NSObject {} - -@available(*, unavailable, renamed: "BLTNPageItem") -@objc public class PageBulletinItem: NSObject {} - -@available(*, unavailable, message: "To specify the appearance, use BLTNItemAppearance. To create standard views, use BLTNInterfaceBuilder.") -@objc public class BulletinInterfaceFactory: NSObject {} - -@available(*, unavailable, renamed: "BLTNSpacing") -@objc public class BulletinPadding: NSObject {} - -@available(*, unavailable, renamed: "BLTNBackgroundViewStyle") -@objc public class BulletinBackgroundViewStyle: NSObject {} - -@available(*, unavailable, renamed: "BLTNHighlightButtonWrapper") -@objc public class HighlightButtonWrapper: UIView {} diff --git a/Pods/BulletinBoard/Sources/Models/BLTNActionItem.h b/Pods/BulletinBoard/Sources/Models/BLTNActionItem.h deleted file mode 100644 index f5792ec..0000000 --- a/Pods/BulletinBoard/Sources/Models/BLTNActionItem.h +++ /dev/null @@ -1,294 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -@import UIKit; - -#import "BLTNItem.h" - -@class BLTNItemManager; -@class BLTNItemAppearance; -@class BLTNInterfaceBuilder; - -/** - * A standard bulletin item with that displays a large action button and a smaller button for alternative options. - * - * You do not use this class directly: - * - * - If your custom item has a title and optional stock elements (description, image), use `BLTNPageItem` - * which provides these stock elements. You can also override this class to insert custom views between the stock - * views. - * - * - If you need to display custom elements with the standard buttons on a page without a title, subclass `BLTNActionItem` - * and implement the `makeContentViews` method to return the elements to display above the buttons. - * - * Subclasses can override several methods to customize the UI: - * - * - In `footerViews`, return the views to display below the buttons. - * - In `actionButtonTapped(sender:)` and `alternativeButtonTapped(sender:)`, perform custom additional button handling - * (ex: haptic feedback). - * - * Use the `appearance` property to customize the appearance of the buttons. If you want to use a different interface - * builder type, change the `interfaceBuilderType` property. - */ - -@interface BLTNActionItem : NSObject - -#pragma mark - Page Contents - -/** - * The title of the action button. The action button represents the main action for the item. - * - * If you set this property to `nil`, no action button will be added (this is the default). - */ - -@property (nonatomic, strong, nullable) NSString *actionButtonTitle; - -/** - * The title of the alternative button. The alternative button represents a second option for - * the user. - * - * If you set this property to `nil`, no alternative button will be added (this is the default). - */ - -@property (nonatomic, strong, nullable) NSString *alternativeButtonTitle; - -#pragma mark - BLTNItem - -/** - * The object managing the item. - * - * This property is set when the item is currently being displayed. It will be set to `nil` when - * the item is removed from bulletin. - */ - -@property (nonatomic, nullable, weak) BLTNItemManager *manager; - -/** - * Whether the page can be dismissed. - * - * If you set this value to `true`, the user will be able to dismiss the bulletin by tapping outside - * of the card or by swiping down. - * - * You should set it to `true` for the last item you want to display. - */ - -@property (nonatomic, getter=isDismissable) BOOL dismissable; - -/** - * Whether the page can be dismissed with a close button. - * - * The default value is `true`. The user will be able to dismiss the bulletin by tapping on a button - * in the corner of the screen. - * - * You should set it to `false` if the interface of the bulletin already has buttons to dismiss the item, - * such as an action button. - */ - -@property (nonatomic) BOOL requiresCloseButton; - -/** - * Whether the page should start with an activity indicator. - * - * Set this value to `false` to display the elements right away. If you set it to `true`, - * you'll need to call `manager?.hideActivityIndicator()` to show the UI. - * - * This defaults to `false`. - */ - -@property (nonatomic) BOOL shouldStartWithActivityIndicator; - -/** - * Whether the item should move with the keyboard. - * - * You must set it to `true` if the item displays a text field. Otherwise, you can set it to `false` if you - * don't want the bulletin to move when system alerts are displayed. - * - * This value defaults to `true`. - */ - -@property (nonatomic) BOOL shouldRespondToKeyboardChanges; - -/** - * The item to display after this one. - * - * If you set this value, you'll be able to call `displayNextItem()` to push the next item to - * the stack. - */ - -@property (nonatomic, strong, nullable) id nextItem; - -/** - * The block of code to execute when the bulletin item is presented. This is called after the - * bulletin is moved onto the view. - * - * - parameter item: The item that is being presented. - */ - -@property (nonatomic, nullable) void(^presentationHandler)(id _Nonnull); - -/** - * The block of code to execute when the bulletin item is dismissed. This is called when the bulletin - * is moved out of view. - * - * You can leave it `nil` if `isDismissable` is set to false. - */ - -@property (nonatomic, nullable) void(^dismissalHandler)(id _Nonnull); - -#pragma mark - Customization - -/** - * The appearance manager used to generate the interface of the page. - * - * Use this property to customize the appearance of the generated elements. - * - * Make sure to customize the appearance before presenting the page. Changing the appearance properties - * after the bulletin page was presented has no effect. - */ - -@property (nonatomic, strong, nonnull) BLTNItemAppearance *appearance; - -/** - * The type of interface builder to use to generate the components. - * - * Make sure to customize this property before presenting the page. Changing the interface builder type - * after the bulletin page was presented has no effect. - */ - -@property (nonatomic, strong, nonnull) Class interfaceBuilderType; - -#pragma mark - Buttons - -/** - * The action button managed by the item. - */ - -@property (nonatomic, strong, nullable, readonly) UIButton *actionButton; - -/** - * The alternative button managed by the item. - */ - -@property (nonatomic, strong, nullable, readonly) UIButton *alternativeButton; - -/** - * The code to execute when the action button is tapped. - */ - -@property (nonatomic, nullable) void(^actionHandler)(BLTNActionItem * _Nonnull); - -/** - * The code to execute when the alternative button is tapped. - */ - -@property (nonatomic, nullable) void(^alternativeHandler)(BLTNActionItem * _Nonnull); - -/** - * Handles a tap on the action button. - * - * You can override this method to add custom tap handling. You have to call `super.actionButtonTapped(sender:)` - * in your implementation. - */ - -- (void)actionButtonTappedWithSender:(UIButton * _Nonnull)sender NS_SWIFT_NAME(actionButtonTapped(sender:)); - -/** - * Handles a tap on the alternative button. - * - * You can override this method to add custom tap handling. You have to call `super.alternativeButtonTapped(sender:)` - * in your implementation. - */ - -- (void)alternativeButtonTappedWithSender:(UIButton * _Nonnull)sender NS_SWIFT_NAME(alternativeButtonTapped(sender:)); - -#pragma mark - View Management - -/** - * The views to display below the buttons. - * - * You can override this method to insert custom views after the buttons. The default implementation returns `nil` and - * does not append footer elements. - * - * This method is called inside `makeArrangedSubviews` after the buttons are created. - * - * - parameter interfaceBuilder: The interface builder used to create the buttons. - * - returns: The footer views for the item, or `nil` if no footer views should be added. - */ - -- (NSArray * _Nullable)makeFooterViewsWithInterfaceBuilder:(BLTNInterfaceBuilder * _Nonnull)interfaceBuilder; - -/** - * Creates the content views of the page. Content views are displayed above the buttons. - * - * You must override this method to return the elements displayed above the buttons. Your implementation - * must not call `super`. - * - * If you do not implement this method, an exception will be raised. - * - * - parameter interfaceBuilder: The interface builder used to create the buttons. - * - returns: The views to display above the buttons. - */ - -- (NSArray * _Nonnull)makeContentViewsWithInterfaceBuilder:(BLTNInterfaceBuilder * _Nonnull)interfaceBuilder; - -/** - * Creates the list of views to display on the bulletin. - * - * This is an implementation detail of `BLTNItem` and you should not call it directly. Subclasses should not override this method, and should - * implement `makeContentViewsWithInterfaceBuilder:` instead. - */ - -- (NSArray * _Nonnull)makeArrangedSubviews; - -#pragma mark - Events - -/** - * Called by the manager when the item was added to the bulletin. - * - * Override this function to configure your managed views, and allocate any resources required - * for this item. Make sure to call `super` if you override this method. - */ - -- (void)setUp; - -/** - * Called by the manager when the item was removed from the bulletin view. - * - * Override this method if elements you returned in `makeContentViews` need cleanup. Make sure - * to call `super` if you override this method. - * - * This is an implementation detail of `BLTNItem` and you should not call it directly. - */ - -- (void)tearDown; - -/** -* Called by the manager when bulletin item is about to be pushed onto the view. -*/ - -- (void)willDisplay; - -/** - * Called by the manager when bulletin item is pushed onto the view. - * - * By default, this method calls trhe `presentationHandler` of the action item. Override this - * method if you need to perform additional preparation after presentation (although using - * `setUp` is preferred). - */ - -- (void)onDisplay; - -/** - * Called by the manager when bulletin item is dismissed. This is called after the bulletin - * is moved out of view. - * - * By default, this method calls trhe `dismissalHandler` of the action item. Override this - * method if you need to perform additional cleanup after dismissal (although using - * `tearDown` is preferred). - */ - -- (void)onDismiss; - -@end diff --git a/Pods/BulletinBoard/Sources/Models/BLTNActionItem.m b/Pods/BulletinBoard/Sources/Models/BLTNActionItem.m deleted file mode 100644 index ca172ea..0000000 --- a/Pods/BulletinBoard/Sources/Models/BLTNActionItem.m +++ /dev/null @@ -1,174 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -#import "BLTNActionItem.h" -#import "BLTNBoardSwiftSupport.h" -#import - -@interface BLTNActionItem () - -@property (nonatomic, strong, nullable, readwrite) UIButton *actionButton; -@property (nonatomic, strong, nullable, readwrite) UIButton *alternativeButton; - -@end - -@implementation BLTNActionItem - -- (instancetype)init -{ - self = [super init]; - if (self) { - self.actionButtonTitle = nil; - self.alternativeButtonTitle = nil; - self.manager = nil; - self.dismissable = YES; - self.requiresCloseButton = YES; - self.shouldStartWithActivityIndicator = NO; - self.shouldRespondToKeyboardChanges = YES; - self.nextItem = nil; - self.presentationHandler = nil; - self.dismissalHandler = nil; - self.appearance = [[BLTNItemAppearance alloc] init]; - self.interfaceBuilderType = [BLTNInterfaceBuilder class]; - self.actionButton = nil; - self.alternativeButton = nil; - self.actionHandler = nil; - self.alternativeHandler = nil; - } - return self; -} - -#pragma mark - Properties - -- (void)setActionButtonTitle:(NSString *)actionButtonTitle -{ - _actionButtonTitle = actionButtonTitle; - if (self.actionButton) { - [self.actionButton setTitle:actionButtonTitle forState:UIControlStateNormal]; - } -} - -- (void)setAlternativeButtonTitle:(NSString *)alternativeButtonTitle -{ - _alternativeButtonTitle = alternativeButtonTitle; - if (self.alternativeButton) { - [self.alternativeButton setTitle:alternativeButtonTitle forState:UIControlStateNormal]; - } -} - -#pragma mark - Buttons - -- (void)actionButtonTappedWithSender:(UIButton *)sender -{ - if (self.actionHandler) { - self.actionHandler(self); - } -} - -- (void)alternativeButtonTappedWithSender:(UIButton *)sender -{ - if (self.alternativeHandler) { - self.alternativeHandler(self); - } -} - -#pragma mark - View Management - -- (NSArray *)makeFooterViewsWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - return nil; -} - -- (NSArray *)makeContentViewsWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - return @[]; -} - -- (NSArray *)makeArrangedSubviews -{ - NSMutableArray *arrangedSubviews = [[NSMutableArray alloc] init]; - - NSAssert([self.interfaceBuilderType isSubclassOfClass:[BLTNInterfaceBuilder class]], - @"InterfaceBuilderType must be a subclass of BulletinInterfaceBuilder, or BulletinInterfaceBuilder."); - - BLTNInterfaceBuilder *interfaceBuilder = [[self.interfaceBuilderType alloc] initWithAppearance:self.appearance - item:self]; - - NSArray *contentViews = [self makeContentViewsWithInterfaceBuilder:interfaceBuilder]; - [arrangedSubviews addObjectsFromArray:contentViews]; - - // Buttons stack - - if (self.actionButtonTitle == nil && self.alternativeButtonTitle == nil) { - return arrangedSubviews; - } - - UIStackView *buttonsStack = [interfaceBuilder makeGroupStackWithSpacing:10]; - - if (self.actionButtonTitle) { - BLTNHighlightButtonWrapper *buttonWrapper = [interfaceBuilder makeActionButtonWithTitle:self.actionButtonTitle]; - [buttonsStack addArrangedSubview:buttonWrapper]; - self.actionButton = buttonWrapper.button; - } - - if (self.alternativeButtonTitle) { - UIButton *button = [interfaceBuilder makeAlternativeButtonWithTitle:self.alternativeButtonTitle]; - [buttonsStack addArrangedSubview:button]; - self.alternativeButton = button; - } - - [arrangedSubviews addObject:buttonsStack]; - - // Footer - - NSArray *footerViews = [self makeFooterViewsWithInterfaceBuilder:interfaceBuilder]; - - if (footerViews) { - [arrangedSubviews addObjectsFromArray:footerViews]; - } - - return arrangedSubviews; -} - -#pragma mark - Events - -- (void)setUp -{ - [self.actionButton addTarget:self - action:@selector(actionButtonTappedWithSender:) - forControlEvents:UIControlEventTouchUpInside]; - - [self.alternativeButton addTarget:self - action:@selector(alternativeButtonTappedWithSender:) - forControlEvents:UIControlEventTouchUpInside]; -} - -- (void)tearDown -{ - [self.actionButton removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside]; - [self.alternativeButton removeTarget:self action:NULL forControlEvents:UIControlEventTouchUpInside]; - self.actionButton = nil; - self.alternativeButton = nil; -} - -- (void)willDisplay -{ -} - -- (void)onDisplay -{ - if (self.presentationHandler) { - self.presentationHandler(self); - } -} - -- (void)onDismiss -{ - if (self.dismissalHandler) { - self.dismissalHandler(self); - } -} - -@end diff --git a/Pods/BulletinBoard/Sources/Models/BLTNItem.h b/Pods/BulletinBoard/Sources/Models/BLTNItem.h deleted file mode 100644 index bde30ed..0000000 --- a/Pods/BulletinBoard/Sources/Models/BLTNItem.h +++ /dev/null @@ -1,128 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -@import UIKit; - -@class BLTNItemManager; - -/** - * An item that can be displayed inside a bulletin card. - */ - -@protocol BLTNItem - -#pragma mark - Configuration - -/** - * The current object managing the item. - * - * This property is set when the item is currently being displayed. It will be set to `nil` when - * the item is removed from view. - * - * When implementing `BLTNItem`, you should mark this property `weak` to avoid retain cycles. - */ - -@property (nonatomic, nullable, weak) BLTNItemManager *manager; - -/** - * Whether the page can be dismissed. - * - * If you set this value to `true`, the user will be able to dismiss the bulletin by tapping outside - * of the card or by swiping down. - * - * You should set it to `true` for the last item you want to display, or for items that start an optional flow - * (ex: a purchase). - */ - -@property (nonatomic, getter=isDismissable) BOOL dismissable; - -/** - * Whether the page can be dismissed with a close button. - * - * The default value is `true`. The user will be able to dismiss the bulletin by tapping on a button - * in the corner of the screen. - * - * You should set it to `false` if the interface of the bulletin already has buttons to dismiss the item, - * such as an action button. - */ - -@property (nonatomic) BOOL requiresCloseButton; - -/** - * Whether the card should start with an activity indicator. - * - * Set this value to `false` to display the elements right away. If you set it to `true`, - * you'll need to call `manager?.hideActivityIndicator()` to show the UI. - */ - -@property (nonatomic) BOOL shouldStartWithActivityIndicator; - -/** - * Whether the item should move with the keyboard. - * - * You must set it to `true` if the item displays a text field. You can set it to `false` if you - * don't want the bulletin to move when system alerts containing a text field (ex: iTunes login) - * are displayed. - */ - -@property (nonatomic) BOOL shouldRespondToKeyboardChanges; - -/** - * The item to display after this one. - * - * If you set this value, you'll be able to call `manager?.displayNextItem()` to push the next item to - * the stack. - */ - -@property (nonatomic, nullable, strong) id nextItem; - -// MARK: - Interface - -/** - * Creates the list of views to display inside the bulletin card. - * - * The views will be arranged vertically, in the order they are stored in the return array. - */ - -- (NSArray * _Nonnull)makeArrangedSubviews; - -/** - * Called by the manager when the item was added to the bulletin. - * - * Use this function to configure your managed views, and allocate any resources required - * for this item. - */ - -- (void)setUp; - -/** - * Called by the manager when the item was removed from the bulletin. - * - * Use this function to remove any button target or gesture recognizers from your managed views, and - * deallocate any resources created for this item that are no longer needed. - */ - -- (void)tearDown; - -/** -* Called by the manager when bulletin item is about to be pushed onto the view. -*/ - -- (void)willDisplay; - -/** - * Called by the manager when bulletin item is pushed onto the view. - */ - -- (void)onDisplay; - -/** - * Called by the manager when bulletin item is dismissed. This is called after the bulletin - * is moved out of view. - */ - -- (void)onDismiss; - -@end diff --git a/Pods/BulletinBoard/Sources/Models/BLTNPageItem.h b/Pods/BulletinBoard/Sources/Models/BLTNPageItem.h deleted file mode 100644 index 42f8ffe..0000000 --- a/Pods/BulletinBoard/Sources/Models/BLTNPageItem.h +++ /dev/null @@ -1,140 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -@import UIKit; - -#import "BLTNActionItem.h" - -@class BLTNTitleLabelContainer; - -NS_ASSUME_NONNULL_BEGIN - -/** - * A standard bulletin item with a title and optional additional informations. It can display a large - * action button and a smaller button for alternative options. - * - * - If you need to display custom elements with the standard buttons, subclass `BLTNPageItem` and - * implement the `makeArrangedSubviews` method to return the elements to display above the buttons. - * - * You can also override this class to customize button tap handling. Override the `actionButtonTapped(sender:)` - * and `alternativeButtonTapped(sender:)` methods to handle tap events. Make sure to call `super` in your - * implementations if you do. - * - * Use the `appearance` property to customize the appearance of the page. If you want to use a different interface - * builder type, change the `interfaceBuilderType` property. - */ - -@interface BLTNPageItem : BLTNActionItem - -/** - * Creates a bulletin page with the specified title. - * - parameter title: The title of the page. - */ - -- (instancetype)initWithTitle:(NSString *)title; - -#pragma mark - Page Contents - -/// The title of the page. -@property (nonatomic, nonnull, readonly) NSString *title; - -/** - * An image to display below the title. - * - * If you set this property to `nil`, no image will be displayed (this is the default). - * - * The image should have a size of 128x128 pixels (@1x). - */ - -@property (nonatomic, nullable) UIImage *image; - -/// An accessibility label which gets announced to VoiceOver users if the image gets focused. -@property (nonatomic, nullable) NSString *imageAccessibilityLabel; - -/** - * An description text to display below the image. - * - * If you set this property to `nil`, no label will be displayed (this is the default). - */ - -@property (nonatomic, nullable) NSString *descriptionText; - -/** - * An attributed description text to display below the image. - * - * If you set this property to `nil`, no label will be displayed (this is the default). The attributed - * text takes priority over the regular description label. If you set both values, only the - * `attributedDescriptionText` will be used. - */ - -@property (nonatomic, nullable) NSAttributedString *attributedDescriptionText; - -#pragma mark - View Management - -@property (nonatomic, nonnull, readonly) BLTNTitleLabelContainer *titleLabel; -@property (nonatomic, nullable, readonly) UILabel *descriptionLabel; -@property (nonatomic, nullable, readonly) UIImageView *imageView; - -#pragma mark - Customization - -/** - * The views to display above the title. - * - * You can override this method to insert custom views before the title. The default implementation returns `nil` and - * does not append header elements. - * - * This method is called inside `makeArrangedSubviews` before the title is created. - * - * - parameter interfaceBuilder: The interface builder used to create the title. - * - returns: The header views for the item, or `nil` if no header views should be added. - */ - -- (NSArray * _Nullable)makeHeaderViewsWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder; - -/** - * The views to display below the title. - * - * You can override this method to insert custom views after the title. The default implementation returns `nil` and - * does not append elements after the title. - * - * This method is called inside `makeArrangedSubviews` after the title is created. - * - * - parameter interfaceBuilder: The interface builder used to create the title. - * - returns: The views to display after the title, or `nil` if no views should be added. - */ - -- (NSArray * _Nullable)makeViewsUnderTitleWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder; - -/** - * The views to display below the image. - * - * You can override this method to insert custom views after the image. The default implementation returns `nil` and - * does not append elements after the image. - * - * This method is called inside `makeArrangedSubviews` after the image is created. - * - * - parameter interfaceBuilder: The interface builder used to create the image. - * - returns: The views to display after the image, or `nil` if no views should be added. - */ - -- (NSArray * _Nullable)makeViewsUnderImageWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder; - -/** - * The views to display below the description. - * - * You can override this method to insert custom views after the description. The default implementation - * returns `nil` and does not append elements after the description. - * - * This method is called inside `makeArrangedSubviews` after the description is created. - * - * - parameter interfaceBuilder: The interface builder used to create the description. - * - returns: The views to display after the description, or `nil` if no views should be added. - */ - -- (NSArray * _Nullable)makeViewsUnderDescriptionWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Pods/BulletinBoard/Sources/Models/BLTNPageItem.m b/Pods/BulletinBoard/Sources/Models/BLTNPageItem.m deleted file mode 100644 index 0d5d6b3..0000000 --- a/Pods/BulletinBoard/Sources/Models/BLTNPageItem.m +++ /dev/null @@ -1,162 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -#import "BLTNPageItem.h" -#import "BLTNBoardSwiftSupport.h" - -@interface BLTNPageItem () - -@property (nonatomic, nonnull, readwrite) NSString *title; -@property (nonatomic, nullable, readwrite) BLTNTitleLabelContainer *titleLabel; -@property (nonatomic, nullable, readwrite) UILabel *descriptionLabel; -@property (nonatomic, nullable, readwrite) UIImageView *imageView; - -@end - -@implementation BLTNPageItem - -- (instancetype)initWithTitle:(NSString *)title -{ - self = [super init]; - if (self) { - self.title = title; - self.image = nil; - self.imageAccessibilityLabel = nil; - self.descriptionText = nil; - self.titleLabel = nil; - self.descriptionLabel = nil; - self.imageView = nil; - } - return self; -} - -#pragma mark - View Updates - -- (void)setDescriptionText:(NSString *)descriptionText -{ - _descriptionText = [descriptionText copy]; - if (self.attributedDescriptionText) { - return; - } - if (self.descriptionLabel) { - self.descriptionLabel.text = descriptionText; - } -} - -- (void)setImage:(UIImage *)image -{ - _image = image; - if (self.imageView) { - self.imageView.image = image; - } -} - -- (void)setImageAccessibilityLabel:(NSString *)imageAccessibilityLabel -{ - _imageAccessibilityLabel = [imageAccessibilityLabel copy]; - if (self.imageView) { - self.imageView.accessibilityLabel = imageAccessibilityLabel; - } -} - -- (void)setAttributedDescriptionText:(NSAttributedString *)attributedDescriptionText -{ - _attributedDescriptionText = [attributedDescriptionText copy]; - self.descriptionText = nil; - if (self.descriptionLabel) { - self.descriptionLabel.attributedText = attributedDescriptionText; - } -} - -#pragma mark - View Management - -- (NSArray *)makeContentViewsWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - NSMutableArray *contentViews = [[NSMutableArray alloc] init]; - - void (^insertComplementaryViews)(SEL) = ^(SEL generator) { -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Warc-performSelector-leaks" - NSObject *result = [self performSelector:generator withObject:interfaceBuilder]; -#pragma clang diagnostic pop - - if ([result isKindOfClass:[NSArray class]]) { - [contentViews addObjectsFromArray:(NSArray *)result]; - } - }; - - insertComplementaryViews(@selector(makeHeaderViewsWithInterfaceBuilder:)); - - // Title label - - self.titleLabel = [interfaceBuilder makeTitleLabel]; - self.titleLabel.label.text = self.title; - - [contentViews addObject:self.titleLabel]; - insertComplementaryViews(@selector(makeViewsUnderTitleWithInterfaceBuilder:)); - - // Image View - - if (self.image) { - - UIImageView *imageView = [[UIImageView alloc] init]; - imageView.image = self.image; - imageView.contentMode = UIViewContentModeScaleAspectFit; - imageView.tintColor = self.appearance.imageViewTintColor; - - if (self.imageAccessibilityLabel) { - imageView.isAccessibilityElement = YES; - imageView.accessibilityLabel = self.imageAccessibilityLabel; - } - - self.imageView = imageView; - [contentViews addObject:imageView]; - - insertComplementaryViews(@selector(makeViewsUnderImageWithInterfaceBuilder:)); - - } - - // Description Label - - if (self.attributedDescriptionText) { - self.descriptionLabel = [interfaceBuilder makeDescriptionLabel]; - self.descriptionLabel.attributedText = self.attributedDescriptionText; - [contentViews addObject:self.descriptionLabel]; - insertComplementaryViews(@selector(makeViewsUnderDescriptionWithInterfaceBuilder:)); - - } else if (self.descriptionText) { - self.descriptionLabel = [interfaceBuilder makeDescriptionLabel]; - self.descriptionLabel.text = self.descriptionText; - [contentViews addObject:self.descriptionLabel]; - insertComplementaryViews(@selector(makeViewsUnderDescriptionWithInterfaceBuilder:)); - } - - return contentViews; - -} - -#pragma mark - Customization - -- (NSArray *)makeHeaderViewsWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - return nil; -} - -- (NSArray *)makeViewsUnderTitleWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - return nil; -} - -- (NSArray *)makeViewsUnderImageWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - return nil; -} - -- (NSArray *)makeViewsUnderDescriptionWithInterfaceBuilder:(BLTNInterfaceBuilder *)interfaceBuilder -{ - return nil; -} - -@end diff --git a/Pods/BulletinBoard/Sources/Support/Animations/AnimationChain.swift b/Pods/BulletinBoard/Sources/Support/Animations/AnimationChain.swift deleted file mode 100644 index 627feab..0000000 --- a/Pods/BulletinBoard/Sources/Support/Animations/AnimationChain.swift +++ /dev/null @@ -1,163 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import Foundation -import UIKit - -// MARK: AnimationChain - -/** - * A sequence of animations where animations are executed the one after the other. - * - * Animations are represented by `AnimationPhase` objects, that contain the code of the animation, - * its duration relative to the chain duration, their curve and their individual completion handlers. - */ - -public class AnimationChain { - - /// The total duration of the animation chain. - public let duration: TimeInterval - - /// The initial delay before the animation chain starts. - public var initialDelay: TimeInterval = 0 - - /// The code to execute after animation chain is executed. - public var completionHandler: () -> Void - - /// Whether the chain is being run. - public private(set) var isRunning: Bool = false - - // MARK: Initialization - - private var animations: [AnimationPhase] = [] - private var didFinishFirstAnimation: Bool = false - - /** - * Creates an animation chain with the specified duration. - */ - - public init(duration: TimeInterval) { - self.duration = duration - self.completionHandler = {} - } - - // MARK: - Interacting with the Chain - - /** - * Add an animation at the end of the chain. - * - * You cannot add animations if the chain is running. - * - * - parameter animation: The animation phase to add. - */ - - public func add(_ animation: AnimationPhase) { - precondition(!isRunning, "Cannot add an animation to the chain because it is already performing.") - animations.append(animation) - } - - /** - * Starts the animation chain. - */ - - public func start() { - - precondition(!isRunning, "Animation chain already running.") - - isRunning = true - performNextAnimation() - - } - - private func performNextAnimation() { - - guard animations.count > 0 else { - completeGroup() - return - } - - let animation = animations.removeFirst() - - let duration = animation.relativeDuration * self.duration - let options = UIView.AnimationOptions(rawValue: UInt(animation.curve.rawValue << 16)) - let delay: TimeInterval = didFinishFirstAnimation ? 0 : initialDelay - - UIView.animate(withDuration: duration, delay: delay, options: options, animations: animation.block) { _ in - - self.didFinishFirstAnimation = true - - animation.completionHandler() - self.performNextAnimation() - - } - - } - - private func completeGroup() { - isRunning = false - completionHandler() - } - -} - -// MARK: - AnimationPhase - -/** - * A member of an `AnimationChain`, representing a single animation. - * - * Set the `block` property to a block containing the animations. Set the `completionHandler` with - * a block to execute at the end of the animation. The default values do nothing. - */ - -public class AnimationPhase { - - /** - * The duration of the animation, relative to the total duration of the chain. - * - * Must be between 0 and 1. - */ - - public let relativeDuration: TimeInterval - - /** - * The animation curve. - */ - - public let curve: UIView.AnimationCurve - - /** - * The animation code. - */ - - public var block: () -> Void - - /** - * A block to execute at the end of the animation. - */ - - public var completionHandler: () -> Void - - // MARK: Initialization - - /** - * Creates an animtion phase object. - * - * - parameter relativeDuration: The duration of the animation, as a fraction of the total chain - * duration. Must be between 0 and 1. - * - parameter curve: The animation curve - */ - - public init(relativeDuration: TimeInterval, curve: UIView.AnimationCurve) { - - self.relativeDuration = relativeDuration - self.curve = curve - - self.block = {} - self.completionHandler = {} - - } - -} - diff --git a/Pods/BulletinBoard/Sources/Support/Animations/BulletinDismissAnimationController.swift b/Pods/BulletinBoard/Sources/Support/Animations/BulletinDismissAnimationController.swift deleted file mode 100644 index 24a6193..0000000 --- a/Pods/BulletinBoard/Sources/Support/Animations/BulletinDismissAnimationController.swift +++ /dev/null @@ -1,90 +0,0 @@ -import UIKit - -/** - * The animation controller for bulletin dismissal. - * - * It moves the card out of the screen, fades out the background view and removes it from the hierarchy - * on completion. - */ - -class BulletinDismissAnimationController: NSObject, UIViewControllerAnimatedTransitioning { - - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.3 - } - - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - - guard let fromVC = transitionContext.viewController(forKey: .from) as? BulletinViewController else { - transitionContext.completeTransition(false) - return - } - - let rootView = fromVC.view! - let contentView = fromVC.contentView - let backgroundView = fromVC.backgroundView! - let activityIndicatorView = fromVC.activityIndicator - let snapshotActivityIndicator = ActivityIndicator() - snapshotActivityIndicator.startAnimating() - - // Take Snapshot - - guard let snapshot = contentView.snapshotView(afterScreenUpdates: true) else { - transitionContext.completeTransition(false) - return - } - - snapshotActivityIndicator.translatesAutoresizingMaskIntoConstraints = false - - snapshot.addSubview(snapshotActivityIndicator) - snapshotActivityIndicator.topAnchor.constraint(equalTo: snapshot.topAnchor).isActive = true - snapshotActivityIndicator.leftAnchor.constraint(equalTo: snapshot.leftAnchor).isActive = true - snapshotActivityIndicator.rightAnchor.constraint(equalTo: snapshot.rightAnchor).isActive = true - snapshotActivityIndicator.bottomAnchor.constraint(equalTo: snapshot.bottomAnchor).isActive = true - - if #available(iOS 13.0, *) { - snapshotActivityIndicator.style = UIActivityIndicatorView.Style.large - } else { - snapshotActivityIndicator.style = .whiteLarge - } - snapshotActivityIndicator.color = .black - snapshotActivityIndicator.isUserInteractionEnabled = false - - snapshotActivityIndicator.alpha = activityIndicatorView.alpha - - rootView.insertSubview(snapshot, aboveSubview: contentView) - snapshot.frame = contentView.frame - contentView.isHidden = true - activityIndicatorView.isHidden = true - - fromVC.prepareForDismissal(displaying: snapshot) - - // Animate dismissal - - let duration = transitionDuration(using: transitionContext) - let options = UIView.AnimationOptions(rawValue: 6 << 16) - - let animations = { - snapshot.frame.origin.y = rootView.frame.maxY + 12 - backgroundView.hide() - } - - UIView.animate(withDuration: duration, delay: 0, options: options, animations: animations) { finished in - - let isCancelled = transitionContext.transitionWasCancelled - - if !isCancelled { - fromVC.view.removeFromSuperview() - } else { - contentView.isHidden = false - activityIndicatorView.isHidden = false - snapshot.removeFromSuperview() - } - - transitionContext.completeTransition(!isCancelled) - - } - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Animations/BulletinPresentationAnimationController.swift b/Pods/BulletinBoard/Sources/Support/Animations/BulletinPresentationAnimationController.swift deleted file mode 100644 index 2eaf3ee..0000000 --- a/Pods/BulletinBoard/Sources/Support/Animations/BulletinPresentationAnimationController.swift +++ /dev/null @@ -1,79 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * The animation controller for bulletin presentation. - * - * It moves the card on screen, creates and fades in the background view. - */ - -class BulletinPresentationAnimationController: NSObject, UIViewControllerAnimatedTransitioning { - - let style: BLTNBackgroundViewStyle - - init(style: BLTNBackgroundViewStyle) { - self.style = style - } - - // MARK: - Transition - - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.3 - } - - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - - guard let toVC = transitionContext.viewController(forKey: .to) as? BulletinViewController else { - return - } - - // Fix the frame (Needed for iPad app running in split view) - if let fromFrame = transitionContext.viewController(forKey: .from)?.view.frame { - toVC.view.frame = fromFrame - } - - let rootView = toVC.view! - let contentView = toVC.contentView - let backgroundView = toVC.backgroundView! - let containerView = transitionContext.containerView - - // Add root view - - containerView.addSubview(rootView) - - // Prepare background view - - rootView.insertSubview(backgroundView, at: 0) - backgroundView.leadingAnchor.constraint(equalTo: rootView.leadingAnchor).isActive = true - backgroundView.trailingAnchor.constraint(equalTo: rootView.trailingAnchor).isActive = true - backgroundView.topAnchor.constraint(equalTo: rootView.topAnchor).isActive = true - backgroundView.bottomAnchor.constraint(equalTo: rootView.bottomAnchor).isActive = true - - rootView.setNeedsLayout() - contentView.setNeedsLayout() - - rootView.layoutIfNeeded() - contentView.layoutIfNeeded() - backgroundView.layoutIfNeeded() - - // Animate presentation - - let duration = transitionDuration(using: transitionContext) - let options = UIView.AnimationOptions(rawValue: 7 << 16) - - let animations = { - toVC.moveIntoPlace() - backgroundView.show() - } - - UIView.animate(withDuration: duration, delay: 0, options: options, animations: animations) { _ in - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - } - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Animations/BulletinSwipeInteractionController.swift b/Pods/BulletinBoard/Sources/Support/Animations/BulletinSwipeInteractionController.swift deleted file mode 100644 index 32d6ab1..0000000 --- a/Pods/BulletinBoard/Sources/Support/Animations/BulletinSwipeInteractionController.swift +++ /dev/null @@ -1,261 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * An interaction controller that handles swipe-to-dismiss for bulletins. - */ - -class BulletinSwipeInteractionController: UIPercentDrivenInteractiveTransition, UIGestureRecognizerDelegate { - - /// Whether a panning interaction is in progress. - var isInteractionInProgress = false - - var panGestureRecognizer: UIPanGestureRecognizer? - - // MARK: - State - - private var isFinished = false - private var currentPercentage: CGFloat = -1 - private weak var viewController: BulletinViewController! - - private var snapshotView: UIView? { - return viewController.activeSnapshotView - } - - private var contentView: UIView { - return viewController.contentView - } - - private var activityIndicatorView: UIView { - return viewController.activityIndicator - } - - // MARK: - Preparation - - /** - * Sets up the interaction recognizer for the given view controller and content view. - */ - - func wire(to viewController: BulletinViewController) { - self.viewController = viewController - prepareGestureRecognizer() - } - - private func prepareGestureRecognizer() { - - let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture)) - panGesture.maximumNumberOfTouches = 1 - panGesture.cancelsTouchesInView = false - panGesture.delegate = self - - self.panGestureRecognizer = panGesture - contentView.addGestureRecognizer(panGesture) - - } - - - // MARK: - Gesture Recognizer - - func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { - return !(touch.view is UIControl) - } - - @objc func handlePanGesture(gestureRecognizer: UIPanGestureRecognizer) { - - /// Constants - - let screenHeight = viewController.view.bounds.height - let distanceFactor: CGFloat = screenHeight >= 500 ? 3/4 : 2/3 - - let dismissThreshold: CGFloat = 256 * distanceFactor - let elasticThreshold: CGFloat = 128 * distanceFactor - let trackScreenPercentage = dismissThreshold / contentView.bounds.height - - switch gestureRecognizer.state { - case .began: - - isFinished = false - - gestureRecognizer.setTranslation(.zero, in: contentView) - - let isCompactWidth = viewController.traitCollection.horizontalSizeClass == .compact - - guard viewController.isDismissable && isCompactWidth else { - isInteractionInProgress = false - return - } - - isInteractionInProgress = true - - viewController.dismiss(animated: true) { - - guard self.isFinished else { - return - } - - self.viewController.manager?.completeDismissal() - - } - - case .changed: - - guard !isFinished else { - return - } - - let translation = gestureRecognizer.translation(in: contentView) - let verticalTranslation = translation.y - isFinished = false - - guard (verticalTranslation > 0) && isInteractionInProgress else { - update(0) - updateCardViews(forTranslation: translation) - return - } - - snapshotView?.transform = .identity - - let adaptativeTranslation = self.adaptativeTranslation(for: verticalTranslation, elasticThreshold: elasticThreshold) - let newPercentage = (adaptativeTranslation / dismissThreshold) * trackScreenPercentage - - guard currentPercentage != newPercentage else { - return - } - - currentPercentage = newPercentage - update(currentPercentage) - - case .cancelled, .failed: - - isInteractionInProgress = false - - if !isFinished { - resetCardViews() - } - - panGestureRecognizer?.isEnabled = true - - case .ended: - - guard isInteractionInProgress else { - resetCardViews() - isFinished = false - return - } - - isInteractionInProgress = false - - let translation = gestureRecognizer.translation(in: contentView).y - - if translation >= dismissThreshold { - isFinished = true - finish() - } else { - resetCardViews() - cancel() - isFinished = false - } - - default: - break - } - - } - - // MARK: - Math - - // Source: https://github.com/HarshilShah/DeckTransition - let elasticTranslationCurve = { (translation: CGFloat, translationFactor: CGFloat) -> CGFloat in - return 30 * atan(translation/120) + translation/10 - } - - private func adaptativeTranslation(for translation: CGFloat, elasticThreshold: CGFloat) -> CGFloat { - - let translationFactor: CGFloat = 2/3 - - if translation >= elasticThreshold { - let frictionLength = translation - elasticThreshold - let frictionTranslation = elasticTranslationCurve(frictionLength, translationFactor) - return frictionTranslation + (elasticThreshold * translationFactor) - } else { - return translation * translationFactor - } - - } - - private func transform(forTranslation translation: CGPoint) -> CGAffineTransform { - - let translationFactor: CGFloat = 1/3 - var adaptedTranslation = translation - - // Vertical - - if translation.y < 0 || !(isInteractionInProgress) { - adaptedTranslation.y = elasticTranslationCurve(translation.y, translationFactor) - } - - let yTransform = adaptedTranslation.y * translationFactor - - if viewController.traitCollection.horizontalSizeClass == .compact { - return CGAffineTransform(translationX: 0, y: yTransform) - } - - // Horizontal - - adaptedTranslation.x = elasticTranslationCurve(translation.x, translationFactor) - let xTransform = adaptedTranslation.x * translationFactor - - return CGAffineTransform(translationX: xTransform, y: yTransform) - - } - - // MARK: - Position Management - - private func updateCardViews(forTranslation translation: CGPoint) { - - let transform = self.transform(forTranslation: translation) - - snapshotView?.transform = transform - contentView.transform = transform - activityIndicatorView.transform = transform - - } - - private func resetCardViews() { - - let options = UIView.AnimationOptions(rawValue: 6 << 7) - - let animations = { - self.snapshotView?.transform = .identity - self.contentView.transform = .identity - self.activityIndicatorView.transform = .identity - } - - viewController.backgroundView.show() - - UIView.animate(withDuration: 0.15, delay: 0, options: options, animations: animations) { _ in - self.update(0) - self.cancel() - } - - } - - // MARK: - Cancellation - - /** - * Resets the view if needed. - */ - - func cancelIfNeeded() { - - if panGestureRecognizer?.state == .changed { - panGestureRecognizer?.isEnabled = false - } - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/BLTNBoardSwiftSupport.h b/Pods/BulletinBoard/Sources/Support/BLTNBoardSwiftSupport.h deleted file mode 100644 index adc979c..0000000 --- a/Pods/BulletinBoard/Sources/Support/BLTNBoardSwiftSupport.h +++ /dev/null @@ -1,13 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -// Workaround needed to allow static library usage through Cocoapods. -// https://github.com/CocoaPods/CocoaPods/issues/7594 -// https://github.com/mxcl/PromiseKit/issues/825 -#if __has_include("BLTNBoard-Swift.h") - #import "BLTNBoard-Swift.h" -#else - #import -#endif diff --git a/Pods/BulletinBoard/Sources/Support/BulletinViewController.swift b/Pods/BulletinBoard/Sources/Support/BulletinViewController.swift deleted file mode 100644 index 054a953..0000000 --- a/Pods/BulletinBoard/Sources/Support/BulletinViewController.swift +++ /dev/null @@ -1,632 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A view controller that displays a card at the bottom of the screen. - */ - -final class BulletinViewController: UIViewController, UIGestureRecognizerDelegate { - - /// The object managing the view controller. - weak var manager: BLTNItemManager? - - // MARK: - UI Elements - - /// The subview that contains the contents of the card. - let contentView = RoundedView() - - /// The button that allows the users to close the bulletin. - let closeButton = BulletinCloseButton() - - /** - * The stack view displaying the content of the card. - * - * - warning: You should not customize the distribution, axis and alignment of the stack, as this - * may break the layout of the card. - */ - - let contentStackView = UIStackView() - - /// The view covering the content. Generated in `loadBackgroundView`. - var backgroundView: BulletinBackgroundView! - - /// The activity indicator. - let activityIndicator = ActivityIndicator() - - // MARK: - Dismissal Support Properties - - /// Indicates whether the bulletin can be dismissed by a tap outside the card. - var isDismissable: Bool = false - - /// The snapshot view of the content used during dismissal. - var activeSnapshotView: UIView? - - /// The active swipe interaction controller. - var swipeInteractionController: BulletinSwipeInteractionController! - - // MARK: - Private Interface Elements - - // Compact constraints - fileprivate var leadingConstraint: NSLayoutConstraint! - fileprivate var trailingConstraint: NSLayoutConstraint! - fileprivate var centerXConstraint: NSLayoutConstraint! - fileprivate var maxWidthConstraint: NSLayoutConstraint! - - // Regular constraints - fileprivate var widthConstraint: NSLayoutConstraint! - fileprivate var centerYConstraint: NSLayoutConstraint! - - // Stack view constraints - fileprivate var stackLeadingConstraint: NSLayoutConstraint! - fileprivate var stackTrailingConstraint: NSLayoutConstraint! - fileprivate var stackBottomConstraint: NSLayoutConstraint! - - // Position constraints - fileprivate var minYConstraint: NSLayoutConstraint! - fileprivate var contentTopConstraint: NSLayoutConstraint! - fileprivate var contentBottomConstraint: NSLayoutConstraint! - - // MARK: - Deinit - - deinit { - cleanUpKeyboardLogic() - } - -} - -// MARK: - Lifecycle - -extension BulletinViewController { - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - setUpLayout(with: traitCollection) - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - /// Animate status bar appearance when hiding - UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseInOut, animations: { - self.setNeedsStatusBarAppearanceUpdate() - }) - - } - - override func loadView() { - - super.loadView() - view.backgroundColor = .clear - - let recognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap(recognizer:))) - recognizer.delegate = self - recognizer.cancelsTouchesInView = false - recognizer.delaysTouchesEnded = false - - view.addGestureRecognizer(recognizer) - - contentView.accessibilityViewIsModal = true - contentView.translatesAutoresizingMaskIntoConstraints = false - contentStackView.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(contentView) - - // Content View - - centerXConstraint = contentView.centerXAnchor.constraint(equalTo: view.safeCenterXAnchor) - - centerYConstraint = contentView.centerYAnchor.constraint(equalTo: view.safeCenterYAnchor) - centerYConstraint.constant = 2500 - - widthConstraint = contentView.widthAnchor.constraint(equalToConstant: 444) - widthConstraint.priority = .required - - // Close button - - contentView.addSubview(closeButton) - closeButton.translatesAutoresizingMaskIntoConstraints = false - closeButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12).isActive = true - closeButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -12).isActive = true - closeButton.heightAnchor.constraint(equalToConstant: 44).isActive = true - closeButton.widthAnchor.constraint(equalToConstant: 44).isActive = true - closeButton.isUserInteractionEnabled = true - - closeButton.addTarget(self, action: #selector(closeButtonTapped), for: .touchUpInside) - - // Content Stack View - - contentView.addSubview(contentStackView) - - stackLeadingConstraint = contentStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor) - stackLeadingConstraint.isActive = true - - stackTrailingConstraint = contentStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor) - stackTrailingConstraint.isActive = true - - minYConstraint = contentView.topAnchor.constraint(greaterThanOrEqualTo: view.safeTopAnchor) - minYConstraint.isActive = true - minYConstraint.priority = UILayoutPriority.required - - contentStackView.axis = .vertical - contentStackView.alignment = .fill - contentStackView.distribution = .fill - - // Activity Indicator - - activityIndicator.translatesAutoresizingMaskIntoConstraints = false - - view.addSubview(activityIndicator) - activityIndicator.leftAnchor.constraint(equalTo: contentView.leftAnchor).isActive = true - activityIndicator.rightAnchor.constraint(equalTo: contentView.rightAnchor).isActive = true - activityIndicator.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true - activityIndicator.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true - - if #available(iOS 13.0, *) { - activityIndicator.style = UIActivityIndicatorView.Style.large - } else { - activityIndicator.style = .whiteLarge - } - activityIndicator.color = .black - activityIndicator.isUserInteractionEnabled = false - - activityIndicator.alpha = 0 - - // Vertical Position - - stackBottomConstraint = contentStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) - contentTopConstraint = contentView.topAnchor.constraint(equalTo: contentStackView.topAnchor) - - stackBottomConstraint.isActive = true - contentTopConstraint.isActive = true - - // Configuration - - configureContentView() - setUpKeyboardLogic() - - contentView.bringSubviewToFront(closeButton) - - } - - @available(iOS 11.0, *) - override func viewSafeAreaInsetsDidChange() { - super.viewSafeAreaInsetsDidChange() - updateCornerRadius() - setUpLayout(with: traitCollection) - } - - /// Configure content view with customizations. - - fileprivate func configureContentView() { - - guard let manager = self.manager else { - fatalError("Trying to set up the content view, but the BulletinViewController is not managed.") - } - - contentView.backgroundColor = manager.backgroundColor - contentView.cornerRadius = CGFloat((manager.cardCornerRadius ?? 12).doubleValue) - closeButton.updateColors(isDarkBackground: manager.backgroundColor.needsDarkText == false) - - let cardPadding = manager.edgeSpacing.rawValue - - // Set left and right padding - leadingConstraint = contentView.leadingAnchor.constraint(equalTo: view.safeLeadingAnchor, - constant: cardPadding) - - trailingConstraint = contentView.trailingAnchor.constraint(equalTo: view.safeTrailingAnchor, - constant: -cardPadding) - - // Set maximum width with padding - - maxWidthConstraint = contentView.widthAnchor.constraint(lessThanOrEqualTo: view.safeWidthAnchor, - constant: -(cardPadding * 2)) - - maxWidthConstraint.priority = .required - maxWidthConstraint.isActive = true - - if manager.hidesHomeIndicator { - contentBottomConstraint = contentView.bottomAnchor.constraint(equalTo: view.bottomAnchor) - } else { - contentBottomConstraint = contentView.bottomAnchor.constraint(equalTo: view.safeBottomAnchor) - } - - contentBottomConstraint.constant = 1000 - contentBottomConstraint.isActive = true - - } - - // MARK: - Gesture Recognizer - - internal func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { - if touch.view?.isDescendant(of: contentView) == true { - return false - } - - return true - } - -} - -// MARK: - Layout - -extension BulletinViewController { - - override func willTransition(to newCollection: UITraitCollection, with coordinator: UIViewControllerTransitionCoordinator) { - - coordinator.animate(alongsideTransition: { _ in - self.setUpLayout(with: newCollection) - }) - - } - - fileprivate func setUpLayout(with traitCollection: UITraitCollection) { - - switch traitCollection.horizontalSizeClass { - case .regular: - leadingConstraint.isActive = false - trailingConstraint.isActive = false - contentBottomConstraint.isActive = false - centerXConstraint.isActive = true - centerYConstraint.isActive = true - widthConstraint.isActive = true - - case .compact: - leadingConstraint.isActive = true - trailingConstraint.isActive = true - contentBottomConstraint.isActive = true - centerXConstraint.isActive = false - centerYConstraint.isActive = false - widthConstraint.isActive = false - - default: - break - } - - switch (traitCollection.verticalSizeClass, traitCollection.horizontalSizeClass) { - case (.regular, .regular): - stackLeadingConstraint.constant = 32 - stackTrailingConstraint.constant = -32 - stackBottomConstraint.constant = -32 - contentTopConstraint.constant = -32 - contentStackView.spacing = 32 - - default: - stackLeadingConstraint.constant = 24 - stackTrailingConstraint.constant = -24 - stackBottomConstraint.constant = -24 - contentTopConstraint.constant = -24 - contentStackView.spacing = 24 - - } - - } - - // MARK: - Transition Adaptivity - - var defaultBottomMargin: CGFloat { - return manager?.edgeSpacing.rawValue ?? 12 - } - - func bottomMargin() -> CGFloat { - - if #available(iOS 11, *) { - if view.safeAreaInsets.bottom > 0 { - return 0 - } - } - - var bottomMargin: CGFloat = manager?.edgeSpacing.rawValue ?? 12 - - if manager?.hidesHomeIndicator == true { - bottomMargin = manager?.edgeSpacing.rawValue == 0 ? 0 : 6 - } - - return bottomMargin - - } - - /// Moves the content view to its final location on the screen. Use during presentation. - func moveIntoPlace() { - - contentBottomConstraint.constant = -bottomMargin() - centerYConstraint.constant = 0 - - view.layoutIfNeeded() - contentView.layoutIfNeeded() - backgroundView.layoutIfNeeded() - - } - - // MARK: - Presentation/Dismissal - - /// Dismisses the presnted BulletinViewController if `isDissmisable` is set to `true`. - @discardableResult - func dismissIfPossible() -> Bool { - - guard isDismissable else { - return false - } - - manager?.dismissBulletin(animated: true) - return true - - } - - // MARK: - Touch Events - - @objc fileprivate func handleTap(recognizer: UITapGestureRecognizer) { - dismissIfPossible() - } - - // MARK: - Accessibility - - override func accessibilityPerformEscape() -> Bool { - return dismissIfPossible() - } - -} - -// MARK: - System Elements - -extension BulletinViewController { - - override var preferredStatusBarStyle: UIStatusBarStyle { - if let manager = manager { - switch manager.statusBarAppearance { - case .lightContent: - return .lightContent - case .automatic: - return manager.backgroundViewStyle.rawValue.isDark ? .lightContent : .default - default: - break - } - } - - return .default - } - - override var preferredStatusBarUpdateAnimation: UIStatusBarAnimation { - return manager?.statusBarAnimation ?? .fade - } - - override var prefersStatusBarHidden: Bool { - return manager?.statusBarAppearance == .hidden - } - - @available(iOS 11.0, *) - override var prefersHomeIndicatorAutoHidden: Bool { - return manager?.hidesHomeIndicator ?? false - } - -} - -// MARK: - Safe Area - -extension BulletinViewController { - - @available(iOS 11.0, *) - fileprivate var screenHasRoundedCorners: Bool { - return view.safeAreaInsets.bottom > 0 - } - - fileprivate func updateCornerRadius() { - - if manager?.edgeSpacing.rawValue == 0 { - contentView.cornerRadius = 0 - return - } - - var defaultRadius: NSNumber = 12 - - if #available(iOS 11.0, *) { - defaultRadius = screenHasRoundedCorners ? 36 : 12 - } - - contentView.cornerRadius = CGFloat((manager?.cardCornerRadius ?? defaultRadius).doubleValue) - - } - -} - -// MARK: - Background - -extension BulletinViewController { - - /// Creates a new background view for the bulletin. - func loadBackgroundView() { - backgroundView = BulletinBackgroundView(style: manager?.backgroundViewStyle ?? .dimmed) - } - -} - -// MARK: - Activity Indicator - -extension BulletinViewController { - - /// Displays the activity indicator. - func displayActivityIndicator(color: UIColor) { - - activityIndicator.color = color - activityIndicator.startAnimating() - - let animations = { - self.activityIndicator.alpha = 1 - self.contentStackView.alpha = 0 - self.closeButton.alpha = 0 - } - - UIView.animate(withDuration: 0.25, animations: animations) { _ in - UIAccessibility.post(notification: .screenChanged, argument: self.activityIndicator) - } - - } - - /// Hides the activity indicator. - func hideActivityIndicator() { - - activityIndicator.stopAnimating() - activityIndicator.alpha = 0 - - let needsCloseButton = manager?.needsCloseButton == true - - let animations = { - self.activityIndicator.alpha = 0 - self.updateCloseButton(isRequired: needsCloseButton) - } - - UIView.animate(withDuration: 0.25, animations: animations) - - } - -} - -// MARK: - Close Button - -extension BulletinViewController { - - func updateCloseButton(isRequired: Bool) { - isRequired ? showCloseButton() : hideCloseButton() - } - - func showCloseButton() { - closeButton.alpha = 1 - } - - func hideCloseButton() { - closeButton.alpha = 0 - } - - @objc func closeButtonTapped() { - manager?.dismissBulletin(animated: true) - } - -} - -// MARK: - Transitions - -extension BulletinViewController: UIViewControllerTransitioningDelegate { - - func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return BulletinPresentationAnimationController(style: manager?.backgroundViewStyle ?? .dimmed) - } - - func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - return BulletinDismissAnimationController() - } - - func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning) - -> UIViewControllerInteractiveTransitioning? { - - guard manager?.allowsSwipeInteraction == true else { - return nil - } - - let isEligible = swipeInteractionController.isInteractionInProgress - return isEligible ? swipeInteractionController : nil - - } - - /// Creates a new view swipe interaction controller and wires it to the content view. - func refreshSwipeInteractionController() { - - guard manager?.allowsSwipeInteraction == true else { - return - } - - swipeInteractionController = BulletinSwipeInteractionController() - swipeInteractionController.wire(to: self) - - } - - /// Prepares the view controller for dismissal. - func prepareForDismissal(displaying snapshot: UIView) { - activeSnapshotView = snapshot - } - -} - -// MARK: - Keyboard - -extension BulletinViewController { - func setUpKeyboardLogic() { - NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardShow), name: UIResponder.keyboardWillShowNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardHide), name: UIResponder.keyboardWillHideNotification, object: nil) - } - - func cleanUpKeyboardLogic() { - NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillShowNotification, object: nil) - NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil) - } - - @objc func onKeyboardShow(_ notification: Notification) { - - guard manager?.currentItem.shouldRespondToKeyboardChanges == true else { - return - } - - guard let userInfo = notification.userInfo, - let keyboardFrameFinal = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect, - let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double, - let curveInt = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int - else { - return - } - - let animationCurve = UIView.AnimationCurve(rawValue: curveInt) ?? .linear - let animationOptions = UIView.AnimationOptions(curve: animationCurve) - - UIView.animate(withDuration: duration, delay: 0, options: animationOptions, animations: { - var bottomSpacing = -(keyboardFrameFinal.size.height + self.defaultBottomMargin) - - if #available(iOS 11.0, *) { - - if self.manager?.hidesHomeIndicator == false { - bottomSpacing += self.view.safeAreaInsets.bottom - } - - } - - self.minYConstraint.isActive = false - self.contentBottomConstraint.constant = bottomSpacing - self.centerYConstraint.constant = -(keyboardFrameFinal.size.height + 12) / 2 - self.contentView.superview?.layoutIfNeeded() - - }, completion: nil) - - } - - @objc func onKeyboardHide(_ notification: Notification) { - - guard manager?.currentItem.shouldRespondToKeyboardChanges == true else { - return - } - - guard let userInfo = notification.userInfo, - let duration = userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? Double, - let curveInt = userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? Int - else { - return - } - - let animationCurve = UIView.AnimationCurve(rawValue: curveInt) ?? .linear - let animationOptions = UIView.AnimationOptions(curve: animationCurve) - - UIView.animate(withDuration: duration, delay: 0, options: animationOptions, animations: { - self.minYConstraint.isActive = true - self.contentBottomConstraint.constant = -self.bottomMargin() - self.centerYConstraint.constant = 0 - self.contentView.superview?.layoutIfNeeded() - }, completion: nil) - - } -} - -extension UIView.AnimationOptions { - init(curve: UIView.AnimationCurve) { - self = UIView.AnimationOptions(rawValue: UInt(curve.rawValue << 16)) - } -} diff --git a/Pods/BulletinBoard/Sources/Support/Helpers/UIButton+BackgroundColor.swift b/Pods/BulletinBoard/Sources/Support/Helpers/UIButton+BackgroundColor.swift deleted file mode 100644 index c268361..0000000 --- a/Pods/BulletinBoard/Sources/Support/Helpers/UIButton+BackgroundColor.swift +++ /dev/null @@ -1,25 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -extension UIButton { - - /** - * Sets a solid background color for the button. - */ - - func setBackgroundColor(_ color: UIColor, forState controlState: UIControl.State) { - - UIGraphicsBeginImageContext(CGSize(width: 1, height: 1)) - UIGraphicsGetCurrentContext()?.setFillColor(color.cgColor) - UIGraphicsGetCurrentContext()?.fill(CGRect(x: 0, y: 0, width: 1, height: 1)) - let colorImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - setBackgroundImage(colorImage, for: controlState) - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Helpers/UIColor+Luminance.swift b/Pods/BulletinBoard/Sources/Support/Helpers/UIColor+Luminance.swift deleted file mode 100644 index 7425e87..0000000 --- a/Pods/BulletinBoard/Sources/Support/Helpers/UIColor+Luminance.swift +++ /dev/null @@ -1,25 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -extension UIColor { - - var luminance: CGFloat { - - var red: CGFloat = 0 - var green: CGFloat = 0 - var blue: CGFloat = 0 - - getRed(&red, green: &green, blue: &blue, alpha: nil) - return 0.2126 * red + 0.7152 * green + 0.0722 * blue - - } - - var needsDarkText: Bool { - return luminance > sqrt(1.05 * 0.05) - 0.05 - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Helpers/UIView+SafeAnchors.swift b/Pods/BulletinBoard/Sources/Support/Helpers/UIView+SafeAnchors.swift deleted file mode 100644 index 495da58..0000000 --- a/Pods/BulletinBoard/Sources/Support/Helpers/UIView+SafeAnchors.swift +++ /dev/null @@ -1,27 +0,0 @@ -import UIKit - -// Source: https://gist.github.com/HarshilShah/6d75593d4c78a8015f54a090b115a40b - -extension UIView { - - var safeTopAnchor: NSLayoutYAxisAnchor { return safeAreaLayoutGuideIfAvailable?.topAnchor ?? topAnchor } - var safeBottomAnchor: NSLayoutYAxisAnchor { return safeAreaLayoutGuideIfAvailable?.bottomAnchor ?? bottomAnchor } - - var safeLeadingAnchor: NSLayoutXAxisAnchor { return safeAreaLayoutGuideIfAvailable?.leadingAnchor ?? leadingAnchor } - var safeTrailingAnchor: NSLayoutXAxisAnchor { return safeAreaLayoutGuideIfAvailable?.trailingAnchor ?? trailingAnchor } - - var safeCenterXAnchor: NSLayoutXAxisAnchor { return safeAreaLayoutGuideIfAvailable?.centerXAnchor ?? centerXAnchor } - var safeCenterYAnchor: NSLayoutYAxisAnchor { return safeAreaLayoutGuideIfAvailable?.centerYAnchor ?? centerYAnchor } - - var safeWidthAnchor: NSLayoutDimension { return safeAreaLayoutGuideIfAvailable?.widthAnchor ?? widthAnchor } - var safeHeightAnchor: NSLayoutDimension { return safeAreaLayoutGuideIfAvailable?.heightAnchor ?? heightAnchor } - - private var safeAreaLayoutGuideIfAvailable: UILayoutGuide? { - if #available(iOS 11.0, *) { - return safeAreaLayoutGuide - } else { - return nil - } - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/ActivityIndicator.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/ActivityIndicator.swift deleted file mode 100644 index eeb44fe..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/ActivityIndicator.swift +++ /dev/null @@ -1,70 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A view that contains an activity indicator. The indicator is centered inside the view. - */ - -class ActivityIndicator: UIView { - - private let activityIndicatorView = UIActivityIndicatorView() - - // MARK: - Lifecycle - - override init(frame: CGRect) { - super.init(frame: frame) - initialize() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - initialize() - } - - private func initialize() { - - activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false - addSubview(activityIndicatorView) - - activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true - activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - - } - - // MARK: - Activity Indicator - - /// Starts the animation of the activity indicator. - func startAnimating() { - activityIndicatorView.startAnimating() - } - - /// Stops the animation of the activity indicator. - func stopAnimating() { - activityIndicatorView.stopAnimating() - } - - /// The color of the activity indicator. - var color: UIColor? { - get { - return activityIndicatorView.color - } - set { - activityIndicatorView.color = newValue - } - } - - /// The style of the activity indicator. - var style: UIActivityIndicatorView.Style { - get { - return activityIndicatorView.style - } - set { - activityIndicatorView.style = newValue - } - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinBackgroundView.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinBackgroundView.swift deleted file mode 100644 index 7ebe5fd..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinBackgroundView.swift +++ /dev/null @@ -1,134 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * The view to display behind the bulletin. - */ - -class BulletinBackgroundView: UIView { - - let style: BLTNBackgroundViewStyle - - // MARK: - Content View - - enum ContentView { - - case dim(UIView, CGFloat) - case blur(UIVisualEffectView, UIBlurEffect) - - var instance: UIView { - switch self { - case .dim(let dimmingView, _): - return dimmingView - case .blur(let blurView, _): - return blurView - } - } - - } - - private(set) var contentView: ContentView! - - // MARK: - Initialization - - init(style: BLTNBackgroundViewStyle) { - self.style = style - super.init(frame: .zero) - initialize() - } - - override init(frame: CGRect) { - style = .dimmed - super.init(frame: frame) - initialize() - } - - required init?(coder aDecoder: NSCoder) { - style = .dimmed - super.init(coder: aDecoder) - initialize() - } - - private func initialize() { - - translatesAutoresizingMaskIntoConstraints = false - - func makeDimmingView() -> UIView { - - let dimmingView = UIView() - dimmingView.alpha = 0.0 - dimmingView.backgroundColor = UIColor(white: 0.0, alpha: 0.5) - dimmingView.translatesAutoresizingMaskIntoConstraints = false - - return dimmingView - - } - - switch style.rawValue { - case .none: - - let dimmingView = makeDimmingView() - - addSubview(dimmingView) - contentView = .dim(dimmingView, 0.0) - - case .dimmed: - - let dimmingView = makeDimmingView() - - addSubview(dimmingView) - contentView = .dim(dimmingView, 1.0) - - case .blurred(let blurredBackground): - - let blurEffect = UIBlurEffect(style: blurredBackground.style) - let blurEffectView = UIVisualEffectView(effect: nil) - blurEffectView.translatesAutoresizingMaskIntoConstraints = false - - addSubview(blurEffectView) - contentView = .blur(blurEffectView, blurEffect) - - } - - let contentViewInstance = contentView.instance - - contentViewInstance.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true - contentViewInstance.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true - contentViewInstance.topAnchor.constraint(equalTo: topAnchor).isActive = true - contentViewInstance.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true - - } - - // MARK: - Interactions - - /// Shows the background view. Animatable. - func show() { - - switch contentView! { - case .dim(let dimmingView, let maxAlpha): - dimmingView.alpha = maxAlpha - - case .blur(let blurView, let blurEffect): - blurView.effect = blurEffect - } - - } - - /// Hides the background view. Animatable. - func hide() { - - switch contentView! { - case .dim(let dimmingView, _): - dimmingView.alpha = 0 - - case .blur(let blurView, _): - blurView.effect = nil - } - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinCloseButton.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinCloseButton.swift deleted file mode 100644 index 42b9ffb..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/BulletinCloseButton.swift +++ /dev/null @@ -1,166 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A button to close the bulletin. - */ - -class BulletinCloseButton: UIControl, HighlighterTarget { - - private let backgroundContainer = UIView() - private let closeGlyph = UIImageView() - - private let highlighter = Highlighter() - - // MARK: - Initialization - - override init(frame: CGRect) { - super.init(frame: frame) - highlighter.target = self - configureSubviews() - configureConstraints() - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - highlighter.target = self - configureSubviews() - configureConstraints() - } - - private func configureSubviews() { - - // Content - - isAccessibilityElement = true - accessibilityLabel = Bundle.UIKitCore.localizedString(forKey: "Close", value: "Close", table: nil) - - // Layout - addSubview(backgroundContainer) - addSubview(closeGlyph) - - backgroundContainer.layer.cornerRadius = 14 - - closeGlyph.image = UIImage.closeButton.withRenderingMode(.alwaysTemplate) - closeGlyph.contentMode = .scaleAspectFit - closeGlyph.clipsToBounds = true - - backgroundContainer.isUserInteractionEnabled = false - closeGlyph.isUserInteractionEnabled = false - - } - - private func configureConstraints() { - - backgroundContainer.translatesAutoresizingMaskIntoConstraints = false - closeGlyph.translatesAutoresizingMaskIntoConstraints = false - - backgroundContainer.widthAnchor.constraint(equalToConstant: 28).isActive = true - backgroundContainer.heightAnchor.constraint(equalToConstant: 28).isActive = true - backgroundContainer.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true - backgroundContainer.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - - closeGlyph.widthAnchor.constraint(equalToConstant: 12).isActive = true - closeGlyph.heightAnchor.constraint(equalToConstant: 12).isActive = true - closeGlyph.centerXAnchor.constraint(equalTo: backgroundContainer.centerXAnchor).isActive = true - closeGlyph.centerYAnchor.constraint(equalTo: backgroundContainer.centerYAnchor).isActive = true - - } - - // MARK: - Customization - - func updateColors(isDarkBackground: Bool) { - if isDarkBackground { - backgroundContainer.backgroundColor = #colorLiteral(red: 0.9529411765, green: 0.9607843137, blue: 0.9607843137, alpha: 1) - closeGlyph.tintColor = #colorLiteral(red: 0.3764705882, green: 0.3921568627, blue: 0.431372549, alpha: 1) - } else { - backgroundContainer.backgroundColor = #colorLiteral(red: 0.3764705882, green: 0.3921568627, blue: 0.431372549, alpha: 1) - closeGlyph.tintColor = #colorLiteral(red: 0.9529411765, green: 0.9607843137, blue: 0.9607843137, alpha: 1) - } - } - - // MARK: - Highlighting - - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - highlighter.handleTouchesBegan(touches, with: event) - } - - override func touchesMoved(_ touches: Set, with event: UIEvent?) { - highlighter.handleTouchesMoved(touches, with: event) - } - - override func touchesEnded(_ touches: Set, with event: UIEvent?) { - highlighter.handleTouchesEnded(touches, with: event) - } - - func highlight() { - - let animations = { - self.alpha = 0.5 - } - - UIView.transition(with: self, duration: 0.1, animations: animations) - - } - - func unhighlight() { - - let animations = { - self.alpha = 1 - } - - UIView.transition(with: self, duration: 0.1, animations: animations) - - } - -} - -extension Bundle { - fileprivate static var UIKitCore: Bundle { - if #available(iOS 12, *) { - return Bundle(identifier: "com.apple.UIKitCore")! - } else { - return Bundle(for: UIApplication.self) - } - } -} - -extension UIImage { - fileprivate static var closeButton: UIImage { - let shape = UIBezierPath() - shape.move(to: CGPoint(x: 0.93, y: 30.21)) - shape.addCurve(to: CGPoint(x: 0.97, y: 35.02), controlPoint1: CGPoint(x: -0.28, y: 31.44), controlPoint2: CGPoint(x: -0.35, y: 33.72)) - shape.addCurve(to: CGPoint(x: 5.78, y: 35.06), controlPoint1: CGPoint(x: 2.29, y: 36.34), controlPoint2: CGPoint(x: 4.55, y: 36.3)) - shape.addLine(to: CGPoint(x: 18.01, y: 22.84)) - shape.addLine(to: CGPoint(x: 30.21, y: 35.04)) - shape.addCurve(to: CGPoint(x: 35, y: 34.99), controlPoint1: CGPoint(x: 31.49, y: 36.34), controlPoint2: CGPoint(x: 33.7, y: 36.32)) - shape.addCurve(to: CGPoint(x: 35.05, y: 30.21), controlPoint1: CGPoint(x: 36.33, y: 33.69), controlPoint2: CGPoint(x: 36.33, y: 31.48)) - shape.addLine(to: CGPoint(x: 22.84, y: 18.01)) - shape.addLine(to: CGPoint(x: 35.05, y: 5.79)) - shape.addCurve(to: CGPoint(x: 35, y: 1), controlPoint1: CGPoint(x: 36.33, y: 4.51), controlPoint2: CGPoint(x: 36.33, y: 2.3)) - shape.addCurve(to: CGPoint(x: 30.21, y: 0.95), controlPoint1: CGPoint(x: 33.7, y: -0.32), controlPoint2: CGPoint(x: 31.49, y: -0.32)) - shape.addLine(to: CGPoint(x: 18.01, y: 13.15)) - shape.addLine(to: CGPoint(x: 5.78, y: 0.93)) - shape.addCurve(to: CGPoint(x: 0.97, y: 0.98), controlPoint1: CGPoint(x: 4.55, y: -0.28), controlPoint2: CGPoint(x: 2.27, y: -0.35)) - shape.addCurve(to: CGPoint(x: 0.93, y: 5.79), controlPoint1: CGPoint(x: -0.33, y: 2.3), controlPoint2: CGPoint(x: -0.28, y: 4.55)) - shape.addLine(to: CGPoint(x: 13.15, y: 18.01)) - shape.addLine(to: CGPoint(x: 0.93, y: 30.21)) - shape.close() - - let size = CGSize(width: 36, height: 36) - UIGraphicsBeginImageContext(size) - - defer { - UIGraphicsEndImageContext() - } - - UIColor.black.setFill() - shape.fill() - - return UIGraphicsGetImageFromCurrentImageContext()! - } -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/ContinuousMaskLayer.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/ContinuousMaskLayer.swift deleted file mode 100644 index 2cbccef..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/ContinuousMaskLayer.swift +++ /dev/null @@ -1,81 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A shape layer that animates its path inside a block. - */ - -private class AnimatingShapeLayer: CAShapeLayer { - - override class func defaultAction(forKey event: String) -> CAAction? { - - if event == "path" { - return CABasicAnimation(keyPath: event) - } else { - return super.defaultAction(forKey: event) - } - - } - -} - -/** - * A layer whose corners are rounded with a continuous mask (“squircle“). - */ - -class ContinuousMaskLayer: CALayer { - - /// The corner radius. - var continuousCornerRadius: CGFloat = 0 { - didSet { - refreshMask() - } - } - - /// The corners to round. - var roundedCorners: UIRectCorner = .allCorners { - didSet { - refreshMask() - } - } - - // MARK: - Initialization - - override init(layer: Any) { - super.init(layer: layer) - } - - override init() { - super.init() - self.mask = AnimatingShapeLayer() - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Layout - - override func layoutSublayers() { - super.layoutSublayers() - refreshMask() - } - - private func refreshMask() { - - guard let mask = mask as? CAShapeLayer else { - return - } - - let radii = CGSize(width: continuousCornerRadius, height: continuousCornerRadius) - let roundedPath = UIBezierPath(roundedRect: bounds, byRoundingCorners: roundedCorners, cornerRadii: radii) - - mask.path = roundedPath.cgPath - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/RoundedViewProtocol.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/RoundedViewProtocol.swift deleted file mode 100644 index 9c965a2..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/RoundedViewProtocol.swift +++ /dev/null @@ -1,45 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A view with rounded corners. Adopt this protocol if your view's layer is a `ContinuousMaskLayer`. - * This protocol provides utilities to easily change the rounded corners. - * - * You need to override `+ (Class *)layerClass` on `UIView` before conforming to this protocol. - */ - -protocol RoundedViewProtocol: NSObjectProtocol { - var layer: CALayer { get } -} - -extension RoundedViewProtocol { - - /// The corner radius of the view. - var cornerRadius: CGFloat { - get { - return roundedLayer.continuousCornerRadius - } - set { - roundedLayer.continuousCornerRadius = newValue - } - } - - /// The corners to round. - var roundedCorners: UIRectCorner { - get { - return roundedLayer.roundedCorners - } - set { - roundedLayer.roundedCorners = newValue - } - } - - private var roundedLayer: ContinuousMaskLayer { - return layer as! ContinuousMaskLayer - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/UIView+RoundedView.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/UIView+RoundedView.swift deleted file mode 100644 index a3c5987..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/ContinuousCorners/UIView+RoundedView.swift +++ /dev/null @@ -1,30 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A view with rounded corners. - */ - -class RoundedView: UIView, RoundedViewProtocol { - - override class var layerClass: AnyClass { - return ContinuousMaskLayer.self - } - -} - -/** - * A button with rounded corners. - */ - -class RoundedButton: UIButton, RoundedViewProtocol { - - override class var layerClass: AnyClass { - return ContinuousMaskLayer.self - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/HighlightButton.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/HighlightButton.swift deleted file mode 100644 index 307069d..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/HighlightButton.swift +++ /dev/null @@ -1,71 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A button that provides a visual feedback when the user interacts with it. - * - * This style of button works best with a solid background color. Use the `setBackgroundColor` - * function on `UIButton` to set one. - */ - -class HighlightButton: RoundedButton, HighlighterTarget { - - private let highlighter = Highlighter() - - override var bounds: CGRect { - didSet { - highlighter.updateBounds(bounds) - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - highlighter.target = self - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - highlighter.target = self - } - - // MARK: - Touch Handling - - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - highlighter.handleTouchesBegan(touches, with: event) - } - - override func touchesMoved(_ touches: Set, with event: UIEvent?) { - highlighter.handleTouchesMoved(touches, with: event) - } - - override func touchesEnded(_ touches: Set, with event: UIEvent?) { - highlighter.handleTouchesEnded(touches, with: event) - } - - // MARK: - Transitions - - func highlight() { - - let animations = { - self.alpha = 0.5 - } - - UIView.transition(with: self, duration: 0.1, animations: animations) - - } - - func unhighlight() { - - let animations = { - self.alpha = 1 - } - - UIView.transition(with: self, duration: 0.1, animations: animations) - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Internal/Highlighter.swift b/Pods/BulletinBoard/Sources/Support/Views/Internal/Highlighter.swift deleted file mode 100644 index 2fab0c5..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Internal/Highlighter.swift +++ /dev/null @@ -1,110 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/// An item that can be highlighted due to a touch event. -protocol HighlighterTarget: class { - - /// Highlight the item. - func highlight() - - /// Unhighlight the item. - func unhighlight() - -} - -/** - * An object that determines when an item (its target) needs to be highlighted in response to - * touch events. - * - * You must forward the target's `touchesBegan`, `touchesMoved` and `touchesEnded` to this highlighter. - */ - -class Highlighter { - - /// The control targeted for highlight. - weak var target: (UIControl & HighlighterTarget)? - - // MARK: - Hit Area - - private var _cachedHitArea: CGRect! - - private func makeHitArea(bounds: CGRect) -> CGRect { - let scaleTransform = CGAffineTransform(scaleX: 5/3, y: 5/3) - let translateTransform = CGAffineTransform(translationX: -bounds.width/3, y: -bounds.height/3) - return bounds.applying(scaleTransform).applying(translateTransform) - } - - private var hitArea: CGRect { - return _cachedHitArea ?? makeHitArea(bounds: target!.bounds) - } - - // MARK: - Touch Handling - - /** - * Call this method when the bounds of the target change. - */ - - func updateBounds(_ bounds: CGRect) { - _cachedHitArea = makeHitArea(bounds: bounds) - } - - /** - * Call this method when touches begin on the target. - */ - - func handleTouchesBegan(_ touches: Set, with event: UIEvent?) { - target?.highlight() - } - - /** - * Call this method when touches move on the target. - */ - - func handleTouchesMoved(_ touches: Set, with event: UIEvent?) { - - guard let mainTouch = touches.first else { - return - } - - let currentLocation = mainTouch.location(in: target!) - let previousLocation = mainTouch.previousLocation(in: target!) - - let containsCurrentLocation = hitArea.contains(currentLocation) - let containsPreviousLocation = hitArea.contains(previousLocation) - - let isEntering = !containsPreviousLocation && containsCurrentLocation - let isExiting = containsPreviousLocation && !containsCurrentLocation - - if isEntering { - target?.highlight() - } else if isExiting { - target?.unhighlight() - } - - } - - /** - * Call this method when touches end on the target. - */ - - func handleTouchesEnded(_ touches: Set, with event: UIEvent?) { - - guard let mainTouch = touches.first else { - return - } - - let currentLocation = mainTouch.location(in: target!) - - if hitArea.contains(currentLocation) { - target?.sendActions(for: .touchUpInside) - } - - target?.unhighlight() - - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNContainerView.swift b/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNContainerView.swift deleted file mode 100644 index ddf1be7..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNContainerView.swift +++ /dev/null @@ -1,47 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import Foundation - -/** - * A view that contains another view without intrinsic content size. - * - * The intrinsic content size is provided by this view, with the `contentSize` property. - * - * You should not add subviews directly. Instead, call `setChildView(childView:constraintsBuilder:)` - * to specify the view that should be displayed and position it with Auto Layout. - */ - -@objc public class BLTNContainerView: UIView { - - /// The size of the content displayed in this view. - @objc public var contentSize: CGSize = .zero - - /** - * Adds the child view and configures the constraints. - * - parameter childView: The view to display inside the fixed-size container. - * - parameter constraintsBuilder: The block of code to executed for adding constaints to position - * the child view. - */ - - @objc public func setChildView(_ childView: UIView, constraintsBuilder: @escaping (BLTNContainerView, UIView) -> Void) { - currentChildView?.removeFromSuperview() - currentChildView = childView - addSubview(childView) - childView.translatesAutoresizingMaskIntoConstraints = false - constraintsBuilder(self, childView) - } - - // MARK: - Utilties - - private var currentChildView: UIView? - - public override var intrinsicContentSize: CGSize { - return contentSize - } - -} - - diff --git a/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNHighlightButtonWrapper.swift b/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNHighlightButtonWrapper.swift deleted file mode 100644 index e1e0e8c..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNHighlightButtonWrapper.swift +++ /dev/null @@ -1,42 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A view that wraps a HighlightButton. - * - * A wrapper is required to avoid alpha animation issues when unhighlighting the button and performing - * a bulletin transition. - */ - -@objc public class BLTNHighlightButtonWrapper: UIView { - - /// The underlying button. - @objc public let button: UIButton - - public required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) is unavailable. Use init(button:) instead.") - } - - init(button: HighlightButton) { - - self.button = button - super.init(frame: .zero) - - addSubview(button) - button.translatesAutoresizingMaskIntoConstraints = false - button.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true - button.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true - button.topAnchor.constraint(equalTo: topAnchor).isActive = true - button.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true - - } - - public override var intrinsicContentSize: CGSize { - return button.intrinsicContentSize - } - -} diff --git a/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNTitleLabelContainer.swift b/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNTitleLabelContainer.swift deleted file mode 100644 index d962182..0000000 --- a/Pods/BulletinBoard/Sources/Support/Views/Public/BLTNTitleLabelContainer.swift +++ /dev/null @@ -1,45 +0,0 @@ -/** - * BulletinBoard - * Copyright (c) 2017 - present Alexis Aubry. Licensed under the MIT license. - */ - -import UIKit - -/** - * A view that contains a title label. - */ - -@objc public class BLTNTitleLabelContainer: UIView { - - /// The label contained in the view. - @objc public let label: UILabel - - // MARK: - Initialization - - @objc init(label: UILabel, horizontalInset: CGFloat) { - self.label = label - super.init(frame: .zero) - configureSubviews(horizontalInset: horizontalInset) - } - - required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - private func configureSubviews(horizontalInset: CGFloat) { - - addSubview(label) - label.translatesAutoresizingMaskIntoConstraints = false - - label.leadingAnchor.constraint(equalTo: leadingAnchor, constant: horizontalInset).isActive = true - label.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -horizontalInset).isActive = true - label.topAnchor.constraint(equalTo: topAnchor).isActive = true - label.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true - - } - - public override var intrinsicContentSize: CGSize { - return label.intrinsicContentSize - } - -} diff --git a/Pods/Manifest.lock b/Pods/Manifest.lock index 5b97978..4f328e4 100644 --- a/Pods/Manifest.lock +++ b/Pods/Manifest.lock @@ -1,36 +1,36 @@ PODS: - BEMCheckBox (1.4.1) - - BulletinBoard (4.1.2) - Cache (5.3.0) - Imaginary (4.3.1): - Cache (~> 5.3.0) - InstantSearchVoiceOverlay (1.1.0) - Lightbox (2.4.1): - Imaginary (~> 4.3.1) + - MultiProgressView (1.3.0) DEPENDENCIES: - BEMCheckBox - - BulletinBoard - InstantSearchVoiceOverlay (~> 1.1.0) - Lightbox + - MultiProgressView SPEC REPOS: trunk: - BEMCheckBox - - BulletinBoard - Cache - Imaginary - InstantSearchVoiceOverlay - Lightbox + - MultiProgressView SPEC CHECKSUMS: BEMCheckBox: 5ba6e37ade3d3657b36caecc35c8b75c6c2b1a4e - BulletinBoard: 1c0cb191b6c6245d08f51bd2445f1e36414ec0ed Cache: 48762993ec44e1d93483c4d4a13edd18452326f4 Imaginary: 18c5bba364229eef383b925199db442e71d175e1 InstantSearchVoiceOverlay: 8fcbd0c143c872e6b39ef9b6475f1dfeb9ebfbcf Lightbox: cede4a64f2d864da1f7e7959aa78a8659a311e7c + MultiProgressView: 65e5bb8181687099ade56d16d85d245a92fafa96 -PODFILE CHECKSUM: f3980290d04c5177b1dbe326de2cf20746993044 +PODFILE CHECKSUM: 36d6cf94c2dc4596b9853e92bb677330039c916e COCOAPODS: 1.9.1 diff --git a/Pods/BulletinBoard/LICENSE b/Pods/MultiProgressView/LICENSE similarity index 92% rename from Pods/BulletinBoard/LICENSE rename to Pods/MultiProgressView/LICENSE index b6dc9f3..5020693 100644 --- a/Pods/BulletinBoard/LICENSE +++ b/Pods/MultiProgressView/LICENSE @@ -1,6 +1,6 @@ -The MIT License (MIT) +MIT License -Copyright (c) 2017-present Alexis Aubry +Copyright (c) 2018 Mac Gallagher Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -19,4 +19,3 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/Pods/MultiProgressView/README.md b/Pods/MultiProgressView/README.md new file mode 100644 index 0000000..1711f7e --- /dev/null +++ b/Pods/MultiProgressView/README.md @@ -0,0 +1,156 @@ + + +Build Status +Platform +Swift 5 +Code Coverage +CocoaPods +Carthage +Swift Package Manager +Platform + +📊 **MultiProgressView** is an animatable view that depicts multiple progresses over time. Modeled after [UIProgressView](https://developer.apple.com/documentation/uikit/uiprogressview). + +--- + +## Examples + +To run the example project, clone the repo and run the `MultiProgressViewExample` target. + +

+ +

+

+ +

+ +## Basic Usage + +### Programmatic +1. Add a `MultiProgressView` to your view hierarchy: + + ```swift + let progressView = MultiProgressView() + view.addSubview(progressView) + ``` + +2. Conform your class to the `MultiProgressViewDataSource` protocol and set your progress view's `dataSource`: + + ```swift + func numberOfSections(in progressView: MultiProgressView) -> Int + func progressView(_ progressView: MultiProgressView, viewForSection section: Int) -> ProgressViewSection + ``` + + ```swift + progressView.dataSource = self + ``` +3. Call `setProgress(section:to:)` to update your view's progress: + + ```swift + progressView.setProgress(section: 0, to: 0.4) //animatable + ``` + +### Storyboards + +1. Drag a `UIView` onto your view controller and set the view's class to `MultiProgressView` in the *Identity Inspector*: + + ![IdentityInspector](https://raw.githubusercontent.com/mac-gallagher/MultiProgressView/master/Images/storyboard_identity_inspector.gif) + +3. Connect your progress view to your view controller with an `IBOutlet`: + + ![IBOutlet](https://raw.githubusercontent.com/mac-gallagher/MultiProgressView/master/Images/storyboard_ib_outlet.gif) + +4. Conform your view controller to the `MultiProgressViewDataSource` protocol and implement the required methods: + + ```swift + func numberOfSections(in progressView: MultiProgressView) -> Int + func progressView(_ progressView: MultiProgressView, viewForSection section: Int) -> ProgressViewSection + ``` + +5. Set your view controller as the progress view's `dataSource`: + + ![DataSource](https://raw.githubusercontent.com/mac-gallagher/MultiProgressView/master/Images/storyboard_data_source.gif) + +6. Call `setProgress(section:to:)` to update your view's progress: + + ```swift + progressView.setProgress(section: 0, to: 0.4) //animatable + ``` + +## Customization + +### MultiProgressView +Each `MultiProgressView` exposes the variables listed below. If using storyboards, many of these properties can be customized directly in the view's *Attribute Inspector*. + + +```swift +var cornerRadius: CGFloat = 0 +var borderWidth: CGFloat = 0 +var borderColor: UIColor? = .black +var lineCap: LineCapType = .square + +var trackInset: CGFloat = 0 +var trackBackgroundColor: UIColor? = .clear +var trackBorderColor: UIColor? = .black +var trackBorderWidth: CGFloat = 0 + +var trackImageView: UIImageView + +var trackTitleLabel: UILabel +var trackTitleEdgeInsets: UIEdgeInsets = .zero +var trackTitleAlignment: AlignmentType = .center +``` + +**Note**: To apply a corner radius (using `layer.cornerRadius` or the `cornerRadius` variable) the `lineCap` type must be set to `.round`. + + +### ProgressViewSection +Each `ProgressViewSection` exposes the following variables: + +```swift +var imageView: UIImageView +var titleLabel: UILabel +var titleEdgeInsets: UIEdgeInsets = .zero +var titleAlignment: AlignmentType = .center +``` + +## Installation + +### CocoaPods +MultiProgressView is available through [CocoaPods](). To install it, simply add the following line to your Podfile: + + pod 'MultiProgressView' + +### Carthage + +MultiProgressView is available through [Carthage](). To install it, simply add the following line to your Cartfile: + + github "mac-gallagher/MultiProgressView" + +### Swift Package Manager +MultiProgressView is available through [Swift PM](). To install it, simply add the package as a dependency in `Package.swift`: + +```swift +dependencies: [ + .package(url: "https://github.com/mac-gallagher/MultiProgressView.git", from: "1.2.0"), +] +``` + +### Manual +Download and drop the `MultiProgressView` directory into your project. + +## Requirements +* iOS 9.0+ +* Xcode 10.2+ +* Swift 5.0+ + +## Apps Using MultiProgressView +We love to hear about apps that use MultiProgressView - feel free to submit a pull request and share yours here! + +--- + +

+ Made with ❤️ by Mac Gallagher +
+(Header design by Mazen Ghani) +

\ No newline at end of file diff --git a/Pods/MultiProgressView/Sources/MultiProgressView.h b/Pods/MultiProgressView/Sources/MultiProgressView.h new file mode 100644 index 0000000..b687a4e --- /dev/null +++ b/Pods/MultiProgressView/Sources/MultiProgressView.h @@ -0,0 +1,19 @@ +// +// MultiProgressView.h +// MultiProgressView +// +// Created by Mac Gallagher on 3/26/19. +// Copyright © 2019 Mac Gallagher. All rights reserved. +// + +#import + +//! Project version number for MultiProgressView. +FOUNDATION_EXPORT double MultiProgressViewVersionNumber; + +//! Project version string for MultiProgressView. +FOUNDATION_EXPORT const unsigned char MultiProgressViewVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Pods/MultiProgressView/Sources/MultiProgressView/AlignmentType.swift b/Pods/MultiProgressView/Sources/MultiProgressView/AlignmentType.swift new file mode 100644 index 0000000..ec63157 --- /dev/null +++ b/Pods/MultiProgressView/Sources/MultiProgressView/AlignmentType.swift @@ -0,0 +1,11 @@ +public enum AlignmentType { + case left + case topLeft + case top + case topRight + case right + case bottomRight + case bottom + case bottomLeft + case center +} diff --git a/Pods/MultiProgressView/Sources/MultiProgressView/LayoutProvider.swift b/Pods/MultiProgressView/Sources/MultiProgressView/LayoutProvider.swift new file mode 100644 index 0000000..bb28090 --- /dev/null +++ b/Pods/MultiProgressView/Sources/MultiProgressView/LayoutProvider.swift @@ -0,0 +1,155 @@ +import UIKit + +protocol LayoutProvidable { + static var trackFrame: (MultiProgressView) -> CGRect { get } + static var trackImageViewFrame: (MultiProgressView) -> CGRect { get } + static var cornerRadius: (MultiProgressView) -> CGFloat { get } + static var trackCornerRadius: (MultiProgressView) -> CGFloat { get } + + static var sectionFrame: (MultiProgressView, Int) -> CGRect { get } + static var sectionImageViewFrame: (ProgressViewSection) -> CGRect { get } + + static func anchorToSuperview(_ view: UIView, + withAlignment alignment: AlignmentType, + insets: UIEdgeInsets) -> [NSLayoutConstraint] +} + +struct LayoutProvider: LayoutProvidable { + + static var trackFrame: (MultiProgressView) -> CGRect { + return { progressView in + switch progressView.lineCap { + case .butt: + return CGRect(x: 0, + y: progressView.trackInset, + width: progressView.frame.width, + height: progressView.frame.height - 2 * progressView.trackInset) + case .round, .square: + return CGRect(x: progressView.trackInset, + y: progressView.trackInset, + width: progressView.frame.width - 2 * progressView.trackInset, + height: progressView.frame.height - 2 * progressView.trackInset) + } + } + } + + static var trackImageViewFrame: (MultiProgressView) -> CGRect { + return { progressView in + return progressView.track.bounds + } + } + + static var cornerRadius: (MultiProgressView) -> CGFloat { + return { progressView in + switch progressView.lineCap { + case .round: + return progressView.cornerRadius == 0 ? + progressView.bounds.height / 2 : progressView.cornerRadius + case .butt, .square: + return 0 + } + } + } + + static var trackCornerRadius: (MultiProgressView) -> CGFloat { + return { progressView in + let cornerRadiusFactor = progressView.cornerRadius / progressView.bounds.height + let trackHeight = progressView.track.bounds.height + + switch progressView.lineCap { + case .round: + return progressView.cornerRadius == 0 ? + trackHeight / 2 : cornerRadiusFactor * trackHeight + case .butt, .square: + return 0 + } + } + } + + static var sectionFrame: (MultiProgressView, Int) -> CGRect { + return { progressView, section in + let trackBounds = progressView.track.bounds + let width = trackBounds.width * CGFloat(progressView.progress(forSection: section)) + let size = CGSize(width: width, height: trackBounds.height) + + var origin: CGPoint = trackBounds.origin + for (bar, index) in progressView.progressViewSections { + if index < section { + origin.x += bar.frame.width + } + } + + return CGRect(origin: origin, size: size) + } + } + + static var sectionImageViewFrame: (ProgressViewSection) -> CGRect { + return { section in + return section.bounds + } + } + + static func anchorToSuperview(_ view: UIView, + withAlignment alignment: AlignmentType, + insets: UIEdgeInsets) -> [NSLayoutConstraint] { + guard let superview = view.superview else { return [] } + view.translatesAutoresizingMaskIntoConstraints = false + + var constraints = [NSLayoutConstraint]() + + let topConstraint = view.topAnchor.constraint(equalTo: superview.topAnchor, + constant: insets.top) + let leftConstraint = view.leftAnchor.constraint(equalTo: superview.leftAnchor, + constant: insets.left) + let rightConstraint = view.rightAnchor.constraint(equalTo: superview.rightAnchor, + constant: -insets.right) + let bottomConstraint = view.bottomAnchor.constraint(equalTo: superview.bottomAnchor, + constant: -insets.bottom) + let centerXConstraint = view.centerXAnchor.constraint(equalTo: superview.centerXAnchor, + constant: insets.left - insets.right) + let centerYConstraint = view.centerYAnchor.constraint(equalTo: superview.centerYAnchor, + constant: insets.top - insets.bottom) + + switch alignment { + case .bottom: + constraints.append(bottomConstraint) + constraints.append(centerXConstraint) + + case .bottomLeft: + constraints.append(bottomConstraint) + constraints.append(leftConstraint) + + case .bottomRight: + constraints.append(bottomConstraint) + constraints.append(rightConstraint) + + case .center: + constraints.append(centerXConstraint) + constraints.append(centerYConstraint) + + case .left: + constraints.append(leftConstraint) + constraints.append(centerYConstraint) + + case .right: + constraints.append(rightConstraint) + constraints.append(centerYConstraint) + + case .top: + constraints.append(topConstraint) + constraints.append(centerXConstraint) + + case .topLeft: + constraints.append(topConstraint) + constraints.append(leftConstraint) + + case .topRight: + constraints.append(topConstraint) + constraints.append(rightConstraint) + } + + constraints.forEach { $0.isActive = true } + + return constraints + } +} diff --git a/Pods/MultiProgressView/Sources/MultiProgressView/LineCapType.swift b/Pods/MultiProgressView/Sources/MultiProgressView/LineCapType.swift new file mode 100644 index 0000000..2792329 --- /dev/null +++ b/Pods/MultiProgressView/Sources/MultiProgressView/LineCapType.swift @@ -0,0 +1,5 @@ +public enum LineCapType { + case round + case butt + case square +} diff --git a/Pods/MultiProgressView/Sources/MultiProgressView/MultiProgressView.swift b/Pods/MultiProgressView/Sources/MultiProgressView/MultiProgressView.swift new file mode 100644 index 0000000..10fc29a --- /dev/null +++ b/Pods/MultiProgressView/Sources/MultiProgressView/MultiProgressView.swift @@ -0,0 +1,238 @@ +import UIKit + +@objc public protocol MultiProgressViewDataSource: class { + func numberOfSections(in progressView: MultiProgressView) -> Int + func progressView(_ progressView: MultiProgressView, + viewForSection section: Int) -> ProgressViewSection +} + +@objc public protocol MultiProgressViewDelegate: class { + @objc optional func progressView(_ progressView: MultiProgressView, didTapSectionAt index: Int) +} + +@IBDesignable +open class MultiProgressView: UIView { + + @IBOutlet public weak var dataSource: MultiProgressViewDataSource? { + didSet { + reloadData() + } + } + + @IBOutlet public weak var delegate: MultiProgressViewDelegate? + + @IBInspectable public var cornerRadius: CGFloat = 0 { + didSet { + updateCornerRadius() + } + } + + @IBInspectable public var borderWidth: CGFloat = 0 { + didSet { + layer.borderWidth = borderWidth + } + } + + @IBInspectable public var borderColor: UIColor? = .black { + didSet { + layer.borderColor = borderColor?.cgColor + } + } + + @IBInspectable public var trackInset: CGFloat = 0 { + didSet { + setNeedsLayout() + } + } + + @IBInspectable public var trackBackgroundColor: UIColor? = .clear { + didSet { + track.backgroundColor = trackBackgroundColor + } + } + + @IBInspectable public var trackBorderColor: UIColor? = .black { + didSet { + track.layer.borderColor = trackBorderColor?.cgColor + } + } + + @IBInspectable public var trackBorderWidth: CGFloat = 0 { + didSet { + track.layer.borderWidth = trackBorderWidth + } + } + + @IBInspectable public var trackTitleLabel: UILabel { + return label + } + + private var label: UILabel = UILabel() + + public var trackTitleEdgeInsets: UIEdgeInsets = .zero { + didSet { + setNeedsLayout() + } + } + + public var trackTitleAlignment: AlignmentType = .center { + didSet { + setNeedsLayout() + } + } + + public var trackImageView: UIImageView { + return imageView + } + + private var imageView: UIImageView = UIImageView() + + public var lineCap: LineCapType = .square { + didSet { + setNeedsLayout() + } + } + + public var totalProgress: Float { + return currentProgress.reduce(0) { $0 + $1 } + } + + lazy var track: UIView = { + let view = UIView() + view.layer.masksToBounds = true + view.addSubview(trackTitleLabel) + view.addSubview(trackImageView) + return view + }() + + /// A map containing the sections of the progress view. + /// The key is the section and the value is the section's index in the progress view. + var progressViewSections: [ProgressViewSection: Int] = [:] + + private var numberOfSections: Int = 0 + private var currentProgress: [Float] = [] + + private var layoutProvider: LayoutProvidable.Type = LayoutProvider.self + + // MARK: - Initialization + + public override init(frame: CGRect) { + super.init(frame: frame) + initialize() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialize() + } + + convenience init(layoutProvider: LayoutProvidable.Type) { + self.init(frame: .zero) + self.layoutProvider = layoutProvider + } + + private func initialize() { + layer.masksToBounds = true + addSubview(track) + } + + // MARK: - Layout + + var trackTitleLabelConstraints = [NSLayoutConstraint]() { + didSet { + NSLayoutConstraint.deactivate(oldValue) + NSLayoutConstraint.activate(trackTitleLabelConstraints) + } + } + + open override func layoutSubviews() { + super.layoutSubviews() + track.frame = layoutProvider.trackFrame(self) + trackTitleLabelConstraints = layoutProvider.anchorToSuperview(trackTitleLabel, + withAlignment: trackTitleAlignment, + insets: trackTitleEdgeInsets) + imageView.frame = layoutProvider.trackImageViewFrame(self) + track.sendSubviewToBack(imageView) + layoutSections() + updateCornerRadius() + } + + private func layoutSections() { + for (section, index) in progressViewSections { + section.frame = layoutProvider.sectionFrame(self, index) + track.bringSubviewToFront(section) + } + } + + func updateCornerRadius() { + layer.cornerRadius = layoutProvider.cornerRadius(self) + track.layer.cornerRadius = layoutProvider.trackCornerRadius(self) + } + + // MARK: - Data Source + + public func reloadData() { + guard let dataSource = dataSource else { return } + numberOfSections = dataSource.numberOfSections(in: self) + + progressViewSections.keys.forEach { $0.removeFromSuperview() } + progressViewSections.removeAll() + currentProgress.removeAll() + + for index in 0.. Float { + return currentProgress[section] + } + + // MARK: - Main Methods + + public func setProgress(section: Int, to progress: Float) { + currentProgress[section] = max(0, min(progress, 1 - totalProgress + currentProgress[section])) + setNeedsLayout() + layoutIfNeeded() + } + + public func resetProgress() { + for section in 0.. -@interface PodsDummy_BulletinBoard : NSObject -@end -@implementation PodsDummy_BulletinBoard -@end diff --git a/Pods/Target Support Files/BulletinBoard/BulletinBoard-umbrella.h b/Pods/Target Support Files/BulletinBoard/BulletinBoard-umbrella.h deleted file mode 100644 index 6f678c3..0000000 --- a/Pods/Target Support Files/BulletinBoard/BulletinBoard-umbrella.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifdef __OBJC__ -#import -#else -#ifndef FOUNDATION_EXPORT -#if defined(__cplusplus) -#define FOUNDATION_EXPORT extern "C" -#else -#define FOUNDATION_EXPORT extern -#endif -#endif -#endif - -#import "BLTNBoard.h" -#import "BLTNActionItem.h" -#import "BLTNItem.h" -#import "BLTNPageItem.h" - -FOUNDATION_EXPORT double BLTNBoardVersionNumber; -FOUNDATION_EXPORT const unsigned char BLTNBoardVersionString[]; - diff --git a/Pods/Target Support Files/BulletinBoard/BulletinBoard.modulemap b/Pods/Target Support Files/BulletinBoard/BulletinBoard.modulemap deleted file mode 100644 index d764d81..0000000 --- a/Pods/Target Support Files/BulletinBoard/BulletinBoard.modulemap +++ /dev/null @@ -1,6 +0,0 @@ -framework module BLTNBoard { - umbrella header "BulletinBoard-umbrella.h" - - export * - module * { export * } -} diff --git a/Pods/Target Support Files/BulletinBoard/BulletinBoard-Info.plist b/Pods/Target Support Files/MultiProgressView/MultiProgressView-Info.plist similarity index 96% rename from Pods/Target Support Files/BulletinBoard/BulletinBoard-Info.plist rename to Pods/Target Support Files/MultiProgressView/MultiProgressView-Info.plist index 7ecb368..b6b2813 100644 --- a/Pods/Target Support Files/BulletinBoard/BulletinBoard-Info.plist +++ b/Pods/Target Support Files/MultiProgressView/MultiProgressView-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 4.1.2 + 1.3.0 CFBundleSignature ???? CFBundleVersion diff --git a/Pods/Target Support Files/MultiProgressView/MultiProgressView-dummy.m b/Pods/Target Support Files/MultiProgressView/MultiProgressView-dummy.m new file mode 100644 index 0000000..7c98f82 --- /dev/null +++ b/Pods/Target Support Files/MultiProgressView/MultiProgressView-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_MultiProgressView : NSObject +@end +@implementation PodsDummy_MultiProgressView +@end diff --git a/Pods/Target Support Files/BulletinBoard/BulletinBoard-prefix.pch b/Pods/Target Support Files/MultiProgressView/MultiProgressView-prefix.pch similarity index 100% rename from Pods/Target Support Files/BulletinBoard/BulletinBoard-prefix.pch rename to Pods/Target Support Files/MultiProgressView/MultiProgressView-prefix.pch diff --git a/Pods/Target Support Files/MultiProgressView/MultiProgressView-umbrella.h b/Pods/Target Support Files/MultiProgressView/MultiProgressView-umbrella.h new file mode 100644 index 0000000..e0ba6f5 --- /dev/null +++ b/Pods/Target Support Files/MultiProgressView/MultiProgressView-umbrella.h @@ -0,0 +1,17 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "MultiProgressView.h" + +FOUNDATION_EXPORT double MultiProgressViewVersionNumber; +FOUNDATION_EXPORT const unsigned char MultiProgressViewVersionString[]; + diff --git a/Pods/Target Support Files/BulletinBoard/BulletinBoard.debug.xcconfig b/Pods/Target Support Files/MultiProgressView/MultiProgressView.debug.xcconfig similarity index 69% rename from Pods/Target Support Files/BulletinBoard/BulletinBoard.debug.xcconfig rename to Pods/Target Support Files/MultiProgressView/MultiProgressView.debug.xcconfig index cbb4b82..632e70c 100644 --- a/Pods/Target Support Files/BulletinBoard/BulletinBoard.debug.xcconfig +++ b/Pods/Target Support Files/MultiProgressView/MultiProgressView.debug.xcconfig @@ -1,11 +1,10 @@ -CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BulletinBoard +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MultiProgressView GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -OTHER_LDFLAGS = $(inherited) -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} -PODS_TARGET_SRCROOT = ${PODS_ROOT}/BulletinBoard +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MultiProgressView PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/MultiProgressView/MultiProgressView.modulemap b/Pods/Target Support Files/MultiProgressView/MultiProgressView.modulemap new file mode 100644 index 0000000..cd22cfb --- /dev/null +++ b/Pods/Target Support Files/MultiProgressView/MultiProgressView.modulemap @@ -0,0 +1,6 @@ +framework module MultiProgressView { + umbrella header "MultiProgressView-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/BulletinBoard/BulletinBoard.release.xcconfig b/Pods/Target Support Files/MultiProgressView/MultiProgressView.release.xcconfig similarity index 69% rename from Pods/Target Support Files/BulletinBoard/BulletinBoard.release.xcconfig rename to Pods/Target Support Files/MultiProgressView/MultiProgressView.release.xcconfig index cbb4b82..632e70c 100644 --- a/Pods/Target Support Files/BulletinBoard/BulletinBoard.release.xcconfig +++ b/Pods/Target Support Files/MultiProgressView/MultiProgressView.release.xcconfig @@ -1,11 +1,10 @@ -CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/BulletinBoard +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MultiProgressView GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -OTHER_LDFLAGS = $(inherited) -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) PODS_ROOT = ${SRCROOT} -PODS_TARGET_SRCROOT = ${PODS_ROOT}/BulletinBoard +PODS_TARGET_SRCROOT = ${PODS_ROOT}/MultiProgressView PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} SKIP_INSTALL = YES USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.markdown b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.markdown index 65bcd3a..5d1a80a 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.markdown +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.markdown @@ -26,32 +26,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## BulletinBoard - -The MIT License (MIT) - -Copyright (c) 2017-present Alexis Aubry - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - ## Cache Licensed under the **MIT** license @@ -141,4 +115,29 @@ Licensed under the **MIT** license > TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE > SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## MultiProgressView + +MIT License + +Copyright (c) 2018 Mac Gallagher + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.plist b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.plist index e6dc295..b653400 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.plist +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-acknowledgements.plist @@ -43,38 +43,6 @@ THE SOFTWARE. Type PSGroupSpecifier - - FooterText - The MIT License (MIT) - -Copyright (c) 2017-present Alexis Aubry <me@alexaubry.fr> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - License - MIT - Title - BulletinBoard - Type - PSGroupSpecifier - FooterText Licensed under the **MIT** license @@ -189,6 +157,37 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI Type PSGroupSpecifier + + FooterText + MIT License + +Copyright (c) 2018 Mac Gallagher + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + License + MIT + Title + MultiProgressView + Type + PSGroupSpecifier + FooterText Generated by CocoaPods - https://cocoapods.org diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-input-files.xcfilelist b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-input-files.xcfilelist index 19b7c00..339b216 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-input-files.xcfilelist +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-input-files.xcfilelist @@ -1,7 +1,7 @@ ${PODS_ROOT}/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks.sh ${BUILT_PRODUCTS_DIR}/BEMCheckBox/BEMCheckBox.framework -${BUILT_PRODUCTS_DIR}/BulletinBoard/BLTNBoard.framework ${BUILT_PRODUCTS_DIR}/Cache/Cache.framework ${BUILT_PRODUCTS_DIR}/Imaginary/Imaginary.framework ${BUILT_PRODUCTS_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework -${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework \ No newline at end of file +${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework +${BUILT_PRODUCTS_DIR}/MultiProgressView/MultiProgressView.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-output-files.xcfilelist b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-output-files.xcfilelist index 79922b0..ed08da6 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-output-files.xcfilelist +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Debug-output-files.xcfilelist @@ -1,6 +1,6 @@ ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BEMCheckBox.framework -${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BLTNBoard.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cache.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Imaginary.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/InstantSearchVoiceOverlay.framework -${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lightbox.framework \ No newline at end of file +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lightbox.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MultiProgressView.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-input-files.xcfilelist b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-input-files.xcfilelist index 19b7c00..339b216 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-input-files.xcfilelist +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-input-files.xcfilelist @@ -1,7 +1,7 @@ ${PODS_ROOT}/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks.sh ${BUILT_PRODUCTS_DIR}/BEMCheckBox/BEMCheckBox.framework -${BUILT_PRODUCTS_DIR}/BulletinBoard/BLTNBoard.framework ${BUILT_PRODUCTS_DIR}/Cache/Cache.framework ${BUILT_PRODUCTS_DIR}/Imaginary/Imaginary.framework ${BUILT_PRODUCTS_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework -${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework \ No newline at end of file +${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework +${BUILT_PRODUCTS_DIR}/MultiProgressView/MultiProgressView.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-output-files.xcfilelist b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-output-files.xcfilelist index 79922b0..ed08da6 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-output-files.xcfilelist +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks-Release-output-files.xcfilelist @@ -1,6 +1,6 @@ ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BEMCheckBox.framework -${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/BLTNBoard.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cache.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Imaginary.framework ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/InstantSearchVoiceOverlay.framework -${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lightbox.framework \ No newline at end of file +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Lightbox.framework +${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MultiProgressView.framework \ No newline at end of file diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks.sh b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks.sh index 88e77af..e3d3509 100755 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks.sh +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List-frameworks.sh @@ -198,19 +198,19 @@ fi if [[ "$CONFIGURATION" == "Debug" ]]; then install_framework "${BUILT_PRODUCTS_DIR}/BEMCheckBox/BEMCheckBox.framework" - install_framework "${BUILT_PRODUCTS_DIR}/BulletinBoard/BLTNBoard.framework" install_framework "${BUILT_PRODUCTS_DIR}/Cache/Cache.framework" install_framework "${BUILT_PRODUCTS_DIR}/Imaginary/Imaginary.framework" install_framework "${BUILT_PRODUCTS_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework" install_framework "${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework" + install_framework "${BUILT_PRODUCTS_DIR}/MultiProgressView/MultiProgressView.framework" fi if [[ "$CONFIGURATION" == "Release" ]]; then install_framework "${BUILT_PRODUCTS_DIR}/BEMCheckBox/BEMCheckBox.framework" - install_framework "${BUILT_PRODUCTS_DIR}/BulletinBoard/BLTNBoard.framework" install_framework "${BUILT_PRODUCTS_DIR}/Cache/Cache.framework" install_framework "${BUILT_PRODUCTS_DIR}/Imaginary/Imaginary.framework" install_framework "${BUILT_PRODUCTS_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework" install_framework "${BUILT_PRODUCTS_DIR}/Lightbox/Lightbox.framework" + install_framework "${BUILT_PRODUCTS_DIR}/MultiProgressView/MultiProgressView.framework" fi if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then wait diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.debug.xcconfig b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.debug.xcconfig index 70827eb..34dc56a 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.debug.xcconfig +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.debug.xcconfig @@ -1,9 +1,9 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox" "${PODS_CONFIGURATION_BUILD_DIR}/BulletinBoard" "${PODS_CONFIGURATION_BUILD_DIR}/Cache" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox" "${PODS_CONFIGURATION_BUILD_DIR}/Cache" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox" "${PODS_CONFIGURATION_BUILD_DIR}/MultiProgressView" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox/BEMCheckBox.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/BulletinBoard/BLTNBoard.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Cache/Cache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary/Imaginary.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox/Lightbox.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox/BEMCheckBox.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Cache/Cache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary/Imaginary.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox/Lightbox.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MultiProgressView/MultiProgressView.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -OTHER_LDFLAGS = $(inherited) -framework "AVFoundation" -framework "AVKit" -framework "BEMCheckBox" -framework "BLTNBoard" -framework "Cache" -framework "Foundation" -framework "Imaginary" -framework "InstantSearchVoiceOverlay" -framework "Lightbox" -framework "UIKit" +OTHER_LDFLAGS = $(inherited) -framework "AVFoundation" -framework "AVKit" -framework "BEMCheckBox" -framework "Cache" -framework "Foundation" -framework "Imaginary" -framework "InstantSearchVoiceOverlay" -framework "Lightbox" -framework "MultiProgressView" -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.release.xcconfig b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.release.xcconfig index 70827eb..34dc56a 100644 --- a/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.release.xcconfig +++ b/Pods/Target Support Files/Pods-Grocery List/Pods-Grocery List.release.xcconfig @@ -1,9 +1,9 @@ ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES -FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox" "${PODS_CONFIGURATION_BUILD_DIR}/BulletinBoard" "${PODS_CONFIGURATION_BUILD_DIR}/Cache" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox" +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox" "${PODS_CONFIGURATION_BUILD_DIR}/Cache" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox" "${PODS_CONFIGURATION_BUILD_DIR}/MultiProgressView" GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 -HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox/BEMCheckBox.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/BulletinBoard/BLTNBoard.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Cache/Cache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary/Imaginary.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox/Lightbox.framework/Headers" +HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/BEMCheckBox/BEMCheckBox.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Cache/Cache.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Imaginary/Imaginary.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/Lightbox/Lightbox.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MultiProgressView/MultiProgressView.framework/Headers" LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' -OTHER_LDFLAGS = $(inherited) -framework "AVFoundation" -framework "AVKit" -framework "BEMCheckBox" -framework "BLTNBoard" -framework "Cache" -framework "Foundation" -framework "Imaginary" -framework "InstantSearchVoiceOverlay" -framework "Lightbox" -framework "UIKit" +OTHER_LDFLAGS = $(inherited) -framework "AVFoundation" -framework "AVKit" -framework "BEMCheckBox" -framework "Cache" -framework "Foundation" -framework "Imaginary" -framework "InstantSearchVoiceOverlay" -framework "Lightbox" -framework "MultiProgressView" -framework "UIKit" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS PODS_BUILD_DIR = ${BUILD_DIR} PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) diff --git a/StoreViewController.swift b/StoreViewController.swift new file mode 100644 index 0000000..5da8eaf --- /dev/null +++ b/StoreViewController.swift @@ -0,0 +1,42 @@ +// +// StoreViewController.swift +// Grocery List +// +// Created by Rushad Antia on 9/3/20. +// Copyright © 2020 Rushad Antia. All rights reserved. +// + +import Foundation +import UIKit + +class StoreViewController: UITableViewController { + var store = Store() + + override func viewDidLoad() { + super.viewDidLoad() + navigationController?.setToolbarHidden(true, animated: true) + navigationController?.navigationBar.barTintColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) + navigationItem.largeTitleDisplayMode = .automatic + navigationController?.navigationBar.prefersLargeTitles = true + + navigationItem.title = store.name.capitalized + + tableView.delegate = self + tableView.dataSource = self + tableView.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) + + } + + override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return self.store.getCategories()[section].capitalized + } + + override func numberOfSections(in tableView: UITableView) -> Int { + return store.categories.count + } + +// override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { +// +// } + +} From ea47d467676d241f35f2f38507d8e3cc7f77df9d Mon Sep 17 00:00:00 2001 From: rushadantia Date: Fri, 4 Sep 2020 18:54:48 -0400 Subject: [PATCH 02/22] works kinda --- Grocery List.xcodeproj/project.pbxproj | 14 +++-- .../StoresTableViewController.swift | 2 - .../UIColor+RandomColor.swift | 22 ++++++++ Grocery List/Views/Base.lproj/Main.storyboard | 5 -- Grocery List/Views/StoreListHeader.swift | 22 ++++++-- Grocery List/Views/StoreListHeader.xib | 55 ------------------- Pods/Pods.xcodeproj/project.pbxproj | 54 +++++++++--------- StoreViewController.swift | 29 ++++++++-- 8 files changed, 97 insertions(+), 106 deletions(-) create mode 100644 Grocery List/View Controllers/UIColor+RandomColor.swift delete mode 100644 Grocery List/Views/StoreListHeader.xib diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index 752e14b..b055af5 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -13,12 +13,12 @@ 2418684524884B6C003E7C69 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2418684424884B6C003E7C69 /* Store.swift */; }; 2418684824885824003E7C69 /* StoresTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2418684724885824003E7C69 /* StoresTableViewController.swift */; }; 241E7C342501730F00C06241 /* StoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241E7C332501730F00C06241 /* StoreViewController.swift */; }; - 241E7C372502E14100C06241 /* StoreListHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = 241E7C362502E14100C06241 /* StoreListHeader.xib */; }; 241E7C392502E16200C06241 /* StoreListHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241E7C382502E16200C06241 /* StoreListHeader.swift */; }; 241F0F7C24B7A35800A3F67C /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241F0F7B24B7A35800A3F67C /* ItemCell.swift */; }; 2423A01F24BB93CC0089181C /* Grocery_ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */; }; + 2427D72B2502E97500BEB252 /* MultiProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2427D72A2502E97500BEB252 /* MultiProgressView.framework */; }; + 2427D72F2502F53700BEB252 /* UIColor+RandomColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2427D72E2502F53700BEB252 /* UIColor+RandomColor.swift */; }; 24283BB124BD017100141807 /* InstantSearchVoiceOverlay.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24283BB024BD017100141807 /* InstantSearchVoiceOverlay.framework */; }; - 243827FE24D1EF8E00AB7E20 /* BLTNBoard.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 243827FD24D1EF8E00AB7E20 /* BLTNBoard.framework */; }; 24390CBF24C61B6700189D75 /* StoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24390CBE24C61B6700189D75 /* StoreCell.swift */; }; 244CEC4824ABC850002E2DCA /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244CEC4724ABC850002E2DCA /* Cache.framework */; }; 244CEC4A24ABC850002E2DCA /* Imaginary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 244CEC4924ABC850002E2DCA /* Imaginary.framework */; }; @@ -69,12 +69,13 @@ 2418684724885824003E7C69 /* StoresTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoresTableViewController.swift; sourceTree = ""; }; 2419C7D824B652FD004F5096 /* StrikethroughLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StrikethroughLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 241E7C332501730F00C06241 /* StoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreViewController.swift; sourceTree = SOURCE_ROOT; }; - 241E7C362502E14100C06241 /* StoreListHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = StoreListHeader.xib; sourceTree = ""; }; 241E7C382502E16200C06241 /* StoreListHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreListHeader.swift; path = "Grocery List/Views/StoreListHeader.swift"; sourceTree = SOURCE_ROOT; }; 241F0F7B24B7A35800A3F67C /* ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; 2423A01C24BB93CC0089181C /* Grocery ListTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Grocery ListTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grocery_ListTests.swift; sourceTree = ""; }; 2423A02024BB93CC0089181C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 2427D72A2502E97500BEB252 /* MultiProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MultiProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2427D72E2502F53700BEB252 /* UIColor+RandomColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "UIColor+RandomColor.swift"; path = "Grocery List/View Controllers/UIColor+RandomColor.swift"; sourceTree = SOURCE_ROOT; }; 24283BB024BD017100141807 /* InstantSearchVoiceOverlay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = InstantSearchVoiceOverlay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 243827FD24D1EF8E00AB7E20 /* BLTNBoard.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BLTNBoard.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24390CBE24C61B6700189D75 /* StoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreCell.swift; path = "Grocery List/Cells/StoreCell.swift"; sourceTree = SOURCE_ROOT; }; @@ -118,8 +119,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2427D72B2502E97500BEB252 /* MultiProgressView.framework in Frameworks */, 24F91AEA24F058120064FDBB /* BEMCheckBox.framework in Frameworks */, - 243827FE24D1EF8E00AB7E20 /* BLTNBoard.framework in Frameworks */, 24283BB124BD017100141807 /* InstantSearchVoiceOverlay.framework in Frameworks */, 244CEC4824ABC850002E2DCA /* Cache.framework in Frameworks */, 244CEC4A24ABC850002E2DCA /* Imaginary.framework in Frameworks */, @@ -168,7 +169,6 @@ children = ( 2461A83224882541009BE0AB /* Main.storyboard */, 2461A83724882543009BE0AB /* LaunchScreen.storyboard */, - 241E7C362502E14100C06241 /* StoreListHeader.xib */, ); path = Views; sourceTree = ""; @@ -252,6 +252,7 @@ 24E5F40424EB16C0007DA4BE /* Extensions */ = { isa = PBXGroup; children = ( + 2427D72E2502F53700BEB252 /* UIColor+RandomColor.swift */, 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */, 24E5F40224EB16B7007DA4BE /* UIView+Separator.swift */, ); @@ -270,6 +271,7 @@ FD6CE4CE15A5E7A1540EC50C /* Frameworks */ = { isa = PBXGroup; children = ( + 2427D72A2502E97500BEB252 /* MultiProgressView.framework */, 24F91AE924F058120064FDBB /* BEMCheckBox.framework */, 243827FD24D1EF8E00AB7E20 /* BLTNBoard.framework */, 24283BB024BD017100141807 /* InstantSearchVoiceOverlay.framework */, @@ -398,7 +400,6 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 241E7C372502E14100C06241 /* StoreListHeader.xib in Resources */, 2461A83924882543009BE0AB /* LaunchScreen.storyboard in Resources */, 2461A83624882543009BE0AB /* Assets.xcassets in Resources */, 2461A83424882541009BE0AB /* Main.storyboard in Resources */, @@ -477,6 +478,7 @@ 241F0F7C24B7A35800A3F67C /* ItemCell.swift in Sources */, 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */, 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */, + 2427D72F2502F53700BEB252 /* UIColor+RandomColor.swift in Sources */, 2418684824885824003E7C69 /* StoresTableViewController.swift in Sources */, 24E5F40124EB14D5007DA4BE /* AddStoreViewController.swift in Sources */, 2418684324884B42003E7C69 /* Category.swift in Sources */, diff --git a/Grocery List/View Controllers/StoresTableViewController.swift b/Grocery List/View Controllers/StoresTableViewController.swift index 83ad45a..0545241 100644 --- a/Grocery List/View Controllers/StoresTableViewController.swift +++ b/Grocery List/View Controllers/StoresTableViewController.swift @@ -5,8 +5,6 @@ // Created by Rushad Antia on 6/3/20. // Copyright © 2020 Rushad Antia. All rights reserved. // - -import BLTNBoard import Foundation import UIKit diff --git a/Grocery List/View Controllers/UIColor+RandomColor.swift b/Grocery List/View Controllers/UIColor+RandomColor.swift new file mode 100644 index 0000000..a8f4a6d --- /dev/null +++ b/Grocery List/View Controllers/UIColor+RandomColor.swift @@ -0,0 +1,22 @@ +// +// UIColor+RandomColor.swift +// Grocery List +// +// Created by Rushad Antia on 9/4/20. +// Copyright © 2020 Rushad Antia. All rights reserved. +// + +import Foundation +import UIKit + +extension UIColor { + class func randomColor(randomAlpha: Bool = false) -> UIColor { + let r = CGFloat(arc4random_uniform(255)) / 255.0 + let g = CGFloat(arc4random_uniform(255)) / 255.0 + let b = CGFloat(arc4random_uniform(255)) / 255.0 + let alpha = randomAlpha ? CGFloat(arc4random_uniform(255)) / 255 : 1 + + return UIColor(red: r, green: g, blue: b, alpha: alpha) + + } +} diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index 3d00ce2..3314dd6 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -493,11 +493,6 @@ - - - - - diff --git a/Grocery List/Views/StoreListHeader.swift b/Grocery List/Views/StoreListHeader.swift index 894b389..52a04e3 100644 --- a/Grocery List/Views/StoreListHeader.swift +++ b/Grocery List/Views/StoreListHeader.swift @@ -4,15 +4,29 @@ // // Created by Rushad Antia on 9/4/20. // Copyright © 2020 Rushad Antia. All rights reserved. -// -import Foundation import UIKit class StoreListHeader: UITableViewHeaderFooterView { static let reuseIdentifier = String(describing: self) - static var nib: UINib { - return UINib(nibName: String(describing: self), bundle: nil) + var addButton: UIButton? + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + + addButton = UIButton() + contentView.addSubview(addButton!) + + addButton?.translatesAutoresizingMaskIntoConstraints = false + + addButton?.widthAnchor.constraint(equalToConstant: 24).isActive = true + addButton?.heightAnchor.constraint(equalToConstant: 24).isActive = true + addButton?.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor).isActive = true + addButton?.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true + } + + required init?(coder: NSCoder) { + super.init(coder: coder) } } diff --git a/Grocery List/Views/StoreListHeader.xib b/Grocery List/Views/StoreListHeader.xib deleted file mode 100644 index f5f6fb1..0000000 --- a/Grocery List/Views/StoreListHeader.xib +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index 8de908e..f40ae67 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -221,7 +221,7 @@ 2C1A0F2B00E9B18D7E2A7C2F7D60CDA6 /* ImageDownloader.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImageDownloader.swift; path = Sources/Shared/Fetcher/ImageDownloader.swift; sourceTree = ""; }; 2D1F717133361C7D9C812A293E7EC8D5 /* Imaginary.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Imaginary.debug.xcconfig; sourceTree = ""; }; 2DA3D7D2B84AE51F50EB2B0A9B0CD87A /* FooterView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = FooterView.swift; path = Source/Views/FooterView.swift; sourceTree = ""; }; - 2DBC19E0436A3E8D2D3670C588B2B9BD /* MultiProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = MultiProgressView.framework; path = MultiProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 2DBC19E0436A3E8D2D3670C588B2B9BD /* MultiProgressView.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MultiProgressView.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 2E2FAE0535B8A5B9C7376B1461EE28D0 /* RecordingButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecordingButton.swift; path = VoiceOverlay/Views/RecordingButton.swift; sourceTree = ""; }; 2F1D7172A0765BD5799AB8D7EA0B796A /* MD5.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MD5.swift; path = Source/Shared/Library/MD5.swift; sourceTree = ""; }; 301A8B6A92CE813AF488748611AFD907 /* RecordingViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = RecordingViewController.swift; path = VoiceOverlay/Controllers/RecordingViewController.swift; sourceTree = ""; }; @@ -233,13 +233,13 @@ 3488704A02C779EB0586A1BD27449296 /* PageView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = PageView.swift; path = Source/Views/PageView.swift; sourceTree = ""; }; 35BFF87AA78BB09C59E7FCB623BF7F5D /* Result.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Result.swift; path = Source/Shared/Library/Result.swift; sourceTree = ""; }; 367F46621B9051C4419670028E0ADDCD /* MultiProgressView.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MultiProgressView.debug.xcconfig; sourceTree = ""; }; - 36D3F225A0D0E73A8526E912481B9046 /* Pods_Grocery_List.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Pods_Grocery_List.framework; path = "Pods-Grocery List.framework"; sourceTree = BUILT_PRODUCTS_DIR; }; + 36D3F225A0D0E73A8526E912481B9046 /* Pods_Grocery_List.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Grocery_List.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3B00E35BB43DFF25B2AAA5470BB3A4F7 /* MultiProgressView.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = MultiProgressView.release.xcconfig; sourceTree = ""; }; 3C306ACDDABD2993CC012CC3E94038E3 /* MultiProgressView-umbrella.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "MultiProgressView-umbrella.h"; sourceTree = ""; }; 3CA91CA501AC280E2803DA2C00A2AA05 /* BEMCheckBox.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = BEMCheckBox.debug.xcconfig; sourceTree = ""; }; 3DACAA1BABAA328444B3BF1FA53EFFB5 /* SpeechController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = SpeechController.swift; path = VoiceOverlay/Controllers/SpeechController.swift; sourceTree = ""; }; 3E9598807FAA98C04C5A711EA497CB59 /* BEMCheckBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = BEMCheckBox.release.xcconfig; sourceTree = ""; }; - 3F282D213AB9D1ECA1228C986CC9D2BA /* BEMCheckBox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = BEMCheckBox.framework; path = BEMCheckBox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 3F282D213AB9D1ECA1228C986CC9D2BA /* BEMCheckBox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BEMCheckBox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 3F3CE273CFDC5AEAB98999C7D530BF3B /* ButtonDisplayer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ButtonDisplayer.swift; path = Sources/iOS/ButtonDisplayer.swift; sourceTree = ""; }; 3F9C989C0E038AC9D3CC1AAA9C07BFEF /* Extensions.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Extensions.swift; path = VoiceOverlay/Helpers/Extensions.swift; sourceTree = ""; }; 4138A5C495871EE8EC35971A9503F970 /* HeaderView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = HeaderView.swift; path = Source/Views/HeaderView.swift; sourceTree = ""; }; @@ -250,7 +250,7 @@ 457E50DAA41EB9DEE7B4C608A98988EF /* MultiProgressView.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = MultiProgressView.modulemap; sourceTree = ""; }; 45C527C0D93F3375763CA6AC8EAB8B84 /* UIView+Gradient.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "UIView+Gradient.swift"; path = "Source/Library/UIView+Gradient.swift"; sourceTree = ""; }; 4611FF3E627BA6FC08A164AB14A5516A /* Cache-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Cache-prefix.pch"; sourceTree = ""; }; - 4839ACA053EFB6CF25272430B180126B /* Lightbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Lightbox.framework; path = Lightbox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 4839ACA053EFB6CF25272430B180126B /* Lightbox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Lightbox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 49C0E8BAB39B7EE76E0CCF1940BA3AFB /* Lightbox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Lightbox.release.xcconfig; sourceTree = ""; }; 4D8411A04A70018F8B2D6CB81AF2B145 /* BEMCheckBox.m */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.objc; name = BEMCheckBox.m; path = Classes/BEMCheckBox.m; sourceTree = ""; }; 52D48F1EBA71800B0891AC3EF50202BD /* MultiProgressView.h */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; name = MultiProgressView.h; path = Sources/MultiProgressView.h; sourceTree = ""; }; @@ -273,7 +273,7 @@ 6D73CA9A5CAE59700A5859619F5BE567 /* ImageFetcher.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ImageFetcher.swift; path = Sources/Shared/Fetcher/ImageFetcher.swift; sourceTree = ""; }; 6DAED555BEF4DDA1ADAC13B263FB7461 /* InstantSearchVoiceOverlay.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = InstantSearchVoiceOverlay.debug.xcconfig; sourceTree = ""; }; 72B0BF2FF76C7902607D4BA685C144DA /* TypeWrapper.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TypeWrapper.swift; path = Source/Shared/Library/TypeWrapper.swift; sourceTree = ""; }; - 736B64357A6C420C3A7062C6D479AC7F /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Cache.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 736B64357A6C420C3A7062C6D479AC7F /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 737CE61C0212066A17BA93CFACD467DE /* Cache.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; path = Cache.debug.xcconfig; sourceTree = ""; }; 744CEA718DE5E54063195B0AE4131C41 /* DataSerializer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DataSerializer.swift; path = Source/Shared/Library/DataSerializer.swift; sourceTree = ""; }; 788A0504A22560CA87F941AD22C3B00A /* BEMCheckBox-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "BEMCheckBox-prefix.pch"; sourceTree = ""; }; @@ -300,13 +300,13 @@ 9BCB2011F2B0D458083A3DD1973FFE5E /* BEMCheckBox.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = BEMCheckBox.modulemap; sourceTree = ""; }; 9C00C257C92C1B663A4A6E496AA633FE /* Transformer.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Transformer.swift; path = Source/Shared/Library/Transformer.swift; sourceTree = ""; }; 9CB7B93A823BF299C4DA4FF0133D067C /* Imaginary-prefix.pch */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.c.h; path = "Imaginary-prefix.pch"; sourceTree = ""; }; - 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; lastKnownFileType = text; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; + 9D940727FF8FB9C785EB98E56350EF41 /* Podfile */ = {isa = PBXFileReference; explicitFileType = text.script.ruby; includeInIndex = 1; indentWidth = 2; name = Podfile; path = ../Podfile; sourceTree = SOURCE_ROOT; tabWidth = 2; xcLanguageSpecificationIdentifier = xcode.lang.ruby; }; A0F7F4C3A596FFE16B92ECA3F11D7BDB /* DecompressorUIKit.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = DecompressorUIKit.swift; path = Sources/iOS/DecompressorUIKit.swift; sourceTree = ""; }; A4C2ED7EF9123B4835C6DD4BD7612BA0 /* Pods-Grocery List-frameworks.sh */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.script.sh; path = "Pods-Grocery List-frameworks.sh"; sourceTree = ""; }; A59ABDE90E938620F99E0361C953F473 /* MemoryCapsule.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = MemoryCapsule.swift; path = Source/Shared/Library/MemoryCapsule.swift; sourceTree = ""; }; A61BE971EACA1AF47E0C56DD5862836A /* ExpirationMode.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpirationMode.swift; path = Source/Shared/Library/ExpirationMode.swift; sourceTree = ""; }; A7C6DA6ABA821FFC3B88896A70E7A985 /* Cache.modulemap */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.module; path = Cache.modulemap; sourceTree = ""; }; - A8EC60D6804D647FCD95230228CDE484 /* Imaginary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = Imaginary.framework; path = Imaginary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + A8EC60D6804D647FCD95230228CDE484 /* Imaginary.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Imaginary.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ADA615D4CFB601EBF6DC90A456D4820D /* Result.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = Result.swift; path = Sources/Shared/Library/Result.swift; sourceTree = ""; }; B0341A205C32E981ED40D6BAB3756CBD /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; }; B3BCA3A9F00DD2788F59F2EB12909F81 /* LoadingIndicator.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = LoadingIndicator.swift; path = Source/Views/LoadingIndicator.swift; sourceTree = ""; }; @@ -320,7 +320,7 @@ C1D3EE70A446343E42159DADA6CD483E /* TintImageProcessor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = TintImageProcessor.swift; path = Sources/iOS/TintImageProcessor.swift; sourceTree = ""; }; C4633464533244205FBF644A17878C54 /* ResultViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ResultViewController.swift; path = VoiceOverlay/Controllers/ResultViewController.swift; sourceTree = ""; }; C48C7D40491BD2D8070DCC3C28A19A1F /* View+Imaginary.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = "View+Imaginary.swift"; path = "Sources/Shared/Extensions/View+Imaginary.swift"; sourceTree = ""; }; - C906FF0017ACE692189192383B875D74 /* InstantSearchVoiceOverlay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; name = InstantSearchVoiceOverlay.framework; path = InstantSearchVoiceOverlay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + C906FF0017ACE692189192383B875D74 /* InstantSearchVoiceOverlay.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = InstantSearchVoiceOverlay.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE7DC77F76F56598044DDD99F0430382 /* VoiceOverlayController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = VoiceOverlayController.swift; path = VoiceOverlay/Controllers/VoiceOverlayController.swift; sourceTree = ""; }; CF88CE8FEE22E4779E067C0A36F29A5B /* InfoLabel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = InfoLabel.swift; path = Source/Views/InfoLabel.swift; sourceTree = ""; }; CFA182DB5F193E973B37D0A66047C9F7 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -439,7 +439,6 @@ 8BE5B50074826450A1DF0829304E2347 /* BEMPathManager.m */, A6E7E7B7752CC5A74336337EFEA8CEDB /* Support Files */, ); - name = BEMCheckBox; path = BEMCheckBox; sourceTree = ""; }; @@ -505,7 +504,6 @@ 9BF41927442DB74284A2F5FED1F4F8EA /* Resources */, CA5C7C8B2293002F106CC17D4136DA76 /* Support Files */, ); - name = Lightbox; path = Lightbox; sourceTree = ""; }; @@ -543,7 +541,6 @@ 00CC708DC406A6546BE82A8D404BDA5F /* Resources */, 535791E00E9DB1FE3537B036AD388974 /* Support Files */, ); - name = InstantSearchVoiceOverlay; path = InstantSearchVoiceOverlay; sourceTree = ""; }; @@ -588,7 +585,6 @@ 32965B94DDF14C1C307E3CEB002B275E /* ProgressViewSection.swift */, 2FEFFB28258574DA13B8B3C5B92BEDD4 /* Support Files */, ); - name = MultiProgressView; path = MultiProgressView; sourceTree = ""; }; @@ -628,7 +624,6 @@ C48C7D40491BD2D8070DCC3C28A19A1F /* View+Imaginary.swift */, B955FD98B8D33A83C1016227D1B48070 /* Support Files */, ); - name = Imaginary; path = Imaginary; sourceTree = ""; }; @@ -734,7 +729,6 @@ 6A078D31AAA8BF61E326E36840AB21C3 /* UIImage+Extensions.swift */, F40C9E6C9B17B9D59419AE2D61A39F8C /* Support Files */, ); - name = Cache; path = Cache; sourceTree = ""; }; @@ -961,7 +955,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 1100; - LastUpgradeCheck = 1100; + LastUpgradeCheck = 1200; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 10.0"; @@ -1256,7 +1250,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-Grocery List/Pods-Grocery List-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1303,6 +1297,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -1353,7 +1348,7 @@ GCC_PREFIX_HEADER = "Target Support Files/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay-prefix.pch"; INFOPLIST_FILE = "Target Support Files/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1388,7 +1383,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Cache/Cache-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Cache/Cache-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1423,7 +1418,7 @@ GCC_PREFIX_HEADER = "Target Support Files/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay-prefix.pch"; INFOPLIST_FILE = "Target Support Files/InstantSearchVoiceOverlay/InstantSearchVoiceOverlay-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1459,7 +1454,7 @@ GCC_PREFIX_HEADER = "Target Support Files/MultiProgressView/MultiProgressView-prefix.pch"; INFOPLIST_FILE = "Target Support Files/MultiProgressView/MultiProgressView-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1495,7 +1490,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Imaginary/Imaginary-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Imaginary/Imaginary-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1529,7 +1524,7 @@ GCC_PREFIX_HEADER = "Target Support Files/BEMCheckBox/BEMCheckBox-prefix.pch"; INFOPLIST_FILE = "Target Support Files/BEMCheckBox/BEMCheckBox-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1564,7 +1559,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Imaginary/Imaginary-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Imaginary/Imaginary-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1599,7 +1594,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Lightbox/Lightbox-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Lightbox/Lightbox-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1635,7 +1630,7 @@ DYLIB_INSTALL_NAME_BASE = "@rpath"; INFOPLIST_FILE = "Target Support Files/Pods-Grocery List/Pods-Grocery List-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1673,7 +1668,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Lightbox/Lightbox-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Lightbox/Lightbox-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1709,7 +1704,7 @@ GCC_PREFIX_HEADER = "Target Support Files/BEMCheckBox/BEMCheckBox-prefix.pch"; INFOPLIST_FILE = "Target Support Files/BEMCheckBox/BEMCheckBox-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1755,6 +1750,7 @@ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; @@ -1809,7 +1805,7 @@ GCC_PREFIX_HEADER = "Target Support Files/Cache/Cache-prefix.pch"; INFOPLIST_FILE = "Target Support Files/Cache/Cache-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1845,7 +1841,7 @@ GCC_PREFIX_HEADER = "Target Support Files/MultiProgressView/MultiProgressView-prefix.pch"; INFOPLIST_FILE = "Target Support Files/MultiProgressView/MultiProgressView-Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", diff --git a/StoreViewController.swift b/StoreViewController.swift index 5da8eaf..e3862cf 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -25,18 +25,37 @@ class StoreViewController: UITableViewController { tableView.dataSource = self tableView.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) + self.tableView.register(StoreListHeader.self, forHeaderFooterViewReuseIdentifier: StoreListHeader.reuseIdentifier) + + } + + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 40.0 } - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - return self.store.getCategories()[section].capitalized + override func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { + return 50.0 } override func numberOfSections(in tableView: UITableView) -> Int { return store.categories.count } -// override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { -// -// } + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + guard let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: StoreListHeader.reuseIdentifier) as? StoreListHeader else { return nil } + + let color = UIColor.randomColor() + + view.textLabel?.text = self.store.getCategories()[section].capitalized + view.textLabel?.font = UIFont.systemFont(ofSize: 21.0, weight: .bold) + view.textLabel?.textColor = color + + view.contentView.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) + + view.addButton?.imageView?.tintColor = color + view.addButton?.setImage(UIImage(systemName: "plus", withConfiguration: UIImage.SymbolConfiguration(scale: .large)), for: .normal) + + return view + } } From fa6ce8647a8dc2031311364f96494889ade37afc Mon Sep 17 00:00:00 2001 From: rushadantia Date: Fri, 4 Sep 2020 19:41:29 -0400 Subject: [PATCH 03/22] label size not going up --- StoreViewController.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/StoreViewController.swift b/StoreViewController.swift index e3862cf..9d278bc 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -47,13 +47,14 @@ class StoreViewController: UITableViewController { let color = UIColor.randomColor() view.textLabel?.text = self.store.getCategories()[section].capitalized - view.textLabel?.font = UIFont.systemFont(ofSize: 21.0, weight: .bold) + view.textLabel?.font = UIFont(name: (view.textLabel?.font.fontName)!, size: 30)//UIFont.systemFont(ofSize: 21.0, weight: .bold) + view.textLabel?.sizeToFit() view.textLabel?.textColor = color view.contentView.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) view.addButton?.imageView?.tintColor = color - view.addButton?.setImage(UIImage(systemName: "plus", withConfiguration: UIImage.SymbolConfiguration(scale: .large)), for: .normal) + view.addButton?.setImage(UIImage(systemName: "plus"), for: .normal) return view } From d752a3489ee1a47cee89060efee5af445016944d Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sun, 6 Sep 2020 14:55:21 -0400 Subject: [PATCH 04/22] fixed font color and size --- Grocery List.xcodeproj/project.pbxproj | 8 +++- .../{Views => Cells}/StoreListHeader.swift | 1 + Grocery List/Data Models/Store.swift | 7 +-- .../AddStoreViewController.swift | 43 +++++++------------ .../View Controllers/ColorManager.swift | 41 ++++++++++++++++++ Pods/Pods.xcodeproj/project.pbxproj | 9 +++- StoreViewController.swift | 20 ++++++--- 7 files changed, 87 insertions(+), 42 deletions(-) rename Grocery List/{Views => Cells}/StoreListHeader.swift (99%) create mode 100644 Grocery List/View Controllers/ColorManager.swift diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index b055af5..ea7a134 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 2461A83924882543009BE0AB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83724882543009BE0AB /* LaunchScreen.storyboard */; }; 2461A84324882D1D009BE0AB /* AddItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461A84224882D1D009BE0AB /* AddItemViewController.swift */; }; 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */; }; + 2486580825055E39004F5F59 /* ColorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2486580725055E39004F5F59 /* ColorManager.swift */; }; 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2494FFA7248C10CA00DC58E0 /* DataStore.swift */; }; 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */; }; 24A3C98324F1912F0019D23F /* UIView+DashedBorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */; }; @@ -69,7 +70,7 @@ 2418684724885824003E7C69 /* StoresTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoresTableViewController.swift; sourceTree = ""; }; 2419C7D824B652FD004F5096 /* StrikethroughLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StrikethroughLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 241E7C332501730F00C06241 /* StoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreViewController.swift; sourceTree = SOURCE_ROOT; }; - 241E7C382502E16200C06241 /* StoreListHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreListHeader.swift; path = "Grocery List/Views/StoreListHeader.swift"; sourceTree = SOURCE_ROOT; }; + 241E7C382502E16200C06241 /* StoreListHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreListHeader.swift; path = "Grocery List/Cells/StoreListHeader.swift"; sourceTree = SOURCE_ROOT; }; 241F0F7B24B7A35800A3F67C /* ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; 2423A01C24BB93CC0089181C /* Grocery ListTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Grocery ListTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grocery_ListTests.swift; sourceTree = ""; }; @@ -91,6 +92,7 @@ 2461A840248829B6009BE0AB /* TableController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableController.swift; sourceTree = ""; }; 2461A84224882D1D009BE0AB /* AddItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddItemViewController.swift; sourceTree = ""; }; 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreIconManager.swift; path = "Grocery List/View Controllers/StoreIconManager.swift"; sourceTree = SOURCE_ROOT; }; + 2486580725055E39004F5F59 /* ColorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorManager.swift; path = "Grocery List/View Controllers/ColorManager.swift"; sourceTree = SOURCE_ROOT; }; 2494FFA7248C10CA00DC58E0 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = ""; }; 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddStoreCell.swift; sourceTree = ""; }; 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+DashedBorder.swift"; sourceTree = ""; }; @@ -153,7 +155,6 @@ 2418684924885827003E7C69 /* View Controllers */ = { isa = PBXGroup; children = ( - 241E7C382502E16200C06241 /* StoreListHeader.swift */, 241E7C332501730F00C06241 /* StoreViewController.swift */, 2461A840248829B6009BE0AB /* TableController.swift */, 2418684724885824003E7C69 /* StoresTableViewController.swift */, @@ -223,6 +224,7 @@ 247E02E724DDF32600148580 /* Other */ = { isa = PBXGroup; children = ( + 2486580725055E39004F5F59 /* ColorManager.swift */, 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */, 2409D27424A7D738001FAD06 /* ImagePicker.swift */, ); @@ -232,6 +234,7 @@ 24A3C98124F180B50019D23F /* Cells */ = { isa = PBXGroup; children = ( + 241E7C382502E16200C06241 /* StoreListHeader.swift */, 24F91AEB24F0589E0064FDBB /* CategoryCell.swift */, 24390CBE24C61B6700189D75 /* StoreCell.swift */, 241F0F7B24B7A35800A3F67C /* ItemCell.swift */, @@ -470,6 +473,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 2486580825055E39004F5F59 /* ColorManager.swift in Sources */, 241E7C342501730F00C06241 /* StoreViewController.swift in Sources */, 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */, 24E5F40324EB16B7007DA4BE /* UIView+Separator.swift in Sources */, diff --git a/Grocery List/Views/StoreListHeader.swift b/Grocery List/Cells/StoreListHeader.swift similarity index 99% rename from Grocery List/Views/StoreListHeader.swift rename to Grocery List/Cells/StoreListHeader.swift index 52a04e3..0988cf4 100644 --- a/Grocery List/Views/StoreListHeader.swift +++ b/Grocery List/Cells/StoreListHeader.swift @@ -24,6 +24,7 @@ class StoreListHeader: UITableViewHeaderFooterView { addButton?.heightAnchor.constraint(equalToConstant: 24).isActive = true addButton?.trailingAnchor.constraint(equalTo: contentView.layoutMarginsGuide.trailingAnchor).isActive = true addButton?.bottomAnchor.constraint(equalTo: contentView.layoutMarginsGuide.bottomAnchor).isActive = true + } required init?(coder: NSCoder) { diff --git a/Grocery List/Data Models/Store.swift b/Grocery List/Data Models/Store.swift index 7ff8797..eeb7b9f 100644 --- a/Grocery List/Data Models/Store.swift +++ b/Grocery List/Data Models/Store.swift @@ -128,12 +128,7 @@ class Store: Codable { } public func getCategories() -> [String] { - var categories = [String]() - - for c in self.categories { - categories.append(c.name.lowercased()) - } - return categories + return self.categories.map { c in c.name.lowercased()} } public func getNumNonDoneItems() -> Int { diff --git a/Grocery List/View Controllers/AddStoreViewController.swift b/Grocery List/View Controllers/AddStoreViewController.swift index 2307f27..d420332 100644 --- a/Grocery List/View Controllers/AddStoreViewController.swift +++ b/Grocery List/View Controllers/AddStoreViewController.swift @@ -16,24 +16,13 @@ class AddStoreViewController: UIViewController { @IBOutlet var categoriesCollection: UICollectionView! - let CustomGrey = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1) + var parentVC: StoresTableViewController? var currentIcon: String! - var defaults = [ - ["veggies", UIColor(red: 0.40, green: 0.77, blue: 0.40, alpha: 1.00)], - ["fruits", UIColor(red: 0.96, green: 0.60, blue: 0.00, alpha: 1.00)], - ["meats", UIColor(red: 0.93, green: 0.11, blue: 0.14, alpha: 1.00)], - ["dairy", UIColor(red: 0.13, green: 0.57, blue: 0.98, alpha: 1.00)], - ["bread", UIColor(red: 0.81, green: 0.36, blue: 0.21, alpha: 1.00)], - ["snacks", UIColor(red: 0.00, green: 0.57, blue: 0.68, alpha: 1.00)], - ["cleaning supplies", UIColor(red: 1.00, green: 0.78, blue: 0.00, alpha: 1.00)], - ["beauty", UIColor(red: 0.99, green: 0.38, blue: 0.66, alpha: 1.00)], - ["baking", UIColor(red: 0.61, green: 0.46, blue: 0.325, alpha: 1)], - ["frozen foods", UIColor(red: 0.54, green: 0.82, blue: 0.86, alpha: 1.00)], - ] + var defaults = ColorManager.defaultsArr var selectedCategories = Set() @@ -42,11 +31,11 @@ class AddStoreViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - + toolbarView.addSeparator(at: .top, color: #colorLiteral(red: 0.7764705882, green: 0.7764705882, blue: 0.7960784314, alpha: 1), weight: 1.0, insets: .zero) storeField.inputAccessoryView = toolbarView - storeField.attributedPlaceholder = NSAttributedString(string: "New List", attributes: [NSAttributedString.Key.foregroundColor: CustomGrey]) + storeField.attributedPlaceholder = NSAttributedString(string: "New List", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) toolbarView.add.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(addList))) toolbarView.image.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(iconClicked))) @@ -80,7 +69,7 @@ class AddStoreViewController: UIViewController { storeToEdit?.getCategories().forEach { storeCat in if !defaultCats.contains(storeCat), storeCat != "other" { - defaults.append([storeCat, CustomGrey]) + defaults.append([storeCat, ColorManager.CUSTOMGRAY]) selectedCategories.insert(storeCat) } } @@ -261,11 +250,11 @@ extension AddStoreViewController: UICollectionViewDataSource { cell.checkbox.reload() } else { cell.checkbox.on = false - cell.label.textColor = CustomGrey + cell.label.textColor = ColorManager.CUSTOMGRAY cell.contentView.layer.backgroundColor = UIColor.white.cgColor - cell.contentView.layer.borderColor = CustomGrey.cgColor - cell.checkbox.onTintColor = CustomGrey + cell.contentView.layer.borderColor = ColorManager.CUSTOMGRAY.cgColor + cell.checkbox.onTintColor = ColorManager.CUSTOMGRAY cell.checkbox.onCheckColor = .white cell.checkbox.reload() } @@ -279,12 +268,12 @@ extension AddStoreViewController: UICollectionViewDataSource { } else { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "addStoreCell", for: indexPath) as! AddStoreCell - cell.textfield.attributedPlaceholder = NSAttributedString(string: "Add New Category", attributes: [NSAttributedString.Key.foregroundColor: CustomGrey]) - cell.textfield.textColor = CustomGrey + cell.textfield.attributedPlaceholder = NSAttributedString(string: "Add New Category", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) + cell.textfield.textColor = ColorManager.CUSTOMGRAY cell.textfield.inputAccessoryView = toolbarView cell.textfield.delegate = self - cell.contentView.addDashedBorder(color: CustomGrey) + cell.contentView.addDashedBorder(color: ColorManager.CUSTOMGRAY) cell.contentView.layer.cornerRadius = 15.0 return cell @@ -302,15 +291,15 @@ extension AddStoreViewController: UICollectionViewDelegate { cell.checkbox.setOn(isOn, animated: true) UIView.animate(withDuration: 0.5, animations: { - cell.label.textColor = isOn ? .white : self.CustomGrey + cell.label.textColor = isOn ? .white : ColorManager.CUSTOMGRAY cell.contentView.layer.backgroundColor = isOn ? currColor : UIColor.white.cgColor - cell.contentView.layer.borderColor = isOn ? currColor : self.CustomGrey.cgColor + cell.contentView.layer.borderColor = isOn ? currColor : ColorManager.CUSTOMGRAY.cgColor }, completion: { _ in cell.checkbox.offFillColor = .white cell.checkbox.onFillColor = .white - cell.checkbox.onTintColor = isOn ? UIColor(cgColor: currColor) : self.CustomGrey + cell.checkbox.onTintColor = isOn ? UIColor(cgColor: currColor) : ColorManager.CUSTOMGRAY cell.checkbox.onCheckColor = isOn ? UIColor(cgColor: currColor) : .white }) @@ -341,10 +330,10 @@ extension AddStoreViewController: UITextFieldDelegate { if text == "" || currentCategories.contains(text.lowercased()) || text.count > 32 || text.lowercased() == "other" { cell.contentView.addDashedBorder(color: .red) } else { - defaults.append([text.lowercased(), CustomGrey]) + defaults.append([text.lowercased(), ColorManager.CUSTOMGRAY]) selectedCategories.insert(text.lowercased()) categoriesCollection.reloadData() - cell.contentView.addDashedBorder(color: CustomGrey) + cell.contentView.addDashedBorder(color: ColorManager.CUSTOMGRAY) } } diff --git a/Grocery List/View Controllers/ColorManager.swift b/Grocery List/View Controllers/ColorManager.swift new file mode 100644 index 0000000..4d48127 --- /dev/null +++ b/Grocery List/View Controllers/ColorManager.swift @@ -0,0 +1,41 @@ +// +// ColorManager.swift +// Grocery List +// +// Created by Rushad Antia on 9/6/20. +// Copyright © 2020 Rushad Antia. All rights reserved. +// + +import Foundation +import UIKit + +class ColorManager { + static let defaultsArr = [ + ["veggies", UIColor(red: 0.40, green: 0.77, blue: 0.40, alpha: 1.00)], + ["fruits", UIColor(red: 0.96, green: 0.60, blue: 0.00, alpha: 1.00)], + ["meats", UIColor(red: 0.93, green: 0.11, blue: 0.14, alpha: 1.00)], + ["dairy", UIColor(red: 0.13, green: 0.57, blue: 0.98, alpha: 1.00)], + ["bread", UIColor(red: 0.81, green: 0.36, blue: 0.21, alpha: 1.00)], + ["snacks", UIColor(red: 0.00, green: 0.57, blue: 0.68, alpha: 1.00)], + ["cleaning supplies", UIColor(red: 1.00, green: 0.78, blue: 0.00, alpha: 1.00)], + ["beauty", UIColor(red: 0.99, green: 0.38, blue: 0.66, alpha: 1.00)], + ["baking", UIColor(red: 0.61, green: 0.46, blue: 0.325, alpha: 1)], + ["frozen foods", UIColor(red: 0.54, green: 0.82, blue: 0.86, alpha: 1.00)] + ] + + static let defaultsMap: [String: UIColor] = [ + "veggies": UIColor(red: 0.40, green: 0.77, blue: 0.40, alpha: 1.00), + "fruits": UIColor(red: 0.96, green: 0.60, blue: 0.00, alpha: 1.00), + "meats": UIColor(red: 0.93, green: 0.11, blue: 0.14, alpha: 1.00), + "dairy": UIColor(red: 0.13, green: 0.57, blue: 0.98, alpha: 1.00), + "bread": UIColor(red: 0.81, green: 0.36, blue: 0.21, alpha: 1.00), + "snacks": UIColor(red: 0.00, green: 0.57, blue: 0.68, alpha: 1.00), + "cleaning supplies": UIColor(red: 1.00, green: 0.78, blue: 0.00, alpha: 1.00), + "beauty": UIColor(red: 0.99, green: 0.38, blue: 0.66, alpha: 1.00), + "baking": UIColor(red: 0.61, green: 0.46, blue: 0.325, alpha: 1), + "frozen foods": UIColor(red: 0.54, green: 0.82, blue: 0.86, alpha: 1.00), + "other": CUSTOMGRAY + ] + + static let CUSTOMGRAY = UIColor(red: 0.6, green: 0.6, blue: 0.6, alpha: 1) +} diff --git a/Pods/Pods.xcodeproj/project.pbxproj b/Pods/Pods.xcodeproj/project.pbxproj index f40ae67..6aaa556 100644 --- a/Pods/Pods.xcodeproj/project.pbxproj +++ b/Pods/Pods.xcodeproj/project.pbxproj @@ -956,6 +956,11 @@ attributes = { LastSwiftUpdateCheck = 1100; LastUpgradeCheck = 1200; + TargetAttributes = { + 3A186D5E4FEF43A5AF44DB305B59EC1F = { + LastSwiftMigration = 1200; + }; + }; }; buildConfigurationList = 4821239608C13582E20E6DA73FD5F1F9 /* Build configuration list for PBXProject "Pods" */; compatibilityVersion = "Xcode 10.0"; @@ -1360,7 +1365,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -1430,7 +1435,7 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) "; - SWIFT_VERSION = 4.2; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/StoreViewController.swift b/StoreViewController.swift index 9d278bc..4576cf0 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -44,19 +44,29 @@ class StoreViewController: UITableViewController { override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { guard let view = tableView.dequeueReusableHeaderFooterView(withIdentifier: StoreListHeader.reuseIdentifier) as? StoreListHeader else { return nil } - let color = UIColor.randomColor() + let catName = self.store.getCategories()[section].lowercased() - view.textLabel?.text = self.store.getCategories()[section].capitalized - view.textLabel?.font = UIFont(name: (view.textLabel?.font.fontName)!, size: 30)//UIFont.systemFont(ofSize: 21.0, weight: .bold) - view.textLabel?.sizeToFit() + var color: UIColor? = ColorManager.CUSTOMGRAY + + if (ColorManager.defaultsMap.keys.contains(catName)) { + color = ColorManager.defaultsMap[catName] + } + + view.textLabel?.text = catName.capitalized view.textLabel?.textColor = color view.contentView.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) view.addButton?.imageView?.tintColor = color - view.addButton?.setImage(UIImage(systemName: "plus"), for: .normal) + view.addButton?.setImage(UIImage(systemName: "plus", withConfiguration: UIImage.SymbolConfiguration(pointSize: 16, weight: .bold)), for: .normal) return view } + override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + if let header = view as? StoreListHeader { + header.textLabel?.font = UIFont.systemFont(ofSize: 20, weight: UIFont.Weight.init(rawValue: 0.600)) + } + } + } From 1bc56013518eb0c74ccf770deb0fdebd4e07699f Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sun, 6 Sep 2020 15:42:34 -0400 Subject: [PATCH 05/22] added store cell --- Grocery List.xcodeproj/project.pbxproj | 8 ++- Grocery List/Cells/ItemCellCollapsible.swift | 26 ++++++++ Grocery List/Views/Base.lproj/Main.storyboard | 63 +++++++++++++++++-- StoreViewController.swift | 8 +++ 4 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 Grocery List/Cells/ItemCellCollapsible.swift diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index ea7a134..f7ef64d 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -14,7 +14,6 @@ 2418684824885824003E7C69 /* StoresTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2418684724885824003E7C69 /* StoresTableViewController.swift */; }; 241E7C342501730F00C06241 /* StoreViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241E7C332501730F00C06241 /* StoreViewController.swift */; }; 241E7C392502E16200C06241 /* StoreListHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241E7C382502E16200C06241 /* StoreListHeader.swift */; }; - 241F0F7C24B7A35800A3F67C /* ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 241F0F7B24B7A35800A3F67C /* ItemCell.swift */; }; 2423A01F24BB93CC0089181C /* Grocery_ListTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */; }; 2427D72B2502E97500BEB252 /* MultiProgressView.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2427D72A2502E97500BEB252 /* MultiProgressView.framework */; }; 2427D72F2502F53700BEB252 /* UIColor+RandomColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2427D72E2502F53700BEB252 /* UIColor+RandomColor.swift */; }; @@ -30,6 +29,7 @@ 2461A84324882D1D009BE0AB /* AddItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461A84224882D1D009BE0AB /* AddItemViewController.swift */; }; 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */; }; 2486580825055E39004F5F59 /* ColorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2486580725055E39004F5F59 /* ColorManager.swift */; }; + 2492D62A250570BD00BAE3DA /* ItemCellCollapsible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */; }; 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2494FFA7248C10CA00DC58E0 /* DataStore.swift */; }; 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */; }; 24A3C98324F1912F0019D23F /* UIView+DashedBorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */; }; @@ -93,6 +93,7 @@ 2461A84224882D1D009BE0AB /* AddItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddItemViewController.swift; sourceTree = ""; }; 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreIconManager.swift; path = "Grocery List/View Controllers/StoreIconManager.swift"; sourceTree = SOURCE_ROOT; }; 2486580725055E39004F5F59 /* ColorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorManager.swift; path = "Grocery List/View Controllers/ColorManager.swift"; sourceTree = SOURCE_ROOT; }; + 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCellCollapsible.swift; sourceTree = ""; }; 2494FFA7248C10CA00DC58E0 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = ""; }; 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddStoreCell.swift; sourceTree = ""; }; 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+DashedBorder.swift"; sourceTree = ""; }; @@ -237,8 +238,9 @@ 241E7C382502E16200C06241 /* StoreListHeader.swift */, 24F91AEB24F0589E0064FDBB /* CategoryCell.swift */, 24390CBE24C61B6700189D75 /* StoreCell.swift */, - 241F0F7B24B7A35800A3F67C /* ItemCell.swift */, 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */, + 241F0F7B24B7A35800A3F67C /* ItemCell.swift */, + 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */, ); path = Cells; sourceTree = ""; @@ -479,7 +481,7 @@ 24E5F40324EB16B7007DA4BE /* UIView+Separator.swift in Sources */, 241E7C392502E16200C06241 /* StoreListHeader.swift in Sources */, 24F91AEC24F0589E0064FDBB /* CategoryCell.swift in Sources */, - 241F0F7C24B7A35800A3F67C /* ItemCell.swift in Sources */, + 2492D62A250570BD00BAE3DA /* ItemCellCollapsible.swift in Sources */, 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */, 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */, 2427D72F2502F53700BEB252 /* UIColor+RandomColor.swift in Sources */, diff --git a/Grocery List/Cells/ItemCellCollapsible.swift b/Grocery List/Cells/ItemCellCollapsible.swift new file mode 100644 index 0000000..1e0a2b7 --- /dev/null +++ b/Grocery List/Cells/ItemCellCollapsible.swift @@ -0,0 +1,26 @@ +// +// ItemCellCollapsible.swift +// Grocery List +// +// Created by Rushad Antia on 9/6/20. +// Copyright © 2020 Rushad Antia. All rights reserved. + +import Lightbox +import UIKit +import BEMCheckBox + +class ItemCellCollapsible: UITableViewCell { + + @IBOutlet var checkbox: BEMCheckBox! + @IBOutlet var itemLabel: UILabel! + @IBOutlet var itemImageView: UIImageView! + @IBOutlet var descriptionLabel: UILabel! + + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } +} diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index 3314dd6..809796b 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -56,14 +56,61 @@ - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -99,7 +146,7 @@ - + @@ -493,6 +540,14 @@ + + + + + + + + diff --git a/StoreViewController.swift b/StoreViewController.swift index 4576cf0..9f62059 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -29,6 +29,14 @@ class StoreViewController: UITableViewController { } + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + print(self.store.categories[indexPath[0]].items[indexPath[1]]) + } + + + + // MARK: - Start Header + override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 40.0 } From 6c9553a82cb433e412bd257ed56f65e720dd5975 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sun, 6 Sep 2020 15:53:09 -0400 Subject: [PATCH 06/22] do later --- Grocery List.xcodeproj/project.pbxproj | 6 - .../AddItemViewController.swift | 165 --------- .../View Controllers/TableController.swift | 341 ------------------ 3 files changed, 512 deletions(-) delete mode 100644 Grocery List/View Controllers/AddItemViewController.swift delete mode 100644 Grocery List/View Controllers/TableController.swift diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index f7ef64d..8f86301 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -26,7 +26,6 @@ 2461A83424882541009BE0AB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83224882541009BE0AB /* Main.storyboard */; }; 2461A83624882543009BE0AB /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83524882543009BE0AB /* Assets.xcassets */; }; 2461A83924882543009BE0AB /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2461A83724882543009BE0AB /* LaunchScreen.storyboard */; }; - 2461A84324882D1D009BE0AB /* AddItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2461A84224882D1D009BE0AB /* AddItemViewController.swift */; }; 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */; }; 2486580825055E39004F5F59 /* ColorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2486580725055E39004F5F59 /* ColorManager.swift */; }; 2492D62A250570BD00BAE3DA /* ItemCellCollapsible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */; }; @@ -89,8 +88,6 @@ 2461A83524882543009BE0AB /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 2461A83824882543009BE0AB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 2461A83A24882543009BE0AB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 2461A840248829B6009BE0AB /* TableController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableController.swift; sourceTree = ""; }; - 2461A84224882D1D009BE0AB /* AddItemViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddItemViewController.swift; sourceTree = ""; }; 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreIconManager.swift; path = "Grocery List/View Controllers/StoreIconManager.swift"; sourceTree = SOURCE_ROOT; }; 2486580725055E39004F5F59 /* ColorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorManager.swift; path = "Grocery List/View Controllers/ColorManager.swift"; sourceTree = SOURCE_ROOT; }; 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCellCollapsible.swift; sourceTree = ""; }; @@ -157,9 +154,7 @@ isa = PBXGroup; children = ( 241E7C332501730F00C06241 /* StoreViewController.swift */, - 2461A840248829B6009BE0AB /* TableController.swift */, 2418684724885824003E7C69 /* StoresTableViewController.swift */, - 2461A84224882D1D009BE0AB /* AddItemViewController.swift */, 24E5F40024EB14D5007DA4BE /* AddStoreViewController.swift */, 24E5F3FE24EB1345007DA4BE /* ToolBarView.swift */, ); @@ -489,7 +484,6 @@ 24E5F40124EB14D5007DA4BE /* AddStoreViewController.swift in Sources */, 2418684324884B42003E7C69 /* Category.swift in Sources */, 241525B724AAAD56000DE4BA /* Item.swift in Sources */, - 2461A84324882D1D009BE0AB /* AddItemViewController.swift in Sources */, 24E5F3FF24EB1345007DA4BE /* ToolBarView.swift in Sources */, 2418684524884B6C003E7C69 /* Store.swift in Sources */, 2409D27524A7D738001FAD06 /* ImagePicker.swift in Sources */, diff --git a/Grocery List/View Controllers/AddItemViewController.swift b/Grocery List/View Controllers/AddItemViewController.swift deleted file mode 100644 index 48b32a9..0000000 --- a/Grocery List/View Controllers/AddItemViewController.swift +++ /dev/null @@ -1,165 +0,0 @@ -// -// AddItem.swift -// Grocery List -// -// Created by Rushad Antia on 6/3/20. -// Copyright © 2020 Rushad Antia. All rights reserved. -// - -import Foundation -import UIKit - -class AddItemViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate { - var store: Store? - var selectedCategory: Int? - - var editMode = false - var itemToEdit: String = "" - var itemCategory: String = "" - var item: Item = Item() - - var imagePicker: ImagePicker! - - @IBOutlet var textField: UITextField! - @IBOutlet var tableView: UITableView! - - @IBOutlet var addButton: UIBarButtonItem! - - @IBOutlet var addImageBtn: UIButton! - - override func viewDidLoad() { - super.viewDidLoad() - navigationController?.setToolbarHidden(false, animated: true) - navigationItem.largeTitleDisplayMode = .never - - addImageBtn.layer.cornerRadius = 10 - addImageBtn.layer.borderWidth = 3 - addImageBtn.layer.borderColor = #colorLiteral(red: 0.9921568627, green: 0, blue: 0.4274509804, alpha: 1) - addImageBtn.clipsToBounds = true - - tableView.delegate = self - tableView.dataSource = self - tableView.allowsSelection = true - tableView.separatorColor = .clear - tableView.tableFooterView = UIView() - - textField.delegate = self - - let tapGR = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) - tapGR.cancelsTouchesInView = false - view.addGestureRecognizer(tapGR) - - imagePicker = ImagePicker(presentationController: self, delegate: self) - - // if we are editing an item - if editMode { - textField.text = itemToEdit - - if let categoryRow = store!.categories.firstIndex(where: { $0.name == itemCategory }) { - selectedCategory = categoryRow - } - - navigationItem.title = "Edit Item" - addButton.title = "Edit Item" - - addImageBtn.layer.backgroundColor = UIColor.gray.cgColor - addImageBtn.isEnabled = false - - if item.hasImage { - addImageBtn.setImage(item.getGreyImage(), for: .normal) - } - - addImageBtn.layer.borderColor = #colorLiteral(red: 0.2549019754, green: 0.2745098174, blue: 0.3019607961, alpha: 1) - - } else { - navigationItem.title = "Add Item" - addButton.title = "Add Item" - } - } - - @objc func dismissKeyboard() { - view.endEditing(true) - } - - // show the image picker - @IBAction func addImage(_ sender: UIButton) { - imagePicker.present(from: sender) - } - - // add an item or edit an item - @IBAction func addItem(_: Any) { - if !textField.text!.isEmpty, selectedCategory != nil { - let category = store!.categories[selectedCategory!] - - if editMode { - if category.name != itemCategory { - store?.deleteItem(category: itemCategory, item: item) - let newItem = item.hasImage ? Item(name: textField.text!.capitalized, isFave: item.isFavorite, imageString: item.imageString!, isDone: item.isDone) : Item(name: textField.text!.capitalized, isFave: item.isFavorite, isDone: item.isDone) - store?.addItem(category: (store?.categories[selectedCategory!])!, item: newItem) - } else { - if let row = store!.categories[selectedCategory!].getItems().firstIndex(where: { $0 == itemToEdit }) { - store!.editItem(category: category, itemIndex: row, newItemName: textField.text!.capitalized) - } - } - } else { - let toAdd = Item(name: textField.text!.capitalized) - - if let image = addImageBtn.backgroundImage(for: .normal) { - let imageData = image.jpegData(compressionQuality: 0.3) - let imageb64 = imageData?.base64EncodedString() - - if let i64 = imageb64 { - toAdd.imageString = i64 - } - } - - store?.addItem(category: category, item: toAdd) - } - navigationController?.popViewController(animated: true) - } - } - - /* TABLE VIEW STUFF */ - func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int { - return store?.categories.count ?? 0 - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "cell") ?? UITableViewCell(style: .default, reuseIdentifier: "cell") - - cell.textLabel?.text = store?.categories[indexPath.row].name - cell.textLabel?.font = UIFont(name: "Avenir-Medium", size: 14) - - return cell - } - - func tableView(_: UITableView, didSelectRowAt indexPath: IndexPath) { - selectedCategory = indexPath.row - - textField.resignFirstResponder() - } - - func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? { - if let oldIndex = tableView.indexPathForSelectedRow { - tableView.cellForRow(at: oldIndex)?.accessoryType = .none - } - - tableView.cellForRow(at: indexPath)?.accessoryType = .checkmark - - return indexPath - } - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - view.endEditing(true) - return true - } -} - -extension AddItemViewController: ImagePickerDelegate { - func didSelect(image: UIImage?) { - addImageBtn.setBackgroundImage(image, for: .normal) - addImageBtn.imageView?.layer.cornerRadius = 10 - addImageBtn.setImage(nil, for: .normal) - } -} diff --git a/Grocery List/View Controllers/TableController.swift b/Grocery List/View Controllers/TableController.swift deleted file mode 100644 index 0877aa0..0000000 --- a/Grocery List/View Controllers/TableController.swift +++ /dev/null @@ -1,341 +0,0 @@ -// -// TableController.swift -// Grocery List -// -// Created by Rushad Antia on 6/3/20. -// Copyright © 2020 Rushad Antia. All rights reserved. -// - -import BLTNBoard -import Foundation -import InstantSearchVoiceOverlay -import UIKit - -class TableController: UITableViewController { - var store = Store() - var isCollapsed = false - let vc = VoiceOverlayController() - - var bulletinManager: BLTNItemManager? - - override func viewDidLoad() { - super.viewDidLoad() - navigationController?.setToolbarHidden(false, animated: true) - navigationItem.largeTitleDisplayMode = .never - navigationItem.title = store.name.capitalized - - tableView.estimatedRowHeight = 44.0 - tableView.rowHeight = UITableView.automaticDimension - - tableView.delegate = self - - // add share list bar item - let shareBar = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(TableController.userDidTapShare)) - navigationItem.rightBarButtonItem = shareBar - - // collapse items on tapping the bar - let barTap = UITapGestureRecognizer(target: self, action: #selector(didTapBar)) - navigationController?.navigationBar.addGestureRecognizer(barTap) - - // add pull to refresh - refreshControl = UIRefreshControl() - refreshControl!.tintColor = .white - tableView.addSubview(refreshControl!) - refreshControl!.addTarget(self, action: #selector(refreshTableData), for: .valueChanged) - - if let savedStore = DataStore.getStoreData(store: store) { - store = savedStore - tableView.reloadData() - } - - tableView.register(ItemCell.self, forCellReuseIdentifier: "cell") - - // setup voice controller - vc.settings.autoStart = true - vc.settings.autoStop = true - vc.settings.autoStopTimeout = 1 - - vc.settings.showResultScreen = false - - vc.settings.layout.inputScreen.subtitleBulletList = ["Add item [under] [category name]", "Add item [category] [category name]"] - vc.settings.layout.inputScreen.titleListening = "Listening for item" - vc.settings.layout.permissionScreen.backgroundColor = .red - - tableView.separatorColor = .clear - tableView.tableFooterView = UIView() - } - - // action for when a user is done shopping - @IBAction func finishShopping() { - bulletinManager = BLTNItemManager(rootItem: makeFinishShoppingBulletin()) - bulletinManager!.backgroundViewStyle = .blurredDark - bulletinManager!.showBulletin(above: self) - } - - func makeFinishShoppingBulletin() -> BLTNPageItem { - let page = BLTNPageItem(title: "Finished shopping?") - - page.isDismissable = true - page.descriptionText = "Enter a Store Name" - - page.appearance.actionButtonColor = #colorLiteral(red: 0.9911134839, green: 0.0004280109715, blue: 0.4278825819, alpha: 1) - page.appearance.alternativeButtonTitleColor = #colorLiteral(red: 0.9911134839, green: 0.0004280109715, blue: 0.4278825819, alpha: 1) - page.appearance.actionButtonTitleColor = .white - page.appearance.titleTextColor = .white - - if store.getNumNonDoneItems() == 0 { - page.descriptionText = "Are you sure?" - } else { - page.descriptionText = "Your list still has \(store.getNumNonDoneItems()) items left" - } - - page.actionButtonTitle = "Yes" - page.alternativeButtonTitle = "Cancel" - - page.isDismissable = true - - page.actionHandler = { _ in - self.store.finishShopping() - self.tableView.reloadData() - self.bulletinManager?.dismissBulletin(animated: true) - } - - page.alternativeHandler = { _ in - self.bulletinManager?.dismissBulletin(animated: true) - } - - return page - } - - // add an item button click - @IBAction func addItem(_: Any) { - performSegue(withIdentifier: "toAdd", sender: store) - } - - // add an item with the voice controller - @IBAction func addItemVoice(_: Any) { - vc.start(on: self, textHandler: { text, final, _ in - if final { - self.store.addItemFromVoiceString(text) - - self.tableView.reloadData() - } - }, errorHandler: { error in - print(error ?? "Error") - }) - } - - // refresh all the data in the table on pull - @objc func refreshTableData() { - if let savedStore = DataStore.getStoreData(store: store) { - store = savedStore - tableView.reloadData() - } - - var paths: [IndexPath] = [IndexPath]() - - for i in 0 ..< store.categories.count { - let count = tableView.numberOfRows(inSection: i) - paths.append(contentsOf: (0 ..< count).map { IndexPath(row: $0, section: i) }) - } - - tableView.reloadRows(at: paths, with: .left) - refreshControl?.endRefreshing() - } - - // collapse or dont collapse all items - @objc func didTapBar() { - for c in store.categories { - c.collapsed = isCollapsed - } - isCollapsed.toggle() - tableView.reloadData() - } - - // function to export list to share - @objc func userDidTapShare() { - let url = store.exportToURL() - - let activity = UIActivityViewController(activityItems: ["Here is my list for \(store.name)", url!], applicationActivities: nil) - - present(activity, animated: true, completion: nil) - } - - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - if segue.destination is AddItemViewController { - let vc = segue.destination as? AddItemViewController - - if segue.identifier == "toAdd" { - let s = sender as? Store - vc?.store = s! - } else if segue.identifier == "toEdit" { - let s = sender as? (String, Store, String, Item) - vc?.store = s!.1 - vc?.itemToEdit = s!.0 - vc?.itemCategory = s!.2 - vc?.item = s!.3 - vc?.editMode = true - } - } - } - - // resave store on view shown and reload - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - navigationController?.setToolbarHidden(false, animated: true) - if let savedStore = DataStore.getStoreData(store: store) { - store = savedStore - } - tableView.reloadData() - } - - // add edit functionality - override func tableView(_: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - let action = UIContextualAction(style: .normal, title: "Edit") { [self] _, _, completion in - let item = self.store.categories[indexPath[0]].items[indexPath[1]] - - self.performSegue(withIdentifier: "toEdit", sender: (item.name, self.store, self.store.categories[indexPath[0]].name, item)) - completion(true) - } - action.title = "Edit" - - action.backgroundColor = .systemBlue - return UISwipeActionsConfiguration(actions: [action]) - } - - override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - let item = store.categories[indexPath.section].items[indexPath.row] - - let delete = UIContextualAction(style: .normal, title: "Delete") { [self] _, _, completion in - if item.isFavorite == false { - // delete the data from the thing and make it persist - self.store.categories[indexPath[0]].items.remove(at: indexPath[1]) - tableView.beginUpdates() - tableView.deleteRows(at: [indexPath], with: .fade) - tableView.endUpdates() - self.store.save() - - tableView.reloadData() - } - completion(true) - } - - delete.title = "Delete" - delete.backgroundColor = item.isFavorite ? .gray : .systemRed - - // swipe action to mark item as done - let done = UIContextualAction(style: .normal, title: "Done") { [self] _, _, completion in - - // get the selected item and toggle its "doneness" - let item = self.store.categories[indexPath[0]].items[indexPath[1]] - item.isDone.toggle() - - // if thats the last item of the section then collapse it - if self.store.categories[indexPath[0]].getNonDoneItems() == 0 { - let sectionHeader = tableView.headerView(forSection: indexPath.section) as! CollapsibleTableViewHeader - sectionHeader.delegate?.toggleSection(sectionHeader, section: indexPath.section) - } - - // reload table to trigger rerender of info - tableView.reloadData() - - // make the change persist - self.store.save() - - completion(true) - } - - done.title = "Done" - done.backgroundColor = .blue - - return UISwipeActionsConfiguration(actions: [done, delete]) - } - - // return number of categories in the store - override func numberOfSections(in _: UITableView) -> Int { - return store.categories.count - } - - // return the number of items in the category - override func tableView(_: UITableView, numberOfRowsInSection section: Int) -> Int { - return store.categories[section].collapsed ? 0 : store.categories[section].items.count - } - - override func tableView(_: UITableView, heightForRowAt _: IndexPath) -> CGFloat { - return UITableView.automaticDimension - } - - // return the collapsible header - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "header") as? CollapsibleTableViewHeader ?? CollapsibleTableViewHeader(reuseIdentifier: "header") - - header.titleLabel.text = store.categories[section].name.capitalized - header.titleLabel.font = UIFont(name: "Avenir-Medium", size: 14) - - header.arrowLabel.font = UIFont(name: "Avenir-Medium", size: 14) - - let numItems = store.categories[section].getNonDoneItems() - - header.setCollapsed(store.categories[section].collapsed, numItems) - - header.section = section - header.delegate = self - return header - } - - // header height - override func tableView(_: UITableView, heightForHeaderInSection _: Int) -> CGFloat { - return 34 - } - - // style the cells - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! ItemCell - - let item = store.categories[indexPath.section].items[indexPath.row] - - cell.item = item - cell.store = store - - cell.setItemTitle() - cell.setImageView() - cell.setFavorite() - - return cell - } - - // allow row movement - override func tableView(_: UITableView, canEditRowAt _: IndexPath) -> Bool { - return true - } - - override func tableView(_: UITableView, willDisplay cell: UITableViewCell, forRowAt _: IndexPath) { - cell.contentView.layer.masksToBounds = true - - let radius = cell.contentView.layer.cornerRadius - cell.layer.shadowPath = UIBezierPath(roundedRect: cell.bounds, cornerRadius: radius).cgPath - } - - override func viewWillDisappear(_ animated: Bool) { - super.viewWillDisappear(animated) - - // just save incase something happens between segues - if isMovingFromParent { - store.save() - } - tableView.reloadData() - } -} - -extension TableController: CollapsibleTableViewHeaderDelegate { - func toggleSection(_ header: CollapsibleTableViewHeader, section: Int) { - let collapsed = !store.categories[section].collapsed - - if store.categories[section].items.count != 0 { - store.categories[section].collapsed = collapsed - header.setCollapsed(collapsed, store.categories[section].getNonDoneItems()) - } - - tableView.reloadSections(NSIndexSet(index: section) as IndexSet, with: .automatic) - } -} From dbe4a4cd6735569e55c82880ccaeb41d49b39b5b Mon Sep 17 00:00:00 2001 From: rushadantia Date: Wed, 9 Sep 2020 18:21:03 -0400 Subject: [PATCH 07/22] + gives u the add item cell. formatting is still broken --- Grocery List.xcodeproj/project.pbxproj | 6 +- Grocery List/Cells/ItemCell.swift | 125 ------------------ Grocery List/Data Models/Category.swift | 4 +- Grocery List/Views/AddItemCell.swift | 17 +++ Grocery List/Views/Base.lproj/Main.storyboard | 67 ++++++++-- StoreViewController.swift | 32 ++++- 6 files changed, 109 insertions(+), 142 deletions(-) delete mode 100644 Grocery List/Cells/ItemCell.swift create mode 100644 Grocery List/Views/AddItemCell.swift diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index 8f86301..32f9e4f 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -29,6 +29,7 @@ 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */; }; 2486580825055E39004F5F59 /* ColorManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2486580725055E39004F5F59 /* ColorManager.swift */; }; 2492D62A250570BD00BAE3DA /* ItemCellCollapsible.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */; }; + 2492D62C2509755900BAE3DA /* AddItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2492D62B2509755900BAE3DA /* AddItemCell.swift */; }; 2494FFA8248C10CA00DC58E0 /* DataStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2494FFA7248C10CA00DC58E0 /* DataStore.swift */; }; 24A3C98024F1804F0019D23F /* AddStoreCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */; }; 24A3C98324F1912F0019D23F /* UIView+DashedBorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */; }; @@ -70,7 +71,6 @@ 2419C7D824B652FD004F5096 /* StrikethroughLabel.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = StrikethroughLabel.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 241E7C332501730F00C06241 /* StoreViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StoreViewController.swift; sourceTree = SOURCE_ROOT; }; 241E7C382502E16200C06241 /* StoreListHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreListHeader.swift; path = "Grocery List/Cells/StoreListHeader.swift"; sourceTree = SOURCE_ROOT; }; - 241F0F7B24B7A35800A3F67C /* ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCell.swift; sourceTree = ""; }; 2423A01C24BB93CC0089181C /* Grocery ListTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Grocery ListTests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 2423A01E24BB93CC0089181C /* Grocery_ListTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Grocery_ListTests.swift; sourceTree = ""; }; 2423A02024BB93CC0089181C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -91,6 +91,7 @@ 2480FBC124F84D0700F1D22F /* StoreIconManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StoreIconManager.swift; path = "Grocery List/View Controllers/StoreIconManager.swift"; sourceTree = SOURCE_ROOT; }; 2486580725055E39004F5F59 /* ColorManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ColorManager.swift; path = "Grocery List/View Controllers/ColorManager.swift"; sourceTree = SOURCE_ROOT; }; 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemCellCollapsible.swift; sourceTree = ""; }; + 2492D62B2509755900BAE3DA /* AddItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AddItemCell.swift; path = "Grocery List/Views/AddItemCell.swift"; sourceTree = SOURCE_ROOT; }; 2494FFA7248C10CA00DC58E0 /* DataStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataStore.swift; sourceTree = ""; }; 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddStoreCell.swift; sourceTree = ""; }; 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+DashedBorder.swift"; sourceTree = ""; }; @@ -230,11 +231,11 @@ 24A3C98124F180B50019D23F /* Cells */ = { isa = PBXGroup; children = ( + 2492D62B2509755900BAE3DA /* AddItemCell.swift */, 241E7C382502E16200C06241 /* StoreListHeader.swift */, 24F91AEB24F0589E0064FDBB /* CategoryCell.swift */, 24390CBE24C61B6700189D75 /* StoreCell.swift */, 24A3C97F24F1804F0019D23F /* AddStoreCell.swift */, - 241F0F7B24B7A35800A3F67C /* ItemCell.swift */, 2492D629250570BD00BAE3DA /* ItemCellCollapsible.swift */, ); path = Cells; @@ -473,6 +474,7 @@ 2486580825055E39004F5F59 /* ColorManager.swift in Sources */, 241E7C342501730F00C06241 /* StoreViewController.swift in Sources */, 2480FBC224F84D0700F1D22F /* StoreIconManager.swift in Sources */, + 2492D62C2509755900BAE3DA /* AddItemCell.swift in Sources */, 24E5F40324EB16B7007DA4BE /* UIView+Separator.swift in Sources */, 241E7C392502E16200C06241 /* StoreListHeader.swift in Sources */, 24F91AEC24F0589E0064FDBB /* CategoryCell.swift in Sources */, diff --git a/Grocery List/Cells/ItemCell.swift b/Grocery List/Cells/ItemCell.swift deleted file mode 100644 index d54fd3d..0000000 --- a/Grocery List/Cells/ItemCell.swift +++ /dev/null @@ -1,125 +0,0 @@ -// -// ItemCell.swift -// Grocery List -// -// Created by Rushad Antia on 7/9/20. -// Copyright © 2020 Rushad Antia. All rights reserved. -// - -import Lightbox -import UIKit - -class ItemCell: UITableViewCell { - var item: Item? - var store: Store? - var starButton: UIButton? - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - starButton = UIButton(type: .system) - starButton!.setImage(UIImage(systemName: "star.fill"), for: .normal) - starButton!.frame = CGRect(x: 0, y: 0, width: 50, height: 50) - - starButton!.addTarget(self, action: #selector(handleFav), for: .touchUpInside) - accessoryView = starButton - - layer.masksToBounds = false - layer.shadowOpacity = 0.23 - layer.shadowRadius = 4 - layer.shadowOffset = CGSize(width: 0, height: 0) - layer.shadowColor = UIColor.clear.cgColor // UIColor.black.cgColor - - // cell color - contentView.backgroundColor = #colorLiteral(red: 0.1215499714, green: 0.1215790883, blue: 0.1215502545, alpha: 1) - contentView.layer.cornerRadius = 20 - - backgroundColor = .clear - starButton!.tintColor = .lightGray - - separatorInset = .zero - } - - override func layoutSubviews() { - super.layoutSubviews() - - var cView = contentView.frame - cView = cView.insetBy(dx: 5, dy: 0) - - contentView.frame = cView - contentView.frame.size.width += (accessoryView?.frame.size.width)! - 10 - contentView.frame.size.height -= 2 - - imageView?.frame.size.height -= 2 - imageView?.frame = (imageView?.frame.insetBy(dx: 0, dy: 4))! - } - - required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - } - - @objc private func handleFav() { - if let i = item { - if let s = store { - i.isFavorite.toggle() - s.save() - setFavorite() - } - } - } - - func setFavorite() { - if let i = item { - starButton!.tintColor = i.isFavorite ? #colorLiteral(red: 0.9529411793, green: 0.6862745285, blue: 0.1333333403, alpha: 1) : UIColor.lightGray - } - } - - func setImageView() { - if let i = item { - imageView?.isUserInteractionEnabled = true - - if i.hasImage { - let longpressRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longPress)) - imageView?.addGestureRecognizer(longpressRecognizer) - - imageView?.image = (i.isDone ? i.getGreyImage() : i.getImage()) - imageView?.layer.cornerRadius = 8.0 - imageView?.clipsToBounds = true - - } else { - imageView?.image = nil - } - } - } - - @objc func longPress() { - if let i = item { - if i.hasImage { - let images = [LightboxImage(image: i.getImage()!)] - - let controller = LightboxController(images: images) - - controller.dynamicBackground = true - controller.modalPresentationStyle = .fullScreen - - window?.rootViewController?.present(controller, animated: true, completion: nil) - } - } - } - - func setItemTitle() { - if let i = item { - var attributedString = NSMutableAttributedString(string: i.name) - - // if the item is marked as done then make the string strikedthrough - if i.isDone { - attributedString = NSMutableAttributedString(string: i.name, attributes: [NSAttributedString.Key.strikethroughStyle: NSUnderlineStyle.thick]) - attributedString.addAttribute(NSAttributedString.Key.strikethroughStyle, value: NSUnderlineStyle.single.rawValue, range: NSMakeRange(0, i.name.count)) - } - selectionStyle = .none - textLabel?.attributedText = attributedString - textLabel?.textColor = .white - textLabel?.font = UIFont(name: "Avenir-Medium", size: 20) - } - } -} diff --git a/Grocery List/Data Models/Category.swift b/Grocery List/Data Models/Category.swift index 9a976de..2a875a6 100644 --- a/Grocery List/Data Models/Category.swift +++ b/Grocery List/Data Models/Category.swift @@ -8,12 +8,12 @@ class Category: Codable { var name: String var items: [Item] - var collapsed: Bool + var toAdd: Bool init(name: String, items: [Item] = [Item](), collapsed: Bool = false) { self.name = name.lowercased() self.items = items - self.collapsed = collapsed + self.toAdd = collapsed } func getItems() -> [String] { diff --git a/Grocery List/Views/AddItemCell.swift b/Grocery List/Views/AddItemCell.swift new file mode 100644 index 0000000..0366c8c --- /dev/null +++ b/Grocery List/Views/AddItemCell.swift @@ -0,0 +1,17 @@ +// +// AddItemCell.swift +// Grocery List +// +// Created by Rushad Antia on 9/9/20. +// Copyright © 2020 Rushad Antia. All rights reserved. +// + +import Foundation +import UIKit + +class AddItemCell: UITableViewCell { + + @IBOutlet weak var itemTextField: UITextField! + @IBOutlet weak var itemImage: UIImageView! + @IBOutlet weak var itemDescriptionTextField: UITextField! +} diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index 809796b..7133d3a 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -75,13 +75,13 @@ - - - + + - + - - - - - + + - - - - - - + + + - + + - - - - - - - - - - - - - + + + + + + + + + + + @@ -593,8 +586,16 @@ + + + + + + + + - + diff --git a/StoreViewController.swift b/StoreViewController.swift index 6a2fb24..76032dd 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -62,10 +62,14 @@ class StoreViewController: UITableViewController { let cell = tableView.dequeueReusableCell(withIdentifier: "addItemCell") as! AddItemCell cell.itemTextField.attributedPlaceholder = NSAttributedString(string: "New Item", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) - cell.itemDescriptionTextField.attributedPlaceholder = NSAttributedString(string: "Add Description", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) - - //cell.selectionStyle = .none + + + let descriptionText = NSMutableAttributedString(string: "Description ", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) + descriptionText.append(NSAttributedString(string: "(Optional)", attributes: [NSAttributedString.Key.obliqueness: 0.2, NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY])) + + cell.itemDescriptionTextField.attributedPlaceholder = descriptionText + cell.itemImage.isUserInteractionEnabled = true cell.itemImage.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tappedImage(sender:)))) From 99d682693cf40ba0347f09f6ad60e9aad62078a5 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Fri, 25 Sep 2020 15:28:15 -0400 Subject: [PATCH 11/22] can add data to list. image broken rn and bad scaling --- Grocery List.xcodeproj/project.pbxproj | 4 + Grocery List/Data Models/Category.swift | 18 --- Grocery List/Data Models/Item.swift | 20 ++-- Grocery List/Data Models/Store.swift | 9 -- .../UIImage+GetB64String.swift | 19 ++++ Grocery List/Views/Base.lproj/Main.storyboard | 2 +- StoreViewController.swift | 104 ++++++++++++++++-- 7 files changed, 128 insertions(+), 48 deletions(-) create mode 100644 Grocery List/View Controllers/UIImage+GetB64String.swift diff --git a/Grocery List.xcodeproj/project.pbxproj b/Grocery List.xcodeproj/project.pbxproj index 32f9e4f..c414725 100644 --- a/Grocery List.xcodeproj/project.pbxproj +++ b/Grocery List.xcodeproj/project.pbxproj @@ -39,6 +39,7 @@ 24E5F40324EB16B7007DA4BE /* UIView+Separator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24E5F40224EB16B7007DA4BE /* UIView+Separator.swift */; }; 24F91AEA24F058120064FDBB /* BEMCheckBox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 24F91AE924F058120064FDBB /* BEMCheckBox.framework */; }; 24F91AEC24F0589E0064FDBB /* CategoryCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F91AEB24F0589E0064FDBB /* CategoryCell.swift */; }; + 24FA2E29251E76C100F6338B /* UIImage+GetB64String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24FA2E28251E76C100F6338B /* UIImage+GetB64String.swift */; }; CFAF001F565611D9E60E2D73 /* Pods_Grocery_List.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E89EC5A48903AAE3D1DC49C /* Pods_Grocery_List.framework */; }; /* End PBXBuildFile section */ @@ -103,6 +104,7 @@ 24E5F40224EB16B7007DA4BE /* UIView+Separator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Separator.swift"; sourceTree = ""; }; 24F91AE924F058120064FDBB /* BEMCheckBox.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BEMCheckBox.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 24F91AEB24F0589E0064FDBB /* CategoryCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryCell.swift; sourceTree = ""; }; + 24FA2E28251E76C100F6338B /* UIImage+GetB64String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "UIImage+GetB64String.swift"; path = "Grocery List/View Controllers/UIImage+GetB64String.swift"; sourceTree = SOURCE_ROOT; }; 4FD008632E60DB9E3C8B3BC9 /* Pods-Grocery List.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Grocery List.debug.xcconfig"; path = "Target Support Files/Pods-Grocery List/Pods-Grocery List.debug.xcconfig"; sourceTree = ""; }; 8E89EC5A48903AAE3D1DC49C /* Pods_Grocery_List.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Grocery_List.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AD38424FF3E64C73D4C651DF /* Pods-Grocery List.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Grocery List.release.xcconfig"; path = "Target Support Files/Pods-Grocery List/Pods-Grocery List.release.xcconfig"; sourceTree = ""; }; @@ -253,6 +255,7 @@ 24E5F40424EB16C0007DA4BE /* Extensions */ = { isa = PBXGroup; children = ( + 24FA2E28251E76C100F6338B /* UIImage+GetB64String.swift */, 2427D72E2502F53700BEB252 /* UIColor+RandomColor.swift */, 24A3C98224F1912F0019D23F /* UIView+DashedBorder.swift */, 24E5F40224EB16B7007DA4BE /* UIView+Separator.swift */, @@ -491,6 +494,7 @@ 2409D27524A7D738001FAD06 /* ImagePicker.swift in Sources */, 24390CBF24C61B6700189D75 /* StoreCell.swift in Sources */, 24A3C98324F1912F0019D23F /* UIView+DashedBorder.swift in Sources */, + 24FA2E29251E76C100F6338B /* UIImage+GetB64String.swift in Sources */, 2461A82F24882541009BE0AB /* AppDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Grocery List/Data Models/Category.swift b/Grocery List/Data Models/Category.swift index 2a875a6..14d9142 100644 --- a/Grocery List/Data Models/Category.swift +++ b/Grocery List/Data Models/Category.swift @@ -34,22 +34,4 @@ class Category: Codable { return total } - func pruneNonFavorites() { - var faves = [Item]() - - for item in items { - if item.isFavorite { - faves.append(item) - } - } - items = faves - } - - func resetFavorites() { - for item in items { - if item.isFavorite, item.isDone { - item.isDone = false - } - } - } } diff --git a/Grocery List/Data Models/Item.swift b/Grocery List/Data Models/Item.swift index 4a37c53..770a0fb 100644 --- a/Grocery List/Data Models/Item.swift +++ b/Grocery List/Data Models/Item.swift @@ -16,44 +16,44 @@ class Item: Codable { var name: String var isDone: Bool = false - var isFavorite: Bool + var description: String - init(name: String, isFave: Bool, imageString: String, isDone: Bool) { + init(name: String, imageString: String, isDone: Bool) { self.name = name.lowercased() self.imageString = imageString self.isDone = isDone - isFavorite = isFave + self.description = "" } - init(name: String, isFave: Bool, isDone: Bool) { + init(name: String, isDone: Bool) { self.name = name.lowercased() self.isDone = isDone - isFavorite = isFave + self.description = "" } init(name: String) { self.name = name.lowercased() isDone = false - isFavorite = false + self.description = "" } init(name: String, isFav: Bool) { self.name = name isDone = false - isFavorite = isFav + self.description = "" } init() { name = "" isDone = false - isFavorite = false + self.description = "" } - init(name: String, imageString: String) { + init(name: String, imageString: String, _ description: String = "") { self.name = name.lowercased() self.imageString = imageString isDone = false - isFavorite = false + self.description = description } func getImage() -> UIImage? { diff --git a/Grocery List/Data Models/Store.swift b/Grocery List/Data Models/Store.swift index eeb7b9f..d3fa956 100644 --- a/Grocery List/Data Models/Store.swift +++ b/Grocery List/Data Models/Store.swift @@ -118,15 +118,6 @@ class Store: Codable { } } - public func finishShopping() { - for category in categories { - category.pruneNonFavorites() - category.resetFavorites() - } - - save() - } - public func getCategories() -> [String] { return self.categories.map { c in c.name.lowercased()} } diff --git a/Grocery List/View Controllers/UIImage+GetB64String.swift b/Grocery List/View Controllers/UIImage+GetB64String.swift new file mode 100644 index 0000000..eef68da --- /dev/null +++ b/Grocery List/View Controllers/UIImage+GetB64String.swift @@ -0,0 +1,19 @@ +// +// UIImage+GetB64String.swift +// Grocery List +// +// Created by Rushad Antia on 9/25/20. +// Copyright © 2020 Rushad Antia. All rights reserved. +// + + +import UIKit + +extension UIImage { + + func getB64String(_ compressionQuality: CGFloat = 0.3) -> String? { + let imageData = self.jpegData(compressionQuality: compressionQuality) + return imageData?.base64EncodedString() + } + +} diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index 6feb60e..d248e82 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -56,7 +56,7 @@ - + diff --git a/StoreViewController.swift b/StoreViewController.swift index 76032dd..1d1728f 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -8,6 +8,7 @@ import Foundation import UIKit +import BEMCheckBox class StoreViewController: UITableViewController { var store = Store() @@ -28,11 +29,20 @@ class StoreViewController: UITableViewController { tableView.dataSource = self tableView.backgroundColor = #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1) - + self.tableView.register(StoreListHeader.self, forHeaderFooterViewReuseIdentifier: StoreListHeader.reuseIdentifier) imagePicker = ImagePicker(presentationController: self, delegate: self) } + override func viewDidAppear(_ animated: Bool) { + super.viewDidAppear(animated) + + store.categories.forEach { c in + c.toAdd = false + } + store.save() + } + @objc func addItemHeader(sender: UIButton){ let header = sender.superview?.superview as! StoreListHeader let section = header.tag @@ -55,21 +65,35 @@ class StoreViewController: UITableViewController { if indexPath[1] < currCategory.items.count { let cell = tableView.dequeueReusableCell(withIdentifier: "itemCell") as! ItemCellCollapsible - + let currItem = currCategory.items[indexPath[1]] + + let categoryColor = ColorManager.defaultsMap[currCategory.name] ?? ColorManager.CUSTOMGRAY + + cell.checkbox.delegate = self + cell.checkbox.onTintColor = categoryColor + cell.checkbox.onCheckColor = categoryColor + cell.checkbox.on = currItem.isDone + + cell.itemLabel.text = currItem.name + cell.descriptionLabel.text = currItem.description + + print("Name: \(currItem.name) Selected: \(currItem.isDone)") + return cell } else { let cell = tableView.dequeueReusableCell(withIdentifier: "addItemCell") as! AddItemCell cell.itemTextField.attributedPlaceholder = NSAttributedString(string: "New Item", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) - - + cell.itemTextField.text = "" + cell.itemTextField.delegate = self + let descriptionText = NSMutableAttributedString(string: "Description ", attributes: [NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY]) descriptionText.append(NSAttributedString(string: "(Optional)", attributes: [NSAttributedString.Key.obliqueness: 0.2, NSAttributedString.Key.foregroundColor: ColorManager.CUSTOMGRAY])) - + cell.itemDescriptionTextField.text = "" cell.itemDescriptionTextField.attributedPlaceholder = descriptionText - + cell.itemImage.isUserInteractionEnabled = true cell.itemImage.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(tappedImage(sender:)))) @@ -81,9 +105,9 @@ class StoreViewController: UITableViewController { } override func tableView(_ tableView: UITableView, shouldUpdateFocusIn context: UITableViewFocusUpdateContext) -> Bool { - let cell1 = context.nextFocusedItem - let cell2 = context.previouslyFocusedView - + // let cell1 = context.nextFocusedItem + // let cell2 = context.previouslyFocusedView + // return true } @@ -94,7 +118,7 @@ class StoreViewController: UITableViewController { } override func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat { - return 52.0 + return 50.0 } override func numberOfSections(in tableView: UITableView) -> Int { @@ -139,6 +163,66 @@ class StoreViewController: UITableViewController { } +extension StoreViewController: UITextFieldDelegate { + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + + let cell = tableView.cellForSubview(cellSubview: textField) as? AddItemCell + let indexPath = tableView.indexPathForCellWithSubview(cellSubview: textField)! + let currentCategory = store.categories[indexPath[0]] + + //if an item is present + if let itemName = cell?.itemTextField.text { + + let itemToAdd = Item(name: itemName) + + if let description = cell?.itemDescriptionTextField.text { + itemToAdd.description = description + } + + if let image = cell?.itemImage.image { + itemToAdd.imageString = image.getB64String() + } + + store.addItem(category: currentCategory.name, item: itemToAdd) + currentCategory.toAdd = false + tableView.reloadData() + } + + textField.resignFirstResponder() + return true + } + +} + +extension UITableView { + func cellForSubview(cellSubview: UIView) -> UITableViewCell? { + if let ip = indexPathForCellWithSubview(cellSubview: cellSubview) { + return cellForRow(at: ip) + } + return nil + } + func indexPathForCellWithSubview(cellSubview: UIView) -> IndexPath? { + let cellFrame = convert(cellSubview.bounds, from: cellSubview) + let cellCenter = CGPoint(x: cellFrame.midX, y: cellFrame.midY) + + return indexPathForRow(at: cellCenter) + + } +} + +extension StoreViewController: BEMCheckBoxDelegate { + + func didTap(_ checkBox: BEMCheckBox) { + if let indexPath = tableView.indexPathForCellWithSubview(cellSubview: checkBox){ + let item = store.categories[indexPath[0]].items[indexPath[1]] + item.isDone = checkBox.on + store.save() + } + } + +} + extension StoreViewController: ImagePickerDelegate { func didSelect(image: UIImage?) { self.currImageView?.image = image From 7400977175630e10d45e757de847e7e3725ce574 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Fri, 25 Sep 2020 15:58:55 -0400 Subject: [PATCH 12/22] added delete and refresh control --- StoreViewController.swift | 65 ++++++++++++++++++++++++++++----------- 1 file changed, 47 insertions(+), 18 deletions(-) diff --git a/StoreViewController.swift b/StoreViewController.swift index 1d1728f..aafb4d0 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -32,18 +32,26 @@ class StoreViewController: UITableViewController { self.tableView.register(StoreListHeader.self, forHeaderFooterViewReuseIdentifier: StoreListHeader.reuseIdentifier) imagePicker = ImagePicker(presentationController: self, delegate: self) + + refreshControl = UIRefreshControl() + refreshControl?.tintColor = .black + tableView.addSubview(refreshControl!) + refreshControl!.addTarget(self, action: #selector(refreshTableData), for: .valueChanged) + } + + @objc func refreshTableData() { + tableView.reloadData() + refreshControl?.endRefreshing() } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - - store.categories.forEach { c in - c.toAdd = false - } - store.save() + closeAddCells() } - + @objc func addItemHeader(sender: UIButton){ + closeAddCells() + let header = sender.superview?.superview as! StoreListHeader let section = header.tag store.categories[section].toAdd = true @@ -56,8 +64,40 @@ class StoreViewController: UITableViewController { imagePicker.present(from: sender) } + func closeAddCells() { + store.categories.forEach { c in + c.toAdd = false + } + store.save() + tableView.reloadData() + } + + + // MARK: - Start Cells + + override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { + + let delete = UIContextualAction(style: .normal, title: "Delete") { [self] (action, view, completion) in + + self.store.categories[indexPath[0]].items.remove(at: indexPath[1]) + tableView.beginUpdates() + tableView.deleteRows(at: [indexPath], with: .fade) + tableView.endUpdates() + self.store.save() + + tableView.reloadData() + + completion(true) + } + + delete.title = "Delete" + delete.backgroundColor = .systemRed + + return UISwipeActionsConfiguration(actions: [delete]) + } + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - //print(self.store.categories[indexPath[0]].items[indexPath[1]]) + print(self.store.categories[indexPath[0]].items[indexPath[1]].name) } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -77,8 +117,6 @@ class StoreViewController: UITableViewController { cell.itemLabel.text = currItem.name cell.descriptionLabel.text = currItem.description - print("Name: \(currItem.name) Selected: \(currItem.isDone)") - return cell } else { @@ -104,13 +142,6 @@ class StoreViewController: UITableViewController { } } - override func tableView(_ tableView: UITableView, shouldUpdateFocusIn context: UITableViewFocusUpdateContext) -> Bool { - // let cell1 = context.nextFocusedItem - // let cell2 = context.previouslyFocusedView - // - return true - } - // MARK: - Start Header override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { @@ -212,7 +243,6 @@ extension UITableView { } extension StoreViewController: BEMCheckBoxDelegate { - func didTap(_ checkBox: BEMCheckBox) { if let indexPath = tableView.indexPathForCellWithSubview(cellSubview: checkBox){ let item = store.categories[indexPath[0]].items[indexPath[1]] @@ -220,7 +250,6 @@ extension StoreViewController: BEMCheckBoxDelegate { store.save() } } - } extension StoreViewController: ImagePickerDelegate { From afdcff3b8d650b53efbb18dde049a467460c63f7 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sat, 26 Sep 2020 17:26:01 -0400 Subject: [PATCH 13/22] it now collapses and expands cells. no constraints on cell tho do that --- Grocery List/Data Models/Item.swift | 7 +- Grocery List/Data Models/Store.swift | 5 + Grocery List/Views/Base.lproj/Main.storyboard | 142 +++--------------- StoreViewController.swift | 65 ++++++-- 4 files changed, 78 insertions(+), 141 deletions(-) diff --git a/Grocery List/Data Models/Item.swift b/Grocery List/Data Models/Item.swift index 770a0fb..66901ab 100644 --- a/Grocery List/Data Models/Item.swift +++ b/Grocery List/Data Models/Item.swift @@ -17,7 +17,8 @@ class Item: Codable { var name: String var isDone: Bool = false var description: String - + var isExpanded: Bool = false + init(name: String, imageString: String, isDone: Bool) { self.name = name.lowercased() self.imageString = imageString @@ -56,6 +57,10 @@ class Item: Codable { self.description = description } + func isExpandable() -> Bool { + return description != "" + } + func getImage() -> UIImage? { if hasImage { let newImageData = Data(base64Encoded: imageString!) diff --git a/Grocery List/Data Models/Store.swift b/Grocery List/Data Models/Store.swift index d3fa956..daec1f6 100644 --- a/Grocery List/Data Models/Store.swift +++ b/Grocery List/Data Models/Store.swift @@ -46,6 +46,11 @@ class Store: Codable { category.items[itemIndex].name = newItemName save() } + + public func getItem(indexPath: IndexPath) -> Item { + print(indexPath) + return self.categories[indexPath[0]].items[indexPath[1]] + } public func deleteItem(category: String, item: Item) { let items = getCategory(name: category)!.items diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index d248e82..8144d5b 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -56,53 +56,39 @@ - - + + - + - - + + - - - - - - - - - - - - - - - - - - @@ -114,7 +100,7 @@ - + @@ -185,10 +171,6 @@ - - - - @@ -412,90 +394,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -588,22 +486,18 @@ - + - - - - diff --git a/StoreViewController.swift b/StoreViewController.swift index aafb4d0..1146372 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -37,6 +37,8 @@ class StoreViewController: UITableViewController { refreshControl?.tintColor = .black tableView.addSubview(refreshControl!) refreshControl!.addTarget(self, action: #selector(refreshTableData), for: .valueChanged) + + closeAddCells() } @objc func refreshTableData() { @@ -46,15 +48,16 @@ class StoreViewController: UITableViewController { override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - closeAddCells() + } - + @objc func addItemHeader(sender: UIButton){ closeAddCells() - let header = sender.superview?.superview as! StoreListHeader - let section = header.tag - store.categories[section].toAdd = true + if let header = sender.superview?.superview as? StoreListHeader { + let section = header.tag + store.categories[section].toAdd = true + } tableView.reloadData() } @@ -65,6 +68,7 @@ class StoreViewController: UITableViewController { } func closeAddCells() { + collapseItemCells() store.categories.forEach { c in c.toAdd = false } @@ -72,20 +76,29 @@ class StoreViewController: UITableViewController { tableView.reloadData() } + func collapseItemCells(_ isExpanded: Bool = false) { + store.categories.forEach { category in + category.items.forEach { item in + item.isExpanded = isExpanded + } + } + store.save() + } + // MARK: - Start Cells override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - + let delete = UIContextualAction(style: .normal, title: "Delete") { [self] (action, view, completion) in - - self.store.categories[indexPath[0]].items.remove(at: indexPath[1]) - tableView.beginUpdates() - tableView.deleteRows(at: [indexPath], with: .fade) - tableView.endUpdates() - self.store.save() - - tableView.reloadData() + + self.store.categories[indexPath[0]].items.remove(at: indexPath[1]) + tableView.beginUpdates() + tableView.deleteRows(at: [indexPath], with: .fade) + tableView.endUpdates() + self.store.save() + + tableView.reloadData() completion(true) } @@ -95,9 +108,29 @@ class StoreViewController: UITableViewController { return UISwipeActionsConfiguration(actions: [delete]) } - + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - print(self.store.categories[indexPath[0]].items[indexPath[1]].name) + let currCategory = store.categories[indexPath[0]] + if indexPath[1] < currCategory.items.count { + store.getItem(indexPath: indexPath).isExpanded.toggle() + tableView.beginUpdates() + tableView.endUpdates() + } + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { + let currCategory = store.categories[indexPath[0]] + if indexPath[1] < currCategory.items.count { + let item = store.getItem(indexPath: indexPath) + + if item.isExpandable() && item.isExpanded { + return 115 + } + else { + return 40 + } + } + return super.tableView(tableView, heightForRowAt: indexPath) } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { From e84b42a35f80e280517352ce424ce54f2349c26b Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sat, 26 Sep 2020 20:08:45 -0400 Subject: [PATCH 14/22] removed constraints --- Grocery List/Views/Base.lproj/Main.storyboard | 2 +- StoreViewController.swift | 33 +++++++++++-------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index 8144d5b..5d27eda 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -70,7 +70,7 @@ + + + + + + + + @@ -93,6 +101,7 @@ + diff --git a/StoreViewController.swift b/StoreViewController.swift index 294ec20..cc8aafc 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -138,8 +138,8 @@ class StoreViewController: UITableViewController { } @objc func longPress(sender: UIGestureRecognizer) { - let tappedView = (sender.view as? UIImageView) - let images = [LightboxImage(image: (tappedView?.image!)!)] + let tappedView = (sender.view as? UIImageView)! + let images = [LightboxImage(image: (tappedView.image!))] let controller = LightboxController(images: images) @@ -166,6 +166,8 @@ class StoreViewController: UITableViewController { cell.itemLabel.text = currItem.name cell.descriptionLabel.text = currItem.description + cell.favoriteView.circleColor = .yellow + if let img = currItem.getImage() { cell.itemImageView.isUserInteractionEnabled = true cell.itemImageView.image = img From be77eed48d2b5236caaf9707ad587b373114ecb4 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sun, 28 Mar 2021 13:54:54 -0400 Subject: [PATCH 20/22] can toggle favorite --- Grocery List/Cells/ItemCellCollapsible.swift | 12 ++++++---- Grocery List/Data Models/Item.swift | 3 ++- Grocery List/Data Models/Store.swift | 1 - Grocery List/Views/Base.lproj/Main.storyboard | 2 +- StoreViewController.swift | 23 +++++++++++++++---- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Grocery List/Cells/ItemCellCollapsible.swift b/Grocery List/Cells/ItemCellCollapsible.swift index 9ed1315..b11b3a7 100644 --- a/Grocery List/Cells/ItemCellCollapsible.swift +++ b/Grocery List/Cells/ItemCellCollapsible.swift @@ -29,22 +29,24 @@ class ItemCellCollapsible: UITableViewCell { class CircleView: UIView { - var circleColor: UIColor? + var circleColor: UIColor! + var favorite: Bool! override func draw(_ rect: CGRect) { let path = UIBezierPath(ovalIn: CGRect(x: 2, y: 2, width: 12, height: 12)) path.lineWidth = 1 - if let mainColor = self.circleColor { - mainColor.setStroke() - mainColor.setFill() - path.fill() + if favorite { + circleColor.setStroke() + circleColor.setFill() } else { #colorLiteral(red: 0.6000000238, green: 0.6000000238, blue: 0.6000000238, alpha: 1).setStroke() + #colorLiteral(red: 0.9176470588, green: 0.9176470588, blue: 0.9176470588, alpha: 1).setFill() } + path.fill() path.stroke() } } diff --git a/Grocery List/Data Models/Item.swift b/Grocery List/Data Models/Item.swift index 787a4cf..d62971a 100644 --- a/Grocery List/Data Models/Item.swift +++ b/Grocery List/Data Models/Item.swift @@ -13,7 +13,8 @@ class Item: Codable { var name: String var isDone: Bool = false var description: String - var isExpanded: Bool = false + var isExpanded: Bool = false // if there is image to expand + var favorite: Bool = false init(name: String, imageString: String, isDone: Bool) { self.name = name.lowercased() diff --git a/Grocery List/Data Models/Store.swift b/Grocery List/Data Models/Store.swift index daec1f6..0cccf18 100644 --- a/Grocery List/Data Models/Store.swift +++ b/Grocery List/Data Models/Store.swift @@ -48,7 +48,6 @@ class Store: Codable { } public func getItem(indexPath: IndexPath) -> Item { - print(indexPath) return self.categories[indexPath[0]].items[indexPath[1]] } diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index f604449..0876bfa 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -89,7 +89,7 @@ - + diff --git a/StoreViewController.swift b/StoreViewController.swift index cc8aafc..9b3690d 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -38,9 +38,24 @@ class StoreViewController: UITableViewController { tableView.addSubview(refreshControl!) refreshControl!.addTarget(self, action: #selector(refreshTableData), for: .valueChanged) + let longpresscell = UILongPressGestureRecognizer(target: self, action: #selector(StoreViewController.favoritedItem(sender:))) + self.tableView.addGestureRecognizer(longpresscell) + closeAddCells() } + @objc func favoritedItem(sender: UILongPressGestureRecognizer) { + if sender.state == UIGestureRecognizer.State.began { + let touchPoint = sender.location(in: self.tableView) + if let indexPath = self.tableView.indexPathForRow(at: touchPoint) { + let selectedItem = store.getItem(indexPath: indexPath) + selectedItem.favorite.toggle() + self.store.save() + self.tableView.reloadData() + } + } + } + @objc func refreshTableData() { tableView.reloadData() refreshControl?.endRefreshing() @@ -166,8 +181,10 @@ class StoreViewController: UITableViewController { cell.itemLabel.text = currItem.name cell.descriptionLabel.text = currItem.description - cell.favoriteView.circleColor = .yellow - + cell.favoriteView.circleColor = categoryColor + cell.favoriteView.favorite = currItem.favorite + cell.favoriteView.setNeedsDisplay() + if let img = currItem.getImage() { cell.itemImageView.isUserInteractionEnabled = true cell.itemImageView.image = img @@ -323,8 +340,6 @@ extension StoreViewController: ImagePickerDelegate { if let iv = currImageView { iv.image = image -// iv.layer.cornerRadius = self.currImageView?.bounds.width ?? 10 / 2 - } } } From f4c5e0f712bdfb0d7ebd7892c575baec8682a5e4 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Sun, 28 Mar 2021 14:10:40 -0400 Subject: [PATCH 21/22] finish shopping --- Grocery List/Data Models/Category.swift | 4 ++++ Grocery List/Data Models/Store.swift | 7 +++++++ StoreViewController.swift | 14 ++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/Grocery List/Data Models/Category.swift b/Grocery List/Data Models/Category.swift index 14d9142..f75ef3e 100644 --- a/Grocery List/Data Models/Category.swift +++ b/Grocery List/Data Models/Category.swift @@ -34,4 +34,8 @@ class Category: Codable { return total } + func removeNonFavorites() { + self.items = items.filter { $0.favorite } + } + } diff --git a/Grocery List/Data Models/Store.swift b/Grocery List/Data Models/Store.swift index 0cccf18..1c8db12 100644 --- a/Grocery List/Data Models/Store.swift +++ b/Grocery List/Data Models/Store.swift @@ -182,4 +182,11 @@ class Store: Codable { func save() { DataStore.saveStoreData(store: self) } + + func finishShopping() { + self.categories.forEach { category in + category.removeNonFavorites() + } + save() + } } diff --git a/StoreViewController.swift b/StoreViewController.swift index 9b3690d..f50de12 100644 --- a/StoreViewController.swift +++ b/StoreViewController.swift @@ -41,8 +41,22 @@ class StoreViewController: UITableViewController { let longpresscell = UILongPressGestureRecognizer(target: self, action: #selector(StoreViewController.favoritedItem(sender:))) self.tableView.addGestureRecognizer(longpresscell) + let barTap = UILongPressGestureRecognizer(target: self, action: #selector(finishShopping(sender:))) + self.navigationController?.navigationBar.addGestureRecognizer(barTap) + closeAddCells() } + @objc func finishShopping(sender: UILongPressGestureRecognizer) { + let alert = UIAlertController(title: "Finish shopping?", message: "This will delete all non favorited items", preferredStyle: .alert) + + alert.addAction(UIAlertAction(title: "Yes", style: .destructive, handler: { _ in + self.store.finishShopping() + self.tableView.reloadData() + })) + + alert.addAction(UIAlertAction(title: "No", style: .cancel, handler: nil)) + self.present(alert, animated: true, completion: nil) + } @objc func favoritedItem(sender: UILongPressGestureRecognizer) { if sender.state == UIGestureRecognizer.State.began { From c0e3727936a65d7e5de68cca6176224598ee5679 Mon Sep 17 00:00:00 2001 From: rushadantia Date: Thu, 25 Nov 2021 11:15:49 -0500 Subject: [PATCH 22/22] update --- Grocery List/Data Models/Category.swift | 3 +++ Grocery List/Views/Base.lproj/Main.storyboard | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Grocery List/Data Models/Category.swift b/Grocery List/Data Models/Category.swift index f75ef3e..a16066c 100644 --- a/Grocery List/Data Models/Category.swift +++ b/Grocery List/Data Models/Category.swift @@ -36,6 +36,9 @@ class Category: Codable { func removeNonFavorites() { self.items = items.filter { $0.favorite } + for item in self.items { + item.isDone = false + } } } diff --git a/Grocery List/Views/Base.lproj/Main.storyboard b/Grocery List/Views/Base.lproj/Main.storyboard index 0876bfa..4601bfb 100644 --- a/Grocery List/Views/Base.lproj/Main.storyboard +++ b/Grocery List/Views/Base.lproj/Main.storyboard @@ -1,9 +1,9 @@ - + - + @@ -57,7 +57,7 @@ - + @@ -107,7 +107,7 @@ - +