diff --git a/Arrived.xcodeproj/project.pbxproj b/Arrived.xcodeproj/project.pbxproj index ee997eb..532f0a4 100644 --- a/Arrived.xcodeproj/project.pbxproj +++ b/Arrived.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 8901681B1B1431D300180942 /* SimpleAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890168191B1431D300180942 /* SimpleAlert.swift */; }; + 8901681C1B1431D300180942 /* SimpleAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8901681A1B1431D300180942 /* SimpleAlert.xib */; }; 8908FF561AE01ECF00C990DC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8908FF551AE01ECF00C990DC /* AppDelegate.swift */; }; 8908FF601AE01ECF00C990DC /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 8908FF5E1AE01ECF00C990DC /* LaunchScreen.xib */; }; 8908FF6C1AE01ECF00C990DC /* ArrivedTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8908FF6B1AE01ECF00C990DC /* ArrivedTests.swift */; }; @@ -24,13 +26,19 @@ 890D72B51B0739E5006360E7 /* SHSPhoneTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 890D72B01B0739E5006360E7 /* SHSPhoneTextField.m */; }; 890D72B71B0741C5006360E7 /* UserAgreementVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890D72B61B0741C5006360E7 /* UserAgreementVC.swift */; }; 890E3FBD1AEC5B9500F22912 /* HelperMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890E3FBC1AEC5B9500F22912 /* HelperMethods.swift */; }; - 890F54C71B0175200066E835 /* OrdersListTVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54C61B0175200066E835 /* OrdersListTVC.swift */; }; - 890F54C91B0175370066E835 /* OrdersListTVCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54C81B0175370066E835 /* OrdersListTVCell.swift */; }; 890F54CE1B01F4120066E835 /* AudioContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54CA1B01F4120066E835 /* AudioContext.swift */; }; 890F54CF1B01F4120066E835 /* AudioManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54CB1B01F4120066E835 /* AudioManager.swift */; }; 890F54D01B01F4120066E835 /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54CC1B01F4120066E835 /* AudioPlayer.swift */; }; 890F54D11B01F4120066E835 /* AudioRecorder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54CD1B01F4120066E835 /* AudioRecorder.swift */; }; 890F54D31B01F41D0066E835 /* MakeOrderVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 890F54D21B01F41D0066E835 /* MakeOrderVC.swift */; }; + 891B845C1B176EC700BFC3E7 /* SwiftNotice.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891B845B1B176EC700BFC3E7 /* SwiftNotice.swift */; }; + 891B84631B17B99E00BFC3E7 /* RRAddTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891B84601B17B99E00BFC3E7 /* RRAddTagView.swift */; }; + 891B84641B17B99E00BFC3E7 /* RRTagCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891B84611B17B99E00BFC3E7 /* RRTagCollectionViewCell.swift */; }; + 891B84651B17B99E00BFC3E7 /* RRTagController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891B84621B17B99E00BFC3E7 /* RRTagController.swift */; }; + 892C17451B14344E00D2D37F /* AlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892C17441B14344E00D2D37F /* AlertController.swift */; }; + 892C17491B143B2800D2D37F /* AddBankCardVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892C17481B143B2800D2D37F /* AddBankCardVC.swift */; }; + 892CC7801B198C6F00C8EB76 /* OrdersListViewTVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892CC77F1B198C6F00C8EB76 /* OrdersListViewTVC.swift */; }; + 892CC7831B198CDF00C8EB76 /* OrdersListViewTVCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892CC7821B198CDF00C8EB76 /* OrdersListViewTVCell.swift */; }; 89471C471B09F6C600EFE101 /* HoshiTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89471C3D1B09F6C600EFE101 /* HoshiTextField.swift */; }; 89471C481B09F6C600EFE101 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 89471C3E1B09F6C600EFE101 /* Info.plist */; }; 89471C491B09F6C600EFE101 /* IsaoTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89471C3F1B09F6C600EFE101 /* IsaoTextField.swift */; }; @@ -84,15 +92,60 @@ 89C413681AF3252F000C2C95 /* key-100.png in Resources */ = {isa = PBXBuildFile; fileRef = 89C413671AF3252F000C2C95 /* key-100.png */; }; 89C4136A1AF40402000C2C95 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 89C413691AF40402000C2C95 /* Main.storyboard */; }; 89C4136E1AF4052C000C2C95 /* MainScreenVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C4136D1AF4052C000C2C95 /* MainScreenVC.swift */; }; + 89C738BE1B1D9713007030DA /* NewOrderFVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89C738BD1B1D9713007030DA /* NewOrderFVC.swift */; }; 89CAA3DC1B10A50A00D7E4C2 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 89CAA3DB1B10A50A00D7E4C2 /* Images.xcassets */; }; 89CAA3E01B10BA7700D7E4C2 /* UICountingLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 89CAA3DF1B10BA7700D7E4C2 /* UICountingLabel.m */; }; - 89D7C6B61AE44D0A00FFD592 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89D7C6B51AE44D0A00FFD592 /* ViewController.swift */; }; 89D7C6B81AE4796500FFD592 /* ImageLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89D7C6B71AE4796500FFD592 /* ImageLoader.swift */; }; + 89D7F4451B17407F00ADA69C /* OrdersMapViewVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89D7F4441B17407F00ADA69C /* OrdersMapViewVC.swift */; }; 89E6FB861B11EA98003A8276 /* UserMenuVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89E6FB851B11EA98003A8276 /* UserMenuVC.swift */; }; 89E6FB881B12029C003A8276 /* MenuTransitionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89E6FB871B12029C003A8276 /* MenuTransitionManager.swift */; }; 89EEF5001B00720B006881FD /* TestReviewService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF4FF1B00720B006881FD /* TestReviewService.swift */; }; 89EEF5021B007233006881FD /* TestRequestService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5011B007233006881FD /* TestRequestService.swift */; }; - 89EEF5061B008B05006881FD /* OrderDetailVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5051B008B05006881FD /* OrderDetailVC.swift */; }; + 89F88E321B19D4EC00674561 /* OrderDetailVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E311B19D4EC00674561 /* OrderDetailVC.swift */; }; + 89F88E441B1B51F500674561 /* dotActive.png in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E381B1B51F500674561 /* dotActive.png */; }; + 89F88E451B1B51F500674561 /* dotActive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E391B1B51F500674561 /* dotActive@2x.png */; }; + 89F88E461B1B51F500674561 /* dotActive@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E3A1B1B51F500674561 /* dotActive@3x.png */; }; + 89F88E471B1B51F500674561 /* dotInactive.png in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E3B1B1B51F500674561 /* dotInactive.png */; }; + 89F88E481B1B51F500674561 /* dotInactive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E3C1B1B51F500674561 /* dotInactive@2x.png */; }; + 89F88E491B1B51F500674561 /* dotInactive@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E3D1B1B51F500674561 /* dotInactive@3x.png */; }; + 89F88E4A1B1B51F500674561 /* image1.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E3E1B1B51F500674561 /* image1.jpg */; }; + 89F88E4B1B1B51F500674561 /* image2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E3F1B1B51F500674561 /* image2.jpg */; }; + 89F88E4C1B1B51F500674561 /* image3.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E401B1B51F500674561 /* image3.jpg */; }; + 89F88E4D1B1B51F500674561 /* image4.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E411B1B51F500674561 /* image4.jpg */; }; + 89F88E4E1B1B51F500674561 /* image5.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E421B1B51F500674561 /* image5.jpg */; }; + 89F88E4F1B1B51F500674561 /* image6.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E431B1B51F500674561 /* image6.jpg */; }; + 89F88E521B1B59DA00674561 /* ContentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E511B1B59DA00674561 /* ContentViewController.xib */; }; + 89F88E541B1B59E600674561 /* ContentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E531B1B59E600674561 /* ContentViewController.swift */; }; + 89F88E571B1B683F00674561 /* MyOrdersVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E561B1B683F00674561 /* MyOrdersVC.swift */; }; + 89F88E5B1B1B778B00674561 /* MyOrdersRequestsTVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E5A1B1B778B00674561 /* MyOrdersRequestsTVC.swift */; }; + 89F88E5D1B1B77B000674561 /* MyOrdersRequestsTVCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E5C1B1B77B000674561 /* MyOrdersRequestsTVCell.swift */; }; + 89F88E5F1B1B84B200674561 /* MyOrdersRequestViewDetailVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E5E1B1B84B200674561 /* MyOrdersRequestViewDetailVC.swift */; }; + 89F88E611B1B96FB00674561 /* MyOrdersRequestsShowTakerTVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E601B1B96FB00674561 /* MyOrdersRequestsShowTakerTVC.swift */; }; + 89F88E631B1B971200674561 /* MyOrdersRequestsShowTakerTVCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E621B1B971200674561 /* MyOrdersRequestsShowTakerTVCell.swift */; }; + 89F88E651B1BB3AB00674561 /* ShowProgressVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E641B1BB3AB00674561 /* ShowProgressVC.swift */; }; + 89F88E671B1D769500674561 /* PIRipple.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E661B1D769500674561 /* PIRipple.swift */; }; + 89F88E6B1B1D780900674561 /* LNBRippleEffect.m in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E6A1B1D780900674561 /* LNBRippleEffect.m */; }; + 89F88E871B1D8C0C00674561 /* FormBaseCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E6F1B1D8C0C00674561 /* FormBaseCell.swift */; }; + 89F88E881B1D8C0C00674561 /* FormTitleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E701B1D8C0C00674561 /* FormTitleCell.swift */; }; + 89F88E891B1D8C0C00674561 /* FormValueCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E711B1D8C0C00674561 /* FormValueCell.swift */; }; + 89F88E8A1B1D8C0C00674561 /* FormButtonCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E721B1D8C0C00674561 /* FormButtonCell.swift */; }; + 89F88E8B1B1D8C0C00674561 /* FormCheckCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E731B1D8C0C00674561 /* FormCheckCell.swift */; }; + 89F88E8C1B1D8C0C00674561 /* FormDateCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E741B1D8C0C00674561 /* FormDateCell.swift */; }; + 89F88E8D1B1D8C0C00674561 /* FormPickerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E751B1D8C0C00674561 /* FormPickerCell.swift */; }; + 89F88E8E1B1D8C0C00674561 /* FormSegmentedControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E761B1D8C0C00674561 /* FormSegmentedControlCell.swift */; }; + 89F88E8F1B1D8C0C00674561 /* FormSelectorCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E771B1D8C0C00674561 /* FormSelectorCell.swift */; }; + 89F88E901B1D8C0C00674561 /* FormSliderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E781B1D8C0C00674561 /* FormSliderCell.swift */; }; + 89F88E911B1D8C0C00674561 /* FormStepperCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E791B1D8C0C00674561 /* FormStepperCell.swift */; }; + 89F88E921B1D8C0C00674561 /* FormSwitchCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E7A1B1D8C0C00674561 /* FormSwitchCell.swift */; }; + 89F88E931B1D8C0C00674561 /* FormTextFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E7B1B1D8C0C00674561 /* FormTextFieldCell.swift */; }; + 89F88E941B1D8C0C00674561 /* FormTextViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E7C1B1D8C0C00674561 /* FormTextViewCell.swift */; }; + 89F88E951B1D8C0C00674561 /* FormOptionsSelectorController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E7E1B1D8C0C00674561 /* FormOptionsSelectorController.swift */; }; + 89F88E961B1D8C0C00674561 /* FormSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E7F1B1D8C0C00674561 /* FormSelector.swift */; }; + 89F88E971B1D8C0C00674561 /* FormViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E801B1D8C0C00674561 /* FormViewController.swift */; }; + 89F88E981B1D8C0C00674561 /* FormDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E821B1D8C0C00674561 /* FormDescriptor.swift */; }; + 89F88E991B1D8C0C00674561 /* FormRowDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E831B1D8C0C00674561 /* FormRowDescriptor.swift */; }; + 89F88E9A1B1D8C0C00674561 /* FormSectionDescriptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F88E841B1D8C0C00674561 /* FormSectionDescriptor.swift */; }; + 89F88E9B1B1D8C0C00674561 /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 89F88E851B1D8C0C00674561 /* Info.plist */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -106,6 +159,8 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 890168191B1431D300180942 /* SimpleAlert.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SimpleAlert.swift; sourceTree = ""; }; + 8901681A1B1431D300180942 /* SimpleAlert.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SimpleAlert.xib; sourceTree = ""; }; 8908FF501AE01ECF00C990DC /* Arrived.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Arrived.app; sourceTree = BUILT_PRODUCTS_DIR; }; 8908FF541AE01ECF00C990DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 8908FF551AE01ECF00C990DC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -134,13 +189,19 @@ 890D72B01B0739E5006360E7 /* SHSPhoneTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SHSPhoneTextField.m; sourceTree = ""; }; 890D72B61B0741C5006360E7 /* UserAgreementVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserAgreementVC.swift; sourceTree = ""; }; 890E3FBC1AEC5B9500F22912 /* HelperMethods.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HelperMethods.swift; sourceTree = ""; }; - 890F54C61B0175200066E835 /* OrdersListTVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrdersListTVC.swift; sourceTree = ""; }; - 890F54C81B0175370066E835 /* OrdersListTVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrdersListTVCell.swift; sourceTree = ""; }; 890F54CA1B01F4120066E835 /* AudioContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioContext.swift; sourceTree = ""; }; 890F54CB1B01F4120066E835 /* AudioManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioManager.swift; sourceTree = ""; }; 890F54CC1B01F4120066E835 /* AudioPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = ""; }; 890F54CD1B01F4120066E835 /* AudioRecorder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioRecorder.swift; sourceTree = ""; }; 890F54D21B01F41D0066E835 /* MakeOrderVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MakeOrderVC.swift; sourceTree = ""; }; + 891B845B1B176EC700BFC3E7 /* SwiftNotice.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SwiftNotice.swift; path = Frameworks/SwiftNotice.swift; sourceTree = ""; }; + 891B84601B17B99E00BFC3E7 /* RRAddTagView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RRAddTagView.swift; sourceTree = ""; }; + 891B84611B17B99E00BFC3E7 /* RRTagCollectionViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RRTagCollectionViewCell.swift; sourceTree = ""; }; + 891B84621B17B99E00BFC3E7 /* RRTagController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RRTagController.swift; sourceTree = ""; }; + 892C17441B14344E00D2D37F /* AlertController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AlertController.swift; path = ../Frameworks/SimpleAlert/AlertController.swift; sourceTree = ""; }; + 892C17481B143B2800D2D37F /* AddBankCardVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddBankCardVC.swift; sourceTree = ""; }; + 892CC77F1B198C6F00C8EB76 /* OrdersListViewTVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrdersListViewTVC.swift; sourceTree = ""; }; + 892CC7821B198CDF00C8EB76 /* OrdersListViewTVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrdersListViewTVCell.swift; sourceTree = ""; }; 89471C3D1B09F6C600EFE101 /* HoshiTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HoshiTextField.swift; sourceTree = ""; }; 89471C3E1B09F6C600EFE101 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 89471C3F1B09F6C600EFE101 /* IsaoTextField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IsaoTextField.swift; sourceTree = ""; }; @@ -175,7 +236,7 @@ 8981A4CE1AF5641500F3046A /* UserLocationsTVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserLocationsTVCell.swift; sourceTree = ""; }; 8981A4D01AF56DB700F3046A /* UserBankCardsTVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserBankCardsTVCell.swift; sourceTree = ""; }; 8981A4D21AF58FCE00F3046A /* AddLocationVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddLocationVC.swift; sourceTree = ""; }; - 8981A4D41AF5B0AD00F3046A /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationManager.swift; sourceTree = ""; }; + 8981A4D41AF5B0AD00F3046A /* LocationManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LocationManager.swift; path = Classes/Supports/LocationManager.swift; sourceTree = ""; }; 898455A11AF6EABD0071A31B /* OrdersVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrdersVC.swift; sourceTree = ""; }; 899DA8C81AF40B5E00F0C476 /* ProfileVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProfileVC.swift; sourceTree = ""; }; 899DA8CA1AF419C000F0C476 /* thumbs_down-104.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "thumbs_down-104.png"; path = "Assets/UI/Icons/thumbs_down-104.png"; sourceTree = ""; }; @@ -196,16 +257,63 @@ 89C413671AF3252F000C2C95 /* key-100.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "key-100.png"; path = "Assets/UI/Icons/key-100.png"; sourceTree = ""; }; 89C413691AF40402000C2C95 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 89C4136D1AF4052C000C2C95 /* MainScreenVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainScreenVC.swift; sourceTree = ""; }; + 89C738BD1B1D9713007030DA /* NewOrderFVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NewOrderFVC.swift; sourceTree = ""; }; 89CAA3DB1B10A50A00D7E4C2 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 89CAA3DE1B10BA7700D7E4C2 /* UICountingLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UICountingLabel.h; sourceTree = ""; }; 89CAA3DF1B10BA7700D7E4C2 /* UICountingLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UICountingLabel.m; sourceTree = ""; }; - 89D7C6B51AE44D0A00FFD592 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - 89D7C6B71AE4796500FFD592 /* ImageLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageLoader.swift; sourceTree = ""; }; + 89D7C6B71AE4796500FFD592 /* ImageLoader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageLoader.swift; path = Classes/Supports/ImageLoader.swift; sourceTree = ""; }; + 89D7F4441B17407F00ADA69C /* OrdersMapViewVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrdersMapViewVC.swift; sourceTree = ""; }; 89E6FB851B11EA98003A8276 /* UserMenuVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserMenuVC.swift; sourceTree = ""; }; 89E6FB871B12029C003A8276 /* MenuTransitionManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MenuTransitionManager.swift; sourceTree = ""; }; 89EEF4FF1B00720B006881FD /* TestReviewService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestReviewService.swift; sourceTree = ""; }; 89EEF5011B007233006881FD /* TestRequestService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TestRequestService.swift; sourceTree = ""; }; - 89EEF5051B008B05006881FD /* OrderDetailVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderDetailVC.swift; sourceTree = ""; }; + 89F88E311B19D4EC00674561 /* OrderDetailVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OrderDetailVC.swift; sourceTree = ""; }; + 89F88E381B1B51F500674561 /* dotActive.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dotActive.png; sourceTree = ""; }; + 89F88E391B1B51F500674561 /* dotActive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dotActive@2x.png"; sourceTree = ""; }; + 89F88E3A1B1B51F500674561 /* dotActive@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dotActive@3x.png"; sourceTree = ""; }; + 89F88E3B1B1B51F500674561 /* dotInactive.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = dotInactive.png; sourceTree = ""; }; + 89F88E3C1B1B51F500674561 /* dotInactive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dotInactive@2x.png"; sourceTree = ""; }; + 89F88E3D1B1B51F500674561 /* dotInactive@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "dotInactive@3x.png"; sourceTree = ""; }; + 89F88E3E1B1B51F500674561 /* image1.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image1.jpg; sourceTree = ""; }; + 89F88E3F1B1B51F500674561 /* image2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image2.jpg; sourceTree = ""; }; + 89F88E401B1B51F500674561 /* image3.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image3.jpg; sourceTree = ""; }; + 89F88E411B1B51F500674561 /* image4.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image4.jpg; sourceTree = ""; }; + 89F88E421B1B51F500674561 /* image5.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image5.jpg; sourceTree = ""; }; + 89F88E431B1B51F500674561 /* image6.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = image6.jpg; sourceTree = ""; }; + 89F88E511B1B59DA00674561 /* ContentViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContentViewController.xib; sourceTree = ""; }; + 89F88E531B1B59E600674561 /* ContentViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentViewController.swift; sourceTree = ""; }; + 89F88E561B1B683F00674561 /* MyOrdersVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyOrdersVC.swift; sourceTree = ""; }; + 89F88E5A1B1B778B00674561 /* MyOrdersRequestsTVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyOrdersRequestsTVC.swift; sourceTree = ""; }; + 89F88E5C1B1B77B000674561 /* MyOrdersRequestsTVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyOrdersRequestsTVCell.swift; sourceTree = ""; }; + 89F88E5E1B1B84B200674561 /* MyOrdersRequestViewDetailVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyOrdersRequestViewDetailVC.swift; sourceTree = ""; }; + 89F88E601B1B96FB00674561 /* MyOrdersRequestsShowTakerTVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyOrdersRequestsShowTakerTVC.swift; sourceTree = ""; }; + 89F88E621B1B971200674561 /* MyOrdersRequestsShowTakerTVCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MyOrdersRequestsShowTakerTVCell.swift; sourceTree = ""; }; + 89F88E641B1BB3AB00674561 /* ShowProgressVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ShowProgressVC.swift; sourceTree = ""; }; + 89F88E661B1D769500674561 /* PIRipple.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = PIRipple.swift; path = Frameworks/PIRipple.swift; sourceTree = ""; }; + 89F88E691B1D780900674561 /* LNBRippleEffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LNBRippleEffect.h; sourceTree = ""; }; + 89F88E6A1B1D780900674561 /* LNBRippleEffect.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LNBRippleEffect.m; sourceTree = ""; }; + 89F88E6F1B1D8C0C00674561 /* FormBaseCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormBaseCell.swift; sourceTree = ""; }; + 89F88E701B1D8C0C00674561 /* FormTitleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTitleCell.swift; sourceTree = ""; }; + 89F88E711B1D8C0C00674561 /* FormValueCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormValueCell.swift; sourceTree = ""; }; + 89F88E721B1D8C0C00674561 /* FormButtonCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormButtonCell.swift; sourceTree = ""; }; + 89F88E731B1D8C0C00674561 /* FormCheckCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormCheckCell.swift; sourceTree = ""; }; + 89F88E741B1D8C0C00674561 /* FormDateCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormDateCell.swift; sourceTree = ""; }; + 89F88E751B1D8C0C00674561 /* FormPickerCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormPickerCell.swift; sourceTree = ""; }; + 89F88E761B1D8C0C00674561 /* FormSegmentedControlCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSegmentedControlCell.swift; sourceTree = ""; }; + 89F88E771B1D8C0C00674561 /* FormSelectorCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSelectorCell.swift; sourceTree = ""; }; + 89F88E781B1D8C0C00674561 /* FormSliderCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSliderCell.swift; sourceTree = ""; }; + 89F88E791B1D8C0C00674561 /* FormStepperCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormStepperCell.swift; sourceTree = ""; }; + 89F88E7A1B1D8C0C00674561 /* FormSwitchCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSwitchCell.swift; sourceTree = ""; }; + 89F88E7B1B1D8C0C00674561 /* FormTextFieldCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTextFieldCell.swift; sourceTree = ""; }; + 89F88E7C1B1D8C0C00674561 /* FormTextViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormTextViewCell.swift; sourceTree = ""; }; + 89F88E7E1B1D8C0C00674561 /* FormOptionsSelectorController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormOptionsSelectorController.swift; sourceTree = ""; }; + 89F88E7F1B1D8C0C00674561 /* FormSelector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSelector.swift; sourceTree = ""; }; + 89F88E801B1D8C0C00674561 /* FormViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormViewController.swift; sourceTree = ""; }; + 89F88E821B1D8C0C00674561 /* FormDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormDescriptor.swift; sourceTree = ""; }; + 89F88E831B1D8C0C00674561 /* FormRowDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormRowDescriptor.swift; sourceTree = ""; }; + 89F88E841B1D8C0C00674561 /* FormSectionDescriptor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FormSectionDescriptor.swift; sourceTree = ""; }; + 89F88E851B1D8C0C00674561 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 89F88E861B1D8C0C00674561 /* SwiftForms.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwiftForms.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -226,6 +334,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 890168181B1431D300180942 /* SimpleAlert */ = { + isa = PBXGroup; + children = ( + 890168191B1431D300180942 /* SimpleAlert.swift */, + 8901681A1B1431D300180942 /* SimpleAlert.xib */, + ); + name = SimpleAlert; + path = Frameworks/SimpleAlert; + sourceTree = ""; + }; 8908FF471AE01ECF00C990DC = { isa = PBXGroup; children = ( @@ -316,12 +434,10 @@ 890D4C751AE4433400BD05DF /* Supports */ = { isa = PBXGroup; children = ( - 890D4C761AE4433400BD05DF /* MyPlayground.playground */, - 89D7C6B71AE4796500FFD592 /* ImageLoader.swift */, - 890E3FBC1AEC5B9500F22912 /* HelperMethods.swift */, - 8981A4D41AF5B0AD00F3046A /* LocationManager.swift */, 895822131B04E3AB000DA21E /* Arrived-Bridging-Header.h */, + 890E3FBC1AEC5B9500F22912 /* HelperMethods.swift */, 89E6FB871B12029C003A8276 /* MenuTransitionManager.swift */, + 890D4C761AE4433400BD05DF /* MyPlayground.playground */, ); path = Supports; sourceTree = ""; @@ -329,26 +445,13 @@ 890D4C771AE4433400BD05DF /* VCs */ = { isa = PBXGroup; children = ( - 890F54D21B01F41D0066E835 /* MakeOrderVC.swift */, - 890D4C781AE4433400BD05DF /* AddPaymentInfoVC.swift */, - 890D4C791AE4433400BD05DF /* LoggedInVC.swift */, - 890D4C7A1AE4433400BD05DF /* StartVC.swift */, - 890D4C7C1AE4433400BD05DF /* WelcomeVC.swift */, - 890D72B61B0741C5006360E7 /* UserAgreementVC.swift */, - 89D7C6B51AE44D0A00FFD592 /* ViewController.swift */, 89C4136D1AF4052C000C2C95 /* MainScreenVC.swift */, - 899DA8C81AF40B5E00F0C476 /* ProfileVC.swift */, - 8981A4CA1AF55B8800F3046A /* UserBankCardsTVC.swift */, - 8981A4CC1AF55BA100F3046A /* UserLocationsTVC.swift */, - 8981A4CE1AF5641500F3046A /* UserLocationsTVCell.swift */, - 8981A4D01AF56DB700F3046A /* UserBankCardsTVCell.swift */, - 8981A4D21AF58FCE00F3046A /* AddLocationVC.swift */, - 898455A11AF6EABD0071A31B /* OrdersVC.swift */, - 89EEF5051B008B05006881FD /* OrderDetailVC.swift */, - 890F54C61B0175200066E835 /* OrdersListTVC.swift */, - 890F54C81B0175370066E835 /* OrdersListTVCell.swift */, - 8975DAC21B0E2043009D4991 /* WaveformVC.swift */, - 89E6FB851B11EA98003A8276 /* UserMenuVC.swift */, + 89F0E9AE1B131CB800038270 /* Resigter & Login */, + 89F0E9AF1B131D7600038270 /* Profile */, + 89D7F4431B173FFE00ADA69C /* Orders */, + 89F88E551B1B673300674561 /* My Orders */, + 89F0E9B01B131DAB00038270 /* Misc */, + 892CC7811B198CAE00C8EB76 /* Archeived */, ); path = VCs; sourceTree = ""; @@ -375,6 +478,7 @@ 890E3FB01AEC581C00F22912 /* Assets */ = { isa = PBXGroup; children = ( + 89F88E371B1B51F500674561 /* Resources */, 8958224A1B04F0A4000DA21E /* SHSPhoneImage.bundle */, 890E3FB11AEC582600F22912 /* UI */, ); @@ -392,6 +496,45 @@ name = UI; sourceTree = ""; }; + 891B845F1B17B99E00BFC3E7 /* RRTagController */ = { + isa = PBXGroup; + children = ( + 891B84601B17B99E00BFC3E7 /* RRAddTagView.swift */, + 891B84611B17B99E00BFC3E7 /* RRTagCollectionViewCell.swift */, + 891B84621B17B99E00BFC3E7 /* RRTagController.swift */, + ); + name = RRTagController; + path = Frameworks/RRTagController; + sourceTree = ""; + }; + 892C174A1B147CC000D2D37F /* Banking */ = { + isa = PBXGroup; + children = ( + 8981A4CA1AF55B8800F3046A /* UserBankCardsTVC.swift */, + 8981A4D01AF56DB700F3046A /* UserBankCardsTVCell.swift */, + 892C17481B143B2800D2D37F /* AddBankCardVC.swift */, + ); + name = Banking; + sourceTree = ""; + }; + 892C174B1B147CD900D2D37F /* Addresses */ = { + isa = PBXGroup; + children = ( + 8981A4CC1AF55BA100F3046A /* UserLocationsTVC.swift */, + 8981A4CE1AF5641500F3046A /* UserLocationsTVCell.swift */, + 8981A4D21AF58FCE00F3046A /* AddLocationVC.swift */, + ); + name = Addresses; + sourceTree = ""; + }; + 892CC7811B198CAE00C8EB76 /* Archeived */ = { + isa = PBXGroup; + children = ( + 890F54D21B01F41D0066E835 /* MakeOrderVC.swift */, + ); + name = Archeived; + sourceTree = ""; + }; 89471C3C1B09F6C600EFE101 /* TextFieldEffects */ = { isa = PBXGroup; children = ( @@ -476,6 +619,7 @@ 89471C671B0C4D3200EFE101 /* Customizations */ = { isa = PBXGroup; children = ( + 892C17441B14344E00D2D37F /* AlertController.swift */, 89471C681B0C4D6400EFE101 /* CustomizedTabBarItem.swift */, ); name = Customizations; @@ -484,13 +628,21 @@ 8958224C1B0504CD000DA21E /* Frameworks */ = { isa = PBXGroup; children = ( + 89F88E661B1D769500674561 /* PIRipple.swift */, + 891B845B1B176EC700BFC3E7 /* SwiftNotice.swift */, + 89D7C6B71AE4796500FFD592 /* ImageLoader.swift */, + 8958227A1B050AD7000DA21E /* JSSAlertView.swift */, + 8975DAC01B0E187A009D4991 /* SiriWaveformView.swift */, + 8981A4D41AF5B0AD00F3046A /* LocationManager.swift */, + 89F88E6C1B1D8C0C00674561 /* SwiftForms */, + 89F88E681B1D780900674561 /* LBNRippleEffect */, + 890168181B1431D300180942 /* SimpleAlert */, 89CAA3DD1B10BA7700D7E4C2 /* UICountingLabel */, 89471C501B0C0C1700EFE101 /* RAMAnimatedTabBarController */, 89471C3C1B09F6C600EFE101 /* TextFieldEffects */, 890D72A51B0739E5006360E7 /* SHSPhoneComponent */, - 8958227A1B050AD7000DA21E /* JSSAlertView.swift */, 8958226A1B05061C000DA21E /* GoogleWearAlertView */, - 8975DAC01B0E187A009D4991 /* SiriWaveformView.swift */, + 891B845F1B17B99E00BFC3E7 /* RRTagController */, ); name = Frameworks; sourceTree = ""; @@ -545,6 +697,158 @@ path = Frameworks/UICountingLabel; sourceTree = ""; }; + 89D7F4431B173FFE00ADA69C /* Orders */ = { + isa = PBXGroup; + children = ( + 89C738BD1B1D9713007030DA /* NewOrderFVC.swift */, + 898455A11AF6EABD0071A31B /* OrdersVC.swift */, + 89D7F4441B17407F00ADA69C /* OrdersMapViewVC.swift */, + 892CC77F1B198C6F00C8EB76 /* OrdersListViewTVC.swift */, + 892CC7821B198CDF00C8EB76 /* OrdersListViewTVCell.swift */, + 89F88E311B19D4EC00674561 /* OrderDetailVC.swift */, + ); + name = Orders; + sourceTree = ""; + }; + 89F0E9AE1B131CB800038270 /* Resigter & Login */ = { + isa = PBXGroup; + children = ( + 890D4C7A1AE4433400BD05DF /* StartVC.swift */, + 890D4C7C1AE4433400BD05DF /* WelcomeVC.swift */, + 890D72B61B0741C5006360E7 /* UserAgreementVC.swift */, + 890D4C781AE4433400BD05DF /* AddPaymentInfoVC.swift */, + ); + name = "Resigter & Login"; + sourceTree = ""; + }; + 89F0E9AF1B131D7600038270 /* Profile */ = { + isa = PBXGroup; + children = ( + 899DA8C81AF40B5E00F0C476 /* ProfileVC.swift */, + 89E6FB851B11EA98003A8276 /* UserMenuVC.swift */, + 892C174A1B147CC000D2D37F /* Banking */, + 892C174B1B147CD900D2D37F /* Addresses */, + ); + name = Profile; + sourceTree = ""; + }; + 89F0E9B01B131DAB00038270 /* Misc */ = { + isa = PBXGroup; + children = ( + 89F88E531B1B59E600674561 /* ContentViewController.swift */, + 89F88E511B1B59DA00674561 /* ContentViewController.xib */, + 8975DAC21B0E2043009D4991 /* WaveformVC.swift */, + 890D4C791AE4433400BD05DF /* LoggedInVC.swift */, + ); + name = Misc; + sourceTree = ""; + }; + 89F88E371B1B51F500674561 /* Resources */ = { + isa = PBXGroup; + children = ( + 89F88E381B1B51F500674561 /* dotActive.png */, + 89F88E391B1B51F500674561 /* dotActive@2x.png */, + 89F88E3A1B1B51F500674561 /* dotActive@3x.png */, + 89F88E3B1B1B51F500674561 /* dotInactive.png */, + 89F88E3C1B1B51F500674561 /* dotInactive@2x.png */, + 89F88E3D1B1B51F500674561 /* dotInactive@3x.png */, + 89F88E3E1B1B51F500674561 /* image1.jpg */, + 89F88E3F1B1B51F500674561 /* image2.jpg */, + 89F88E401B1B51F500674561 /* image3.jpg */, + 89F88E411B1B51F500674561 /* image4.jpg */, + 89F88E421B1B51F500674561 /* image5.jpg */, + 89F88E431B1B51F500674561 /* image6.jpg */, + ); + name = Resources; + path = Assets/Resources; + sourceTree = ""; + }; + 89F88E551B1B673300674561 /* My Orders */ = { + isa = PBXGroup; + children = ( + 89F88E641B1BB3AB00674561 /* ShowProgressVC.swift */, + 89F88E561B1B683F00674561 /* MyOrdersVC.swift */, + 89F88E5A1B1B778B00674561 /* MyOrdersRequestsTVC.swift */, + 89F88E5C1B1B77B000674561 /* MyOrdersRequestsTVCell.swift */, + 89F88E5E1B1B84B200674561 /* MyOrdersRequestViewDetailVC.swift */, + 89F88E601B1B96FB00674561 /* MyOrdersRequestsShowTakerTVC.swift */, + 89F88E621B1B971200674561 /* MyOrdersRequestsShowTakerTVCell.swift */, + ); + name = "My Orders"; + sourceTree = ""; + }; + 89F88E681B1D780900674561 /* LBNRippleEffect */ = { + isa = PBXGroup; + children = ( + 89F88E691B1D780900674561 /* LNBRippleEffect.h */, + 89F88E6A1B1D780900674561 /* LNBRippleEffect.m */, + ); + name = LBNRippleEffect; + path = Frameworks/LBNRippleEffect; + sourceTree = ""; + }; + 89F88E6C1B1D8C0C00674561 /* SwiftForms */ = { + isa = PBXGroup; + children = ( + 89F88E6D1B1D8C0C00674561 /* cells */, + 89F88E7D1B1D8C0C00674561 /* controllers */, + 89F88E811B1D8C0C00674561 /* descriptors */, + 89F88E851B1D8C0C00674561 /* Info.plist */, + 89F88E861B1D8C0C00674561 /* SwiftForms.h */, + ); + name = SwiftForms; + path = Frameworks/SwiftForms; + sourceTree = ""; + }; + 89F88E6D1B1D8C0C00674561 /* cells */ = { + isa = PBXGroup; + children = ( + 89F88E6E1B1D8C0C00674561 /* base */, + 89F88E721B1D8C0C00674561 /* FormButtonCell.swift */, + 89F88E731B1D8C0C00674561 /* FormCheckCell.swift */, + 89F88E741B1D8C0C00674561 /* FormDateCell.swift */, + 89F88E751B1D8C0C00674561 /* FormPickerCell.swift */, + 89F88E761B1D8C0C00674561 /* FormSegmentedControlCell.swift */, + 89F88E771B1D8C0C00674561 /* FormSelectorCell.swift */, + 89F88E781B1D8C0C00674561 /* FormSliderCell.swift */, + 89F88E791B1D8C0C00674561 /* FormStepperCell.swift */, + 89F88E7A1B1D8C0C00674561 /* FormSwitchCell.swift */, + 89F88E7B1B1D8C0C00674561 /* FormTextFieldCell.swift */, + 89F88E7C1B1D8C0C00674561 /* FormTextViewCell.swift */, + ); + path = cells; + sourceTree = ""; + }; + 89F88E6E1B1D8C0C00674561 /* base */ = { + isa = PBXGroup; + children = ( + 89F88E6F1B1D8C0C00674561 /* FormBaseCell.swift */, + 89F88E701B1D8C0C00674561 /* FormTitleCell.swift */, + 89F88E711B1D8C0C00674561 /* FormValueCell.swift */, + ); + path = base; + sourceTree = ""; + }; + 89F88E7D1B1D8C0C00674561 /* controllers */ = { + isa = PBXGroup; + children = ( + 89F88E7E1B1D8C0C00674561 /* FormOptionsSelectorController.swift */, + 89F88E7F1B1D8C0C00674561 /* FormSelector.swift */, + 89F88E801B1D8C0C00674561 /* FormViewController.swift */, + ); + path = controllers; + sourceTree = ""; + }; + 89F88E811B1D8C0C00674561 /* descriptors */ = { + isa = PBXGroup; + children = ( + 89F88E821B1D8C0C00674561 /* FormDescriptor.swift */, + 89F88E831B1D8C0C00674561 /* FormRowDescriptor.swift */, + 89F88E841B1D8C0C00674561 /* FormSectionDescriptor.swift */, + ); + path = descriptors; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -631,9 +935,14 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 89F88E491B1B51F500674561 /* dotInactive@3x.png in Resources */, 8958224B1B04F0A4000DA21E /* SHSPhoneImage.bundle in Resources */, 89CAA3DC1B10A50A00D7E4C2 /* Images.xcassets in Resources */, + 8901681C1B1431D300180942 /* SimpleAlert.xib in Resources */, 899DA8D31AF41AC700F0C476 /* birthday-104.png in Resources */, + 89F88E441B1B51F500674561 /* dotActive.png in Resources */, + 89F88E4F1B1B51F500674561 /* image6.jpg in Resources */, + 89F88E4C1B1B51F500674561 /* image3.jpg in Resources */, 89C4135B1AF1CD91000C2C95 /* Phone Icon.png in Resources */, 89C4136A1AF40402000C2C95 /* Main.storyboard in Resources */, 895822741B05061C000DA21E /* errorIcon@2x.png in Resources */, @@ -642,17 +951,27 @@ 895822761B05061C000DA21E /* successIcon@2x.png in Resources */, 89C413571AF1C523000C2C95 /* Screen.png in Resources */, 89C413681AF3252F000C2C95 /* key-100.png in Resources */, + 89F88E4B1B1B51F500674561 /* image2.jpg in Resources */, 89471C481B09F6C600EFE101 /* Info.plist in Resources */, 895822771B05061C000DA21E /* warningIcon@2x.png in Resources */, + 89F88E4A1B1B51F500674561 /* image1.jpg in Resources */, 895822751B05061C000DA21E /* messageIcon@2x.png in Resources */, + 89F88E4D1B1B51F500674561 /* image4.jpg in Resources */, 899DA8D61AF41AC700F0C476 /* mental_status-96.png in Resources */, 899DA8D41AF41AC700F0C476 /* collaborator-104.png in Resources */, 8908FF601AE01ECF00C990DC /* LaunchScreen.xib in Resources */, 899DA8D51AF41AC700F0C476 /* email-104.png in Resources */, 89C413551AF1C3D9000C2C95 /* background.jpeg in Resources */, 89C413641AF32029000C2C95 /* credit_card-100.png in Resources */, + 89F88E9B1B1D8C0C00674561 /* Info.plist in Resources */, + 89F88E481B1B51F500674561 /* dotInactive@2x.png in Resources */, 899DA8CC1AF419C000F0C476 /* thumbs_down-104.png in Resources */, + 89F88E521B1B59DA00674561 /* ContentViewController.xib in Resources */, 899DA8D71AF41AC700F0C476 /* toilet-104.png in Resources */, + 89F88E471B1B51F500674561 /* dotInactive.png in Resources */, + 89F88E4E1B1B51F500674561 /* image5.jpg in Resources */, + 89F88E461B1B51F500674561 /* dotActive@3x.png in Resources */, + 89F88E451B1B51F500674561 /* dotActive@2x.png in Resources */, 89C413651AF32029000C2C95 /* today-100.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -672,67 +991,105 @@ buildActionMask = 2147483647; files = ( 890A1C441AEAD02F00E6E6D9 /* ServiceHandler.swift in Sources */, + 892C17491B143B2800D2D37F /* AddBankCardVC.swift in Sources */, + 89F88E5B1B1B778B00674561 /* MyOrdersRequestsTVC.swift in Sources */, 890D4C7F1AE4433400BD05DF /* UserService.swift in Sources */, 899DA8C91AF40B5E00F0C476 /* ProfileVC.swift in Sources */, + 891B84651B17B99E00BFC3E7 /* RRTagController.swift in Sources */, + 89F88E971B1D8C0C00674561 /* FormViewController.swift in Sources */, + 89F88E8F1B1D8C0C00674561 /* FormSelectorCell.swift in Sources */, + 89F88E571B1B683F00674561 /* MyOrdersVC.swift in Sources */, 890E3FBD1AEC5B9500F22912 /* HelperMethods.swift in Sources */, 8975DAC31B0E2043009D4991 /* WaveformVC.swift in Sources */, 890F54CE1B01F4120066E835 /* AudioContext.swift in Sources */, - 89EEF5061B008B05006881FD /* OrderDetailVC.swift in Sources */, 89471C4D1B09F6C600EFE101 /* MinoruTextField.swift in Sources */, + 89F88E891B1D8C0C00674561 /* FormValueCell.swift in Sources */, 89471C4C1B09F6C600EFE101 /* MadokaTextField.swift in Sources */, 890D4C851AE4433400BD05DF /* WelcomeVC.swift in Sources */, - 890F54C71B0175200066E835 /* OrdersListTVC.swift in Sources */, 89471C601B0C0C1700EFE101 /* RAMFumeAnimation.swift in Sources */, + 892C17451B14344E00D2D37F /* AlertController.swift in Sources */, 89E6FB861B11EA98003A8276 /* UserMenuVC.swift in Sources */, 89D7C6B81AE4796500FFD592 /* ImageLoader.swift in Sources */, 8981A4CB1AF55B8800F3046A /* UserBankCardsTVC.swift in Sources */, + 891B84641B17B99E00BFC3E7 /* RRTagCollectionViewCell.swift in Sources */, 89471C471B09F6C600EFE101 /* HoshiTextField.swift in Sources */, 89471C4F1B09F6C600EFE101 /* YokoTextField.swift in Sources */, 8981A4CD1AF55BA100F3046A /* UserLocationsTVC.swift in Sources */, 89CAA3E01B10BA7700D7E4C2 /* UICountingLabel.m in Sources */, + 89F88E8A1B1D8C0C00674561 /* FormButtonCell.swift in Sources */, 895822731B05061C000DA21E /* GoogleWearAlertView.swift in Sources */, 890D72B11B0739E5006360E7 /* SHSFlagAccessoryView.m in Sources */, 890D4C811AE4433400BD05DF /* AddPaymentInfoVC.swift in Sources */, 89C4136E1AF4052C000C2C95 /* MainScreenVC.swift in Sources */, 89EEF5001B00720B006881FD /* TestReviewService.swift in Sources */, + 89F88E871B1D8C0C00674561 /* FormBaseCell.swift in Sources */, + 89F88E671B1D769500674561 /* PIRipple.swift in Sources */, 890F54CF1B01F4120066E835 /* AudioManager.swift in Sources */, 899DA8D91AF4222C00F0C476 /* User.swift in Sources */, 890F54D11B01F4120066E835 /* AudioRecorder.swift in Sources */, - 89D7C6B61AE44D0A00FFD592 /* ViewController.swift in Sources */, 890F54D01B01F4120066E835 /* AudioPlayer.swift in Sources */, 8975DAC11B0E187A009D4991 /* SiriWaveformView.swift in Sources */, 89471C4A1B09F6C600EFE101 /* JiroTextField.swift in Sources */, 89471C491B09F6C600EFE101 /* IsaoTextField.swift in Sources */, + 89F88E881B1D8C0C00674561 /* FormTitleCell.swift in Sources */, + 89F88E8E1B1D8C0C00674561 /* FormSegmentedControlCell.swift in Sources */, 890D4C821AE4433400BD05DF /* LoggedInVC.swift in Sources */, 890D72B71B0741C5006360E7 /* UserAgreementVC.swift in Sources */, + 89F88E961B1D8C0C00674561 /* FormSelector.swift in Sources */, 8981A4D31AF58FCE00F3046A /* AddLocationVC.swift in Sources */, + 89F88E951B1D8C0C00674561 /* FormOptionsSelectorController.swift in Sources */, 8981A4CF1AF5641500F3046A /* UserLocationsTVCell.swift in Sources */, + 89C738BE1B1D9713007030DA /* NewOrderFVC.swift in Sources */, + 891B845C1B176EC700BFC3E7 /* SwiftNotice.swift in Sources */, 895822721B05061C000DA21E /* GoogleWearAlert.swift in Sources */, 89C413511AF16ACF000C2C95 /* TestUserService.swift in Sources */, 89E6FB881B12029C003A8276 /* MenuTransitionManager.swift in Sources */, - 890F54C91B0175370066E835 /* OrdersListTVCell.swift in Sources */, + 89F88E631B1B971200674561 /* MyOrdersRequestsShowTakerTVCell.swift in Sources */, + 89F88E541B1B59E600674561 /* ContentViewController.swift in Sources */, + 89F88E6B1B1D780900674561 /* LNBRippleEffect.m in Sources */, + 891B84631B17B99E00BFC3E7 /* RRAddTagView.swift in Sources */, 89471C5F1B0C0C1700EFE101 /* RAMFrameItemAnimation.swift in Sources */, 890D4C7D1AE4433400BD05DF /* BaseService.swift in Sources */, 8958227B1B050AD7000DA21E /* JSSAlertView.swift in Sources */, 8981A4D51AF5B0AD00F3046A /* LocationManager.swift in Sources */, 89471C5E1B0C0C1700EFE101 /* RAMBounceAnimation.swift in Sources */, + 89F88E8C1B1D8C0C00674561 /* FormDateCell.swift in Sources */, + 89F88E651B1BB3AB00674561 /* ShowProgressVC.swift in Sources */, + 89F88E8D1B1D8C0C00674561 /* FormPickerCell.swift in Sources */, 890D72B31B0739E5006360E7 /* SHSPhoneNumberFormatter+UserConfig.m in Sources */, + 89F88E901B1D8C0C00674561 /* FormSliderCell.swift in Sources */, 890D72B21B0739E5006360E7 /* SHSPhoneLogic.m in Sources */, + 89D7F4451B17407F00ADA69C /* OrdersMapViewVC.swift in Sources */, + 89F88E991B1D8C0C00674561 /* FormRowDescriptor.swift in Sources */, 8981A4D11AF56DB700F3046A /* UserBankCardsTVCell.swift in Sources */, 898455A21AF6EABD0071A31B /* OrdersVC.swift in Sources */, + 89F88E321B19D4EC00674561 /* OrderDetailVC.swift in Sources */, 89471C4B1B09F6C600EFE101 /* KaedeTextField.swift in Sources */, + 892CC7801B198C6F00C8EB76 /* OrdersListViewTVC.swift in Sources */, 89471C691B0C4D6400EFE101 /* CustomizedTabBarItem.swift in Sources */, 89EEF5021B007233006881FD /* TestRequestService.swift in Sources */, + 89F88E941B1D8C0C00674561 /* FormTextViewCell.swift in Sources */, + 89F88E9A1B1D8C0C00674561 /* FormSectionDescriptor.swift in Sources */, + 89F88E5D1B1B77B000674561 /* MyOrdersRequestsTVCell.swift in Sources */, + 89F88E611B1B96FB00674561 /* MyOrdersRequestsShowTakerTVC.swift in Sources */, 89471C631B0C0C1700EFE101 /* RAMAnimatedTabBarController.swift in Sources */, + 892CC7831B198CDF00C8EB76 /* OrdersListViewTVCell.swift in Sources */, + 89F88E8B1B1D8C0C00674561 /* FormCheckCell.swift in Sources */, 89471C621B0C0C1700EFE101 /* RAMTransitionItemAnimation.swift in Sources */, 89471C4E1B09F6C600EFE101 /* TextFieldsEffects.swift in Sources */, + 89F88E5F1B1B84B200674561 /* MyOrdersRequestViewDetailVC.swift in Sources */, 890D72B41B0739E5006360E7 /* SHSPhoneNumberFormatter.m in Sources */, 89471C641B0C0C1700EFE101 /* RAMItemAnimationProtocol.swift in Sources */, + 89F88E911B1D8C0C00674561 /* FormStepperCell.swift in Sources */, 8908FF561AE01ECF00C990DC /* AppDelegate.swift in Sources */, 89471C611B0C0C1700EFE101 /* RAMRotationAnimation.swift in Sources */, + 89F88E981B1D8C0C00674561 /* FormDescriptor.swift in Sources */, 890D4C831AE4433400BD05DF /* StartVC.swift in Sources */, + 89F88E921B1D8C0C00674561 /* FormSwitchCell.swift in Sources */, + 8901681B1B1431D300180942 /* SimpleAlert.swift in Sources */, 890F54D31B01F41D0066E835 /* MakeOrderVC.swift in Sources */, 890D72B51B0739E5006360E7 /* SHSPhoneTextField.m in Sources */, + 89F88E931B1D8C0C00674561 /* FormTextFieldCell.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Arrived/Images.xcassets/address icon.imageset/Contents.json b/Arrived/Images.xcassets/address icon.imageset/Contents.json new file mode 100644 index 0000000..7109acd --- /dev/null +++ b/Arrived/Images.xcassets/address icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "address icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "address icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "address icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/address icon.imageset/address icon.png b/Arrived/Images.xcassets/address icon.imageset/address icon.png new file mode 100644 index 0000000..e3f5290 Binary files /dev/null and b/Arrived/Images.xcassets/address icon.imageset/address icon.png differ diff --git a/Arrived/Images.xcassets/address icon.imageset/address icon@2x.png b/Arrived/Images.xcassets/address icon.imageset/address icon@2x.png new file mode 100644 index 0000000..6c45e5f Binary files /dev/null and b/Arrived/Images.xcassets/address icon.imageset/address icon@2x.png differ diff --git a/Arrived/Images.xcassets/address icon.imageset/address icon@3x.png b/Arrived/Images.xcassets/address icon.imageset/address icon@3x.png new file mode 100644 index 0000000..dddb7a4 Binary files /dev/null and b/Arrived/Images.xcassets/address icon.imageset/address icon@3x.png differ diff --git a/Arrived/Images.xcassets/card frame.imageset/Contents.json b/Arrived/Images.xcassets/card frame.imageset/Contents.json new file mode 100644 index 0000000..999d240 --- /dev/null +++ b/Arrived/Images.xcassets/card frame.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "card frame.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "card frame@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "card frame@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/card frame.imageset/card frame.png b/Arrived/Images.xcassets/card frame.imageset/card frame.png new file mode 100644 index 0000000..567efb3 Binary files /dev/null and b/Arrived/Images.xcassets/card frame.imageset/card frame.png differ diff --git a/Arrived/Images.xcassets/card frame.imageset/card frame@2x.png b/Arrived/Images.xcassets/card frame.imageset/card frame@2x.png new file mode 100644 index 0000000..11dedd5 Binary files /dev/null and b/Arrived/Images.xcassets/card frame.imageset/card frame@2x.png differ diff --git a/Arrived/Images.xcassets/card frame.imageset/card frame@3x.png b/Arrived/Images.xcassets/card frame.imageset/card frame@3x.png new file mode 100644 index 0000000..3836ec6 Binary files /dev/null and b/Arrived/Images.xcassets/card frame.imageset/card frame@3x.png differ diff --git a/Arrived/Images.xcassets/default label.imageset/Contents.json b/Arrived/Images.xcassets/default label.imageset/Contents.json new file mode 100644 index 0000000..bb491c8 --- /dev/null +++ b/Arrived/Images.xcassets/default label.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "default label.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "default label@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "default label@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/default label.imageset/default label.png b/Arrived/Images.xcassets/default label.imageset/default label.png new file mode 100644 index 0000000..dbec5fc Binary files /dev/null and b/Arrived/Images.xcassets/default label.imageset/default label.png differ diff --git a/Arrived/Images.xcassets/default label.imageset/default label@2x.png b/Arrived/Images.xcassets/default label.imageset/default label@2x.png new file mode 100644 index 0000000..9d3c4ee Binary files /dev/null and b/Arrived/Images.xcassets/default label.imageset/default label@2x.png differ diff --git a/Arrived/Images.xcassets/default label.imageset/default label@3x.png b/Arrived/Images.xcassets/default label.imageset/default label@3x.png new file mode 100644 index 0000000..d179bab Binary files /dev/null and b/Arrived/Images.xcassets/default label.imageset/default label@3x.png differ diff --git a/Arrived/Images.xcassets/detail dislikes icon.imageset/Contents.json b/Arrived/Images.xcassets/detail dislikes icon.imageset/Contents.json new file mode 100644 index 0000000..4313b18 --- /dev/null +++ b/Arrived/Images.xcassets/detail dislikes icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "detail dislikes icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "detail dislikes icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "detail dislikes icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon.png b/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon.png new file mode 100644 index 0000000..548305f Binary files /dev/null and b/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon.png differ diff --git a/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon@2x.png b/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon@2x.png new file mode 100644 index 0000000..26b467e Binary files /dev/null and b/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon@2x.png differ diff --git a/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon@3x.png b/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon@3x.png new file mode 100644 index 0000000..6ef9ae1 Binary files /dev/null and b/Arrived/Images.xcassets/detail dislikes icon.imageset/detail dislikes icon@3x.png differ diff --git a/Arrived/Images.xcassets/detail interest icon.imageset/Contents.json b/Arrived/Images.xcassets/detail interest icon.imageset/Contents.json new file mode 100644 index 0000000..476efe7 --- /dev/null +++ b/Arrived/Images.xcassets/detail interest icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "detail interest icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "detail interest icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "detail interest icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon.png b/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon.png new file mode 100644 index 0000000..4e81a9e Binary files /dev/null and b/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon.png differ diff --git a/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon@2x.png b/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon@2x.png new file mode 100644 index 0000000..e7b8813 Binary files /dev/null and b/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon@2x.png differ diff --git a/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon@3x.png b/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon@3x.png new file mode 100644 index 0000000..19c5de7 Binary files /dev/null and b/Arrived/Images.xcassets/detail interest icon.imageset/detail interest icon@3x.png differ diff --git a/Arrived/Images.xcassets/detail job finished icon.imageset/Contents.json b/Arrived/Images.xcassets/detail job finished icon.imageset/Contents.json new file mode 100644 index 0000000..67c9448 --- /dev/null +++ b/Arrived/Images.xcassets/detail job finished icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "detail job finished icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "detail job finished icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "detail job finished icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon.png b/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon.png new file mode 100644 index 0000000..2f62ba4 Binary files /dev/null and b/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon.png differ diff --git a/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon@2x.png b/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon@2x.png new file mode 100644 index 0000000..0c6a924 Binary files /dev/null and b/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon@2x.png differ diff --git a/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon@3x.png b/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon@3x.png new file mode 100644 index 0000000..c46d2a4 Binary files /dev/null and b/Arrived/Images.xcassets/detail job finished icon.imageset/detail job finished icon@3x.png differ diff --git a/Arrived/Images.xcassets/detail likes icon.imageset/Contents.json b/Arrived/Images.xcassets/detail likes icon.imageset/Contents.json new file mode 100644 index 0000000..4c14eeb --- /dev/null +++ b/Arrived/Images.xcassets/detail likes icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "detail likes icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "detail likes icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "detail likes icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon.png b/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon.png new file mode 100644 index 0000000..b1c3385 Binary files /dev/null and b/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon.png differ diff --git a/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon@2x.png b/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon@2x.png new file mode 100644 index 0000000..50e85c5 Binary files /dev/null and b/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon@2x.png differ diff --git a/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon@3x.png b/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon@3x.png new file mode 100644 index 0000000..01af1c9 Binary files /dev/null and b/Arrived/Images.xcassets/detail likes icon.imageset/detail likes icon@3x.png differ diff --git a/Arrived/Images.xcassets/in progress pin.imageset/Contents.json b/Arrived/Images.xcassets/in progress pin.imageset/Contents.json new file mode 100644 index 0000000..1017dbe --- /dev/null +++ b/Arrived/Images.xcassets/in progress pin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "in progress pin.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "in progress pin@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "in progress pin@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/in progress pin.imageset/in progress pin.png b/Arrived/Images.xcassets/in progress pin.imageset/in progress pin.png new file mode 100644 index 0000000..031bb7c Binary files /dev/null and b/Arrived/Images.xcassets/in progress pin.imageset/in progress pin.png differ diff --git a/Arrived/Images.xcassets/in progress pin.imageset/in progress pin@2x.png b/Arrived/Images.xcassets/in progress pin.imageset/in progress pin@2x.png new file mode 100644 index 0000000..f874029 Binary files /dev/null and b/Arrived/Images.xcassets/in progress pin.imageset/in progress pin@2x.png differ diff --git a/Arrived/Images.xcassets/in progress pin.imageset/in progress pin@3x.png b/Arrived/Images.xcassets/in progress pin.imageset/in progress pin@3x.png new file mode 100644 index 0000000..0422087 Binary files /dev/null and b/Arrived/Images.xcassets/in progress pin.imageset/in progress pin@3x.png differ diff --git a/Arrived/Images.xcassets/interested icon tiny.imageset/Contents.json b/Arrived/Images.xcassets/interested icon tiny.imageset/Contents.json new file mode 100644 index 0000000..36510db --- /dev/null +++ b/Arrived/Images.xcassets/interested icon tiny.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "interested icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "interested icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "interested icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon.png b/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon.png new file mode 100644 index 0000000..8d0649e Binary files /dev/null and b/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon.png differ diff --git a/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon@2x.png b/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon@2x.png new file mode 100644 index 0000000..3e1dc4d Binary files /dev/null and b/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon@2x.png differ diff --git a/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon@3x.png b/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon@3x.png new file mode 100644 index 0000000..bbba8b6 Binary files /dev/null and b/Arrived/Images.xcassets/interested icon tiny.imageset/interested icon@3x.png differ diff --git a/Arrived/Images.xcassets/interested icon.imageset/Contents.json b/Arrived/Images.xcassets/interested icon.imageset/Contents.json new file mode 100644 index 0000000..36510db --- /dev/null +++ b/Arrived/Images.xcassets/interested icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "interested icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "interested icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "interested icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/interested icon.imageset/interested icon.png b/Arrived/Images.xcassets/interested icon.imageset/interested icon.png new file mode 100644 index 0000000..d1a3aa2 Binary files /dev/null and b/Arrived/Images.xcassets/interested icon.imageset/interested icon.png differ diff --git a/Arrived/Images.xcassets/interested icon.imageset/interested icon@2x.png b/Arrived/Images.xcassets/interested icon.imageset/interested icon@2x.png new file mode 100644 index 0000000..71f2163 Binary files /dev/null and b/Arrived/Images.xcassets/interested icon.imageset/interested icon@2x.png differ diff --git a/Arrived/Images.xcassets/interested icon.imageset/interested icon@3x.png b/Arrived/Images.xcassets/interested icon.imageset/interested icon@3x.png new file mode 100644 index 0000000..6449c41 Binary files /dev/null and b/Arrived/Images.xcassets/interested icon.imageset/interested icon@3x.png differ diff --git a/Arrived/Images.xcassets/interested indicator.imageset/Contents.json b/Arrived/Images.xcassets/interested indicator.imageset/Contents.json new file mode 100644 index 0000000..35589c6 --- /dev/null +++ b/Arrived/Images.xcassets/interested indicator.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "interested indicator.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "interested indicator@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "interested indicator@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/interested indicator.imageset/interested indicator.png b/Arrived/Images.xcassets/interested indicator.imageset/interested indicator.png new file mode 100644 index 0000000..51cbec6 Binary files /dev/null and b/Arrived/Images.xcassets/interested indicator.imageset/interested indicator.png differ diff --git a/Arrived/Images.xcassets/interested indicator.imageset/interested indicator@2x.png b/Arrived/Images.xcassets/interested indicator.imageset/interested indicator@2x.png new file mode 100644 index 0000000..b711ef8 Binary files /dev/null and b/Arrived/Images.xcassets/interested indicator.imageset/interested indicator@2x.png differ diff --git a/Arrived/Images.xcassets/interested indicator.imageset/interested indicator@3x.png b/Arrived/Images.xcassets/interested indicator.imageset/interested indicator@3x.png new file mode 100644 index 0000000..675cc12 Binary files /dev/null and b/Arrived/Images.xcassets/interested indicator.imageset/interested indicator@3x.png differ diff --git a/Arrived/Images.xcassets/interested pin.imageset/Contents.json b/Arrived/Images.xcassets/interested pin.imageset/Contents.json new file mode 100644 index 0000000..842c355 --- /dev/null +++ b/Arrived/Images.xcassets/interested pin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "interested pin.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "interested pin@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "interested pin@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/interested pin.imageset/interested pin.png b/Arrived/Images.xcassets/interested pin.imageset/interested pin.png new file mode 100644 index 0000000..72b97d0 Binary files /dev/null and b/Arrived/Images.xcassets/interested pin.imageset/interested pin.png differ diff --git a/Arrived/Images.xcassets/interested pin.imageset/interested pin@2x.png b/Arrived/Images.xcassets/interested pin.imageset/interested pin@2x.png new file mode 100644 index 0000000..1b3e94b Binary files /dev/null and b/Arrived/Images.xcassets/interested pin.imageset/interested pin@2x.png differ diff --git a/Arrived/Images.xcassets/interested pin.imageset/interested pin@3x.png b/Arrived/Images.xcassets/interested pin.imageset/interested pin@3x.png new file mode 100644 index 0000000..633e580 Binary files /dev/null and b/Arrived/Images.xcassets/interested pin.imageset/interested pin@3x.png differ diff --git a/Arrived/Images.xcassets/map pin.imageset/Contents.json b/Arrived/Images.xcassets/map pin.imageset/Contents.json new file mode 100644 index 0000000..55c99d7 --- /dev/null +++ b/Arrived/Images.xcassets/map pin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "map pin.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "map pin@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "map pin@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/map pin.imageset/map pin.png b/Arrived/Images.xcassets/map pin.imageset/map pin.png new file mode 100644 index 0000000..d28fe3c Binary files /dev/null and b/Arrived/Images.xcassets/map pin.imageset/map pin.png differ diff --git a/Arrived/Images.xcassets/map pin.imageset/map pin@2x.png b/Arrived/Images.xcassets/map pin.imageset/map pin@2x.png new file mode 100644 index 0000000..ee1170a Binary files /dev/null and b/Arrived/Images.xcassets/map pin.imageset/map pin@2x.png differ diff --git a/Arrived/Images.xcassets/map pin.imageset/map pin@3x.png b/Arrived/Images.xcassets/map pin.imageset/map pin@3x.png new file mode 100644 index 0000000..166a812 Binary files /dev/null and b/Arrived/Images.xcassets/map pin.imageset/map pin@3x.png differ diff --git a/Arrived/Images.xcassets/processing icon tiny.imageset/Contents.json b/Arrived/Images.xcassets/processing icon tiny.imageset/Contents.json new file mode 100644 index 0000000..7273372 --- /dev/null +++ b/Arrived/Images.xcassets/processing icon tiny.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "processing icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "processing icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "processing icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon.png b/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon.png new file mode 100644 index 0000000..16e6bd5 Binary files /dev/null and b/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon.png differ diff --git a/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon@2x.png b/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon@2x.png new file mode 100644 index 0000000..98b4609 Binary files /dev/null and b/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon@2x.png differ diff --git a/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon@3x.png b/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon@3x.png new file mode 100644 index 0000000..cafccf4 Binary files /dev/null and b/Arrived/Images.xcassets/processing icon tiny.imageset/processing icon@3x.png differ diff --git a/Arrived/Images.xcassets/processing indicator.imageset/Contents.json b/Arrived/Images.xcassets/processing indicator.imageset/Contents.json new file mode 100644 index 0000000..0ac1fb4 --- /dev/null +++ b/Arrived/Images.xcassets/processing indicator.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "processing indicator.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "processing indicator@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "processing indicator@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/processing indicator.imageset/processing indicator.png b/Arrived/Images.xcassets/processing indicator.imageset/processing indicator.png new file mode 100644 index 0000000..de8da37 Binary files /dev/null and b/Arrived/Images.xcassets/processing indicator.imageset/processing indicator.png differ diff --git a/Arrived/Images.xcassets/processing indicator.imageset/processing indicator@2x.png b/Arrived/Images.xcassets/processing indicator.imageset/processing indicator@2x.png new file mode 100644 index 0000000..a83afd0 Binary files /dev/null and b/Arrived/Images.xcassets/processing indicator.imageset/processing indicator@2x.png differ diff --git a/Arrived/Images.xcassets/processing indicator.imageset/processing indicator@3x.png b/Arrived/Images.xcassets/processing indicator.imageset/processing indicator@3x.png new file mode 100644 index 0000000..18424e2 Binary files /dev/null and b/Arrived/Images.xcassets/processing indicator.imageset/processing indicator@3x.png differ diff --git a/Arrived/Images.xcassets/progressing icon.imageset/Contents.json b/Arrived/Images.xcassets/progressing icon.imageset/Contents.json new file mode 100644 index 0000000..f82ad45 --- /dev/null +++ b/Arrived/Images.xcassets/progressing icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "progressing icon.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "progressing icon@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "progressing icon@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/progressing icon.imageset/progressing icon.png b/Arrived/Images.xcassets/progressing icon.imageset/progressing icon.png new file mode 100644 index 0000000..9b268a7 Binary files /dev/null and b/Arrived/Images.xcassets/progressing icon.imageset/progressing icon.png differ diff --git a/Arrived/Images.xcassets/progressing icon.imageset/progressing icon@2x.png b/Arrived/Images.xcassets/progressing icon.imageset/progressing icon@2x.png new file mode 100644 index 0000000..3565f23 Binary files /dev/null and b/Arrived/Images.xcassets/progressing icon.imageset/progressing icon@2x.png differ diff --git a/Arrived/Images.xcassets/progressing icon.imageset/progressing icon@3x.png b/Arrived/Images.xcassets/progressing icon.imageset/progressing icon@3x.png new file mode 100644 index 0000000..3b49135 Binary files /dev/null and b/Arrived/Images.xcassets/progressing icon.imageset/progressing icon@3x.png differ diff --git a/Arrived/Images.xcassets/regular pin.imageset/Contents.json b/Arrived/Images.xcassets/regular pin.imageset/Contents.json new file mode 100644 index 0000000..ac90f82 --- /dev/null +++ b/Arrived/Images.xcassets/regular pin.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "regular pin.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "regular pin@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "regular pin@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/regular pin.imageset/regular pin.png b/Arrived/Images.xcassets/regular pin.imageset/regular pin.png new file mode 100644 index 0000000..1e019aa Binary files /dev/null and b/Arrived/Images.xcassets/regular pin.imageset/regular pin.png differ diff --git a/Arrived/Images.xcassets/regular pin.imageset/regular pin@2x.png b/Arrived/Images.xcassets/regular pin.imageset/regular pin@2x.png new file mode 100644 index 0000000..088fbd9 Binary files /dev/null and b/Arrived/Images.xcassets/regular pin.imageset/regular pin@2x.png differ diff --git a/Arrived/Images.xcassets/regular pin.imageset/regular pin@3x.png b/Arrived/Images.xcassets/regular pin.imageset/regular pin@3x.png new file mode 100644 index 0000000..fceb41b Binary files /dev/null and b/Arrived/Images.xcassets/regular pin.imageset/regular pin@3x.png differ diff --git a/Arrived/Images.xcassets/requests in progress indicator.imageset/Contents.json b/Arrived/Images.xcassets/requests in progress indicator.imageset/Contents.json new file mode 100644 index 0000000..3b4e0b4 --- /dev/null +++ b/Arrived/Images.xcassets/requests in progress indicator.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x", + "filename" : "requests in progress indicator.png" + }, + { + "idiom" : "universal", + "scale" : "2x", + "filename" : "requests in progress indicator@2x.png" + }, + { + "idiom" : "universal", + "scale" : "3x", + "filename" : "requests in progress indicator@3x.png" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator.png b/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator.png new file mode 100644 index 0000000..aa8b12f Binary files /dev/null and b/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator.png differ diff --git a/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator@2x.png b/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator@2x.png new file mode 100644 index 0000000..a90c7a7 Binary files /dev/null and b/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator@2x.png differ diff --git a/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator@3x.png b/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator@3x.png new file mode 100644 index 0000000..c4ac163 Binary files /dev/null and b/Arrived/Images.xcassets/requests in progress indicator.imageset/requests in progress indicator@3x.png differ diff --git a/Arrived/Main.storyboard b/Arrived/Main.storyboard index fdd4b44..b11c4f3 100644 --- a/Arrived/Main.storyboard +++ b/Arrived/Main.storyboard @@ -449,13 +449,13 @@ - - + + - + + @@ -494,6 +495,7 @@ Moderation is conducted through a democratic system known as the Tribunal. In th + @@ -502,33 +504,53 @@ Moderation is conducted through a democratic system known as the Tribunal. In th + + + + + + + + + + + + + + + + + + + + @@ -718,6 +740,9 @@ Moderation is conducted through a democratic system known as the Tribunal. In th + + + @@ -792,33 +820,6 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -831,80 +832,69 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + - + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -917,26 +907,32 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - @@ -1061,6 +1066,7 @@ Moderation is conducted through a democratic system known as the Tribunal. In th + @@ -1092,19 +1098,19 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - - - - - - - - - - + @@ -1409,43 +1430,104 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + - - - - - - - - - - + + + + + + + @@ -1454,11 +1536,18 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - + + + + + + + + - + @@ -1466,7 +1555,7 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - + @@ -1480,59 +1569,136 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - + + + + - - - - - + - + - - + + + + + + + - + @@ -1548,6 +1714,7 @@ Moderation is conducted through a democratic system known as the Tribunal. In th + @@ -1596,33 +1763,6 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1659,21 +1799,2142 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +YnBsaXN0MDDUAQIDBAUGOzxYJHZlcnNpb25YJG9iamVjdHNZJGFyY2hpdmVyVCR0b3ASAAGGoK0HCBEW +GxwgISksLzU4VSRudWxs1AkKCwwNDg8QViRjbGFzc1xOU0ltYWdlRmxhZ3NWTlNSZXBzV05TQ29sb3KA +DBIAwAAAgAKACtISCRMVWk5TLm9iamVjdHOhFIADgAnSEgkXGqIYGYAEgAWACBAA0h0JHh9fEBROU1RJ +RkZSZXByZXNlbnRhdGlvboAGgAdPESOOTU0AKgAAFohLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaSY/hbUmP4ZlLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaOY7jCUaN5R1JkONsS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaOY7jCQAAAAAAAAAARovgIUuP4XBLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkmP4H1Kj+FdSo/iWUqP4llKj+JZM5nMBQAAAAAAAAAAAAAAAAAAAABFkeMl +SpDgdUuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkqP4pRJj+FURovcFgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAEuP4ClKkeF4S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +SZDgbESI3Q8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAASo7jLUqQ4INLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpKjeFM +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAABOiesNSI7fWEmP4JZLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkiR4lgAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +OY7jCUqO309LkOKTS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaSZDhgQD//wEAAAAA +AAAAAECA1QxIkN01SpDjU0qO32FJkONsSpDhbkqQ4W5KkOFuK4DVBgAAAAAAAAAAAAAAADOZzAVJjuJG +SY/hj0uQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5HgOgAAAABKit8Y +SZDhZUqQ4ZhLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaOY7jCQAAAAAAgP8CS47iPUqP4YlLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4oxLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpKkOKVVar/A0mP4TtKkOCV +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkqP4ZhLkOGaTYDmCkqO4jRKkOKDS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaSpDgfEiO4V9LkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpJkOGBSY/hO0uQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpJkOBzRpPgIUmP4IRLkOGaSo/hgEuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkON+TonrDUmP4XBLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpKj+GASpDilUuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS4/ge0mM4SoAAAAAAAAAAEmP4IRLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +SpDglUiQ4VUzmcwFRovoC0uQ4pNLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkqQ4INLkeEzAAAAAAAAAAAAAAAAAAAAAEmP4IRLkOGaS5DhmkuQ4ZpKkOGRSZHihEmQ4GxLkeRB +SZLbDgAAAAAAAAAASY7hTUuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpKj+GJ +SJHhPAD//wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wEAAP8BAAD/AQAA/wEAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAABFk+IaSY/hkkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaSpDgjkqQ4UVAgP8E +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAAAAECP3xBKkOGHS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpJj+GPSZLkHAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +RozfKEmQ4IxLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5HilkmP41tAj98Q +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEqK3xhJkOFl +SY/hmUuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpKkOKV +SZDiV0mS2w4AAAAAAAAAAAAAAAAAAAAAAAAAAEqN3SZGi9wsRovcLEuR4ixJjuJGSZHjdkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4pNKkOBTQIDVDAAAAAAAAAAAAAAAAEmP4IRLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaSY/hkkqO3085juMJAAAAAEmP4IRLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpKj+GQSJHjSkmQ4YhLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGa +S5DhmkuQ4ZpLkOGaS5DhmkuQ4ZpLkOGaS5DhmkuQ4ZoADgEAAAMAAAABAB4AAAEBAAMAAAABADAAAAEC +AAMAAAAEAAAXNgEDAAMAAAABAAEAAAEGAAMAAAABAAIAAAERAAQAAAABAAAACAESAAMAAAABAAEAAAEV +AAMAAAABAAQAAAEWAAMAAAABADAAAAEXAAQAAAABAAAWgAEcAAMAAAABAAEAAAFSAAMAAAABAAIAAAFT +AAMAAAAEAAAXPodzAAcAAAxIAAAXRgAAAAAACAAIAAgACAABAAEAAQABAAAMSExpbm8CEAAAbW50clJH +QiBYWVogB84AAgAJAAYAMQAAYWNzcE1TRlQAAAAASUVDIHNSR0IAAAAAAAAAAAAAAAAAAPbWAAEAAAAA +0y1IUCAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARY3BydAAA +AVAAAAAzZGVzYwAAAYQAAABsd3RwdAAAAfAAAAAUYmtwdAAAAgQAAAAUclhZWgAAAhgAAAAUZ1hZWgAA +AiwAAAAUYlhZWgAAAkAAAAAUZG1uZAAAAlQAAABwZG1kZAAAAsQAAACIdnVlZAAAA0wAAACGdmlldwAA +A9QAAAAkbHVtaQAAA/gAAAAUbWVhcwAABAwAAAAkdGVjaAAABDAAAAAMclRSQwAABDwAAAgMZ1RSQwAA +BDwAAAgMYlRSQwAABDwAAAgMdGV4dAAAAABDb3B5cmlnaHQgKGMpIDE5OTggSGV3bGV0dC1QYWNrYXJk +IENvbXBhbnkAAGRlc2MAAAAAAAAAEnNSR0IgSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAASc1JHQiBJRUM2 +MTk2Ni0yLjEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFhZ +WiAAAAAAAADzUQABAAAAARbMWFlaIAAAAAAAAAAAAAAAAAAAAABYWVogAAAAAAAAb6IAADj1AAADkFhZ +WiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9kZXNjAAAAAAAAABZJRUMgaHR0cDov +L3d3dy5pZWMuY2gAAAAAAAAAAAAAABZJRUMgaHR0cDovL3d3dy5pZWMuY2gAAAAAAAAAAAAAAAAAAAAA +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZGVzYwAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZh +dWx0IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAuSUVDIDYxOTY2LTIuMSBEZWZhdWx0 +IFJHQiBjb2xvdXIgc3BhY2UgLSBzUkdCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGRlc2MAAAAAAAAALFJl +ZmVyZW5jZSBWaWV3aW5nIENvbmRpdGlvbiBpbiBJRUM2MTk2Ni0yLjEAAAAAAAAAAAAAACxSZWZlcmVu +Y2UgVmlld2luZyBDb25kaXRpb24gaW4gSUVDNjE5NjYtMi4xAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +AAB2aWV3AAAAAAATpP4AFF8uABDPFAAD7cwABBMLAANcngAAAAFYWVogAAAAAABMCVYAUAAAAFcf521l +YXMAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAKPAAAAAnNpZyAAAAAAQ1JUIGN1cnYAAAAAAAAEAAAA +AAUACgAPABQAGQAeACMAKAAtADIANwA7AEAARQBKAE8AVABZAF4AYwBoAG0AcgB3AHwAgQCGAIsAkACV +AJoAnwCkAKkArgCyALcAvADBAMYAywDQANUA2wDgAOUA6wDwAPYA+wEBAQcBDQETARkBHwElASsBMgE4 +AT4BRQFMAVIBWQFgAWcBbgF1AXwBgwGLAZIBmgGhAakBsQG5AcEByQHRAdkB4QHpAfIB+gIDAgwCFAId +AiYCLwI4AkECSwJUAl0CZwJxAnoChAKOApgCogKsArYCwQLLAtUC4ALrAvUDAAMLAxYDIQMtAzgDQwNP +A1oDZgNyA34DigOWA6IDrgO6A8cD0wPgA+wD+QQGBBMEIAQtBDsESARVBGMEcQR+BIwEmgSoBLYExATT +BOEE8AT+BQ0FHAUrBToFSQVYBWcFdwWGBZYFpgW1BcUF1QXlBfYGBgYWBicGNwZIBlkGagZ7BowGnQav +BsAG0QbjBvUHBwcZBysHPQdPB2EHdAeGB5kHrAe/B9IH5Qf4CAsIHwgyCEYIWghuCIIIlgiqCL4I0gjn +CPsJEAklCToJTwlkCXkJjwmkCboJzwnlCfsKEQonCj0KVApqCoEKmAquCsUK3ArzCwsLIgs5C1ELaQuA +C5gLsAvIC+EL+QwSDCoMQwxcDHUMjgynDMAM2QzzDQ0NJg1ADVoNdA2ODakNww3eDfgOEw4uDkkOZA5/ +DpsOtg7SDu4PCQ8lD0EPXg96D5YPsw/PD+wQCRAmEEMQYRB+EJsQuRDXEPURExExEU8RbRGMEaoRyRHo +EgcSJhJFEmQShBKjEsMS4xMDEyMTQxNjE4MTpBPFE+UUBhQnFEkUahSLFK0UzhTwFRIVNBVWFXgVmxW9 +FeAWAxYmFkkWbBaPFrIW1hb6Fx0XQRdlF4kXrhfSF/cYGxhAGGUYihivGNUY+hkgGUUZaxmRGbcZ3RoE +GioaURp3Gp4axRrsGxQbOxtjG4obshvaHAIcKhxSHHscoxzMHPUdHh1HHXAdmR3DHeweFh5AHmoelB6+ +HukfEx8+H2kflB+/H+ogFSBBIGwgmCDEIPAhHCFIIXUhoSHOIfsiJyJVIoIiryLdIwojOCNmI5QjwiPw +JB8kTSR8JKsk2iUJJTglaCWXJccl9yYnJlcmhya3JugnGCdJJ3onqyfcKA0oPyhxKKIo1CkGKTgpaymd +KdAqAio1KmgqmyrPKwIrNitpK50r0SwFLDksbiyiLNctDC1BLXYtqy3hLhYuTC6CLrcu7i8kL1ovkS/H +L/4wNTBsMKQw2zESMUoxgjG6MfIyKjJjMpsy1DMNM0YzfzO4M/E0KzRlNJ402DUTNU01hzXCNf02NzZy +Nq426TckN2A3nDfXOBQ4UDiMOMg5BTlCOX85vDn5OjY6dDqyOu87LTtrO6o76DwnPGU8pDzjPSI9YT2h +PeA+ID5gPqA+4D8hP2E/oj/iQCNAZECmQOdBKUFqQaxB7kIwQnJCtUL3QzpDfUPARANER0SKRM5FEkVV +RZpF3kYiRmdGq0bwRzVHe0fASAVIS0iRSNdJHUljSalJ8Eo3Sn1KxEsMS1NLmkviTCpMcky6TQJNSk2T +TdxOJU5uTrdPAE9JT5NP3VAnUHFQu1EGUVBRm1HmUjFSfFLHUxNTX1OqU/ZUQlSPVNtVKFV1VcJWD1Zc +VqlW91dEV5JX4FgvWH1Yy1kaWWlZuFoHWlZaplr1W0VblVvlXDVchlzWXSddeF3JXhpebF69Xw9fYV+z +YAVgV2CqYPxhT2GiYfViSWKcYvBjQ2OXY+tkQGSUZOllPWWSZedmPWaSZuhnPWeTZ+loP2iWaOxpQ2ma +afFqSGqfavdrT2una/9sV2yvbQhtYG25bhJua27Ebx5veG/RcCtwhnDgcTpxlXHwcktypnMBc11zuHQU +dHB0zHUodYV14XY+dpt2+HdWd7N4EXhueMx5KnmJeed6RnqlewR7Y3vCfCF8gXzhfUF9oX4BfmJ+wn8j +f4R/5YBHgKiBCoFrgc2CMIKSgvSDV4O6hB2EgITjhUeFq4YOhnKG14c7h5+IBIhpiM6JM4mZif6KZIrK +izCLlov8jGOMyo0xjZiN/45mjs6PNo+ekAaQbpDWkT+RqJIRknqS45NNk7aUIJSKlPSVX5XJljSWn5cK +l3WX4JhMmLiZJJmQmfyaaJrVm0Kbr5wcnImc951kndKeQJ6unx2fi5/6oGmg2KFHobaiJqKWowajdqPm +pFakx6U4pammGqaLpv2nbqfgqFKoxKk3qamqHKqPqwKrdavprFys0K1ErbiuLa6hrxavi7AAsHWw6rFg +sdayS7LCszizrrQltJy1E7WKtgG2ebbwt2i34LhZuNG5SrnCuju6tbsuu6e8IbybvRW9j74KvoS+/796 +v/XAcMDswWfB48JfwtvDWMPUxFHEzsVLxcjGRsbDx0HHv8g9yLzJOsm5yjjKt8s2y7bMNcy1zTXNtc42 +zrbPN8+40DnQutE80b7SP9LB00TTxtRJ1MvVTtXR1lXW2Ndc1+DYZNjo2WzZ8dp22vvbgNwF3IrdEN2W +3hzeot8p36/gNuC94UThzOJT4tvjY+Pr5HPk/OWE5g3mlucf56noMui86Ubp0Opb6uXrcOv77IbtEe2c +7ijutO9A78zwWPDl8XLx//KM8xnzp/Q09ML1UPXe9m32+/eK+Bn4qPk4+cf6V/rn+3f8B/yY/Sn9uv5L +/tz/bf//0iIjJCVaJGNsYXNzbmFtZVgkY2xhc3Nlc18QEE5TQml0bWFwSW1hZ2VSZXCjJicoXxAQTlNC +aXRtYXBJbWFnZVJlcFpOU0ltYWdlUmVwWE5TT2JqZWN00iIjKitXTlNBcnJheaIqKNIiIy0uXk5TTXV0 +YWJsZUFycmF5oy0qKNMwMQkyMzRXTlNXaGl0ZVxOU0NvbG9yU3BhY2VEMCAwABADgAvSIiM2N1dOU0Nv +bG9yojYo0iIjOTpXTlNJbWFnZaI5KF8QD05TS2V5ZWRBcmNoaXZlctE9PlRyb290gAEACAARABoAIwAt +ADIANwBFAEsAVABbAGgAbwB3AHkAfgCAAIIAhwCSAJQAlgCYAJ0AoACiAKQApgCoAK0AxADGAMgkWiRf +JGokcySGJIoknSSoJLEktiS+JMEkxiTVJNkk4CToJPUk+iT8JP4lAyULJQ4lEyUbJR4lMCUzJTgAAAAA +AAACAQAAAAAAAAA/AAAAAAAAAAAAAAAAAAAlOg + + + + + + + + + @@ -1682,6 +3943,7 @@ Moderation is conducted through a democratic system known as the Tribunal. In th + @@ -1691,8 +3953,9 @@ Moderation is conducted through a democratic system known as the Tribunal. In th - + - + + diff --git a/Assets/Resources/dotActive.png b/Assets/Resources/dotActive.png new file mode 100755 index 0000000..c3984f6 Binary files /dev/null and b/Assets/Resources/dotActive.png differ diff --git a/Assets/Resources/dotActive@2x.png b/Assets/Resources/dotActive@2x.png new file mode 100755 index 0000000..6eae71d Binary files /dev/null and b/Assets/Resources/dotActive@2x.png differ diff --git a/Assets/Resources/dotActive@3x.png b/Assets/Resources/dotActive@3x.png new file mode 100755 index 0000000..4bfcdfe Binary files /dev/null and b/Assets/Resources/dotActive@3x.png differ diff --git a/Assets/Resources/dotInactive.png b/Assets/Resources/dotInactive.png new file mode 100755 index 0000000..4f09578 Binary files /dev/null and b/Assets/Resources/dotInactive.png differ diff --git a/Assets/Resources/dotInactive@2x.png b/Assets/Resources/dotInactive@2x.png new file mode 100755 index 0000000..0b2f0f4 Binary files /dev/null and b/Assets/Resources/dotInactive@2x.png differ diff --git a/Assets/Resources/dotInactive@3x.png b/Assets/Resources/dotInactive@3x.png new file mode 100755 index 0000000..2a63480 Binary files /dev/null and b/Assets/Resources/dotInactive@3x.png differ diff --git a/Assets/Resources/image1.jpg b/Assets/Resources/image1.jpg new file mode 100755 index 0000000..99d3b2b Binary files /dev/null and b/Assets/Resources/image1.jpg differ diff --git a/Assets/Resources/image2.jpg b/Assets/Resources/image2.jpg new file mode 100755 index 0000000..0826624 Binary files /dev/null and b/Assets/Resources/image2.jpg differ diff --git a/Assets/Resources/image3.jpg b/Assets/Resources/image3.jpg new file mode 100755 index 0000000..5f92f3b Binary files /dev/null and b/Assets/Resources/image3.jpg differ diff --git a/Assets/Resources/image4.jpg b/Assets/Resources/image4.jpg new file mode 100755 index 0000000..3f9fcb9 Binary files /dev/null and b/Assets/Resources/image4.jpg differ diff --git a/Assets/Resources/image5.jpg b/Assets/Resources/image5.jpg new file mode 100755 index 0000000..f24a886 Binary files /dev/null and b/Assets/Resources/image5.jpg differ diff --git a/Assets/Resources/image6.jpg b/Assets/Resources/image6.jpg new file mode 100755 index 0000000..41ebc7c Binary files /dev/null and b/Assets/Resources/image6.jpg differ diff --git a/Classes/Supports/Arrived-Bridging-Header.h b/Classes/Supports/Arrived-Bridging-Header.h index f75b872..43cc19e 100644 --- a/Classes/Supports/Arrived-Bridging-Header.h +++ b/Classes/Supports/Arrived-Bridging-Header.h @@ -11,5 +11,6 @@ #import "SHSPhoneLibrary.h" #import "UICountingLabel.h" +#import "LNBRippleEffect.h" #endif diff --git a/Classes/Supports/HelperMethods.swift b/Classes/Supports/HelperMethods.swift index a1e52be..d79b592 100755 --- a/Classes/Supports/HelperMethods.swift +++ b/Classes/Supports/HelperMethods.swift @@ -158,6 +158,29 @@ func bounceView(myView: UIView) { }, completion: nil) } +func fadeInView(myView: UIView, t: NSTimeInterval) { + UIView.animateWithDuration(t, animations: { + myView.alpha = 1.0 + }) +} + +func fadeOutView(myView: UIView, t: NSTimeInterval) { + UIView.animateWithDuration(t, animations: { + myView.alpha = 0 + }) +} + +/** + rounded corner for only certain sides of the frame +*/ +extension UIView { + func roundCorners(corners:UIRectCorner, radius: CGFloat) { + let path = UIBezierPath(roundedRect: self.bounds, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius)) + let mask = CAShapeLayer() + mask.path = path.CGPath + self.layer.mask = mask + } +} diff --git a/Classes/VCs/AddBankCardVC.swift b/Classes/VCs/AddBankCardVC.swift new file mode 100644 index 0000000..edec744 --- /dev/null +++ b/Classes/VCs/AddBankCardVC.swift @@ -0,0 +1,290 @@ +// +// AddBankCardVC.swift +// Arrived +// +// Created by Lu Cao on 5/25/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class AddBankCardVC: UIViewController, UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource { + + // just a label, I try to track color + @IBOutlet weak var label: UILabel! + + @IBOutlet weak var visaImage: UIImageView! + @IBOutlet weak var americanExpressImage: UIImageView! + @IBOutlet weak var masterCardImage: UIImageView! + @IBOutlet weak var discoverImage: UIImageView! + @IBOutlet weak var jcbImage: UIImageView! + + @IBOutlet weak var bankCardNumberField: SHSPhoneTextField! + // @IBOutlet weak var bankCardNumberField: UITextField! + @IBOutlet weak var cardHolderNameField: UITextField! + @IBOutlet weak var expDateField: UITextField! + @IBOutlet weak var cvvField: UITextField! + + // textFields convenience, for item in loop + private var textFields = [UITextField]() + + // data source of pickerview, used for keyboard of exp date input + private let pickerData = [ + ["January","February","March","April","May","June","July","August","September","October","November","December"], + ["2015","2016","2017","2018","2019","2020","2021","2022","2023","2024","2025","2026","2027","2028","2029","2030"] + ] + + // store the type of card + private var cardType: String? + + override func viewDidLoad() { + super.viewDidLoad() + + setupUI() + } + + // MARK: - UI Work + + func setupUI() { + + // uitoolbar above keyboard for done, next, prev functionalities + self.addDoneButtonOnKeyboard() + + // focus on it, so when enter screen, keyboard pops up and editing + bankCardNumberField.becomeFirstResponder() + bankCardNumberField.formatter.setDefaultOutputPattern("####################") + + textFields = [bankCardNumberField, cardHolderNameField, expDateField, cvvField] + + for item in textFields { + + // adding a single bottom border to the button + var border = CALayer() + var width = CGFloat(0.5) + border.borderColor = UIColor.darkGrayColor().CGColor + border.frame = CGRect(x: 0, y: item.frame.size.height - width, width: item.frame.size.width, height: item.frame.size.height) + border.borderWidth = width + + item.layer.addSublayer(border) + item.layer.masksToBounds = true + + // setup keyboard + item.delegate = self + } + + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + navigationController?.navigationBar.topItem!.title = ""; + + } + + // MARK: - Keyboard customization + + // add a ui tool bar above each keyboard, and done, next, prev button + func addDoneButtonOnKeyboard() + { + var doneToolbar: UIToolbar = UIToolbar(frame: CGRectMake(0, 0, 320, 50)) + doneToolbar.barStyle = UIBarStyle.Default + + var flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil) + var fixedSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil) + var done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: Selector("doneButtonAction")) + done.tintColor = bankCardNumberField.textColor + var prev: UIBarButtonItem = UIBarButtonItem(title: " ⇠ ", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("prevButtonAction")) + prev.tintColor = bankCardNumberField.textColor + var next: UIBarButtonItem = UIBarButtonItem(title: " ⇢ ", style: UIBarButtonItemStyle.Plain, target: self, action: Selector("nextButtonAction")) + next.tintColor = bankCardNumberField.textColor + + var items = NSMutableArray() + items.addObject(prev) + items.addObject(fixedSpace) + items.addObject(next) + items.addObject(flexSpace) + items.addObject(done) + + doneToolbar.items = items as [AnyObject] + doneToolbar.sizeToFit() + doneToolbar.backgroundColor = UIColor.whiteColor() + + bankCardNumberField.inputAccessoryView = doneToolbar + cardHolderNameField.inputAccessoryView = doneToolbar + expDateField.inputAccessoryView = doneToolbar + cvvField.inputAccessoryView = doneToolbar + } + + + func prevButtonAction() + { + if bankCardNumberField.isFirstResponder() { } + else if cardHolderNameField.isFirstResponder() { bankCardNumberField.becomeFirstResponder() } + else if expDateField.isFirstResponder() { cardHolderNameField.becomeFirstResponder() } + else if cvvField.isFirstResponder() { expDateField.becomeFirstResponder() } + } + + func nextButtonAction() + { + if bankCardNumberField.isFirstResponder() { cardHolderNameField.becomeFirstResponder() } + else if cardHolderNameField.isFirstResponder() { expDateField.becomeFirstResponder() } + else if expDateField.isFirstResponder() { cvvField.becomeFirstResponder() } + else if cvvField.isFirstResponder() { } + } + + func doneButtonAction() + { + if bankCardNumberField.isFirstResponder() { bankCardNumberField.resignFirstResponder() } + else if cardHolderNameField.isFirstResponder() { cardHolderNameField.resignFirstResponder() } + else if expDateField.isFirstResponder() { expDateField.resignFirstResponder() } + else if cvvField.isFirstResponder() { cvvField.resignFirstResponder() } + } + + // when exp date is editing, show picker view (month year picker) instead of keyboard + @IBAction func textFieldEditing(sender: AnyObject) { + var datePickerView: UIPickerView = UIPickerView() + datePickerView.delegate = self + datePickerView.backgroundColor = UIColor.whiteColor() + expDateField.inputView = datePickerView + } + + // called by delegate, when selected in pickerview + // update text in expDate field + func updateExpDate(myPicker: UIPickerView) { + let month = pickerData[0][myPicker.selectedRowInComponent(0)] + let year = pickerData[1][myPicker.selectedRowInComponent(1)] + expDateField.text = month + ", " + year + } + + /* + func datePickerValueChanged(sender: UIDatePicker) { + var dateformatter = NSDateFormatter() + dateformatter.dateStyle = NSDateFormatterStyle.MediumStyle + expDateField.text = dateformatter.stringFromDate(sender.date) + } + */ + + // MARK: - Functionalities + + // TODO: - Format input text in above fields + + /** + Detect credit card type and dim or highlight card icons + */ + @IBAction func checkCardType(sender: SHSPhoneTextField) { + let type = detectCreditCardType(sender.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())) + cardType = type + switch type { + case "Visa": + visaImage.alpha = 1 + masterCardImage.alpha = 0.3 + americanExpressImage.alpha = 0.3 + discoverImage.alpha = 0.3 + jcbImage.alpha = 0.3 + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + case "MasterCard": + visaImage.alpha = 0.3 + masterCardImage.alpha = 1 + americanExpressImage.alpha = 0.3 + discoverImage.alpha = 0.3 + jcbImage.alpha = 0.3 + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + case "American Express": + visaImage.alpha = 0.3 + masterCardImage.alpha = 0.3 + americanExpressImage.alpha = 1 + discoverImage.alpha = 0.3 + jcbImage.alpha = 0.3 + sender.formatter.setDefaultOutputPattern("#### ###### #####") + sender.setFormattedText(sender.text) + case "Discover": + visaImage.alpha = 0.3 + masterCardImage.alpha = 0.3 + americanExpressImage.alpha = 0.3 + discoverImage.alpha = 1 + jcbImage.alpha = 0.3 + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + case "JCB": + visaImage.alpha = 0.3 + masterCardImage.alpha = 0.3 + americanExpressImage.alpha = 0.3 + discoverImage.alpha = 0.3 + jcbImage.alpha = 1 + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + case "Invalid": + visaImage.alpha = 1 + masterCardImage.alpha = 1 + americanExpressImage.alpha = 1 + discoverImage.alpha = 1 + jcbImage.alpha = 1 + sender.formatter.setDefaultOutputPattern("####################") + sender.setFormattedText(sender.text) + default: + return + } + } + + /** + CVV should not exceed 3 digit, or 4 depending on card type + */ + @IBAction func trimCVV(sender: UITextField) { + switch cardType! { + case "American Express": + if count(sender.text) > 4 { + sender.text = dropLast(sender.text) + } + default: + if count(sender.text) > 3 { + sender.text = dropLast(sender.text) + } + } + + } + + @IBAction func popView(sender: UIBarButtonItem) { + navigationController?.popViewControllerAnimated(true) + } + + // MARK: - Delegates + + // UITextFiew + func textFieldShouldReturn(textField: UITextField) -> Bool { + if textField === bankCardNumberField { + cardHolderNameField.becomeFirstResponder() + } else if textField === cardHolderNameField { + expDateField.becomeFirstResponder() + } else if textField === expDateField { + cvvField.becomeFirstResponder() + } else if textField === cvvField { + cvvField.resignFirstResponder() + } + return true + } + + // UIPickerView + /* + func pickerView(pickerView: UIPickerView, attributedTitleForRow row: Int, forComponent component: Int) -> NSAttributedString? { + let attributedString = NSAttributedString(string: "\(pickerData[row][component])", attributes: [NSForegroundColorAttributeName : UIColor.redColor()]) + return attributedString + } + */ + + func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { + return pickerData.count + } + + func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return pickerData[component].count + } + + func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! { + return pickerData[component][row] + } + + func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + updateExpDate(pickerView) + } + + +} diff --git a/Classes/VCs/AddLocationVC.swift b/Classes/VCs/AddLocationVC.swift index 205f80e..7032505 100755 --- a/Classes/VCs/AddLocationVC.swift +++ b/Classes/VCs/AddLocationVC.swift @@ -12,6 +12,234 @@ import AddressBookUI class AddLocationVC: UIViewController, MKMapViewDelegate, UISearchBarDelegate { + @IBOutlet weak var myView: UIView! + @IBOutlet weak var mapView: MKMapView! + + @IBOutlet weak var streetLabel: UITextField! + @IBOutlet weak var cityLabel: UITextField! + @IBOutlet weak var stateLabel: UITextField! + @IBOutlet weak var postLabel: UITextField! + @IBOutlet weak var countryLabel: UITextField! + + + // for search location + private var latitude: Double? + private var longitude: Double? + + private var searchController: UISearchController! + private var annotation: MKAnnotation! + private var localSearchRequest: MKLocalSearchRequest! + private var localSearch: MKLocalSearch! + private var localSearchResponse: MKLocalSearchResponse! + private var error: NSError! + private var pointAnnotation: MKPointAnnotation! + private var pinAnnotationView: MKPinAnnotationView! + + // for user location + var manager: CLLocationManager! + var myLocations: [CLLocation] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + updateUIWithUserLocation() + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + navigationController?.navigationBar.topItem!.title = ""; + + myView.layer.borderWidth = 0.3 + myView.layer.borderColor = UIColor.lightGrayColor().CGColor + myView.layer.cornerRadius = 12 + + + } + + // MARK: - Functionalities + + func updateUIWithUserLocation() { + + mapView.delegate = self + + manager = CLLocationManager() + manager.desiredAccuracy = kCLLocationAccuracyBest + manager.requestAlwaysAuthorization() + + + if CLLocationManager.locationServicesEnabled() { + manager.startUpdatingLocation() + + let latitude = manager.location.coordinate.latitude + let longitude = manager.location.coordinate.longitude + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) + let regionRadius: CLLocationDistance = 1000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + mapView.setRegion(coordinateRegion, animated: true) + + var locationManager = LocationManager.sharedInstance + locationManager.reverseGeocodeLocationWithLatLon(latitude: latitude, longitude: longitude) { (reverseGecodeInfo,placemark,error) -> Void in + + if(error != nil) { + + println(error) + } else { + + println(reverseGecodeInfo!) + let address = reverseGecodeInfo!["formattedAddress"] as! String + var splitAddress = address.componentsSeparatedByString(", ") + let country = reverseGecodeInfo!["country"] as? String + let post = reverseGecodeInfo!["postalCode"] as? String + let state = reverseGecodeInfo!["administrativeArea"] as? String + let city = reverseGecodeInfo!["locality"] as? String + for i in 1...3 { + if splitAddress.count > 1 { + splitAddress.removeLast() + } + } + let joiner = ", " + let street = joiner.join(splitAddress) + + dispatch_async(dispatch_get_main_queue()) { + // do ui updates here + + self.streetLabel.text = street + self.cityLabel.text = city + self.stateLabel.text = state + self.postLabel.text = post + self.countryLabel.text = country + } + } + + } + } + + } + + @IBAction func showSearchBar(sender: AnyObject) { + searchController = UISearchController(searchResultsController: nil) + searchController.hidesNavigationBarDuringPresentation = false + self.searchController.searchBar.delegate = self + presentViewController(searchController, animated: true, completion: nil) + } + + func searchBarSearchButtonClicked(searchBar: UISearchBar) { + + searchBar.resignFirstResponder() + dismissViewControllerAnimated(true, completion: nil) + if self.mapView.annotations.count != 0 { + annotation = self.mapView.annotations[0] as! MKAnnotation + self.mapView.removeAnnotation(annotation) + } + + localSearchRequest = MKLocalSearchRequest() + localSearchRequest.naturalLanguageQuery = searchBar.text + localSearch = MKLocalSearch(request: localSearchRequest) + localSearch.startWithCompletionHandler { (localSearchResponse, error) -> Void in + + if localSearchResponse == nil { + var alert = UIAlertView(title: nil, message: "Place not found", delegate: self, cancelButtonTitle: "Try again") + alert.show() + return + } + + self.latitude = localSearchResponse.boundingRegion.center.latitude + self.longitude = localSearchResponse.boundingRegion.center.longitude + + self.pointAnnotation = CustomPointAnnotation() + self.pointAnnotation.title = searchBar.text + self.pointAnnotation.coordinate = CLLocationCoordinate2D(latitude: self.latitude!, longitude: self.longitude!) + + + self.pinAnnotationView = MKPinAnnotationView(annotation: self.pointAnnotation, reuseIdentifier: nil) + // self.mapView.centerCoordinate = self.pointAnnotation.coordinate + + + let center = CLLocationCoordinate2D(latitude: self.latitude!, longitude: self.longitude!) + let region = MKCoordinateRegion(center: center, span: MKCoordinateSpan(latitudeDelta: 0.01, longitudeDelta: 0.01)) + + self.mapView.setRegion(region, animated: true) + self.mapView.addAnnotation(self.pinAnnotationView.annotation) + + var locationManager = LocationManager.sharedInstance + locationManager.reverseGeocodeLocationWithLatLon(latitude: self.latitude!, longitude: self.longitude!) { (reverseGecodeInfo,placemark,error) -> Void in + + if(error != nil) { + + println(error) + } else { + + println(reverseGecodeInfo!) + let address = reverseGecodeInfo!["formattedAddress"] as! String + var splitAddress = address.componentsSeparatedByString(", ") + let country = reverseGecodeInfo!["country"] as! String + let post = reverseGecodeInfo!["postalCode"] as! String + let state = reverseGecodeInfo!["administrativeArea"] as! String + let city = reverseGecodeInfo!["locality"] as! String + splitAddress.removeLast() + splitAddress.removeLast() + splitAddress.removeLast() + let joiner = ", " + let street = joiner.join(splitAddress) + + dispatch_async(dispatch_get_main_queue()) { + // do ui updates here + + self.streetLabel.text = street + self.cityLabel.text = city + self.stateLabel.text = state + self.postLabel.text = post + self.countryLabel.text = country + } + } + + } + } + } + + @IBAction func addAddress(sender: UIButton) { + navigationController?.popViewControllerAnimated(true) + } + + // MARK: - Delegates + + // Customize annotation appearance + func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { + if !(annotation is CustomPointAnnotation) { + return nil + } + + let reuseId = "test" + + var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) + if anView == nil { + anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) + anView.canShowCallout = true + } + else { + anView.annotation = annotation + } + + //Set annotation-specific properties **AFTER** + //the view is dequeued or created... + + let cpa = annotation as! CustomPointAnnotation + anView.image = UIImage(named: "map pin.png") + + return anView + } + + /* + func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) { + var locValue:CLLocationCoordinate2D = manager.location.coordinate + println("locations = \(locValue.latitude) \(locValue.longitude)") + } + */ + + /* @IBOutlet weak var addressField: UITextField! @IBOutlet weak var mapView: MKMapView! @@ -32,6 +260,10 @@ class AddLocationVC: UIViewController, MKMapViewDelegate, UISearchBarDelegate { super.viewDidLoad() // Do any additional setup after loading the view. + + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + navigationController?.navigationBar.topItem!.title = ""; } override func didReceiveMemoryWarning() { @@ -136,6 +368,6 @@ class AddLocationVC: UIViewController, MKMapViewDelegate, UISearchBarDelegate { } } - + */ } diff --git a/Classes/VCs/AddPaymentInfoVC.swift b/Classes/VCs/AddPaymentInfoVC.swift index bc38433..207ebb4 100755 --- a/Classes/VCs/AddPaymentInfoVC.swift +++ b/Classes/VCs/AddPaymentInfoVC.swift @@ -164,8 +164,6 @@ class AddPaymentInfoVC: UIViewController, UITextFieldDelegate, UIPickerViewDeleg // MARK: - Functionalities - // TODO: - Format input text in above fields - /** Detect credit card type and dim or highlight card icons */ @@ -277,6 +275,16 @@ class AddPaymentInfoVC: UIViewController, UITextFieldDelegate, UIPickerViewDeleg updateExpDate(pickerView) } + // MARK: - Navigations + + @IBAction func skitToMainScreen(sender: UIButton) { + performSegueWithIdentifier("AddPaymentInfoNewUserCreated", sender: self) + } + + @IBAction func goToMainScreen(sender: UIButton) { + performSegueWithIdentifier("AddPaymentInfoNewUserCreated", sender: self) + } + /* @IBOutlet weak var nameLabel: UITextField! @IBOutlet weak var cardLabel: UITextField! diff --git a/Classes/VCs/ContentViewController.swift b/Classes/VCs/ContentViewController.swift new file mode 100755 index 0000000..af9d33d --- /dev/null +++ b/Classes/VCs/ContentViewController.swift @@ -0,0 +1,101 @@ +// +// ContentViewController.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit +import MapKit + +class ContentViewController: UIViewController, MKMapViewDelegate { + + @IBOutlet weak var mapView: MKMapView! + @IBOutlet weak var addressLabel: UILabel! + + var toPass: String? + var latitude: Double? + var longitude: Double? + + private var pointAnnotation: MKPointAnnotation! + private var pinAnnotationView: MKPinAnnotationView! + + init() { + super.init(nibName: "ContentViewController", bundle: nil) + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override func viewDidLoad() { + super.viewDidLoad() + + addressLabel.text = toPass! + addressLabel.layer.frame = CGRectMake(mapView.frame.width/2, 0, addressLabel.layer.frame.width, addressLabel.layer.frame.height) + addressLabel.layer.backgroundColor = UIColorFromHex(0xFFFFFF, alpha: 0.65).CGColor + addressLabel.layer.borderColor = UIColor.lightGrayColor().CGColor + addressLabel.layer.borderWidth = 1.2 + addressLabel.layer.cornerRadius = 5 + + mapView.delegate = self + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: latitude!, longitude: longitude!) + let regionRadius: CLLocationDistance = 1000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + mapView.setRegion(coordinateRegion, animated: true) + + var annotation = CustomPointAnnotation() + annotation.coordinate = location + annotation.imageName = "regular pin" + mapView.addAnnotation(annotation) + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + // Customize annotation appearance + func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { + if !(annotation is CustomPointAnnotation) { + return nil + } + + let reuseId = "test" + + var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) + if anView == nil { + anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) + anView.canShowCallout = true + } + else { + anView.annotation = annotation + } + + //Set annotation-specific properties **AFTER** + //the view is dequeued or created... + + let cpa = annotation as! CustomPointAnnotation + anView.image = UIImage(named:cpa.imageName) + + return anView + } + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Classes/VCs/ContentViewController.xib b/Classes/VCs/ContentViewController.xib new file mode 100755 index 0000000..062a5ce --- /dev/null +++ b/Classes/VCs/ContentViewController.xib @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/VCs/MainScreenVC.swift b/Classes/VCs/MainScreenVC.swift index 80d0372..ae73517 100755 --- a/Classes/VCs/MainScreenVC.swift +++ b/Classes/VCs/MainScreenVC.swift @@ -7,6 +7,7 @@ // import UIKit +import MapKit import AVFoundation import Foundation @@ -44,9 +45,9 @@ class MainScreenVC: UITabBarController, UITabBarDelegate, AVAudioPlayerDelegate, private var waveformView = SiriWaveformView() private var recordingView = UIView() - private var centerButtonSelected: Bool? { + private var centerButtonSelected: Bool = false { didSet { - if centerButtonSelected! { + if centerButtonSelected { button.setBackgroundImage(buttonSelectedImage, forState: UIControlState.Normal) button.setBackgroundImage(buttonSelectedImage, forState: UIControlState.Highlighted) } else { @@ -56,6 +57,8 @@ class MainScreenVC: UITabBarController, UITabBarDelegate, AVAudioPlayerDelegate, } } + private var locationManager: CLLocationManager! + override func viewDidLoad() { super.viewDidLoad() @@ -66,6 +69,9 @@ class MainScreenVC: UITabBarController, UITabBarDelegate, AVAudioPlayerDelegate, customizeColorOfBarItems() addCenterRaisedButton() addButtonLongPressGuesture() + + locationManager = CLLocationManager() + locationManager.requestAlwaysAuthorization() } func initAudioRecorder() { @@ -139,21 +145,31 @@ class MainScreenVC: UITabBarController, UITabBarDelegate, AVAudioPlayerDelegate, Add raised center button */ func addCenterRaisedButton() { - button.frame = CGRectMake(0.0, 0.0, buttonImage!.size.width, buttonImage!.size.height) + // raised +// button.frame = CGRectMake(0.0, 0.0, buttonImage!.size.width, buttonImage!.size.height) + // not raised + button.frame = CGRectMake(0.0, 0.0, self.tabBar.frame.size.height, self.tabBar.frame.size.height) button.setBackgroundImage(buttonImage, forState: UIControlState.Normal) button.setBackgroundImage(buttonImage, forState: UIControlState.Highlighted) + + // not raised + button.center = self.tabBar.center - let heightDifference = buttonImage!.size.height - self.tabBar.frame.size.height - if heightDifference < 0 { - button.center = self.tabBar.center - } else { + // raised +// let heightDifference = buttonImage!.size.height - self.tabBar.frame.size.height +// if heightDifference < 0 { +// button.center = self.tabBar.center +// } else { // var center = self.tabBar.center // center.y -= heightDifference/2 // button.center = center; - - var center = CGPointMake(self.tabBar.center.x, self.tabBar.center.y-self.tabBar.frame.size.height/2) - button.center = center - } +// +// /* +// raise it so the mid point match tab bar top +// var center = CGPointMake(self.tabBar.center.x, self.tabBar.center.y-self.tabBar.frame.size.height/2) +// button.center = center +// */ +// } button.addTarget(self, action: "pressed:", forControlEvents: UIControlEvents.TouchDown) self.view.addSubview(button) @@ -183,9 +199,15 @@ class MainScreenVC: UITabBarController, UITabBarDelegate, AVAudioPlayerDelegate, // MARK: - Functionalities func pressed(sender: UIButton!) { + + if centerButtonSelected { + performSegueWithIdentifier("MainToNew", sender: self) + } + self.selectedIndex = 1 centerButtonSelected = true buttonShouldRotate = false + } override func tabBar(tabBar: UITabBar, didSelectItem item: UITabBarItem!) { diff --git a/Classes/VCs/MyOrdersRequestViewDetailVC.swift b/Classes/VCs/MyOrdersRequestViewDetailVC.swift new file mode 100644 index 0000000..709de76 --- /dev/null +++ b/Classes/VCs/MyOrdersRequestViewDetailVC.swift @@ -0,0 +1,261 @@ +// +// MyOrdersRequestViewDetailVC.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class MyOrdersRequestViewDetailVC: UIViewController, UIScrollViewDelegate { + + var toPass: Order? + + @IBOutlet weak var backgroundImageView: UIImageView! + + // price view + + @IBOutlet weak var priceLabel: UICountingLabel! + @IBOutlet weak var priceLabeBackgroundView: UIView! + private var currentPrice: Double? + + private var interested = false + @IBOutlet weak var mapButton: UIButton! + + @IBOutlet weak var leftButton: UIButton! + @IBOutlet weak var midButton: UIButton! + @IBOutlet weak var rightButton: UIButton! + + // detail view + @IBOutlet weak var midView: UIView! + @IBOutlet weak var startTimeLabel: UILabel! + @IBOutlet weak var startLeftView: UILabel! + + @IBOutlet weak var titleLeftView: UILabel! + @IBOutlet weak var titleLabel: UILabel! + + @IBOutlet weak var detailLeftView: UILabel! + + // user view + @IBOutlet weak var leftView: UIView! + + @IBOutlet weak var portraitImageView: UIImageView! + @IBOutlet weak var nicknameLabel: UILabel! + @IBOutlet weak var statusLabel: UILabel! + + // media view + @IBOutlet weak var rightView: UIView! + @IBOutlet weak var mediaScrollView: UIScrollView! + @IBOutlet weak var mediaPageControl: UIPageControl! + + private var testImageViews = [UIImageView]() + + private var textColor: UIColor? + + private var isInitiated = false + + + override func viewDidLoad() { + super.viewDidLoad() + + let scrollViewWidth: CGFloat = mediaScrollView.frame.width + let scrollViewHeight: CGFloat = mediaScrollView.frame.height + + var imageView1 = UIImageView(image: UIImage(named: "image1.jpg")) + imageView1.frame = CGRectMake(0, 30, scrollViewWidth, scrollViewHeight) + var imageView2 = UIImageView(image: UIImage(named: "image2.jpg")) + imageView2.frame = CGRectMake(scrollViewWidth, 30, scrollViewWidth, scrollViewHeight) + var imageView3 = UIImageView(image: UIImage(named: "image3.jpg")) + imageView3.frame = CGRectMake(scrollViewWidth*2, 30, scrollViewWidth, scrollViewHeight) + testImageViews = [imageView1, imageView2, imageView3] + + for item in testImageViews { + mediaScrollView.addSubview(item) + } + mediaScrollView.contentSize = CGSizeMake(scrollViewWidth * CGFloat(testImageViews.count), scrollViewHeight) + mediaScrollView.delegate = self + mediaPageControl.currentPage = 0 + + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + initScene() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if !isInitiated { + isInitiated = true + var blurEffect = UIBlurEffect(style: UIBlurEffectStyle.ExtraLight) + var blurView = UIVisualEffectView(effect: blurEffect) + blurView.frame = backgroundImageView.bounds + backgroundImageView.addSubview(blurView) + + priceLabeBackgroundView.layer.borderWidth = 1.5 + priceLabeBackgroundView.layer.borderColor = UIColor.whiteColor().CGColor + priceLabeBackgroundView.layer.cornerRadius = priceLabeBackgroundView.layer.bounds.height/2 + var blurEffect2 = UIBlurEffect(style: UIBlurEffectStyle.Dark) + var blurView2 = UIVisualEffectView(effect: blurEffect2) + blurView2.frame = priceLabeBackgroundView.bounds + priceLabeBackgroundView.addSubview(blurView2) + priceLabeBackgroundView.alpha = 0.15 + + var timer1 = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("priceBounce"), userInfo: nil, repeats: false) + + leftButton.roundCorners(.TopLeft | .BottomLeft, radius: 9) + rightButton.roundCorners(.TopRight | .BottomRight, radius: 9) + + leftButton.alpha = 0.65 + midButton.alpha = 0.65 + rightButton.alpha = 0.65 + + titleLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + titleLeftView.layer.borderWidth = 0.65 + titleLeftView.layer.cornerRadius = 2 + + detailLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + detailLeftView.layer.borderWidth = 0.65 + detailLeftView.layer.cornerRadius = 2 + + startLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + startLeftView.layer.borderWidth = 0.65 + startLeftView.layer.cornerRadius = 2 + + // endLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + // endLeftView.layer.borderWidth = 0.65 + // endLeftView.layer.cornerRadius = 2 + + let newImage = mapButton.imageView?.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + mapButton.tintColor = UIColor(red:0.29, green:0.56, blue:0.89, alpha:0.5) + mapButton.setImage(newImage, forState: .Normal) + + portraitImageView.layer.borderWidth = 1.5 + portraitImageView.layer.borderColor = UIColor.whiteColor().CGColor + portraitImageView.layer.cornerRadius = 12 + } + } + + func priceBounce() { + bounceView(priceLabel) + } + + func initScene() { + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + textColor = leftButton.titleLabel?.textColor + midButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + midButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + + priceLabel.text = "$ \(toPass!.price!)" + currentPrice = toPass!.price + + startTimeLabel.text = toPass!.effectiveStartDate + // endTimeLabel.text = toPass!.effectiveEndDate + + titleLabel.text = toPass!.title + + // user view + leftView.alpha = 0 + + portraitImageView.image = UIImage(named: "my portrait") + nicknameLabel.text = toPass!.nickname + statusLabel.text = "Come come people, you all need to buy my album" + + // media view + rightView.alpha = 0 + + + } + + @IBAction func buttonTapped(sender: UIButton) { + switch sender.titleLabel!.text! { + case "User": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.leftButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.leftButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.midButton.setTitleColor(self.textColor, forState: .Normal) + self.midButton.backgroundColor = UIColor.whiteColor() + self.rightButton.setTitleColor(self.textColor, forState: .Normal) + self.rightButton.backgroundColor = UIColor.whiteColor() + self.midView.alpha = 0 + self.leftView.alpha = 1 + self.rightView.alpha = 0 + }, completion: nil) + case "Detail": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.midButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.midButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.leftButton.setTitleColor(self.textColor, forState: .Normal) + self.leftButton.backgroundColor = UIColor.whiteColor() + self.rightButton.setTitleColor(self.textColor, forState: .Normal) + self.rightButton.backgroundColor = UIColor.whiteColor() + self.midView.alpha = 1 + self.leftView.alpha = 0 + self.rightView.alpha = 0 + }, completion: nil) + case "Media": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.rightButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.rightButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.midButton.setTitleColor(self.textColor, forState: .Normal) + self.midButton.backgroundColor = UIColor.whiteColor() + self.leftButton.setTitleColor(self.textColor, forState: .Normal) + self.leftButton.backgroundColor = UIColor.whiteColor() + self.midView.alpha = 0 + self.leftView.alpha = 0 + self.rightView.alpha = 1 + }, completion: nil) + default: + break + } + } + + @IBAction func addressButtonTapped(sender: UIButton) { + bounceView(sender) + let viewController = ContentViewController() + viewController.toPass = toPass!.address! + viewController.latitude = toPass!.latitude! + viewController.longitude = toPass!.longitude! + let alert = AlertController(view: viewController.view, style: .ActionSheet) + showAlert(alert) + } + + func showAlert(alert: SimpleAlert.Controller) { + + + + alert.addAction(SimpleAlert.Action(title: "Navigate", style: .Destructive) { action in + }) + + alert.addAction(SimpleAlert.Action(title: "OK", style: .OK) { action in + }) + + self.presentViewController(alert, animated: true, completion: nil) + } + +} + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/VCs/OrdersListTVC.swift b/Classes/VCs/MyOrdersRequestsShowTakerTVC.swift similarity index 50% rename from Classes/VCs/OrdersListTVC.swift rename to Classes/VCs/MyOrdersRequestsShowTakerTVC.swift index ef522fe..8b5d4a2 100644 --- a/Classes/VCs/OrdersListTVC.swift +++ b/Classes/VCs/MyOrdersRequestsShowTakerTVC.swift @@ -1,31 +1,59 @@ // -// OrdersListTVC.swift +// MyOrdersRequestsShowTakerTVC.swift // Arrived // -// Created by Lu Cao on 5/11/15. +// Created by Lu Cao on 5/31/15. // Copyright (c) 2015 LoopCow. All rights reserved. // import UIKit -class OrdersListTVC: UITableViewController { +class MyOrdersRequestsShowTakerTVC: UITableViewController { - var toPass = [[String:AnyObject]]() - var job = [String:AnyObject]() + struct testData { + var name: String? + var line: String? + var likes: Int? + var dislikes: Int? + var jobsDone: Int? + } + + var testDataArray = [testData]() + + var toPass = Order() override func viewDidLoad() { super.viewDidLoad() - // Uncomment the following line to preserve selection between presentations - // self.clearsSelectionOnViewWillAppear = false - - // Uncomment the following line to display an Edit button in the navigation bar for this view controller. - // self.navigationItem.rightBarButtonItem = self.editButtonItem() + setUpTestData() + + initScene() } + + func setUpTestData() { + var data1 = testData(name: "Luu", line: "We all love you", likes: 300, dislikes: 0, jobsDone: 500) + var data2 = testData(name: "Fucker", line: "We all hate you", likes: 0, dislikes: 300, jobsDone: 0) + var data3 = testData(name: "Mr Ordinary", line: "We all ignore you", likes: 0, dislikes: 0, jobsDone: 0) + testDataArray = [data1, data2, data3] + } + + func initScene() { + + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + // add blur background +// var bgBlurView = UIImageView() +// bgBlurView.image = UIImage(named: "my portrait") +// bgBlurView.frame = CGRectMake(-(tableView.frame.height - tableView.frame.width)/2, 0, tableView.frame.height, tableView.frame.height) +// var blurEffect = UIBlurEffect(style: UIBlurEffectStyle.ExtraLight) +// var blurView = UIVisualEffectView(effect: blurEffect) +// blurView.frame = bgBlurView.bounds +// bgBlurView.addSubview(blurView) +// self.tableView.backgroundView = bgBlurView + + // hide seperator below each cell + tableView.separatorStyle = UITableViewCellSeparatorStyle.None - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. } // MARK: - Table view data source @@ -39,29 +67,21 @@ class OrdersListTVC: UITableViewController { override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // #warning Incomplete method implementation. // Return the number of rows in the section. - return toPass.count + return testDataArray.count } - override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCellWithIdentifier("OrdersListCell", forIndexPath: indexPath) as! OrdersListTVCell + let cell = tableView.dequeueReusableCellWithIdentifier("MyOrdersRequestsShowTakerTVCell", forIndexPath: indexPath) as! MyOrdersRequestsShowTakerTVCell - var job = toPass[indexPath.row] - cell.title.text = job["title"] as? String - cell.body.text = job["body"] as? String - - ImageLoader.sharedLoader.imageForUrl(job["portrait"] as! String, completionHandler:{(image: UIImage?, url: String) in - cell.portrait.image = image! - }) + cell.portrait.image = UIImage(named: "my portrait") + cell.nickname.text = testDataArray[indexPath.row].name + cell.status.text = testDataArray[indexPath.row].line + cell.likes.text = "\(testDataArray[indexPath.row].likes!)" + cell.dislikes.text = "\(testDataArray[indexPath.row].dislikes!)" + cell.jobsDone.text = "\(testDataArray[indexPath.row].jobsDone!)" return cell } - - - override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { - job = toPass[indexPath.row] - performSegueWithIdentifier("OrdersListToOrderDetail", sender: self) - } /* // Override to support conditional editing of the table view. @@ -98,17 +118,14 @@ class OrdersListTVC: UITableViewController { } */ - + /* // MARK: - Navigation + // In a storyboard-based application, you will often want to do a little preparation before navigation override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { - - - if segue.identifier == "OrdersListToOrderDetail" { - var svc = segue.destinationViewController as! OrderDetailVC; - svc.toPass = job - } - + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. } + */ } diff --git a/Classes/VCs/MyOrdersRequestsShowTakerTVCell.swift b/Classes/VCs/MyOrdersRequestsShowTakerTVCell.swift new file mode 100644 index 0000000..da52d52 --- /dev/null +++ b/Classes/VCs/MyOrdersRequestsShowTakerTVCell.swift @@ -0,0 +1,139 @@ +// +// MyOrdersRequestsShowTakerTVCell.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class MyOrdersRequestsShowTakerTVCell: UITableViewCell { + + @IBOutlet weak var bgView: UIView! + + @IBOutlet weak var portrait: UIImageView! + @IBOutlet weak var nickname: UILabel! + @IBOutlet weak var status: UILabel! + @IBOutlet weak var price: UILabel! + + @IBOutlet weak var likes: UILabel! + @IBOutlet weak var dislikes: UILabel! + @IBOutlet weak var jobsDone: UILabel! + + // gestures + var originalCenter = CGPoint() + var requireOnDragRelease = false + + var crossLabel: UILabel! // for insterest swipe + + override func awakeFromNib() { + super.awakeFromNib() + + initCell() + + } + + override func layoutSubviews() { + super.layoutSubviews() + + let kUICuesMargin: CGFloat = 10.0, kUICuesWidth: CGFloat = 80.0 + crossLabel.frame = CGRect(x: bounds.size.width + kUICuesMargin, y: 0, + width: kUICuesWidth, height: bounds.size.height) + } + + override func drawRect(rect: CGRect) { + + bgView.alpha = 1 + bgView.backgroundColor = UIColor(red:0.96, green:0.96, blue:0.96, alpha:0.95) + contentView.backgroundColor = UIColor.clearColor() + + bgView.layer.borderColor = UIColor.whiteColor().CGColor + bgView.layer.borderWidth = 1 + bgView.layer.cornerRadius = 12 + + portrait.layer.borderWidth = 1 + portrait.layer.borderColor = UIColor.whiteColor().CGColor + portrait.layer.cornerRadius = 8 + portrait.alpha = 1 + + price.layer.borderWidth = 1 + price.layer.borderColor = UIColor.whiteColor().CGColor + price.layer.cornerRadius = price.layer.frame.height/2 + price.alpha = 0.35 + } + + func initCell() { + + selectionStyle = .None + backgroundColor = UIColor.clearColor() + + // add a pan recognizer + var recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:") + recognizer.delegate = self + addGestureRecognizer(recognizer) + + // tick and cross labels for context cues + crossLabel = createCueLabel() + crossLabel.text = "Require" + crossLabel.font = UIFont(name: "American Typewriter", size: 17) + crossLabel.textAlignment = .Left + addSubview(crossLabel) + + } + + //MARK: - horizontal pan gesture methods + func handlePan(recognizer: UIPanGestureRecognizer) { + // 1 + if recognizer.state == .Began { + // when the gesture begins, record the current center location + originalCenter = center + } + // 2 + if recognizer.state == .Changed { + let translation = recognizer.translationInView(self) + center = CGPointMake(originalCenter.x + translation.x, originalCenter.y) + // has the user dragged the item far enough to initiate a delete/complete? + requireOnDragRelease = frame.origin.x < -frame.size.width / 3.5 + + // fade the contextual clues + let cueAlpha = fabs(frame.origin.x) / (frame.size.width / 3.5) + crossLabel.alpha = cueAlpha + // indicate when the user has pulled the item far enough to invoke the given action + crossLabel.textColor = requireOnDragRelease ? UIColor(red:0.37, green:0.83, blue:0.69, alpha:1) : UIColor.lightGrayColor() + } + // 3 + if recognizer.state == .Ended { + // the frame this cell had before user dragged it + let originalFrame = CGRect(x: 0, y: frame.origin.y, + width: bounds.size.width, height: bounds.size.height) + // if the item is not being deleted, snap back to the original location + UIView.animateWithDuration(0.2, animations: {self.frame = originalFrame}) + + if requireOnDragRelease { + println("123") + } + } + } + + override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool { + if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer { + let translation = panGestureRecognizer.translationInView(superview!) + if fabs(translation.x) > fabs(translation.y) { + return true + } + return false + } + return false + } + + // utility method for creating the contextual cues + func createCueLabel() -> UILabel { + let label = UILabel(frame: CGRect.nullRect) + label.textColor = UIColor.whiteColor() + label.font = UIFont.boldSystemFontOfSize(32.0) + label.backgroundColor = UIColor.clearColor() + return label + } + +} diff --git a/Classes/VCs/MyOrdersRequestsTVC.swift b/Classes/VCs/MyOrdersRequestsTVC.swift new file mode 100644 index 0000000..fcce520 --- /dev/null +++ b/Classes/VCs/MyOrdersRequestsTVC.swift @@ -0,0 +1,173 @@ +// +// MyOrdersRequestsTVC.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class MyOrdersRequestsTVC: UITableViewController { + + var willAnimateRipple = true { + didSet { + if willAnimateRipple { + tableView.reloadData() + } + } + } + + var testOrders = [Order]() + var selectedOrder = Order() + + override func viewDidLoad() { + super.viewDidLoad() + + createTestData() + + tableView.backgroundColor = UIColorFromHex(0xFFFFFF, alpha: 0) + + // hide seperator below each cell + tableView.separatorStyle = UITableViewCellSeparatorStyle.None + + tableView.reloadData() + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + } + + func createTestData() { + let order1 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "I am Order 1", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.34235200, longitude: -122.0322302, address: "rain st.123", status: "regular") + let order2 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "Who can tell I am order 2", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.37235141, longitude: -122.0342182, address: "rain st.123", status: "interested") + let order3 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "These two fuckers are order 1 and 2", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.31235141, longitude: -122.0112182, address: "rain st.123", status: "in progress") + testOrders = [order1, order2, order3] + } + + // MARK: - Table view data source + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + // #warning Potentially incomplete method implementation. + // Return the number of sections. + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + // #warning Incomplete method implementation. + // Return the number of rows in the section. + return testOrders.count + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("MyOrdersRequestsTVCell", forIndexPath: indexPath) as! MyOrdersRequestsTVCell + + cell.titleLabel.text = testOrders[indexPath.row].title + if testOrders[indexPath.row].status! == "in progress" { + cell.takersButton.setTitle("", forState: .Normal) + cell.takersButton.setImage(UIImage(named: "progressing icon"), forState: .Normal) + cell.takersButton.backgroundColor = UIColor.clearColor() + cell.takersButton.addTarget(self, action: "showProgress", forControlEvents: .TouchUpInside) + } else { + cell.takersButton.addTarget(self, action: "showTakers", forControlEvents: .TouchUpInside) + ripple(cell) + } + + cell.selectionStyle = .None + cell.alpha = 0.9 + return cell + } + + func delay(delay:Double, closure:()->()) { + + dispatch_after( + dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), closure) + } + + func ripple(cell: MyOrdersRequestsTVCell) { + + var option = Ripple.option() + //configure + option.borderWidth = CGFloat(1) + option.radius = cell.takersButton.layer.frame.height/2 * 1.2 + option.duration = CFTimeInterval(1.5) + option.borderColor = UIColor(red:0.29, green:0.56, blue:0.89, alpha:0.3) + option.fillColor = UIColor.clearColor() + option.scale = CGFloat(1.1) + + if willAnimateRipple { + Ripple.run(cell.takersButton, locationInView: cell.takersButton.center, option: option) {} + delay(1) { + self.ripple(cell) + } + + } + } + + func showProgress() { + performSegueWithIdentifier("RequestShowProgress", sender: self) + } + + func showTakers() { + performSegueWithIdentifier("RequestShowTakers", sender: self) + } + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + let cell = tableView.dequeueReusableCellWithIdentifier("MyOrdersRequestsTVCell", forIndexPath: indexPath) as! MyOrdersRequestsTVCell + + selectedOrder = testOrders[indexPath.row] + performSegueWithIdentifier("RequestDetail", sender: self) + } + + /* + // Override to support conditional editing of the table view. + override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { + // Return NO if you do not want the specified item to be editable. + return true + } + */ + + /* + // Override to support editing the table view. + override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { + if editingStyle == .Delete { + // Delete the row from the data source + tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) + } else if editingStyle == .Insert { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } + } + */ + + /* + // Override to support rearranging the table view. + override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { + + } + */ + + /* + // Override to support conditional rearranging of the table view. + override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool { + // Return NO if you do not want the item to be re-orderable. + return true + } + */ + + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + if segue.identifier == "RequestDetail" { + var svc = segue.destinationViewController as! MyOrdersRequestViewDetailVC + svc.toPass = selectedOrder + } + if segue.identifier == "RequestShowTakers" { + var svc = segue.destinationViewController as! MyOrdersRequestsShowTakerTVC + svc.toPass = selectedOrder + } + + } + +} diff --git a/Classes/VCs/MyOrdersRequestsTVCell.swift b/Classes/VCs/MyOrdersRequestsTVCell.swift new file mode 100644 index 0000000..b4b3945 --- /dev/null +++ b/Classes/VCs/MyOrdersRequestsTVCell.swift @@ -0,0 +1,51 @@ +// +// MyOrdersRequestsTVCell.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class MyOrdersRequestsTVCell: UITableViewCell { + + @IBOutlet weak var bgView: UIView! + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var inProgressIndicator: UIImageView! + @IBOutlet weak var takersButton: UIButton! + + override func awakeFromNib() { + super.awakeFromNib() + + setUpCell() + + backgroundColor = UIColorFromHex(0xFFFFFF, alpha: 0) + bgView.alpha = 0.65 + } + + func setUpCell() { + + selectionStyle = .None + + bgView.roundCorners(.TopLeft | .BottomLeft, radius: bgView.layer.bounds.height/2) + bgView.layer.borderColor = UIColor.lightGrayColor().CGColor + bgView.layer.borderWidth = 0 + bgView.layer.cornerRadius = 8 + + takersButton.layer.borderWidth = 1.2 + takersButton.layer.borderColor = UIColor.lightGrayColor().CGColor + takersButton.layer.cornerRadius = takersButton.layer.frame.height/2 + takersButton.alpha = 0.65 + + inProgressIndicator.alpha = 0 + + + } + + override func layoutSubviews() { + super.layoutSubviews() + } + +} diff --git a/Classes/VCs/MyOrdersVC.swift b/Classes/VCs/MyOrdersVC.swift new file mode 100644 index 0000000..73a1de9 --- /dev/null +++ b/Classes/VCs/MyOrdersVC.swift @@ -0,0 +1,140 @@ +// +// MyOrdersVC.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class MyOrdersVC: UIViewController { + + var testOrders = [Order]() + var isInitiated = false + + var myOrdersRequestsTVC: MyOrdersRequestsTVC? + + @IBOutlet weak var bgBlurView: UIImageView! + + @IBOutlet weak var leftTab: UIButton! + @IBOutlet weak var midTab: UIButton! + @IBOutlet weak var rightTab: UIButton! + + @IBOutlet weak var leftView: UIView! + @IBOutlet weak var midView: UIView! + + override func viewDidLoad() { + super.viewDidLoad() + + initScene() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if !isInitiated { + isInitiated = !isInitiated + + // add blur background + bgBlurView.image = UIImage(named: "my portrait") + var blurEffect = UIBlurEffect(style: UIBlurEffectStyle.ExtraLight) + var blurView = UIVisualEffectView(effect: blurEffect) + blurView.frame = bgBlurView.bounds + bgBlurView.addSubview(blurView) + + // set up tabs + leftTab.roundCorners(.TopLeft | .BottomLeft, radius: 9) + rightTab.roundCorners(.TopRight | .BottomRight, radius: 9) + + leftTab.alpha = 0.65 + midTab.alpha = 0.65 + rightTab.alpha = 0.65 + + leftView.alpha = 1 + midView.alpha = 0 + } + + + } + + func initScene() { + + // set color of current tab so its defautly enabled + leftTab.setTitleColor(UIColor.whiteColor(), forState: .Normal) + leftTab.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + + } + + @IBAction func tabTapped(sender: UIButton) { + switch sender.titleLabel!.text! { + case "Requests": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.leftTab.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.leftTab.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.midTab.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + self.midTab.backgroundColor = UIColor.whiteColor() + self.rightTab.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + self.rightTab.backgroundColor = UIColor.whiteColor() + self.leftView.alpha = 1 + self.myOrdersRequestsTVC?.willAnimateRipple = true + self.midView.alpha = 0 + }, completion: nil) + case "Jobs": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.midTab.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.midTab.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.leftTab.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + self.leftTab.backgroundColor = UIColor.whiteColor() + self.rightTab.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + self.rightTab.backgroundColor = UIColor.whiteColor() + self.leftView.alpha = 0 + self.myOrdersRequestsTVC?.willAnimateRipple = false + self.midView.alpha = 1 + }, completion: nil) + case "All": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.rightTab.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.rightTab.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.midTab.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + self.midTab.backgroundColor = UIColor.whiteColor() + self.leftTab.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + self.leftTab.backgroundColor = UIColor.whiteColor() + self.leftView.alpha = 0 + self.myOrdersRequestsTVC?.willAnimateRipple = false + self.midView.alpha = 0 + }, completion: nil) + default: + break + } + } + + // MARK: - Navigation + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + if segue.identifier == "MyOrdersRequestsTable" { + var svc = segue.destinationViewController as! MyOrdersRequestsTVC + myOrdersRequestsTVC = svc + } + } + +} + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/VCs/NewOrderFVC.swift b/Classes/VCs/NewOrderFVC.swift new file mode 100644 index 0000000..09511b2 --- /dev/null +++ b/Classes/VCs/NewOrderFVC.swift @@ -0,0 +1,83 @@ +// +// NewOrderFVC.swift +// Arrived +// +// Created by Lu Cao on 6/2/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class NewOrderFVC: FormViewController { + + struct Static { + static let phoneTag = "phone" + static let addressTag = "address" + + static let dateTime = "dateTime" + static let date = "date" + static let time = "time" + + static let titleTag = "title" + static let detailTag = "detail" + + static let priceTag = "price" + } + + required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + self.loadForm() + } + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Submit", style: .Plain, target: self, action: "submit:") + + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + } + + /// MARK: Actions + @IBAction func cancelAction(sender: UIBarButtonItem) { + dismissViewControllerAnimated(true, completion: nil) + } + + func submit(_: UIBarButtonItem!) { + + let message = self.form.formValues().description + + let alert: UIAlertView = UIAlertView(title: "Form output", message: message, delegate: nil, cancelButtonTitle: "OK") + + alert.show() + } + + /// MARK: Private interface + + private func loadForm() { + + let form = FormDescriptor() + + form.title = "New Request" + + let section1 = FormSectionDescriptor() + + var row: FormRowDescriptor! = FormRowDescriptor(tag: Static.phoneTag, rowType: .Phone, title: "Phone") + row.configuration[FormRowDescriptor.Configuration.CellConfiguration] = ["textField.placeholder" : "e.g. +14444444444", "textField.textAlignment" : NSTextAlignment.Right.rawValue] + section1.addRow(row) + + row = FormRowDescriptor(tag: Static.addressTag, rowType: .Password, title: "Address") + row.configuration[FormRowDescriptor.Configuration.CellConfiguration] = ["textField.placeholder" : "Enter Address", "textField.textAlignment" : NSTextAlignment.Right.rawValue] + section1.addRow(row) + + let section2 = FormSectionDescriptor() + + + let section3 = FormSectionDescriptor() + + let section4 = FormSectionDescriptor() + + + form.sections = [section1, section2, section3, section4] + + self.form = form + } +} diff --git a/Classes/VCs/OrderDetailVC.swift b/Classes/VCs/OrderDetailVC.swift index e37ebe4..24004a5 100644 --- a/Classes/VCs/OrderDetailVC.swift +++ b/Classes/VCs/OrderDetailVC.swift @@ -2,36 +2,356 @@ // OrderDetailVC.swift // Arrived // -// Created by Lu Cao on 5/11/15. +// Created by Lu Cao on 5/30/15. // Copyright (c) 2015 LoopCow. All rights reserved. // import UIKit -class OrderDetailVC: UIViewController { +class OrderDetailVC: UIViewController, UIScrollViewDelegate { - var toPass = [String:AnyObject]() + var toPass: Order? + + @IBOutlet weak var backgroundImageView: UIImageView! + + + + + // price view + + @IBOutlet weak var priceLabel: UICountingLabel! + @IBOutlet weak var priceLabeBackgroundView: UIView! + private var currentPrice: Double? + + private var interested = false + @IBOutlet weak var mapButton: UIButton! + @IBOutlet weak var interestedButton: UIButton! + + @IBOutlet weak var plus1Button: UIButton! + @IBOutlet weak var plus5Button: UIButton! + @IBOutlet weak var plus10Button: UIButton! + @IBOutlet weak var clearAddedMoneyButton: UIButton! + + @IBOutlet weak var leftButton: UIButton! + @IBOutlet weak var midButton: UIButton! + @IBOutlet weak var rightButton: UIButton! + + // detail view + @IBOutlet weak var midView: UIView! + @IBOutlet weak var startTimeLabel: UILabel! + @IBOutlet weak var startLeftView: UILabel! + + @IBOutlet weak var titleLeftView: UILabel! + @IBOutlet weak var titleLabel: UILabel! + + @IBOutlet weak var detailLeftView: UILabel! + + // user view + @IBOutlet weak var leftView: UIView! + + @IBOutlet weak var portraitImageView: UIImageView! + @IBOutlet weak var nicknameLabel: UILabel! + @IBOutlet weak var statusLabel: UILabel! + + // media view + @IBOutlet weak var rightView: UIView! + @IBOutlet weak var mediaScrollView: UIScrollView! + @IBOutlet weak var mediaPageControl: UIPageControl! + + private var testImageViews = [UIImageView]() + + private var textColor: UIColor? + + private var isInitiated = false - @IBOutlet weak var price: UILabel! override func viewDidLoad() { super.viewDidLoad() - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. + + let scrollViewWidth: CGFloat = mediaScrollView.frame.width + let scrollViewHeight: CGFloat = mediaScrollView.frame.height + + var imageView1 = UIImageView(image: UIImage(named: "image1.jpg")) + imageView1.frame = CGRectMake(0, 30, scrollViewWidth, scrollViewHeight) + var imageView2 = UIImageView(image: UIImage(named: "image2.jpg")) + imageView2.frame = CGRectMake(scrollViewWidth, 30, scrollViewWidth, scrollViewHeight) + var imageView3 = UIImageView(image: UIImage(named: "image3.jpg")) + imageView3.frame = CGRectMake(scrollViewWidth*2, 30, scrollViewWidth, scrollViewHeight) + testImageViews = [imageView1, imageView2, imageView3] + + for item in testImageViews { + mediaScrollView.addSubview(item) + } + mediaScrollView.contentSize = CGSizeMake(scrollViewWidth * CGFloat(testImageViews.count), scrollViewHeight) + mediaScrollView.delegate = self + mediaPageControl.currentPage = 0 + } override func viewWillAppear(animated: Bool) { super.viewWillAppear(true) - price.text = toPass["price"] as? String + initScene() + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if !isInitiated { + isInitiated = true + var blurEffect = UIBlurEffect(style: UIBlurEffectStyle.ExtraLight) + var blurView = UIVisualEffectView(effect: blurEffect) + blurView.frame = backgroundImageView.bounds + backgroundImageView.addSubview(blurView) + + priceLabeBackgroundView.layer.borderWidth = 1.5 + priceLabeBackgroundView.layer.borderColor = UIColor.whiteColor().CGColor + priceLabeBackgroundView.layer.cornerRadius = priceLabeBackgroundView.layer.bounds.height/2 + var blurEffect2 = UIBlurEffect(style: UIBlurEffectStyle.Dark) + var blurView2 = UIVisualEffectView(effect: blurEffect2) + blurView2.frame = priceLabeBackgroundView.bounds + priceLabeBackgroundView.addSubview(blurView2) + priceLabeBackgroundView.alpha = 0.15 + + var timer1 = NSTimer.scheduledTimerWithTimeInterval(1, target: self, selector: Selector("priceBounce"), userInfo: nil, repeats: false) + + leftButton.roundCorners(.TopLeft | .BottomLeft, radius: 9) + rightButton.roundCorners(.TopRight | .BottomRight, radius: 9) + + leftButton.alpha = 0.65 + midButton.alpha = 0.65 + rightButton.alpha = 0.65 + + plus1Button.layer.borderColor = UIColor.whiteColor().CGColor + plus1Button.layer.borderWidth = 1.2 + plus1Button.layer.cornerRadius = plus1Button.layer.bounds.height/2 + + plus5Button.layer.borderColor = UIColor.whiteColor().CGColor + plus5Button.layer.borderWidth = 1.2 + plus5Button.layer.cornerRadius = plus1Button.layer.bounds.height/2 + + plus10Button.layer.borderColor = UIColor.whiteColor().CGColor + plus10Button.layer.borderWidth = 1.2 + plus10Button.layer.cornerRadius = plus1Button.layer.bounds.height/2 + + drawLineFromPoint(plus1Button.center, toPoint: plus5Button.center, ofColor: UIColor.whiteColor(), inView: view) + drawLineFromPoint(plus5Button.center, toPoint: plus10Button.center, ofColor: UIColor.whiteColor(), inView: view) + view.bringSubviewToFront(plus1Button) + view.bringSubviewToFront(plus5Button) + view.bringSubviewToFront(plus10Button) + + titleLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + titleLeftView.layer.borderWidth = 0.65 + titleLeftView.layer.cornerRadius = 2 + + detailLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + detailLeftView.layer.borderWidth = 0.65 + detailLeftView.layer.cornerRadius = 2 + + startLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor + startLeftView.layer.borderWidth = 0.65 + startLeftView.layer.cornerRadius = 2 + +// endLeftView.layer.borderColor = UIColor.lightGrayColor().CGColor +// endLeftView.layer.borderWidth = 0.65 +// endLeftView.layer.cornerRadius = 2 + + let newImage = mapButton.imageView?.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + mapButton.tintColor = UIColor(red:0.29, green:0.56, blue:0.89, alpha:0.5) + mapButton.setImage(newImage, forState: .Normal) + + let newImage2 = interestedButton.imageView?.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + interestedButton.tintColor = UIColor.lightGrayColor() + interestedButton.setImage(newImage2, forState: .Normal) + + portraitImageView.layer.borderWidth = 1.5 + portraitImageView.layer.borderColor = UIColor.whiteColor().CGColor + portraitImageView.layer.cornerRadius = 12 + } + } + + func priceBounce() { + bounceView(priceLabel) } + + func initScene() { + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + textColor = leftButton.titleLabel?.textColor + midButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + midButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + + priceLabel.text = "$ \(toPass!.price!)" + currentPrice = toPass!.price + + startTimeLabel.text = toPass!.effectiveStartDate +// endTimeLabel.text = toPass!.effectiveEndDate + + titleLabel.text = toPass!.title + + // user view + leftView.alpha = 0 + + portraitImageView.image = UIImage(named: "my portrait") + nicknameLabel.text = toPass!.nickname + statusLabel.text = "Come come people, you all need to buy my album" + + // media view + rightView.alpha = 0 - @IBAction func interest(sender: AnyObject) { } + + @IBAction func buttonTapped(sender: UIButton) { + switch sender.titleLabel!.text! { + case "User": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.leftButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.leftButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.midButton.setTitleColor(self.textColor, forState: .Normal) + self.midButton.backgroundColor = UIColor.whiteColor() + self.rightButton.setTitleColor(self.textColor, forState: .Normal) + self.rightButton.backgroundColor = UIColor.whiteColor() + self.midView.alpha = 0 + self.leftView.alpha = 1 + self.rightView.alpha = 0 + }, completion: nil) + case "Detail": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.midButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.midButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.leftButton.setTitleColor(self.textColor, forState: .Normal) + self.leftButton.backgroundColor = UIColor.whiteColor() + self.rightButton.setTitleColor(self.textColor, forState: .Normal) + self.rightButton.backgroundColor = UIColor.whiteColor() + self.midView.alpha = 1 + self.leftView.alpha = 0 + self.rightView.alpha = 0 + }, completion: nil) + case "Media": + UIView.animateWithDuration(0.65, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.rightButton.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.rightButton.backgroundColor = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + self.midButton.setTitleColor(self.textColor, forState: .Normal) + self.midButton.backgroundColor = UIColor.whiteColor() + self.leftButton.setTitleColor(self.textColor, forState: .Normal) + self.leftButton.backgroundColor = UIColor.whiteColor() + self.midView.alpha = 0 + self.leftView.alpha = 0 + self.rightView.alpha = 1 + }, completion: nil) + default: + break + } + } + + @IBAction func interestedButtonTapped(sender: UIButton) { + bounceView(sender) + if !interested { + interested = !interested + let newImage = sender.imageView?.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + sender.tintColor = UIColor(red:0.95, green:0.69, blue:0.25, alpha:0.6) + sender.setImage(newImage, forState: .Normal) + } else { + interested = !interested + let newImage = sender.imageView?.image!.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + sender.tintColor = UIColor.lightGrayColor() + sender.setImage(newImage, forState: .Normal) + } + } + @IBAction func addressButtonTapped(sender: UIButton) { + bounceView(sender) + let viewController = ContentViewController() + viewController.toPass = toPass!.address! + viewController.latitude = toPass!.latitude! + viewController.longitude = toPass!.longitude! + let alert = AlertController(view: viewController.view, style: .ActionSheet) + showAlert(alert) + } + + func showAlert(alert: SimpleAlert.Controller) { + + + + alert.addAction(SimpleAlert.Action(title: "Navigate", style: .Destructive) { action in + }) + + alert.addAction(SimpleAlert.Action(title: "OK", style: .OK) { action in + }) + + self.presentViewController(alert, animated: true, completion: nil) + } + + @IBAction func plusMoney(sender: UIButton) { + if !interested { + switch sender.titleLabel!.text! { + case "+1": + priceLabel.text = "$ \(currentPrice! + 1)" + currentPrice! += 1 + bounceView(priceLabel) + case "+5": + priceLabel.text = "$ \(currentPrice! + 5)" + currentPrice! += 5 + bounceView(priceLabel) + case "+10": + priceLabel.text = "$ \(currentPrice! + 10)" + currentPrice! += 10 + bounceView(priceLabel) + default: + break + } + } + } + + @IBAction func clearAddedMoney(sender: UIButton) { + priceLabel.text = "$ \(toPass!.price!)" + bounceView(priceLabel) + } + + func drawLineFromPoint(start : CGPoint, toPoint end:CGPoint, ofColor lineColor: UIColor, inView view:UIView) { + + //design the path + var path = UIBezierPath() + path.moveToPoint(start) + path.addLineToPoint(end) + + //design path in layer + var shapeLayer = CAShapeLayer() + shapeLayer.path = path.CGPath + shapeLayer.strokeColor = lineColor.CGColor + shapeLayer.lineWidth = 2 + + view.layer.addSublayer(shapeLayer) + } + + func scrollViewDidEndDecelerating(scrollView: UIScrollView){ + // Test the offset and calculate the current page after scrolling ends + var pageWidth:CGFloat = CGRectGetWidth(scrollView.frame) + var currentPage:CGFloat = floor((scrollView.contentOffset.x-pageWidth/2)/pageWidth)+1 + // Change the indicator + mediaPageControl.currentPage = Int(currentPage); + } } + + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/VCs/OrdersListTVCell.swift b/Classes/VCs/OrdersListTVCell.swift deleted file mode 100644 index f1ba966..0000000 --- a/Classes/VCs/OrdersListTVCell.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// OrdersListTVCell.swift -// Arrived -// -// Created by Lu Cao on 5/11/15. -// Copyright (c) 2015 LoopCow. All rights reserved. -// - -import UIKit - -class OrdersListTVCell: UITableViewCell { - - - @IBOutlet weak var portrait: UIImageView! - @IBOutlet weak var title: UILabel! - @IBOutlet weak var body: UILabel! - - - override func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override func setSelected(selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - -} diff --git a/Classes/VCs/OrdersListViewTVC.swift b/Classes/VCs/OrdersListViewTVC.swift new file mode 100644 index 0000000..c08e033 --- /dev/null +++ b/Classes/VCs/OrdersListViewTVC.swift @@ -0,0 +1,154 @@ +// +// OrdersListViewTVC.swift +// Arrived +// +// Created by Lu Cao on 5/29/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit +import MapKit + +class OrdersListViewTVC: UITableViewController { + + + private var testOrders = [Order]() + + // for user location + var manager: CLLocationManager! + var myLocations: [CLLocation] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + let order1 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "I am Order 1", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.34235200, longitude: -122.0322302, address: "rain st.123", status: "regular") + let order2 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "Who can tell I am order 2", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.37235141, longitude: -122.0342182, address: "rain st.123", status: "interested") + let order3 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "These two fuckers are order 1 and 2", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.31235141, longitude: -122.0112182, address: "rain st.123", status: "in progress") + testOrders = [order1, order2, order3] + + // hide seperator below each cell + tableView.separatorStyle = UITableViewCellSeparatorStyle.None + + // set top margin of table view + tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0) + + self.tableView.backgroundColor = UIColor(red:0.95, green:0.69, blue:0.25, alpha:0.06) + + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + // MARK: - Table view data source + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + // #warning Potentially incomplete method implementation. + // Return the number of sections. + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + // #warning Incomplete method implementation. + // Return the number of rows in the section. + return testOrders.count + } + + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("OrdersListViewTVCell", forIndexPath: indexPath) as! OrdersListViewTVCell + + cell.selectionStyle = .None + + ImageLoader.sharedLoader.imageForUrl(self.testOrders[indexPath.row].portrait!, completionHandler:{(image: UIImage?, url: String) in + cell.portrait.image = image! + }) + cell.titleLabel.text = testOrders[indexPath.row].title + cell.priceLabel.text = "$ \(testOrders[indexPath.row].price!)" + + manager = CLLocationManager() + manager.desiredAccuracy = kCLLocationAccuracyBest + manager.requestAlwaysAuthorization() + + if CLLocationManager.locationServicesEnabled() { + manager.startUpdatingLocation() + + let latitude = manager.location.coordinate.latitude + let longitude = manager.location.coordinate.longitude + let location = CLLocation(latitude: latitude, longitude: longitude) + + let newLatitude = testOrders[indexPath.row].latitude! + let newLongitude = testOrders[indexPath.row].longitude! + let newLocation = CLLocation(latitude: newLatitude, longitude: newLongitude) + + cell.distanceLabel.text = "\(Int((location.distanceFromLocation(newLocation))/1000)) miles" + + switch testOrders[indexPath.row].status! { + case "regular": + cell.status.image = UIImage(named: "") + case "interested": + cell.status.image = UIImage(named: "interested indicator") + case "in progress": + cell.status.image = UIImage(named: "processing indicator") + default: + break + } + } + + return cell + } + + + /* + // Override to support conditional editing of the table view. + override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool { + // Return NO if you do not want the specified item to be editable. + return true + } + */ + + /* + // Override to support editing the table view. + override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { + + } + + override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [AnyObject]? { + + var shareAction = UITableViewRowAction(style: UITableViewRowActionStyle.Default, title: "Interested" , handler: { (action:UITableViewRowAction!, indexPath:NSIndexPath!) -> Void in + self.tableView.setEditing(false, animated: false) + }) + + return [shareAction] + } + */ + + /* + // Override to support rearranging the table view. + override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { + + } + */ + + /* + // Override to support conditional rearranging of the table view. + override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool { + // Return NO if you do not want the item to be re-orderable. + return true + } + */ + + // MARK: - Functionalities + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + // Get the new view controller using [segue destinationViewController]. + // Pass the selected object to the new view controller. + } + */ + +} diff --git a/Classes/VCs/OrdersListViewTVCell.swift b/Classes/VCs/OrdersListViewTVCell.swift new file mode 100644 index 0000000..c61e260 --- /dev/null +++ b/Classes/VCs/OrdersListViewTVCell.swift @@ -0,0 +1,124 @@ +// +// OrdersListViewTVCell.swift +// Arrived +// +// Created by Lu Cao on 5/29/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class OrdersListViewTVCell: UITableViewCell { + + @IBOutlet weak var view: UIView! + + @IBOutlet weak var portrait: UIImageView! + @IBOutlet weak var status: UIImageView! + + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var distanceLabel: UILabel! + @IBOutlet weak var reviewLabel: UILabel! + @IBOutlet weak var priceLabel: UILabel! + + // gestures + var originalCenter = CGPoint() + var interestedOnDragRelease = false + + var crossLabel: UILabel! // for insterest swipe + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + + self.backgroundColor = UIColor(red:0.95, green:0.69, blue:0.25, alpha:0) + + reviewLabel.text = "❤️ 33 💔 17" + + // add a pan recognizer + var recognizer = UIPanGestureRecognizer(target: self, action: "handlePan:") + recognizer.delegate = self + addGestureRecognizer(recognizer) + + // tick and cross labels for context cues + crossLabel = createCueLabel() + crossLabel.text = "Interest" + crossLabel.font = UIFont(name: "American Typewriter", size: 17) + crossLabel.textAlignment = .Left + addSubview(crossLabel) + + + } + + override func layoutSubviews() { + super.layoutSubviews() + let kUICuesMargin: CGFloat = 10.0, kUICuesWidth: CGFloat = 80.0 + crossLabel.frame = CGRect(x: bounds.size.width + kUICuesMargin, y: 0, + width: kUICuesWidth, height: bounds.size.height) + + view.roundCorners(.TopLeft | .BottomLeft, radius: view.layer.bounds.height/2) + view.layer.borderColor = UIColor.lightGrayColor().CGColor + view.layer.borderWidth = 0 + view.layer.cornerRadius = 12 + + portrait.layer.borderColor = UIColor.whiteColor().CGColor + portrait.layer.borderWidth = 2 + portrait.layer.cornerRadius = portrait.layer.bounds.height/2 + } + + //MARK: - horizontal pan gesture methods + func handlePan(recognizer: UIPanGestureRecognizer) { + // 1 + if recognizer.state == .Began { + // when the gesture begins, record the current center location + originalCenter = center + } + // 2 + if recognizer.state == .Changed { + let translation = recognizer.translationInView(self) + center = CGPointMake(originalCenter.x + translation.x, originalCenter.y) + // has the user dragged the item far enough to initiate a delete/complete? + interestedOnDragRelease = frame.origin.x < -frame.size.width / 3.5 + + // fade the contextual clues + let cueAlpha = fabs(frame.origin.x) / (frame.size.width / 3.5) + crossLabel.alpha = cueAlpha + // indicate when the user has pulled the item far enough to invoke the given action + crossLabel.textColor = interestedOnDragRelease ? UIColor(red:0.95, green:0.69, blue:0.25, alpha:1) : UIColor.lightGrayColor() + } + // 3 + if recognizer.state == .Ended { + // the frame this cell had before user dragged it + let originalFrame = CGRect(x: 0, y: frame.origin.y, + width: bounds.size.width, height: bounds.size.height) + // if the item is not being deleted, snap back to the original location + UIView.animateWithDuration(0.2, animations: {self.frame = originalFrame}) + + if interestedOnDragRelease { + // change status to interested or not interested + if status.image == UIImage(named: "") { status.image = UIImage(named: "interested indicator") } + else if status.image == UIImage(named: "interested indicator") { status.image = UIImage(named: "") } + } + } + } + + override func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool { + if let panGestureRecognizer = gestureRecognizer as? UIPanGestureRecognizer { + let translation = panGestureRecognizer.translationInView(superview!) + if fabs(translation.x) > fabs(translation.y) { + return true + } + return false + } + return false + } + + // utility method for creating the contextual cues + func createCueLabel() -> UILabel { + let label = UILabel(frame: CGRect.nullRect) + label.textColor = UIColor.whiteColor() + label.font = UIFont.boldSystemFontOfSize(32.0) + label.backgroundColor = UIColor.clearColor() + return label + } + +} diff --git a/Classes/VCs/OrdersMapViewVC.swift b/Classes/VCs/OrdersMapViewVC.swift new file mode 100644 index 0000000..570da71 --- /dev/null +++ b/Classes/VCs/OrdersMapViewVC.swift @@ -0,0 +1,316 @@ + +// +// OrdersMapViewVC.swift +// Arrived +// +// Created by Lu Cao on 5/28/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit +import MapKit + +class OrdersMapViewVC: UIViewController, MKMapViewDelegate { + + @IBOutlet weak var mapView: MKMapView! + @IBOutlet weak var detailView: UIView! + + // detail view + @IBOutlet weak var portraitImage: UIImageView! + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var priceLabel: UILabel! + + @IBOutlet weak var interestView: UIView! + @IBOutlet weak var progressingView: UIView! + + private var testOrders = [Order]() + private var currentOrderIndex = 0 + + private var annotations = [CustomPointAnnotation]() + + // for user location + var manager: CLLocationManager! + var myLocations: [CLLocation] = [] + + override func viewDidLoad() { + super.viewDidLoad() + + let order1 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "I am Order 1", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.34235200, longitude: -122.0322302, address: "rain st.123", status: "regular") + let order2 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "Who can tell I am order 2", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.37235141, longitude: -122.0342182, address: "rain st.123", status: "interested") + let order3 = Order(requestId: 1, phoneNumber: 13304650123, nickname: "Sam", portrait: "http://i.imgur.com/YrbaaFr.png", price: 133, title: "These two fuckers are order 1 and 2", body: "In SCU ENGINEER 1st Floor bathroom, help", effectiveStartDate: "21/06/2015, 12:23:00", effectiveEndDate: "21/06/2015, 12:33:00", tags: "", latitude: 37.31235141, longitude: -122.0112182, address: "rain st.123", status: "in progress") + testOrders = [order1, order2, order3] + + loadScene() + } + + func loadScene() { + + initMapCenter() + + if testOrders.count > 0 { + addAnnotations() + setDetailView() + goToOrder(currentOrderIndex) + } + + addSwipeGesturesToDetailView() + } + + func reloadScene() { + mapView.removeAnnotations(mapView.annotations) + + if testOrders.count > 0 { + addAnnotations() + setDetailView() + goToOrder(currentOrderIndex) + } + } + + func setDetailView() { + detailView.layer.borderWidth = 0.3 + detailView.layer.borderColor = UIColor.lightGrayColor().CGColor + detailView.layer.cornerRadius = 12 + detailView.alpha = 0.9 + + interestView.layer.borderWidth = 0.3 + interestView.layer.borderColor = UIColor.lightGrayColor().CGColor + interestView.layer.cornerRadius = 12 + interestView.alpha = 0.9 + + interestView.alpha = 0 + + progressingView.layer.borderWidth = 0.3 + progressingView.layer.borderColor = UIColor.lightGrayColor().CGColor + progressingView.layer.cornerRadius = 12 + progressingView.alpha = 0.9 + + progressingView.alpha = 0 + + } + + func initMapCenter() { + + mapView.delegate = self + + manager = CLLocationManager() + manager.desiredAccuracy = kCLLocationAccuracyBest + manager.requestAlwaysAuthorization() + + if CLLocationManager.locationServicesEnabled() { + manager.startUpdatingLocation() + + let latitude = manager.location.coordinate.latitude + let longitude = manager.location.coordinate.longitude + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) + let regionRadius: CLLocationDistance = 10000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + mapView.setRegion(coordinateRegion, animated: true) + } + + } + + func addAnnotations() { + for order in testOrders { + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: order.latitude!, longitude: order.longitude!) + var annotation = CustomPointAnnotation() + annotation.coordinate = location + switch order.status! { + case "regular": + annotation.imageName = "regular pin" + case "interested": + annotation.imageName = "interested pin" + case "in progress": + annotation.imageName = "in progress pin" + default: + break + } + + mapView.addAnnotation(annotation) + annotations.append(annotation) + } + } + + func goToOrder(i: Int) { + setDetailViewContent(i) + centerMapOnOrder(i) + } + + + func setDetailViewContent(i: Int) { + dispatch_async(dispatch_get_main_queue()) { + ImageLoader.sharedLoader.imageForUrl(self.testOrders[i].portrait!, completionHandler:{(image: UIImage?, url: String) in + self.portraitImage.image = image! + }) + } + titleLabel.text = testOrders[i].title + priceLabel.text = "$ \(testOrders[i].price!)" + priceLabel.layer.backgroundColor = UIColorFromHex(0x000000, alpha: 0.02).CGColor + + hideAndShowStatusViews(testOrders[i].status!) + } + + func centerMapOnOrder(i: Int) { + let latitude = manager.location.coordinate.latitude + let longitude = manager.location.coordinate.longitude + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: testOrders[i].latitude!, longitude: testOrders[i].longitude!) + let regionRadius: CLLocationDistance = 1000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + mapView.setRegion(coordinateRegion, animated: true) + } + + func fadeAndChangeDetailViewContent(i: Int) { + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { + self.detailView.alpha = 0.0 + }, completion: { + (finished: Bool) -> Void in + + self.goToOrder(i) + + // Fade in + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.detailView.alpha = 1.0 + }, completion: nil) + }) + } + + func hideAndShowStatusViews(status: String) { + switch status { + case "regular": + fadeOutView(interestView, 0.2) + fadeOutView(progressingView, 0.2) + case "interested": + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { + self.progressingView.alpha = 0.0 + }, completion: { + (finished: Bool) -> Void in + + // Fade in + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.interestView.alpha = 1.0 + }, completion: nil) + }) + case "in progress": + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: { + self.interestView.alpha = 0.0 + }, completion: { + (finished: Bool) -> Void in + + // Fade in + UIView.animateWithDuration(0.2, delay: 0.0, options: UIViewAnimationOptions.CurveEaseIn, animations: { + self.progressingView.alpha = 1.0 + }, completion: nil) + }) + default: + break + } + } + + // MARK: - User Interaction + func addSwipeGesturesToDetailView() { + var swipeRight = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:") + swipeRight.direction = UISwipeGestureRecognizerDirection.Right + detailView.addGestureRecognizer(swipeRight) + + var swipeLeft = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:") + swipeLeft.direction = UISwipeGestureRecognizerDirection.Left + detailView.addGestureRecognizer(swipeLeft) + + var swipeUp = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:") + swipeUp.direction = UISwipeGestureRecognizerDirection.Up + detailView.addGestureRecognizer(swipeUp) + + var swipeDown = UISwipeGestureRecognizer(target: self, action: "respondToSwipeGesture:") + swipeDown.direction = UISwipeGestureRecognizerDirection.Down + detailView.addGestureRecognizer(swipeDown) + } + + func respondToSwipeGesture(gesture: UIGestureRecognizer) { + + if let swipeGesture = gesture as? UISwipeGestureRecognizer { + + switch swipeGesture.direction { + case UISwipeGestureRecognizerDirection.Right: + if currentOrderIndex == 0 { + fadeAndChangeDetailViewContent(testOrders.count - 1) + currentOrderIndex = testOrders.count - 1 + } else { + fadeAndChangeDetailViewContent(--currentOrderIndex) + } + + case UISwipeGestureRecognizerDirection.Left: + if currentOrderIndex == testOrders.count - 1 { + fadeAndChangeDetailViewContent(0) + currentOrderIndex = 0 + } else { + fadeAndChangeDetailViewContent(++currentOrderIndex) + } + + case UISwipeGestureRecognizerDirection.Up: + if testOrders[currentOrderIndex].status == "regular" { + fadeInView(interestView, 0.6) + bounceView(interestView) + testOrders[currentOrderIndex].status = "interested" + mapView.removeAnnotation(annotations[currentOrderIndex]) + annotations[currentOrderIndex].imageName = "interested pin" + mapView.addAnnotation(annotations[currentOrderIndex]) + } else if testOrders[currentOrderIndex].status == "interested" { + fadeOutView(interestView, 0.6) + bounceView(interestView) + testOrders[currentOrderIndex].status = "regular" + mapView.removeAnnotation(annotations[currentOrderIndex]) + annotations[currentOrderIndex].imageName = "regular pin" + mapView.addAnnotation(annotations[currentOrderIndex]) + } + + case UISwipeGestureRecognizerDirection.Down: + // TODO: - Something like refresh + break + default: + break + } + } + } + + // MARK: - Delegates + + // Customize annotation appearance + func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { + if !(annotation is CustomPointAnnotation) { + return nil + } + + let reuseId = "test" + + var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) + if anView == nil { + anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) + anView.canShowCallout = true + } + else { + anView.annotation = annotation + } + + //Set annotation-specific properties **AFTER** + //the view is dequeued or created... + + let cpa = annotation as! CustomPointAnnotation + anView.image = UIImage(named:cpa.imageName) + + return anView + } + + // MARK: - Navigation + @IBAction func goToDetailView(sender: UIButton) { + performSegueWithIdentifier("OrdersMapViewToOrderDetailView", sender: self) + } + + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + if segue.identifier == "OrdersMapViewToOrderDetailView" { + var svc = segue.destinationViewController as! OrderDetailVC; + svc.toPass = testOrders[currentOrderIndex] + } + } + + + +} diff --git a/Classes/VCs/OrdersVC.swift b/Classes/VCs/OrdersVC.swift index 0c7580f..63c0155 100755 --- a/Classes/VCs/OrdersVC.swift +++ b/Classes/VCs/OrdersVC.swift @@ -7,18 +7,105 @@ // import UIKit -import CoreLocation -import MapKit -class myAnnotation: MKPointAnnotation { +struct Order { - var imageURL: String? - var detail: [String:AnyObject]? + var requestId: Int? + var phoneNumber: Int? + var nickname: String? + var portrait: String? + var price: Double? + var title: String? + var body: String? + var effectiveStartDate: String? + var effectiveEndDate: String? + var tags: String? + var latitude: Double? + var longitude: Double? + var address: String? + var status: String? } -class OrdersVC: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate { +class OrdersVC: UIViewController { - @IBOutlet weak var theMap: MKMapView! + @IBOutlet weak var rightBarItem: UIBarButtonItem! + private var arrangeBarButton: UIBarButtonItem! + + @IBOutlet weak var containerView: UIView! + + @IBOutlet weak var containerViewList: UIView! + + private var ordersMapViewVC: OrdersMapViewVC? + private var ordersListViewTVC: OrdersListViewTVC? + + override func viewDidLoad() { + super.viewDidLoad() + + arrangeBarButton = UIBarButtonItem(title: "Arrange", style: UIBarButtonItemStyle.Plain, target: self, action: nil) + arrangeBarButton.tintColor = UIColor.whiteColor() + self.navigationItem.setRightBarButtonItems([rightBarItem,arrangeBarButton], animated: true) + + arrangeBarButton.enabled = false + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + containerView.hidden = false + containerViewList.hidden = true + } + + // MARK: - Tags + + @IBAction func showTags(sender: UIBarButtonItem) { + + let item1 = Tag(issSelected: true, isLocked: true, textContent: "Hello1") + let item2 = Tag(issSelected: true, isLocked: true, textContent: "Hello2") + let item3 = Tag(issSelected: false, isLocked: true, textContent: "Hello3") + let item4 = Tag(issSelected: false, isLocked: true, textContent: "Hello4") + let item5 = Tag(issSelected: true, isLocked: true, textContent: "Hello5") + let tags = [item1, item2, item3, item4, item5] + + RRTagController.displayTagController(parentController: self, tags: tags, blockFinish: { (selectedTags, unSelectedTags) -> () in + // ok + for tag in selectedTags { + // TODO: save selectedTags + self.ordersMapViewVC?.reloadScene() + + } + }) { () -> () in + // cancelled + } + } + + /** + Swap container view to show list or map + */ + @IBAction func swapContainerView(sender: UIBarButtonItem) { + if containerView.hidden == true { + containerView.hidden = false + containerViewList.hidden = true + sender.title = "List" + arrangeBarButton.enabled = false + } else { + containerViewList.hidden = false + containerView.hidden = true + sender.title = "Map" + arrangeBarButton.enabled = true + } + } + + + // MARK: - Navigations + + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + if segue.identifier == "OrdersMapView" { + ordersMapViewVC = segue.destinationViewController as? OrdersMapViewVC + } else if segue.identifier == "OrdersListView" { + ordersListViewTVC = segue.destinationViewController as? OrdersListViewTVC + } + } + // let locationManager = CLLocationManager() // diff --git a/Classes/VCs/ShowProgressVC.swift b/Classes/VCs/ShowProgressVC.swift new file mode 100644 index 0000000..31da308 --- /dev/null +++ b/Classes/VCs/ShowProgressVC.swift @@ -0,0 +1,156 @@ +// +// ShowProgressVC.swift +// Arrived +// +// Created by Lu Cao on 5/31/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit +import MapKit + +class ShowProgressVC: UIViewController, MKMapViewDelegate { + + var isInitiated = false + + @IBOutlet weak var bgView: UIView! + + @IBOutlet weak var mapView: MKMapView! + @IBOutlet weak var priceLabel: UILabel! + @IBOutlet weak var contactButton: UIButton! + @IBOutlet weak var actionButton: UIButton! + + override func viewDidLoad() { + super.viewDidLoad() + + setUpScene() + } + + func setUpScene() { + + navigationController?.navigationBar.tintColor = UIColor.whiteColor() + + mapView.delegate = self + + // setup map latitude: 37.31235141, longitude: -122.0112182 + let latitude: Double = 37.31235141 + let longitude: Double = -122.0112182 + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: latitude, longitude: longitude) + let regionRadius: CLLocationDistance = 1000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + mapView.setRegion(coordinateRegion, animated: true) + + var annotation = CustomPointAnnotation() + annotation.coordinate = location + annotation.imageName = "regular pin" + mapView.addAnnotation(annotation) + } + + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + +// if !isInitiated { + isInitiated = !isInitiated + + bgView.layer.borderColor = UIColor.lightGrayColor().CGColor + bgView.layer.borderWidth = 1.2 + bgView.layer.cornerRadius = 12 + + priceLabel.layer.borderColor = UIColor.lightGrayColor().CGColor + priceLabel.layer.borderWidth = 0.65 + priceLabel.layer.cornerRadius = priceLabel.frame.height/2 + priceLabel.alpha = 0.85 + + contactButton.layer.borderColor = UIColor.lightGrayColor().CGColor + contactButton.layer.borderWidth = 0.65 + contactButton.layer.cornerRadius = contactButton.frame.height/2 + priceLabel.alpha = 0.85 + + actionButton.layer.borderColor = UIColor.lightGrayColor().CGColor + actionButton.layer.borderWidth = 0.65 + actionButton.layer.cornerRadius = actionButton.frame.height/2 + actionButton.alpha = 0.85 +// } + } + + @IBAction func actionTapped(sender: UIButton) { + bounceView(actionButton) + } + + @IBAction func contactTapped(sender: UIButton) { + bounceView(contactButton) + let alert = AlertController(title: "Contact", message: nil, style: .ActionSheet) + showAlert(alert) + } + + func showAlert(alert: SimpleAlert.Controller) { + + alert.addAction(SimpleAlert.Action(title: "Call", style: .Default) { action in + }) + alert.addAction(SimpleAlert.Action(title: "Message", style: .Default) { action in + }) + + alert.addAction(SimpleAlert.Action(title: "Cancel", style: .Cancel) { action in + }) + + self.presentViewController(alert, animated: true, completion: nil) + } + + // Customize annotation appearance + func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { + if !(annotation is CustomPointAnnotation) { + return nil + } + + let reuseId = "test" + + var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) + if anView == nil { + anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) + anView.canShowCallout = true + } + else { + anView.annotation = annotation + } + + //Set annotation-specific properties **AFTER** + //the view is dequeued or created... + + let cpa = annotation as! CustomPointAnnotation + anView.image = UIImage(named:cpa.imageName) + + return anView + } + + + /* + // MARK: - Navigation + + // In a storyboard-based application, you will often want to do a little preparation before navigation + override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { + // Get the new view controller using segue.destinationViewController. + // Pass the selected object to the new view controller. + } + */ + +} + + + + + + + + + + + + + + + + + + + + diff --git a/Classes/VCs/UserBankCardsTVC.swift b/Classes/VCs/UserBankCardsTVC.swift index 04c0155..aadf44d 100755 --- a/Classes/VCs/UserBankCardsTVC.swift +++ b/Classes/VCs/UserBankCardsTVC.swift @@ -8,8 +8,147 @@ import UIKit -class UserBankCardsTVC: UITableViewController { +class UserBankCardsTVC: UITableViewController, UITableViewDelegate{ + private struct bankCard { + var name: String? + var number: Int? + var exp: String? + var cvv: Int? + } + + private var card1 = bankCard(name: "Lu Cao", number: 4111111111111111, exp: "May, 2016", cvv: 123) + private var card2 = bankCard(name: "Yetian Mao", number: 5500000000000004, exp: "June, 2017", cvv: 345) + private var card3 = bankCard(name: "Mr. WTF", number: 340000000000009, exp: "Jan, 2025", cvv: 567) + + private var testingCards = [bankCard]() + + private var checkedIndexPath : NSIndexPath? + + override func viewDidLoad() { + super.viewDidLoad() + + // hide seperator below each cell + tableView.separatorStyle = UITableViewCellSeparatorStyle.None + + testingCards = [card1, card2, card3] + +// tableView.contentInset = UIEdgeInsets(top: navigationController!.navigationBar.bounds.height + 35, left: 0, bottom: 0, right: 0) + tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0) + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + title = "Bank Cards" + tableView.reloadData() + } + + // MARK: - Functionalities + + func checkCardType(sender: SHSPhoneTextField, icon: UIImageView) { + let type = detectCreditCardType(sender.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet())) + switch type { + case "Visa": + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + icon.image = UIImage(named: "ic_card_visa") + case "MasterCard": + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + icon.image = UIImage(named: "ic_card_master_card") + case "American Express": + sender.formatter.setDefaultOutputPattern("#### ###### #####") + sender.setFormattedText(sender.text) + icon.image = UIImage(named: "ic_card_american_express") + case "Discover": + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + icon.image = UIImage(named: "ic_card_discover") + case "JCB": + sender.formatter.setDefaultOutputPattern("#### #### #### ####") + sender.setFormattedText(sender.text) + icon.image = UIImage(named: "ic_credit_card") + case "Invalid": + sender.formatter.setDefaultOutputPattern("####################") + sender.setFormattedText(sender.text) + icon.image = UIImage(named: "ic_credit_card") + default: + return + } + } + + // MARK: - TableView Delegates + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return testingCards.count + } + + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("UserBankCardsTVCell", forIndexPath: indexPath) as! UserBankCardsTVCell + + var bankCard = testingCards[indexPath.row] + cell.bankCardNumber.text = "\(bankCard.number!)" + cell.expirationDate.text = bankCard.exp + cell.fullName.text = bankCard.name + cell.cvv.text = "\(bankCard.cvv!)" + + cell.selectionStyle = .None + + checkCardType(cell.bankCardNumber, icon: cell.icon) + + return cell + } + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + + if (self.checkedIndexPath != nil) { + if let var cell = tableView.cellForRowAtIndexPath(self.checkedIndexPath!) as? UserBankCardsTVCell { + fadeOutView(cell.defaultIndicator, 0.35) + } + + } + + var cell = tableView.cellForRowAtIndexPath(indexPath) as! UserBankCardsTVCell + fadeInView(cell.defaultIndicator, 0.35) + + self.checkedIndexPath = indexPath + } + + // Override to support editing the table view. + override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { + if editingStyle == UITableViewCellEditingStyle.Delete { + // Delete the row from the data source + testingCards.removeAtIndex(indexPath.row) + + // also need to delete from the server) + + tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) + } else if editingStyle == .Insert { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } + } + + + + // Override to support rearranging the table view. + override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { + + } + + // MARK: - Navigation + + + @IBAction func dismissScene(sender: UIBarButtonItem) { + self.dismissViewControllerAnimated(true, completion: nil) + } + + + /* var bankCards = [[String:AnyObject]]() override func viewDidLoad() { @@ -196,7 +335,7 @@ class UserBankCardsTVC: UITableViewController { self.presentViewController(alertController, animated: true, completion: nil) } - + */ diff --git a/Classes/VCs/UserBankCardsTVCell.swift b/Classes/VCs/UserBankCardsTVCell.swift index 813987b..272054f 100755 --- a/Classes/VCs/UserBankCardsTVCell.swift +++ b/Classes/VCs/UserBankCardsTVCell.swift @@ -10,20 +10,34 @@ import UIKit class UserBankCardsTVCell: UITableViewCell { - @IBOutlet weak var bankCardNumber: UILabel! + + @IBOutlet weak var bankCardNumber: SHSPhoneTextField! @IBOutlet weak var expirationDate: UILabel! @IBOutlet weak var fullName: UILabel! @IBOutlet weak var cvv: UITextField! + @IBOutlet weak var icon: UIImageView! + + @IBOutlet weak var myView: UIView! + @IBOutlet weak var defaultIndicator: UIView! override func awakeFromNib() { super.awakeFromNib() // Initialization code + + myView.layer.borderWidth = 0.3 + myView.layer.borderColor = UIColor.lightGrayColor().CGColor + myView.layer.cornerRadius = 12 + + defaultIndicator.roundCorners(.TopRight | .BottomRight, radius: 12) + defaultIndicator.layer.backgroundColor = UIColorFromHex(0x3ABE68, alpha: 0.65).CGColor + defaultIndicator.alpha = 0 + } override func setSelected(selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) - // Configure the view for the selected state +// defaultIndicator.hidden = false } } diff --git a/Classes/VCs/UserLocationsTVC.swift b/Classes/VCs/UserLocationsTVC.swift index 83df1ca..2612336 100755 --- a/Classes/VCs/UserLocationsTVC.swift +++ b/Classes/VCs/UserLocationsTVC.swift @@ -9,8 +9,181 @@ import UIKit import MapKit -class UserLocationsTVC: UITableViewController, MKMapViewDelegate { +class CustomPointAnnotation: MKPointAnnotation { + var imageName: String! +} + +class UserLocationsTVC: UITableViewController, MKMapViewDelegate, UITableViewDelegate { + + private struct address { + var street: String? + var city: String? + var state: String? + var country: String? + var post: Int? + var latitude: Double? + var longitude: Double? + } + + private var address1 = address(street: "Apple Inc., Infinite Loop", city: "Cupertino", state: "CA", country: "USA", post: 95014, latitude: 37.3320951, longitude: -122.0307425) + private var address2 = address(street: "14055 Chester Ave", city: "Saratoga", state: "CA", country: "USA", post: 95070, latitude: 37.264462, longitude: -122.001732) + private var address3 = address(street: "14055 Chester Ave", city: "Saratoga", state: "CA", country: "USA", post: 95070, latitude: 37.264462, longitude: -122.001732) + + private var addresses = [address]() + + private var checkedIndexPath : NSIndexPath? + + override func viewDidLoad() { + super.viewDidLoad() + + addresses = [address1, address2, address3] + + // hide seperator below each cell + tableView.separatorStyle = UITableViewCellSeparatorStyle.None + + // set top margin of table view + tableView.contentInset = UIEdgeInsets(top: 20, left: 0, bottom: 0, right: 0) + } + + override func viewWillAppear(animated: Bool) { + super.viewWillAppear(true) + + title = "Addresses" + tableView.reloadData() + } + + // MARK: - TableView Delegates + + override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1 + } + + override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return addresses.count + } + override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCellWithIdentifier("UserLocationsTVCell", forIndexPath: indexPath) as! UserLocationsTVCell + + + + var cellAddress = addresses[indexPath.row] + cell.streetLabel.text = cellAddress.street + cell.cityLabel.text = cellAddress.city + cell.stateLabel.text = cellAddress.state + cell.countryLabel.text = cellAddress.country + cell.postLabel.text = "\(cellAddress.post!)" + + cell.map.delegate = self + + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: cellAddress.latitude!, longitude: cellAddress.longitude!) + let regionRadius: CLLocationDistance = 1000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + cell.map.setRegion(coordinateRegion, animated: true) + + /* display annotation in middle + var annotation = CustomPointAnnotation() + annotation.coordinate = location + annotation.imageName = "map pin.png" + cell.map.addAnnotation(annotation) + */ + cell.map.showsUserLocation = true + + /* encontered a problem where only the last map got updated + var locationManager = LocationManager.sharedInstance + let addressString = "\(cellAddress.street), \(cellAddress.city), \(cellAddress.state) \(cellAddress.post), \(cellAddress.country)" + locationManager.geocodeAddressString(address: addressString) { + (geocodeInfo,placemark,error) -> Void in + + if(error != nil) { + println(error) + } else { + print(geocodeInfo!) + let location: CLLocationCoordinate2D = CLLocationCoordinate2D(latitude: Double((geocodeInfo!["latitude"]! as! NSString).doubleValue), longitude: Double((geocodeInfo!["longitude"]! as! NSString).doubleValue)) + let regionRadius: CLLocationDistance = 1000 + let coordinateRegion = MKCoordinateRegionMakeWithDistance(location, regionRadius * 2.0, regionRadius * 2.0) + cell.map.setRegion(coordinateRegion, animated: true) + } + } + */ + + cell.selectionStyle = .None + + return cell + } + + override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + + if (self.checkedIndexPath != nil) { + if let var cell = tableView.cellForRowAtIndexPath(self.checkedIndexPath!) as? UserLocationsTVCell { + fadeOutView(cell.defaultIndicator, 0.35) + } + + } + + var cell = tableView.cellForRowAtIndexPath(indexPath) as! UserLocationsTVCell + fadeInView(cell.defaultIndicator, 0.35) + + self.checkedIndexPath = indexPath + } + + // Override to support editing the table view. + override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) { + if editingStyle == UITableViewCellEditingStyle.Delete { + // Delete the row from the data source + addresses.removeAtIndex(indexPath.row) + + // also need to delete from the server) + + tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) + } else if editingStyle == .Insert { + // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view + } + } + + + + // Override to support rearranging the table view. + override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) { + + } + + // Customize annotation appearance + func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! { + if !(annotation is CustomPointAnnotation) { + return nil + } + + let reuseId = "test" + + var anView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) + if anView == nil { + anView = MKAnnotationView(annotation: annotation, reuseIdentifier: reuseId) + anView.canShowCallout = true + } + else { + anView.annotation = annotation + } + + //Set annotation-specific properties **AFTER** + //the view is dequeued or created... + + let cpa = annotation as! CustomPointAnnotation + anView.image = UIImage(named:cpa.imageName) + + return anView + } + + // MARK: - Navigation + + + @IBAction func dismissScene(sender: UIBarButtonItem) { + self.dismissViewControllerAnimated(true, completion: nil) + } + + + + /* var locations = [[String:AnyObject]]() override func viewDidLoad() { @@ -147,6 +320,7 @@ class UserLocationsTVC: UITableViewController, MKMapViewDelegate { // Pass the selected object to the new view controller. } */ - + */ + } diff --git a/Classes/VCs/UserLocationsTVCell.swift b/Classes/VCs/UserLocationsTVCell.swift index a29954a..36e4e90 100755 --- a/Classes/VCs/UserLocationsTVCell.swift +++ b/Classes/VCs/UserLocationsTVCell.swift @@ -11,18 +11,25 @@ import MapKit class UserLocationsTVCell: UITableViewCell { - @IBOutlet weak var addressLabel: UILabel! @IBOutlet weak var map: MKMapView! + @IBOutlet weak var streetLabel: UILabel! + @IBOutlet weak var cityLabel: UILabel! + @IBOutlet weak var stateLabel: UILabel! + @IBOutlet weak var countryLabel: UILabel! + @IBOutlet weak var postLabel: UILabel! + + @IBOutlet weak var myView: UIView! + @IBOutlet weak var defaultIndicator: UIImageView! override func awakeFromNib() { super.awakeFromNib() - // Initialization code - } - - override func setSelected(selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - // Configure the view for the selected state + myView.layer.borderWidth = 0.3 + myView.layer.borderColor = UIColor.lightGrayColor().CGColor + myView.layer.cornerRadius = 12 + + defaultIndicator.layer.backgroundColor = UIColorFromHex(0x3ABE68, alpha: 0.65).CGColor + defaultIndicator.alpha = 0 } } diff --git a/Classes/VCs/UserMenuVC.swift b/Classes/VCs/UserMenuVC.swift index 27f6a8e..2e05676 100644 --- a/Classes/VCs/UserMenuVC.swift +++ b/Classes/VCs/UserMenuVC.swift @@ -8,7 +8,7 @@ import UIKit -class UserMenuVC: UIViewController { +class UserMenuVC: UIViewController, UITextFieldDelegate { // create instance of our custom transition manager let transitionManager = MenuTransitionManager() @@ -33,6 +33,16 @@ class UserMenuVC: UIViewController { @IBOutlet weak var cancelButton: UIButton! + private var pinChanngeTextField1: UITextField! + private var pinChanngeTextField2: UITextField! + private var pinChanngeTextField3: UITextField! + private var pinChanngeTextField4: UITextField! + + private var phoneChanngeTextField1: UITextField! + private var phoneChanngeTextField2: UITextField! + private var phoneChanngeTextField3: UITextField! + private var phoneChanngeTextField4: UITextField! + override func viewDidLoad() { super.viewDidLoad() @@ -45,7 +55,217 @@ class UserMenuVC: UIViewController { cancelButton.layer.cornerRadius = cancelButton.frame.height/2 } + // MARK: - Functionalities + + @IBAction func changePin(sender: UIButton) { + let alert = AlertController(title: "Pin Code", message: "We need to verify you identity in order to protect your account, please enter verification code sent to your phone number 😘", style: .Alert) + showChangePinAlert(alert) + } + + func showChangePinAlert(alert: SimpleAlert.Controller) { + + var verificationCode: Int? + var oldPin: Int? + var newPin: Int? + var newPin2: Int? + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.pinChanngeTextField1 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "Verification code" + } + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.pinChanngeTextField2 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "Old pin code" + textField.secureTextEntry = true + } + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.pinChanngeTextField3 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "New pin code" + textField.secureTextEntry = true + } + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.pinChanngeTextField4 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "New pin code again" + textField.secureTextEntry = true + } + + alert.addAction(SimpleAlert.Action(title: "Resend ↻", style: .Default) { action in + + }) + + alert.addAction(SimpleAlert.Action(title: "Confirm", style: .OK) { action in + + verificationCode = (alert.textFields[0] as UITextField).text.toInt() + oldPin = (alert.textFields[1] as UITextField).text.toInt() + newPin = (alert.textFields[2] as UITextField).text.toInt() + newPin2 = (alert.textFields[3] as UITextField).text.toInt() + }) + + alert.addAction(SimpleAlert.Action(title: "⇠", style: .Cancel) { action in + + }) + + self.presentViewController(alert, animated: true, completion: nil) + } + + + @IBAction func changePhone(sender: UIButton) { + let alert = AlertController(title: "Phone Number", message: "We need to verify you identity in order to protect your account, please enter verification code sent to your phone number 😘", style: .Alert) + showChangePhoneAlert(alert) + } + + func showChangePhoneAlert(alert: SimpleAlert.Controller) { + + var verificationCode: Int? + var oldPhone: Int? + var newPhone: Int? + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.phoneChanngeTextField1 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "Verification code" + } + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.phoneChanngeTextField2 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "Old phone number" + } + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.phoneChanngeTextField3 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "New phone number" + } + + alert.addAction(SimpleAlert.Action(title: "Resend ↻", style: .Default) { action in + + }) + + alert.addAction(SimpleAlert.Action(title: "Get Verification ⇢", style: .OK) { action in + + verificationCode = (alert.textFields[0] as UITextField).text.toInt() + oldPhone = (alert.textFields[1] as UITextField).text.toInt() + newPhone = (alert.textFields[2] as UITextField).text.toInt() + + let alert = AlertController(title: "Verify", message: "We need to verify you identity in order to protect your account, please enter verification code sent to your phone number 😘", style: .Alert) + self.showChangePhoneVerificationAlert(alert) + }) + + alert.addAction(SimpleAlert.Action(title: "⇠", style: .Cancel) { action in + + }) + + self.presentViewController(alert, animated: true, completion: nil) + } + + func showChangePhoneVerificationAlert(alert: SimpleAlert.Controller) { + + var verificationCode: Int? + + alert.addTextFieldWithConfigurationHandler() { textField in + self.addDoneButtonOnKeyboard(textField) + self.phoneChanngeTextField4 = textField + textField.keyboardType = UIKeyboardType.NumberPad + textField.placeholder = "Verification code" + } + + alert.addAction(SimpleAlert.Action(title: "resend ↻", style: .Default) { action in + + }) + + alert.addAction(SimpleAlert.Action(title: "Confirm", style: .OK) { action in + verificationCode = (alert.textFields[0] as UITextField).text.toInt() + }) + + alert.addAction(SimpleAlert.Action(title: "⇠", style: .Cancel) { action in + + }) + + self.presentViewController(alert, animated: true, completion: nil) + } + + // add a ui tool bar above each keyboard, and done + func addDoneButtonOnKeyboard(myTextField: UITextField) + { + var doneToolbar: UIToolbar = UIToolbar(frame: CGRectMake(0, 0, 320, 50)) + doneToolbar.barStyle = UIBarStyle.Default + + var flexSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil) + var fixedSpace = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FixedSpace, target: nil, action: nil) + var done: UIBarButtonItem = UIBarButtonItem(title: "Done", style: UIBarButtonItemStyle.Done, target: self, action: Selector("doneButtonAction")) + done.tintColor = myTextField.textColor + + var items = NSMutableArray() + + items.addObject(flexSpace) + items.addObject(done) + + doneToolbar.items = items as [AnyObject] + doneToolbar.sizeToFit() + doneToolbar.backgroundColor = UIColor.whiteColor() + + myTextField.inputAccessoryView = doneToolbar + } + + func doneButtonAction() + { + if pinChanngeTextField1.isFirstResponder() { + pinChanngeTextField1.resignFirstResponder() + } else if pinChanngeTextField2.isFirstResponder() { + pinChanngeTextField2.resignFirstResponder() + } else if pinChanngeTextField3.isFirstResponder() { + pinChanngeTextField3.resignFirstResponder() + } else if pinChanngeTextField4.isFirstResponder() { + pinChanngeTextField4.resignFirstResponder() + } else if phoneChanngeTextField1.isFirstResponder() { + phoneChanngeTextField1.resignFirstResponder() + } else if phoneChanngeTextField2.isFirstResponder() { + phoneChanngeTextField2.resignFirstResponder() + } else if phoneChanngeTextField3.isFirstResponder() { + phoneChanngeTextField3.resignFirstResponder() + } else if phoneChanngeTextField4.isFirstResponder() { + phoneChanngeTextField4.resignFirstResponder() + } + } + + // MARK: - Navigations + @IBAction func unwindToMainViewController(sender: UIButton) { self.dismissViewControllerAnimated(true, completion: nil) } + + @IBAction func logout(sender: UIButton) { + + performSegueWithIdentifier("UserMenuLogout", sender: self) + } } + + + + + + + + + + + + + + + diff --git a/Classes/VCs/ViewController.swift b/Classes/VCs/ViewController.swift deleted file mode 100755 index 83c2943..0000000 --- a/Classes/VCs/ViewController.swift +++ /dev/null @@ -1,50 +0,0 @@ -// -// ViewController.swift -// Arrive -// -// Created by Yetian Mao on 4/19/15. -// Copyright (c) 2015 yetian. All rights reserved. -// - -import UIKit - -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - -// let test : Dictionary = ["test": "test"] -// -// let service = UserService() -// service.verify("13429239110") { -// (data: Dictionary?, error: String?) -> Void in -// println(data) -// } -// -// service.authenticate("13429239110", verificationCode: "1234"){ -// (data: Dictionary?, error: String?) -> Void in -// println(data) -// } -// -// service.getUser("13429239110"){ -// (data: Dictionary?, error: String?) -> Void in -// println(data) -// } -// -// service.register(test){ -// (data: Dictionary?, error: String?) -> Void in -// println(data) -// } - - - // Do any additional setup after loading the view, typically from a nib. - } - - override func didReceiveMemoryWarning() { - super.didReceiveMemoryWarning() - // Dispose of any resources that can be recreated. - } - - -} - diff --git a/Frameworks/LBNRippleEffect/.DS_Store b/Frameworks/LBNRippleEffect/.DS_Store new file mode 100644 index 0000000..6cfb43d Binary files /dev/null and b/Frameworks/LBNRippleEffect/.DS_Store differ diff --git a/Frameworks/LBNRippleEffect/LNBRippleEffect.h b/Frameworks/LBNRippleEffect/LNBRippleEffect.h new file mode 100755 index 0000000..c53954f --- /dev/null +++ b/Frameworks/LBNRippleEffect/LNBRippleEffect.h @@ -0,0 +1,50 @@ +// +// LNBRippleEffect.h +// LNBRippleEffect +// +// Created by BHARATH Lalgudi Natarajan on 25/12/14. +// Copyright (c) 2014 Bharath. All rights reserved. +// +// 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. + +#import + + + +@interface LNBRippleEffect : UIView{ + + UIImageView *buttonImage; + UITapGestureRecognizer *tapGesture; + SEL selectedMethod; + id senderid; + UIColor *rippleColor; + UIColor *bordercolor; + UIColor *rippleTrailColor; + NSArray *rippleColors; + +} +typedef void (^onFinish)(BOOL success); +@property (nonatomic, copy) onFinish block; +-(instancetype)initWithImage:(UIImage *)image Frame:(CGRect)frame Color:(UIColor*)bordercolor Target:(SEL)action ID:(id)sender; +-(instancetype)initWithImage:(UIImage *)image Frame:(CGRect)frame didEnd:(onFinish)executeOnFinish; +-(void)setRippleColor:(UIColor *)color; +-(void)setRippleTrailColor:(UIColor *)color; + +@end + diff --git a/Frameworks/LBNRippleEffect/LNBRippleEffect.m b/Frameworks/LBNRippleEffect/LNBRippleEffect.m new file mode 100755 index 0000000..83c4cef --- /dev/null +++ b/Frameworks/LBNRippleEffect/LNBRippleEffect.m @@ -0,0 +1,187 @@ +// +// LNBRippleEffect.m +// LNBRippleEffect +// +// Created by BHARATH Lalgudi Natarajan on 25/12/14. +// Copyright (c) 2014 Bharath. All rights reserved. +// +// 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. + + +#import +#import "LNBRippleEffect.h" + +@implementation LNBRippleEffect + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + + } + return self; +} + +-(void)drawImageWithFrame:(UIImage *)image Frame:(CGRect)frame Color:(UIColor*)bordercolor{ + + buttonImage = [[UIImageView alloc]initWithImage:image]; + buttonImage.frame = CGRectMake(0, 0, frame.size.width-5, frame.size.height-5); + buttonImage.layer.borderColor = [UIColor clearColor].CGColor; + buttonImage.layer.borderWidth = 3; + buttonImage.clipsToBounds = YES; + buttonImage.layer.cornerRadius = buttonImage.frame.size.height/2; + [self addSubview:buttonImage]; + + buttonImage.center = CGPointMake(self.frame.size.width/2, self.frame.size.height/2); + self.layer.cornerRadius = self.frame.size.height/2; + self.layer.borderWidth = 5; + self.layer.borderColor = bordercolor.CGColor; + + tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(buttonTapped:)]; + [self addGestureRecognizer:tapGesture]; + [NSTimer scheduledTimerWithTimeInterval:1.2 target:self selector:@selector(continuoousripples) userInfo:nil repeats:YES]; + +} + + +-(instancetype)initWithImage:(UIImage *)image + Frame:(CGRect)frame + Color:(UIColor*)bordercolor + Target:(SEL)action + ID:(id)sender { + self = [super initWithFrame:frame]; + + if(self){ + [self drawImageWithFrame:image Frame:frame Color:bordercolor]; + selectedMethod = action; + senderid = sender; + } + + return self; +} + +-(instancetype)initWithImage:(UIImage *)image Frame:(CGRect)frame didEnd:(onFinish)executeOnFinish { + self = [super initWithFrame:frame]; + + if(self){ + + [self drawImageWithFrame:image Frame:frame Color:bordercolor]; + self.block = executeOnFinish; + } + + return self; +} + + +-(void)setRippleColor:(UIColor *)color { + rippleColor = color; +} + +-(void)setRippleTrailColor:(UIColor *)color { + rippleTrailColor = color; +} + +-(void)buttonTapped:(id)sender { + CGRect pathFrame = CGRectMake(-CGRectGetMidX(self.bounds), -CGRectGetMidY(self.bounds), self.bounds.size.width, self.bounds.size.height); + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:pathFrame cornerRadius:self.layer.cornerRadius]; + + + CGPoint shapePosition = [self convertPoint:self.center fromView:nil]; + + CAShapeLayer *circleShape = [CAShapeLayer layer]; + circleShape.path = path.CGPath; + circleShape.position = shapePosition; + circleShape.fillColor = rippleTrailColor.CGColor; + circleShape.opacity = 0; + circleShape.strokeColor = rippleColor.CGColor; + circleShape.lineWidth = 3; + + [self.layer addSublayer:circleShape]; + + CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + scaleAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; + scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.5, 2.5, 1)]; + + CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + alphaAnimation.fromValue = @1; + alphaAnimation.toValue = @0; + + CAAnimationGroup *animation = [CAAnimationGroup animation]; + animation.animations = @[scaleAnimation, alphaAnimation]; + animation.duration = 2.0f; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + [circleShape addAnimation:animation forKey:nil]; + + + [UIView animateWithDuration:1.1 animations:^{ + buttonImage.alpha = 0.4; + self.layer.borderColor = rippleColor.CGColor; + }completion:^(BOOL finished) { + [UIView animateWithDuration:2.2 animations:^{ //Edit animateWithDuration value to change ripple animtion time + buttonImage.alpha = 1; + self.layer.borderColor = rippleColor.CGColor; + }completion:^(BOOL finished) { + if([senderid respondsToSelector:selectedMethod]){ + [senderid performSelectorOnMainThread:selectedMethod withObject:nil waitUntilDone:NO]; + } + + if(_block) { + BOOL success= YES; + _block(success); + } + }]; + + }]; +} + + + +-(void)continuoousripples +{ + CGRect pathFrame = CGRectMake(-CGRectGetMidX(self.bounds), -CGRectGetMidY(self.bounds), self.bounds.size.width, self.bounds.size.height); + UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:pathFrame cornerRadius:self.layer.cornerRadius]; + CGPoint shapePosition = [self convertPoint:self.center fromView:nil]; + + CAShapeLayer *circleShape = [CAShapeLayer layer]; + circleShape.path = path.CGPath; + circleShape.position = shapePosition; + circleShape.fillColor = rippleTrailColor.CGColor; + circleShape.opacity = 0; + circleShape.strokeColor = rippleColor.CGColor; + circleShape.lineWidth = 2; + + [self.layer addSublayer:circleShape]; + + CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:@"transform.scale"]; + scaleAnimation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity]; + scaleAnimation.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(2.5, 2.5, 1)]; + + CABasicAnimation *alphaAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"]; + alphaAnimation.fromValue = @1; + alphaAnimation.toValue = @0; + + CAAnimationGroup *animation = [CAAnimationGroup animation]; + animation.animations = @[scaleAnimation, alphaAnimation]; + animation.duration = 2.0f; + animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut]; + [circleShape addAnimation:animation forKey:nil]; +} + + +@end diff --git a/Frameworks/PIRipple.swift b/Frameworks/PIRipple.swift new file mode 100644 index 0000000..1991e37 --- /dev/null +++ b/Frameworks/PIRipple.swift @@ -0,0 +1,170 @@ +//--------------------------------------- +// https://github.com/pixel-ink/PIRipple +//--------------------------------------- + +import UIKit + +public extension UIView { + + public func rippleBorder(location:CGPoint, color:UIColor) { + rippleBorder(location, color: color){} + } + + public func rippleBorder(location:CGPoint, color:UIColor, then: ()->() ) { + Ripple.border(self, locationInView: location, color: color, then: then) + } + + public func rippleFill(location:CGPoint, color:UIColor) { + rippleFill(location, color: color){} + } + + public func rippleFill(location:CGPoint, color:UIColor, then: ()->() ) { + Ripple.fill(self, locationInView: location, color: color, then: then) + } + +} + +public class Ripple { + + public struct Option { + public var borderWidth = CGFloat(5.0) + public var radius = CGFloat(30.0) + public var duration = CFTimeInterval(0.4) + public var borderColor = UIColor.whiteColor() + public var fillColor = UIColor.clearColor() + public var scale = CGFloat(3.0) + } + + public class func option () -> Option { + return Option() + } + + public class func run(view:UIView, locationInView:CGPoint, option:Ripple.Option) { + run(view, locationInView: locationInView, option: option){} + } + + public class func run(view:UIView, locationInView:CGPoint, option:Ripple.Option, then: ()->() ) { + prePreform(view, point: locationInView, option: option, isLocationInView: true, isRunSuperView: true, then: then) + } + + public class func run(view:UIView, absolutePosition:CGPoint, option:Ripple.Option) { + run(view, absolutePosition: absolutePosition, option: option){} + } + + public class func run(view:UIView, absolutePosition:CGPoint, option:Ripple.Option, then: ()->() ) { + prePreform(view, point: absolutePosition, option: option, isLocationInView: false, isRunSuperView: true, then: then) + } + + public class func border(view:UIView, locationInView:CGPoint, color:UIColor) { + border(view, locationInView: locationInView, color: color){} + } + + public class func border(view:UIView, locationInView:CGPoint, color:UIColor, then: ()->() ) { + var opt = Ripple.Option() + opt.borderColor = color + prePreform(view, point: locationInView, option: opt, isLocationInView: true, isRunSuperView: true, then: then) + } + + public class func border(view:UIView, absolutePosition:CGPoint, color:UIColor) { + border(view, absolutePosition: absolutePosition, color: color){} + } + + public class func border(view:UIView, absolutePosition:CGPoint, color:UIColor, then: ()->() ) { + var opt = Ripple.Option() + opt.borderColor = color + prePreform(view, point: absolutePosition, option: opt, isLocationInView: false, isRunSuperView: true, then: then) + } + + public class func fill(view:UIView, locationInView:CGPoint, color:UIColor) { + fill(view, locationInView: locationInView, color: color){} + } + + public class func fill(view:UIView, locationInView:CGPoint, color:UIColor, then: ()->() ) { + var opt = Ripple.Option() + opt.borderColor = color + opt.fillColor = color + prePreform(view, point: locationInView, option: opt, isLocationInView: true, isRunSuperView: true, then: then) + } + + public class func fill(view:UIView, absolutePosition:CGPoint, color:UIColor) { + fill(view, absolutePosition: absolutePosition, color: color){} + } + + public class func fill(view:UIView, absolutePosition:CGPoint, color:UIColor, then: ()->() ) { + var opt = Ripple.Option() + opt.borderColor = color + opt.fillColor = color + prePreform(view, point: absolutePosition, option: opt, isLocationInView: false, isRunSuperView: true, then: then) + } + + private class func prePreform(view:UIView, point:CGPoint, option: Ripple.Option, isLocationInView:Bool, isRunSuperView: Bool, then: ()->() ) { + + let p = isLocationInView ? CGPointMake(point.x + view.frame.origin.x, point.y + view.frame.origin.y) : point + if isRunSuperView, let superview = view.superview { + prePreform( + superview, + point: p, + option: option, + isLocationInView: isLocationInView, + isRunSuperView: isRunSuperView, + then: then + ) + } else { + perform( + view, + point:p, + option:option, + then: then + ) + } + } + + private class func perform(view:UIView, point:CGPoint, option: Ripple.Option, then: ()->() ) { + UIGraphicsBeginImageContextWithOptions ( + CGSizeMake((option.radius + option.borderWidth) * 2, (option.radius + option.borderWidth) * 2), false, 3.0) + let path = UIBezierPath( + roundedRect: CGRectMake(option.borderWidth, option.borderWidth, option.radius * 2, option.radius * 2), + cornerRadius: option.radius) + option.fillColor.setFill() + path.fill() + option.borderColor.setStroke() + path.lineWidth = option.borderWidth + path.stroke() + let img = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + let opacity = CABasicAnimation(keyPath: "opacity") + opacity.autoreverses = false + opacity.fillMode = kCAFillModeForwards + opacity.removedOnCompletion = false + opacity.duration = option.duration + opacity.fromValue = 1.0 + opacity.toValue = 0.0 + + let transform = CABasicAnimation(keyPath: "transform") + transform.autoreverses = false + transform.fillMode = kCAFillModeForwards + transform.removedOnCompletion = false + transform.duration = option.duration + transform.fromValue = NSValue(CATransform3D: CATransform3DMakeScale(1.0 / option.scale, 1.0 / option.scale, 1.0)) + transform.toValue = NSValue(CATransform3D: CATransform3DMakeScale(option.scale, option.scale, 1.0)) + + dispatch_async(dispatch_get_main_queue()) { + let layer = CALayer() + layer.contents = img.CGImage + layer.frame = CGRectMake(point.x - option.radius, point.y - option.radius, option.radius * 2, option.radius * 2) + view.layer.addSublayer(layer) + CATransaction.begin() + CATransaction.setAnimationDuration(option.duration) + CATransaction.setCompletionBlock { + layer.contents = nil + layer.removeAllAnimations() + layer.removeFromSuperlayer() + then() + } + layer.addAnimation(opacity, forKey:nil) + layer.addAnimation(transform, forKey:nil) + CATransaction.commit() + } + } +} \ No newline at end of file diff --git a/Frameworks/RRTagController/RRAddTagView.swift b/Frameworks/RRTagController/RRAddTagView.swift new file mode 100755 index 0000000..24e5de7 --- /dev/null +++ b/Frameworks/RRTagController/RRAddTagView.swift @@ -0,0 +1,45 @@ +// +// RRAddTagView.swift +// RRTagController +// +// Created by Remi Robert on 20/02/15. +// Copyright (c) 2015 Remi Robert. All rights reserved. +// + +import UIKit + +class RRAddTagView: UIView, UITextViewDelegate { + + lazy var title: UILabel = { + let title = UILabel(frame: CGRectMake(10, 10, UIScreen.mainScreen().bounds.size.width - 20, 20)) + title.font = UIFont.boldSystemFontOfSize(18) + title.textAlignment = NSTextAlignment.Center + return title + }() + + lazy var textEdit: UITextView = { + let textEdit = UITextView(frame: CGRectMake(10, 30, UIScreen.mainScreen().bounds.size.width - 20, 20)) + textEdit.delegate = self + return textEdit + }() + + func textView(textView: UITextView, shouldChangeTextInRange range: NSRange, replacementText text: String) -> Bool { + if strlen(textView.text) + strlen(text) > 44 { + return false + } + return true + } + + override init(frame: CGRect) { + super.init(frame: frame) + title.text = "Create a new tag." + self.addSubview(title) + self.addSubview(textEdit) + self.backgroundColor = UIColor.whiteColor() + } + + required init(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} diff --git a/Frameworks/RRTagController/RRTagCollectionViewCell.swift b/Frameworks/RRTagController/RRTagCollectionViewCell.swift new file mode 100755 index 0000000..c5514f1 --- /dev/null +++ b/Frameworks/RRTagController/RRTagCollectionViewCell.swift @@ -0,0 +1,72 @@ +// +// RRTagCollectionViewCell.swift +// RRTagController +// +// Created by Remi Robert on 20/02/15. +// Copyright (c) 2015 Remi Robert. All rights reserved. +// + +import UIKit + +let RRTagCollectionViewCellIdentifier = "RRTagCollectionViewCellIdentifier" + +class RRTagCollectionViewCell: UICollectionViewCell { + + var issSelected: Bool = false + + lazy var textContent: UILabel! = { + let textContent = UILabel(frame: CGRectZero) + textContent.layer.masksToBounds = true + textContent.layer.cornerRadius = 20 + textContent.layer.borderWidth = 0.6 + textContent.layer.borderColor = UIColor.lightGrayColor().CGColor + textContent.font = UIFont(name: "American Typewriter", size: 15) + textContent.textAlignment = NSTextAlignment.Center + return textContent + }() + + func initContent(tag: Tag) { + self.contentView.addSubview(textContent) + textContent.text = tag.textContent + textContent.sizeToFit() + textContent.frame.size.width = textContent.frame.size.width + 30 + textContent.frame.size.height = textContent.frame.size.height + 20 + issSelected = tag.issSelected + textContent.backgroundColor = UIColor.clearColor() + self.textContent.layer.backgroundColor = (self.issSelected == true) ? colorSelectedTag.CGColor : colorUnselectedTag.CGColor + self.textContent.textColor = (self.issSelected == true) ? colorTextSelectedTag : colorTextUnSelectedTag + } + + func initAddButtonContent() { + self.contentView.addSubview(textContent) + textContent.text = "+" + textContent.sizeToFit() + textContent.frame.size = CGSizeMake(40, 40) + textContent.backgroundColor = UIColor.clearColor() + self.textContent.layer.backgroundColor = UIColor.grayColor().CGColor + self.textContent.textColor = UIColor.whiteColor() + } + + func animateSelection(selection: Bool) { + issSelected = selection + + self.textContent.frame.size = CGSizeMake(self.textContent.frame.size.width - 20, self.textContent.frame.size.height - 20) + self.textContent.frame.origin = CGPointMake(self.textContent.frame.origin.x + 10, self.textContent.frame.origin.y + 10) + UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.3, initialSpringVelocity: 0.4, options: UIViewAnimationOptions.allZeros, animations: { () -> Void in + self.textContent.layer.backgroundColor = (self.issSelected == true) ? colorSelectedTag.CGColor : colorUnselectedTag.CGColor + self.textContent.textColor = (self.issSelected == true) ? colorTextSelectedTag : colorTextUnSelectedTag + self.textContent.frame.size = CGSizeMake(self.textContent.frame.size.width + 20, self.textContent.frame.size.height + 20) + self.textContent.center = CGPointMake(self.contentView.frame.size.width / 2, self.contentView.frame.size.height / 2) + }, completion: nil) + } + + class func contentHeight(content: String) -> CGSize { + let styleText = NSMutableParagraphStyle() + styleText.alignment = NSTextAlignment.Center + let attributs = [NSParagraphStyleAttributeName:styleText, NSFontAttributeName:UIFont.boldSystemFontOfSize(17)] + let sizeBoundsContent = (content as NSString).boundingRectWithSize(CGSizeMake(UIScreen.mainScreen().bounds.size.width, + UIScreen.mainScreen().bounds.size.height), options: NSStringDrawingOptions.UsesLineFragmentOrigin, attributes: attributs, context: nil) + return CGSizeMake(sizeBoundsContent.width + 30, sizeBoundsContent.height + 20) + } +} + diff --git a/Frameworks/RRTagController/RRTagController.swift b/Frameworks/RRTagController/RRTagController.swift new file mode 100755 index 0000000..59f8554 --- /dev/null +++ b/Frameworks/RRTagController/RRTagController.swift @@ -0,0 +1,283 @@ +// +// RRTagController.swift +// RRTagController +// +// Created by Remi Robert on 20/02/15. +// Copyright (c) 2015 Remi Robert. All rights reserved. +// + +import UIKit + +struct Tag { + var issSelected: Bool + var isLocked: Bool + var textContent: String +} + +let colorUnselectedTag = UIColor.whiteColor() +let colorSelectedTag = UIColor(red:0.63, green:0.62, blue:0.89, alpha:1) + +let colorTextUnSelectedTag = UIColor(red:0.48, green:0.48, blue:0.48, alpha:1) +let colorTextSelectedTag = UIColor.whiteColor() + +class RRTagController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + + private var tags: Array! + private var navigationBarItem: UINavigationItem! + private var leftButton: UIBarButtonItem! + private var rigthButton: UIBarButtonItem! + private var _totalTagsSelected = 0 + private let addTagView = RRAddTagView(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.size.width, 64)) + private var heightKeyboard: CGFloat = 0 + + var blockFinih: ((selectedTags: Array, unSelectedTags: Array) -> ())! + var blockCancel: (() -> ())! + + var totalTagsSelected: Int { + get { + return self._totalTagsSelected + } + set { + if newValue == 0 { + self._totalTagsSelected = 0 + return + } + self._totalTagsSelected += newValue + self._totalTagsSelected = (self._totalTagsSelected < 0) ? 0 : self._totalTagsSelected + self.navigationBarItem = UINavigationItem(title: "Tags") + self.navigationBarItem.leftBarButtonItem = self.leftButton + self.navigationBarItem.rightBarButtonItem = self.rigthButton + self.navigationBar.pushNavigationItem(self.navigationBarItem, animated: false) + } + } + + lazy var collectionTag: UICollectionView = { + let layoutCollectionView = UICollectionViewFlowLayout() + layoutCollectionView.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20) + layoutCollectionView.itemSize = CGSizeMake(90, 20) + layoutCollectionView.minimumLineSpacing = 10 + layoutCollectionView.minimumInteritemSpacing = 5 + let collectionTag = UICollectionView(frame: self.view.frame, collectionViewLayout: layoutCollectionView) + collectionTag.contentInset = UIEdgeInsets(top: 84, left: 0, bottom: 20, right: 0) + collectionTag.delegate = self + collectionTag.dataSource = self + collectionTag.backgroundColor = UIColor.whiteColor() + collectionTag.registerClass(RRTagCollectionViewCell.self, forCellWithReuseIdentifier: RRTagCollectionViewCellIdentifier) + return collectionTag + }() + + lazy var addNewTagCell: RRTagCollectionViewCell = { + let addNewTagCell = RRTagCollectionViewCell() + addNewTagCell.contentView.addSubview(addNewTagCell.textContent) + addNewTagCell.textContent.text = "+" + addNewTagCell.frame.size = CGSizeMake(40, 40) + addNewTagCell.backgroundColor = UIColor.grayColor() + return addNewTagCell + }() + + lazy var controlPanelEdition: UIView = { + let controlPanel = UIView(frame: CGRectMake(0, UIScreen.mainScreen().bounds.size.height + 50, UIScreen.mainScreen().bounds.size.width, 50)) + controlPanel.backgroundColor = UIColor.whiteColor() + + let buttonCancel = UIButton(frame: CGRectMake(10, 10, 100, 30)) + buttonCancel.layer.borderColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1).CGColor + buttonCancel.layer.borderWidth = 2 + buttonCancel.backgroundColor = UIColor.whiteColor() + buttonCancel.setTitle("Cancel", forState: UIControlState.Normal) + buttonCancel.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal) + buttonCancel.titleLabel?.font = UIFont.boldSystemFontOfSize(17) + buttonCancel.layer.cornerRadius = 15 + buttonCancel.addTarget(self, action: "cancelEditTag", forControlEvents: UIControlEvents.TouchUpInside) + + let buttonAccept = UIButton(frame: CGRectMake(UIScreen.mainScreen().bounds.size.width - 110, 10, 100, 30)) + buttonAccept.layer.borderColor = UIColor(red:0.88, green:0.88, blue:0.88, alpha:1).CGColor + buttonAccept.layer.borderWidth = 2 + buttonAccept.backgroundColor = UIColor.whiteColor() + buttonAccept.setTitle("Create", forState: UIControlState.Normal) + buttonAccept.setTitleColor(UIColor.blackColor(), forState: UIControlState.Normal) + buttonAccept.titleLabel?.font = UIFont.boldSystemFontOfSize(17) + buttonAccept.layer.cornerRadius = 15 + buttonAccept.addTarget(self, action: "createNewTag", forControlEvents: UIControlEvents.TouchUpInside) + + controlPanel.addSubview(buttonCancel) + controlPanel.addSubview(buttonAccept) + return controlPanel + }() + + lazy var navigationBar: UINavigationBar = { + let navigationBar = UINavigationBar(frame: CGRectMake(0, 0, UIScreen.mainScreen().bounds.size.width, 64)) + + self.navigationBarItem = UINavigationItem(title: "Tags") + self.navigationBarItem.leftBarButtonItem = self.leftButton + + navigationBar.pushNavigationItem(self.navigationBarItem, animated: true) + navigationBar.tintColor = colorSelectedTag + return navigationBar + }() + + func cancelTagController() { + self.dismissViewControllerAnimated(true, completion: { () -> Void in + self.blockCancel() + }) + } + + func finishTagController() { + var selected: Array = Array() + var unSelected: Array = Array() + + for currentTag in tags { + if currentTag.issSelected { + selected.append(currentTag) + } + else { + unSelected.append(currentTag) + } + } + self.dismissViewControllerAnimated(true, completion: { () -> Void in + self.blockFinih(selectedTags: selected, unSelectedTags: unSelected) + }) + } + + func cancelEditTag() { + self.view.endEditing(true) + UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.4, + initialSpringVelocity: 0.4, options: UIViewAnimationOptions.allZeros, animations: { () -> Void in + self.addTagView.frame.origin.y = 0 + self.controlPanelEdition.frame.origin.y = UIScreen.mainScreen().bounds.size.height + self.collectionTag.alpha = 1 + }) { (anim:Bool) -> Void in + + } + } + + func createNewTag() { + let spaceSet = NSCharacterSet.whitespaceCharacterSet() + let contentTag = addTagView.textEdit.text.stringByTrimmingCharactersInSet(spaceSet) + if strlen(contentTag) > 0 { + let newTag = Tag(issSelected: false, isLocked: false, textContent: contentTag) + tags.insert(newTag, atIndex: tags.count) + collectionTag.reloadData() + } + cancelEditTag() + } + + func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return tags.count + } + + func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { + if indexPath.row < tags.count { + return RRTagCollectionViewCell.contentHeight(tags[indexPath.row].textContent) + } + return CGSizeMake(40, 40) + } + + func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) { + let selectedCell: RRTagCollectionViewCell? = collectionView.cellForItemAtIndexPath(indexPath) as? RRTagCollectionViewCell + + if indexPath.row < tags.count { + var currentTag = tags[indexPath.row] + + if tags[indexPath.row].issSelected == false { + tags[indexPath.row].issSelected = true + selectedCell?.animateSelection(tags[indexPath.row].issSelected) + totalTagsSelected = 1 + } + else { + tags[indexPath.row].issSelected = false + selectedCell?.animateSelection(tags[indexPath.row].issSelected) + totalTagsSelected = -1 + } + } + else { +// addTagView.textEdit.text = nil +// UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.4, +// options: UIViewAnimationOptions.allZeros, animations: { () -> Void in +// self.collectionTag.alpha = 0.3 +// self.addTagView.frame.origin.y = 64 +// }, completion: { (anim: Bool) -> Void in +// self.addTagView.textEdit.becomeFirstResponder() +// println("") +// }) + } + } + + func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + let cell: RRTagCollectionViewCell? = collectionView.dequeueReusableCellWithReuseIdentifier(RRTagCollectionViewCellIdentifier, forIndexPath: indexPath) as? RRTagCollectionViewCell + + if indexPath.row < tags.count { + let currentTag = tags[indexPath.row] + cell?.initContent(currentTag) + } + else { +// cell?.initAddButtonContent() + } + return cell! + } + + func keyboardWillShow(notification: NSNotification) { + // TODO: change value + if let userInfo = notification.userInfo { + if let keyboardSize = (userInfo[UIKeyboardFrameBeginUserInfoKey] as? NSValue)?.CGRectValue() { + heightKeyboard = keyboardSize.height + UIView.animateWithDuration(0.5, delay: 0, usingSpringWithDamping: 0.4, initialSpringVelocity: 0.4, + options: UIViewAnimationOptions.allZeros, animations: { () -> Void in + self.controlPanelEdition.frame.origin.y = self.view.frame.size.height - self.heightKeyboard - 50 + }, completion: nil) + } + } + else { + heightKeyboard = 0 + } + } + + func keyboardWillHide(notification: NSNotification) { + heightKeyboard = 0 + } + + override func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = UIColor.whiteColor() + + leftButton = UIBarButtonItem(title: "Cancel", style: UIBarButtonItemStyle.Done, target: self, action: "cancelTagController") + leftButton.tintColor = UIColor.whiteColor() + rigthButton = UIBarButtonItem(title: "OK", style: UIBarButtonItemStyle.Done, target: self, action: "finishTagController") + rigthButton.tintColor = UIColor.whiteColor() + + totalTagsSelected = 0 + self.view.addSubview(collectionTag) +// self.view.addSubview(addTagView) +// self.view.addSubview(controlPanelEdition) + self.view.addSubview(navigationBar) + NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow:"), name:UIKeyboardWillShowNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillHide:"), name:UIKeyboardWillHideNotification, object: nil) + } + + class func displayTagController(#parentController: UIViewController, tagsString: [String]?, + blockFinish: (selectedTags: Array, unSelectedTags: Array)->(), blockCancel: ()->()) { + let tagController = RRTagController() + tagController.tags = Array() + if tagsString != nil { + for currentTag in tagsString! { + tagController.tags.append(Tag(issSelected: false, isLocked: false, textContent: currentTag)) + } + } + tagController.blockCancel = blockCancel + tagController.blockFinih = blockFinish + parentController.presentViewController(tagController, animated: false, completion: nil) + } + + class func displayTagController(#parentController: UIViewController, tags: [Tag]?, + blockFinish: (selectedTags: Array, unSelectedTags: Array)->(), blockCancel: ()->()) { + let tagController = RRTagController() + tagController.tags = tags + tagController.blockCancel = blockCancel + tagController.blockFinih = blockFinish + tagController.modalPresentationStyle = UIModalPresentationStyle.OverFullScreen + tagController.modalTransitionStyle = UIModalTransitionStyle.CrossDissolve + parentController.presentViewController(tagController, animated: true, completion: nil) + + } + +} diff --git a/Frameworks/SimpleAlert/AlertController.swift b/Frameworks/SimpleAlert/AlertController.swift new file mode 100644 index 0000000..8208946 --- /dev/null +++ b/Frameworks/SimpleAlert/AlertController.swift @@ -0,0 +1,67 @@ +// +// AlertController.swift +// Arrived +// +// Created by Lu Cao on 5/25/15. +// Copyright (c) 2015 LoopCow. All rights reserved. +// + +import UIKit + +class AlertController: SimpleAlert.Controller { + override func addTextFieldWithConfigurationHandler(configurationHandler: ((UITextField!) -> Void)? = nil) { + super.addTextFieldWithConfigurationHandler() { textField in + textField.frame.size.height = 33 + textField.backgroundColor = UIColorFromHex(0x3D4656, alpha: 0.3) + textField.layer.borderColor = UIColor.whiteColor().CGColor + textField.layer.borderWidth = 0.3 + textField.tintColor = UIColorFromHex(0x3D4656, alpha: 0.9) + textField.font = UIFont(name: "American Typewriter", size: 17) + textField.textColor = UIColorFromHex(0x3D4656, alpha: 0.9) + + configurationHandler?(textField) + } + } + + override func configurButton(style :SimpleAlert.Action.Style, forButton button: UIButton) { + super.configurButton(style, forButton: button) + + if let font = button.titleLabel?.font { + switch style { + case .OK: + button.titleLabel?.font = UIFont(name: "American Typewriter", size: 19) + button.setTitleColor(UIColor.grayColor(), forState: .Normal) + case .Cancel: + button.titleLabel?.font = UIFont(name: "American Typewriter", size: 19) + button.backgroundColor = UIColorFromHex(0x54C799, alpha: 0.65) + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + case .Destructive: + button.titleLabel?.font = UIFont(name: "American Typewriter", size: 19) + button.backgroundColor = UIColorFromHex(0x54C799, alpha: 0.65) + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + case .Default: + button.setTitleColor(UIColor.lightGrayColor(), forState: .Normal) + default: + break + } + } + } + + override func viewDidLoad() { + super.viewDidLoad() + + configContentView = { [weak self] view in + if let view = view as? SimpleAlert.ContentView { + view.layer.backgroundColor = UIColorFromHex(0xFFFFFF, alpha: 0.95).CGColor + view.titleLabel.textColor = UIColorFromHex(0x3D4656, alpha: 0.9) + view.titleLabel.font = UIFont(name: "American Typewriter", size: 26) + view.messageLabel.textColor = UIColorFromHex(0x474E5D, alpha: 0.9) + view.messageLabel.font = UIFont(name: "American Typewriter", size: 12) + view.messageLabel.textAlignment = .Left + view.textBackgroundView.layer.backgroundColor = UIColorFromHex(0xFFFFFF, alpha: 0.1).CGColor + view.textBackgroundView.layer.cornerRadius = 3.0 + view.textBackgroundView.clipsToBounds = true + } + } + } +} \ No newline at end of file diff --git a/Frameworks/SimpleAlert/SimpleAlert.swift b/Frameworks/SimpleAlert/SimpleAlert.swift new file mode 100755 index 0000000..6077588 --- /dev/null +++ b/Frameworks/SimpleAlert/SimpleAlert.swift @@ -0,0 +1,693 @@ +// +// SimpleAlert.swift +// SimpleAlert +// +// Created by Kyohei Ito on 2015/01/09. +// Copyright (c) 2015年 kyohei_ito. All rights reserved. +// + +import UIKit + +public class SimpleAlert { + @objc(SimpleAlertAction) + public class Action : NSObject { + public enum Style { + case Default + case OK + case Cancel + case Destructive + } + + public init(title: String, style: Style, handler: ((Action!) -> Void)? = nil) { + self.title = title + self.handler = handler + self.style = style + super.init() + } + + var title: String + var handler: ((Action) -> Void)? + var style: Action.Style + public var enabled: Bool = true { + didSet { + button?.enabled = enabled + } + } + public private(set) var button: UIButton! + } + + @objc(SimpleAlertContentView) + public class ContentView: UIView { + let TextFieldFontSize: CGFloat = 14 + let TextFieldHeight: CGFloat = 25 + + @IBOutlet public weak var baseView: UIView! + @IBOutlet public weak var titleLabel: UILabel! + @IBOutlet public weak var messageLabel: UILabel! + @IBOutlet public weak var textBackgroundView: UIView! + + @IBOutlet private var verticalSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var titleSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var messageSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var textViewHeightConstraint: NSLayoutConstraint! + + public override func awakeFromNib() { + super.awakeFromNib() + + backgroundColor = UIColor.whiteColor() + } + } + + @objc(SimpleAlertController) + public class Controller: UIViewController { + public enum Style { + case Alert + case ActionSheet + } + + @objc(SimpleAlertControllerRespondView) + private class RespondView: UIView { + var touchHandler: ((UIView) -> Void)? + override func touchesEnded(touches: Set, withEvent event: UIEvent) { + touchHandler?(self) + } + } + + @IBOutlet private weak var containerView: UIView! + @IBOutlet private weak var backgroundView: RespondView! + @IBOutlet private weak var coverView: UIView! + @IBOutlet private weak var marginView: UIView! + @IBOutlet private weak var baseView: UIView! + @IBOutlet private weak var mainView: UIScrollView! + @IBOutlet private weak var buttonView: UIScrollView! + @IBOutlet private weak var cancelButtonView: UIScrollView! + @IBOutlet private weak var contentView: ContentView? + + @IBOutlet private var containerViewWidthConstraint: NSLayoutConstraint! + @IBOutlet private var containerViewBottomSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var backgroundViewTopSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var backgroundViewBottomSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var coverViewHeightConstraint: NSLayoutConstraint! + + @IBOutlet private var mainViewHeightConstraint: NSLayoutConstraint! + @IBOutlet private var buttonViewHeightConstraint: NSLayoutConstraint! + @IBOutlet private var cancelButtonViewHeightConstraint: NSLayoutConstraint! + @IBOutlet private var buttonViewSpaceConstraint: NSLayoutConstraint! + + @IBOutlet private var marginViewTopSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var marginViewLeftSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var marginViewBottomSpaceConstraint: NSLayoutConstraint! + @IBOutlet private var marginViewRightSpaceConstraint: NSLayoutConstraint! + + public var configContainerWidth: (() -> CGFloat?)? + public var configContainerCornerRadius: (() -> CGFloat?)? + public var configContentView: ((UIView!) -> Void)? + + public private(set) var actions: [Action] = [] + public private(set) var textFields: [UITextField] = [] + private var textFieldHandlers: [((UITextField!) -> Void)?] = [] + private var customView: UIView? + private var transitionCoverView: UIView? + private var displayTargetView: UIView? + private var presentedAnimation: Bool = true + let AlertDefaultWidth: CGFloat = 270 + let AlertButtonHeight: CGFloat = 48 + let AlertButtonFontSize: CGFloat = 17 + let ActionSheetMargin: CGFloat = 8 + let ActionSheetButtonHeight: CGFloat = 44 + let ActionSheetButtonFontSize: CGFloat = 21 + let ConstraintPriorityRequired: Float = 1000 + + private var message: String? + private var preferredStyle: Style = .Alert + + private var marginInsets: UIEdgeInsets { + set { + marginViewTopSpaceConstraint.constant = newValue.top + marginViewLeftSpaceConstraint.constant = newValue.left + marginViewBottomSpaceConstraint.constant = newValue.bottom + marginViewRightSpaceConstraint.constant = newValue.right + } + get { + let top = marginViewTopSpaceConstraint.constant + let left = marginViewLeftSpaceConstraint.constant + let bottom = marginViewBottomSpaceConstraint.constant + let right = marginViewRightSpaceConstraint.constant + return UIEdgeInsetsMake(top, left, bottom, right) + } + } + + deinit { + NSNotificationCenter.defaultCenter().removeObserver(self) + } + + public convenience init() { + self.init(nibName: "SimpleAlert", bundle: NSBundle(forClass: Controller.self)) + } + + public convenience init(title: String?, message: String?, style: Style) { + self.init() + self.title = title + self.message = message + self.preferredStyle = style + } + + public convenience init(view: UIView?, style: Style) { + self.init() + self.customView = view + self.preferredStyle = style + } + + public convenience init(view: UIView?, style: Style, title: String?, message: String?) { + self.init() + self.title = title + self.message = message + self.customView = view + self.preferredStyle = style + } + + public required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + + modalPresentationStyle = .Custom + modalTransitionStyle = .CrossDissolve + transitioningDelegate = self + + NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardDidHide:", name: UIKeyboardDidHideNotification, object: nil) + } + + public override func viewDidLoad() { + super.viewDidLoad() + + view.autoresizingMask = .FlexibleWidth | .FlexibleHeight + + baseView.layer.cornerRadius = 3.0 + baseView.clipsToBounds = true + + cancelButtonView.layer.cornerRadius = 3.0 + cancelButtonView.clipsToBounds = true + + displayTargetView = contentView + } + + public override func viewWillAppear(animated: Bool) { + super.viewWillAppear(animated) + + if let view = customView { + displayTargetView = view + } + + if displayTargetView == contentView { + setupContnetView() + } + textFieldHandlers.removeAll() + + if let textField = textFields.first { + textField.becomeFirstResponder() + } + + if preferredStyle == .ActionSheet { + containerViewBottomSpaceConstraint.priority = ConstraintPriorityRequired + backgroundView.touchHandler = { [weak self] view in + self?.dismissViewController() + return + } + } + } + + public override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + if transitionCoverView == nil { + return + } + + layoutContainer() + layoutContents() + layoutButtons() + + let margin = marginInsets.top + marginInsets.bottom + let backgroundViewHeight = view.bounds.size.height - backgroundViewBottomSpaceConstraint.constant - margin + + if cancelButtonView.contentSize.height > cancelButtonViewHeightConstraint.constant { + cancelButtonViewHeightConstraint.constant = cancelButtonView.contentSize.height + } + + if cancelButtonViewHeightConstraint.constant > backgroundViewHeight { + cancelButtonView.contentSize.height = cancelButtonViewHeightConstraint.constant + cancelButtonViewHeightConstraint.constant = backgroundViewHeight + + mainViewHeightConstraint.constant = 0 + buttonViewHeightConstraint.constant = 0 + } else { + let baseViewHeight = backgroundViewHeight - cancelButtonViewHeightConstraint.constant - buttonViewSpaceConstraint.constant + if buttonView.contentSize.height > buttonViewHeightConstraint.constant { + buttonViewHeightConstraint.constant = buttonView.contentSize.height + } + + if buttonViewHeightConstraint.constant > baseViewHeight { + buttonView.contentSize.height = buttonViewHeightConstraint.constant + buttonViewHeightConstraint.constant = baseViewHeight + mainViewHeightConstraint.constant = 0 + } else { + let mainViewHeight = baseViewHeight - buttonViewHeightConstraint.constant + if mainViewHeightConstraint.constant > mainViewHeight { + mainView.contentSize.height = mainViewHeightConstraint.constant + mainViewHeightConstraint.constant = mainViewHeight + } + } + } + + if preferredStyle == .ActionSheet { + let contentHeight = cancelButtonViewHeightConstraint.constant + mainViewHeightConstraint.constant + buttonViewHeightConstraint.constant + buttonViewSpaceConstraint.constant + coverViewHeightConstraint.constant = contentHeight + marginInsets.top + marginInsets.bottom + } + + view.layoutSubviews() + } + + public func addTextFieldWithConfigurationHandler(configurationHandler: ((UITextField!) -> Void)? = nil) { + textFieldHandlers.append(configurationHandler) + } + + public func addAction(action: Action) { + var buttonHeight: CGFloat! + if preferredStyle == .ActionSheet { + buttonHeight = ActionSheetButtonHeight + } else { + buttonHeight = AlertButtonHeight + } + + let button = loadButton() + if button.bounds.height <= 0 { + button.frame.size.height = buttonHeight + } + button.autoresizingMask = .FlexibleWidth + button.addTarget(self, action: "buttonWasTapped:", forControlEvents: .TouchUpInside) + action.setButton(button) + configurButton(action.style, forButton: button) + actions.append(action) + } + + /** override if needed */ + public func loadButton() -> UIButton { + let button = UIButton.buttonWithType(.System) as! UIButton + let borderView = UIView(frame: CGRect(x: 0, y: -0.5, width: 0, height: 0.5)) + borderView.backgroundColor = UIColor.lightGrayColor() + borderView.autoresizingMask = .FlexibleWidth + button.addSubview(borderView) + + return button + } + + public func configurButton(style: Action.Style, forButton button: UIButton) { + if preferredStyle == .Alert { + configurAlertButton(style, forButton: button) + } else { + configurActionSheetButton(style, forButton: button) + } + } + } +} + +private extension SimpleAlert.Action { + private func setButton(forButton: UIButton) { + button = forButton + button.setTitle(title, forState: .Normal) + button.enabled = enabled + } +} + +private extension SimpleAlert.ContentView { + class ContentTextField: UITextField { + let TextLeftOffset: CGFloat = 4 + override func textRectForBounds(bounds: CGRect) -> CGRect { + return CGRectOffset(bounds, TextLeftOffset, 0) + } + + override func editingRectForBounds(bounds: CGRect) -> CGRect { + return CGRectOffset(bounds, TextLeftOffset, 0) + } + } + + func addTextField() -> UITextField { + let textField = ContentTextField(frame: textBackgroundView.bounds) + textField.autoresizingMask = .FlexibleWidth + textField.font = UIFont.systemFontOfSize(TextFieldFontSize) + textField.backgroundColor = UIColor.whiteColor() + textField.layer.borderColor = UIColor.darkGrayColor().CGColor + textField.layer.borderWidth = 0.5 + + textBackgroundView.addSubview(textField) + + return textField + } + + func layoutContents() { + titleLabel.preferredMaxLayoutWidth = baseView.bounds.width + titleLabel.layoutIfNeeded() + messageLabel.preferredMaxLayoutWidth = baseView.bounds.width + messageLabel.layoutIfNeeded() + + if textBackgroundView.subviews.isEmpty { + messageSpaceConstraint.constant = 0 + } + + if titleLabel.text == nil && messageLabel.text == nil { + titleSpaceConstraint.constant = 0 + messageSpaceConstraint.constant = 0 + + if textBackgroundView.subviews.isEmpty { + verticalSpaceConstraint.constant = 0 + } + } else if titleLabel.text == nil || messageLabel.text == nil { + titleSpaceConstraint.constant = 0 + } + + baseView.layoutIfNeeded() + + frame.size.height = baseView.bounds.height + (verticalSpaceConstraint.constant * 2) + } + + func layoutTextField(textField: UITextField) { + textField.frame.origin.y = textViewHeightConstraint.constant + if textField.frame.height <= 0 { + textField.frame.size.height = TextFieldHeight + } + textViewHeightConstraint.constant += textField.frame.height + } +} + +private extension SimpleAlert.Controller { + func setupContnetView() { + takeOverColor(contentView) + + contentView?.titleLabel.text = title + contentView?.messageLabel.text = message + + if preferredStyle == .Alert { + textFieldHandlers.map() { handler -> Void in + if let textField = self.contentView?.addTextField() { + self.textFields.append(textField) + handler?(textField) + } + } + } + } + + func layoutContainer() { + var containerWidth = AlertDefaultWidth + if preferredStyle == .ActionSheet { + marginInsets = UIEdgeInsetsMake(ActionSheetMargin, ActionSheetMargin, ActionSheetMargin, ActionSheetMargin) + marginView.layoutIfNeeded() + containerWidth = min(view.bounds.width, view.bounds.height) - marginInsets.top - marginInsets.bottom + } + + if let width = configContainerWidth?() { + containerWidth = width + } + if let radius = configContainerCornerRadius?() { + baseView.layer.cornerRadius = radius + cancelButtonView.layer.cornerRadius = radius + } + + containerViewWidthConstraint.constant = containerWidth + containerView.layoutIfNeeded() + } + + func layoutContents() { + displayTargetView?.frame.size.width = mainView.frame.size.width + displayTargetView?.layoutIfNeeded() + + if let config = configContentView { + config(displayTargetView) + configContentView = nil + } + takeOverColor(displayTargetView) + + if displayTargetView == contentView { + contentView?.textViewHeightConstraint.constant = 0 + textFields.map { self.contentView?.layoutTextField($0) } + contentView?.layoutContents() + } + + if let targetView = displayTargetView { + mainViewHeightConstraint.constant = targetView.bounds.height + mainView.frame.size.height = targetView.bounds.height + mainView.addSubview(targetView) + } + } + + func layoutButtons() { + var buttonActions = actions + if preferredStyle == .ActionSheet { + let cancelActions = actions.filter { $0.style == .Cancel } + let buttonHeight = addButton(cancelButtonView, actions: cancelActions) + cancelButtonViewHeightConstraint.constant = buttonHeight + buttonViewSpaceConstraint.constant = ActionSheetMargin + + buttonActions = actions.filter { $0.style != .Cancel } + } + + let buttonHeight = addButton(buttonView, actions: buttonActions) + if preferredStyle != .Alert || buttonActions.count != 2 { + buttonViewHeightConstraint.constant = buttonHeight + } + } + + func takeOverColor(targetView: UIView?) { + if let color = targetView?.backgroundColor { + mainView.backgroundColor = color + buttonView.backgroundColor = color + cancelButtonView.backgroundColor = color + } + targetView?.backgroundColor = nil + } + + func addButton(view: UIView, actions: [SimpleAlert.Action]) -> CGFloat { + var sizeToFit: ((button: UIButton, index: Int) -> Void) = buttonSizeToFitForVertical + if preferredStyle == .Alert && actions.count == 2 { + sizeToFit = buttonSizeToFitForHorizontal + } + + return actions.reduce(0) { height, action in + let button = action.button + view.addSubview(button) + + let buttonHeight = Int(button.bounds.height) + let buttonsHeight = Int(height) + sizeToFit(button: button, index: buttonsHeight / buttonHeight) + + return CGFloat(buttonsHeight + buttonHeight) + } + } + + func buttonSizeToFitForVertical(button: UIButton, index: Int) { + button.frame.size.width = containerViewWidthConstraint.constant + button.frame.origin.y = button.bounds.height * CGFloat(index) + } + + func buttonSizeToFitForHorizontal(button: UIButton, index: Int) { + button.frame.size.width = containerViewWidthConstraint.constant / 2 + button.frame.origin.x = button.bounds.width * CGFloat(index) + + if index != 0 { + let borderView = UIView(frame: CGRect(x: 0, y: 0, width: 0.5, height: button.bounds.height)) + borderView.backgroundColor = UIColor.lightGrayColor() + borderView.autoresizingMask = .FlexibleHeight + button.addSubview(borderView) + } + } + + func configurAlertButton(style :SimpleAlert.Action.Style, forButton button: UIButton) { + switch style { + case .Destructive: + button.setTitleColor(UIColor.redColor(), forState: .Normal) + button.titleLabel?.font = UIFont.systemFontOfSize(AlertButtonFontSize) + case .Cancel: + button.titleLabel?.font = UIFont.boldSystemFontOfSize(AlertButtonFontSize) + default: + button.titleLabel?.font = UIFont.systemFontOfSize(AlertButtonFontSize) + } + } + + func configurActionSheetButton(style :SimpleAlert.Action.Style, forButton button: UIButton) { + switch style { + case .Destructive: + button.setTitleColor(UIColor.redColor(), forState: .Normal) + button.titleLabel?.font = UIFont.systemFontOfSize(ActionSheetButtonFontSize) + case .Cancel: + button.titleLabel?.font = UIFont.boldSystemFontOfSize(ActionSheetButtonFontSize) + default: + button.titleLabel?.font = UIFont.systemFontOfSize(ActionSheetButtonFontSize) + } + } + + func dismissViewController(sender: AnyObject? = nil) { + dismissViewControllerAnimated(true) { + if let action = self.actions.filter({ $0.button == sender as? UIButton }).first { + action.handler?(action) + } + + self.actions.removeAll() + self.textFields.removeAll() + } + } +} + +// MARK: - Action Methods +extension SimpleAlert.Controller { + func buttonWasTapped(sender: UIButton) { + dismissViewController(sender: sender) + } +} + +// MARK: - NSNotificationCenter Methods +extension SimpleAlert.Controller { + func keyboardDidHide(notification: NSNotification) { + backgroundViewBottomSpaceConstraint?.constant = 0 + } + + func keyboardWillShow(notification: NSNotification) { + if let window = view.window { + if let frame = notification.userInfo?[UIKeyboardFrameEndUserInfoKey]?.CGRectValue() { + let rect = window.convertRect(frame, toView: view) + + backgroundViewBottomSpaceConstraint?.constant = view.bounds.size.height - rect.origin.y + } + } + } +} + +// MARK: - UIViewControllerTransitioningDelegate Methods +extension SimpleAlert.Controller: UIViewControllerTransitioningDelegate { + public func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + presentedAnimation = true + return self + } + + public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + presentedAnimation = false + return self + } +} + +// MARK: - UIViewControllerAnimatedTransitioning Methods +extension SimpleAlert.Controller: UIViewControllerAnimatedTransitioning { + func animateDuration() -> NSTimeInterval { + return 0.25 + } + + func animationOptionsForAnimationCurve(curve: UInt) -> UIViewAnimationOptions { + return UIViewAnimationOptions(curve << 16) + } + + func createCoverView(frame: CGRect) -> UIView { + let coverView = UIView(frame: frame) + coverView.backgroundColor = UIColor.blackColor().colorWithAlphaComponent(0.4) + coverView.alpha = 0 + coverView.autoresizingMask = .FlexibleWidth | .FlexibleHeight + return coverView + } + + func animation(animations: () -> Void, completion: (Bool) -> Void) { + UIView.animateWithDuration(animateDuration(), delay: 0, options: animationOptionsForAnimationCurve(7), animations: animations, completion: completion) + } + + func presentAnimationForAlert(container: UIView, toView: UIView, fromView: UIView, completion: (Bool) -> Void) { + let coverView = createCoverView(container.bounds) + container.addSubview(coverView) + + toView.frame = container.bounds + toView.transform = CGAffineTransformConcat(fromView.transform, CGAffineTransformMakeScale(1.2, 1.2)) + coverView.addSubview(toView) + + transitionCoverView = coverView + + animation({ + toView.transform = fromView.transform + coverView.alpha = 1 + }, completion: completion) + } + + func dismissAnimationForAlert(container: UIView, toView: UIView, fromView: UIView, completion: (Bool) -> Void) { + transitionCoverView?.addSubview(fromView) + + animation({ + self.transitionCoverView?.alpha = 0 + self.transitionCoverView = nil + }, completion: completion) + } + + func presentAnimationForActionSheet(container: UIView, toView: UIView, fromView: UIView, completion: (Bool) -> Void) { + let coverView = createCoverView(container.bounds) + container.addSubview(coverView) + toView.frame = container.bounds + container.addSubview(toView) + + backgroundViewBottomSpaceConstraint.constant = -toView.bounds.height + backgroundViewTopSpaceConstraint.constant = toView.bounds.height + backgroundView.layoutIfNeeded() + backgroundViewBottomSpaceConstraint.constant = 0 + backgroundViewTopSpaceConstraint.constant = 0 + + transitionCoverView = coverView + + animation({ + self.backgroundView.layoutIfNeeded() + coverView.alpha = 1 + }, completion: completion) + } + + func dismissAnimationForActionSheet(container: UIView, toView: UIView, fromView: UIView, completion: (Bool) -> Void) { + container.addSubview(fromView) + + backgroundViewBottomSpaceConstraint.constant = -toView.bounds.height + backgroundViewTopSpaceConstraint.constant = toView.bounds.height + + animation({ + self.backgroundView.layoutIfNeeded() + self.transitionCoverView?.alpha = 0 + self.transitionCoverView = nil + }, completion: completion) + } + + public func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { + return animateDuration() + } + + public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { + if let to = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey) { + if let from = transitionContext.viewControllerForKey(UITransitionContextFromViewControllerKey) { + let container = transitionContext.containerView() + + if presentedAnimation == true { + if preferredStyle == .Alert { + presentAnimationForAlert(container, toView: to.view, fromView: from.view) { _ in + transitionContext.completeTransition(true) + } + } else { + presentAnimationForActionSheet(container, toView: to.view, fromView: from.view) { _ in + transitionContext.completeTransition(true) + } + } + } else { + if preferredStyle == .Alert { + dismissAnimationForAlert(container, toView: to.view, fromView: from.view) { _ in + transitionContext.completeTransition(true) + } + } else { + dismissAnimationForActionSheet(container, toView: to.view, fromView: from.view) { _ in + transitionContext.completeTransition(true) + } + } + } + } + } + } +} diff --git a/Frameworks/SimpleAlert/SimpleAlert.xib b/Frameworks/SimpleAlert/SimpleAlert.xib new file mode 100755 index 0000000..eb1c3b8 --- /dev/null +++ b/Frameworks/SimpleAlert/SimpleAlert.xib @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Frameworks/SwiftForms/.DS_Store b/Frameworks/SwiftForms/.DS_Store new file mode 100644 index 0000000..c8081c5 Binary files /dev/null and b/Frameworks/SwiftForms/.DS_Store differ diff --git a/Frameworks/SwiftForms/Info.plist b/Frameworks/SwiftForms/Info.plist new file mode 100755 index 0000000..652cdc7 --- /dev/null +++ b/Frameworks/SwiftForms/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.ortulabs.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 0.8 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Frameworks/SwiftForms/SwiftForms.h b/Frameworks/SwiftForms/SwiftForms.h new file mode 100755 index 0000000..b14d579 --- /dev/null +++ b/Frameworks/SwiftForms/SwiftForms.h @@ -0,0 +1,19 @@ +// +// SwiftForms.h +// SwiftForms +// +// Created by Miguel Angel Ortuno Ortuno on 14/5/15. +// Copyright (c) 2015 Miguel Angel Ortuno Ortuno. All rights reserved. +// + +#import + +//! Project version number for SwiftForms. +FOUNDATION_EXPORT double SwiftFormsVersionNumber; + +//! Project version string for SwiftForms. +FOUNDATION_EXPORT const unsigned char SwiftFormsVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Frameworks/SwiftForms/cells/FormButtonCell.swift b/Frameworks/SwiftForms/cells/FormButtonCell.swift new file mode 100755 index 0000000..304375f --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormButtonCell.swift @@ -0,0 +1,24 @@ +// +// FormButtonCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 21/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormButtonCell: FormTitleCell { + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + titleLabel.textAlignment = .Center + } + + public override func update() { + super.update() + titleLabel.text = rowDescriptor.title as String + } +} diff --git a/Frameworks/SwiftForms/cells/FormCheckCell.swift b/Frameworks/SwiftForms/cells/FormCheckCell.swift new file mode 100755 index 0000000..0947229 --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormCheckCell.swift @@ -0,0 +1,51 @@ +// +// FormCheckCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 22/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormCheckCell: FormTitleCell { + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + selectionStyle = .Default + accessoryType = .None + } + + public override func update() { + super.update() + + titleLabel.text = rowDescriptor.title + + if rowDescriptor.value == nil { + rowDescriptor.value = false + } + + accessoryType = (rowDescriptor.value as! Bool) ? .Checkmark : .None + } + + public override class func formViewController(formViewController: FormViewController, didSelectRow selectedRow: FormBaseCell) { + + if let row = selectedRow as? FormCheckCell { + row.check() + } + } + + /// MARK: Private interface + + private func check() { + if rowDescriptor.value != nil { + rowDescriptor.value = !(rowDescriptor.value as! Bool) + } + else { + rowDescriptor.value = true + } + accessoryType = (rowDescriptor.value as! Bool) ? .Checkmark : .None + } +} diff --git a/Frameworks/SwiftForms/cells/FormDateCell.swift b/Frameworks/SwiftForms/cells/FormDateCell.swift new file mode 100755 index 0000000..47292d2 --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormDateCell.swift @@ -0,0 +1,101 @@ +// +// FormDateCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 22/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormDateCell: FormValueCell { + + /// MARK: Properties + + private let datePicker = UIDatePicker() + private let hiddenTextField = UITextField(frame: CGRectZero) + private let defaultDateFormatter = NSDateFormatter() + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + contentView.addSubview(hiddenTextField) + hiddenTextField.inputView = datePicker + datePicker.datePickerMode = .Date + datePicker.addTarget(self, action: "valueChanged:", forControlEvents: .ValueChanged) + } + + public override func update() { + super.update() + + if let showsInputToolbar = rowDescriptor.configuration[FormRowDescriptor.Configuration.ShowsInputToolbar] as? Bool { + if showsInputToolbar && hiddenTextField.inputAccessoryView == nil { + hiddenTextField.inputAccessoryView = inputAccesoryView() + } + } + + titleLabel.text = rowDescriptor.title + + switch rowDescriptor.rowType { + case .Date: + datePicker.datePickerMode = .Date + defaultDateFormatter.dateStyle = .LongStyle + defaultDateFormatter.timeStyle = .NoStyle + case .Time: + datePicker.datePickerMode = .Time + defaultDateFormatter.dateStyle = .NoStyle + defaultDateFormatter.timeStyle = .ShortStyle + default: + datePicker.datePickerMode = .DateAndTime + defaultDateFormatter.dateStyle = .LongStyle + defaultDateFormatter.timeStyle = .ShortStyle + } + + if rowDescriptor.value != nil { + let date = rowDescriptor.value as? NSDate + datePicker.date = date! + valueLabel.text = self.getDateFormatter().stringFromDate(date!) + } + } + + public override class func formViewController(formViewController: FormViewController, didSelectRow selectedRow: FormBaseCell) { + + let row: FormDateCell! = selectedRow as? FormDateCell + + if row.rowDescriptor.value == nil { + let date = NSDate() + row.rowDescriptor.value = date + row.valueLabel.text = row.getDateFormatter().stringFromDate(date) + row.update() + } + + row.hiddenTextField.becomeFirstResponder() + } + + public override func firstResponderElement() -> UIResponder? { + return hiddenTextField + } + + public override class func formRowCanBecomeFirstResponder() -> Bool { + return true + } + + /// MARK: Actions + + internal func valueChanged(sender: UIDatePicker) { + rowDescriptor.value = sender.date + valueLabel.text = getDateFormatter().stringFromDate(sender.date) + update() + } + + /// MARK: Private interface + + private func getDateFormatter() -> NSDateFormatter { + + if let dateFormatter = self.rowDescriptor.configuration[FormRowDescriptor.Configuration.DateFormatter] as? NSDateFormatter { + return dateFormatter + } + return defaultDateFormatter + } +} diff --git a/Frameworks/SwiftForms/cells/FormPickerCell.swift b/Frameworks/SwiftForms/cells/FormPickerCell.swift new file mode 100755 index 0000000..fbc4f67 --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormPickerCell.swift @@ -0,0 +1,91 @@ +// +// FormPickerCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 22/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormPickerCell: FormValueCell, UIPickerViewDelegate, UIPickerViewDataSource { + + /// MARK: Properties + + private let picker = UIPickerView() + private let hiddenTextField = UITextField(frame: CGRectZero) + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + accessoryType = .None + + picker.delegate = self + picker.dataSource = self + hiddenTextField.inputView = picker + + contentView.addSubview(hiddenTextField) + } + + public override func update() { + super.update() + + titleLabel.text = rowDescriptor.title + + if rowDescriptor.value != nil { + valueLabel.text = rowDescriptor.titleForOptionValue(rowDescriptor.value) + if let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + let index = options.indexOfObject(rowDescriptor.value) + if index != NSNotFound { + picker.selectRow(index, inComponent: 0, animated: false) + } + } + } + } + + public override class func formViewController(formViewController: FormViewController, didSelectRow selectedRow: FormBaseCell) { + + if selectedRow.rowDescriptor.value == nil { + if let row = selectedRow as? FormPickerCell { + let options = selectedRow.rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray + let optionValue = options?[0] as? NSObject + selectedRow.rowDescriptor.value = optionValue + row.valueLabel.text = selectedRow.rowDescriptor.titleForOptionValue(optionValue!) + row.hiddenTextField.becomeFirstResponder() + } + } else { + if let row = selectedRow as? FormPickerCell { + let optionValue = selectedRow.rowDescriptor.value + row.valueLabel.text = selectedRow.rowDescriptor.titleForOptionValue(optionValue) + row.hiddenTextField.becomeFirstResponder() + } + } + } + + /// MARK: UIPickerViewDelegate + + public func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! { + return rowDescriptor.titleForOptionAtIndex(row) + } + + public func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray + let optionValue = options?[row] as? NSObject + rowDescriptor.value = optionValue + valueLabel.text = rowDescriptor.titleForOptionValue(optionValue!) + } + + /// MARK: UIPickerViewDataSource + + public func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { + return 1 + } + + public func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + if let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + return options.count + } + return 0 + } +} diff --git a/Frameworks/SwiftForms/cells/FormSegmentedControlCell.swift b/Frameworks/SwiftForms/cells/FormSegmentedControlCell.swift new file mode 100755 index 0000000..24b1b4d --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormSegmentedControlCell.swift @@ -0,0 +1,100 @@ +// +// FormSegmentedControlCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 21/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormSegmentedControlCell: FormBaseCell { + + /// MARK: Cell views + + public let titleLabel = UILabel() + public let segmentedControl = UISegmentedControl() + + /// MARK: Properties + + private var customConstraints: [AnyObject]! + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + selectionStyle = .None + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + segmentedControl.setTranslatesAutoresizingMaskIntoConstraints(false) + + titleLabel.setContentCompressionResistancePriority(500, forAxis: .Horizontal) + segmentedControl.setContentCompressionResistancePriority(500, forAxis: .Horizontal) + + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + + contentView.addSubview(titleLabel) + contentView.addSubview(segmentedControl) + + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: segmentedControl, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + + segmentedControl.addTarget(self, action: "valueChanged:", forControlEvents: .ValueChanged) + } + + public override func update() { + super.update() + + titleLabel.text = rowDescriptor.title + updateSegmentedControl() + + var idx = 0 + if rowDescriptor.value != nil { + if let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + for optionValue in options { + if optionValue as! NSObject == rowDescriptor.value { + segmentedControl.selectedSegmentIndex = idx + break + } + ++idx + } + } + } + } + + public override func constraintsViews() -> [String : UIView] { + return ["titleLabel" : titleLabel, "segmentedControl" : segmentedControl] + } + + public override func defaultVisualConstraints() -> [String] { + + if titleLabel.text != nil && count(titleLabel.text!) > 0 { + return ["H:|-16-[titleLabel]-16-[segmentedControl]-16-|"] + } + else { + return ["H:|-16-[segmentedControl]-16-|"] + } + } + + /// MARK: Actions + + internal func valueChanged(sender: UISegmentedControl) { + let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray + let optionValue = options?[sender.selectedSegmentIndex] as? NSObject + rowDescriptor.value = optionValue + } + + /// MARK: Private + + private func updateSegmentedControl() { + segmentedControl.removeAllSegments() + var idx = 0 + if let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + for optionValue in options { + segmentedControl.insertSegmentWithTitle(rowDescriptor.titleForOptionValue(optionValue as! NSObject), atIndex: idx, animated: false) + ++idx + } + } + } +} diff --git a/Frameworks/SwiftForms/cells/FormSelectorCell.swift b/Frameworks/SwiftForms/cells/FormSelectorCell.swift new file mode 100755 index 0000000..ec78a2d --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormSelectorCell.swift @@ -0,0 +1,80 @@ +// +// FormSelectorCell.swift +// SwiftForms +// +// Created by Miguel Ángel Ortuño Ortuño on 23/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormSelectorCell: FormValueCell { + + /// MARK: FormBaseCell + + public override func update() { + super.update() + + titleLabel.text = rowDescriptor.title + + var title: String! + + if let selectedValues = rowDescriptor.value as? NSArray { // multiple values + + let indexedSelectedValues = NSSet(array: selectedValues as [AnyObject]) + + if let options = rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + for optionValue in options { + if indexedSelectedValues.containsObject(optionValue) { + let optionTitle = rowDescriptor.titleForOptionValue(optionValue as! NSObject) + if title != nil { + title = title + ", \(optionTitle)" + } + else { + title = optionTitle + } + } + } + } + } + else if let selectedValue = rowDescriptor.value { // single value + title = rowDescriptor.titleForOptionValue(selectedValue) + } + + if title != nil && count(title) > 0 { + valueLabel.text = title + valueLabel.textColor = UIColor.blackColor() + } + else { + valueLabel.text = rowDescriptor.configuration[FormRowDescriptor.Configuration.Placeholder] as? String + valueLabel.textColor = UIColor.lightGrayColor() + } + } + + public override class func formViewController(formViewController: FormViewController, didSelectRow selectedRow: FormBaseCell) { + if let row = selectedRow as? FormSelectorCell { + + formViewController.view.endEditing(true) + + var selectorClass: UIViewController.Type! + + if let selectorControllerClass: AnyClass = row.rowDescriptor.configuration[FormRowDescriptor.Configuration.SelectorControllerClass] as? AnyClass { + selectorClass = selectorControllerClass as? UIViewController.Type + } + else { // fallback to default cell class + selectorClass = FormOptionsSelectorController.self + } + + if selectorClass != nil { + let selectorController = selectorClass() + if let formRowDescriptorViewController = selectorController as? FormSelector { + formRowDescriptorViewController.formCell = row + formViewController.navigationController?.pushViewController(selectorController, animated: true) + } + else { + fatalError("FormRowDescriptor.Configuration.SelectorControllerClass must conform to FormSelector protocol.") + } + } + } + } +} diff --git a/Frameworks/SwiftForms/cells/FormSliderCell.swift b/Frameworks/SwiftForms/cells/FormSliderCell.swift new file mode 100755 index 0000000..333a21b --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormSliderCell.swift @@ -0,0 +1,81 @@ +// +// FormSliderCell.swift +// SwiftFormsApplication +// +// Created by Miguel Angel Ortuno Ortuno on 23/5/15. +// Copyright (c) 2015 Miguel Angel Ortuno Ortuno. All rights reserved. +// + +public class FormSliderCell: FormTitleCell { + + /// MARK: Cell views + + public let sliderView = UISlider() + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + selectionStyle = .None + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + sliderView.setTranslatesAutoresizingMaskIntoConstraints(false) + + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + + contentView.addSubview(titleLabel) + contentView.addSubview(sliderView) + + titleLabel.setContentHuggingPriority(500, forAxis: .Horizontal) + + contentView.addConstraint(NSLayoutConstraint(item: sliderView, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + + sliderView.addTarget(self, action: "valueChanged:", forControlEvents: .ValueChanged) + } + + public override func update() { + super.update() + + if let maximumValue = rowDescriptor.configuration[FormRowDescriptor.Configuration.MaximumValue] as? Float { + sliderView.maximumValue = maximumValue + } + + if let minimumValue = rowDescriptor.configuration[FormRowDescriptor.Configuration.MinimumValue] as? Float { + sliderView.minimumValue = minimumValue + } + + if let continuous = rowDescriptor.configuration[FormRowDescriptor.Configuration.Continuous] as? Bool { + sliderView.continuous = continuous + } + + titleLabel.text = rowDescriptor.title + + if rowDescriptor.value != nil { + sliderView.value = rowDescriptor.value as! Float + } + else { + sliderView.value = sliderView.minimumValue + rowDescriptor.value = sliderView.minimumValue + } + } + + public override func constraintsViews() -> [String : UIView] { + return ["titleLabel" : titleLabel, "sliderView" : sliderView] + } + + public override func defaultVisualConstraints() -> [String] { + var constraints: [String] = [] + + constraints.append("V:|[titleLabel]|") + constraints.append("H:|-16-[titleLabel]-16-[sliderView]-16-|") + + return constraints + } + + /// MARK: Actions + + internal func valueChanged(_: UISlider) { + rowDescriptor.value = sliderView.value + } +} diff --git a/Frameworks/SwiftForms/cells/FormStepperCell.swift b/Frameworks/SwiftForms/cells/FormStepperCell.swift new file mode 100755 index 0000000..1335acb --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormStepperCell.swift @@ -0,0 +1,89 @@ +// +// FormStepperCell.swift +// SwiftFormsApplication +// +// Created by Miguel Angel Ortuno Ortuno on 23/5/15. +// Copyright (c) 2015 Miguel Angel Ortuno Ortuno. All rights reserved. +// + +public class FormStepperCell: FormTitleCell { + + /// MARK: Cell views + + public let stepperView = UIStepper() + public let countLabel = UILabel() + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + selectionStyle = .None + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + stepperView.setTranslatesAutoresizingMaskIntoConstraints(false) + countLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + countLabel.textAlignment = .Right + + contentView.addSubview(titleLabel) + contentView.addSubview(countLabel) + contentView.addSubview(stepperView) + + titleLabel.setContentHuggingPriority(500, forAxis: .Horizontal) + + contentView.addConstraint(NSLayoutConstraint(item: stepperView, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + + stepperView.addTarget(self, action: "valueChanged:", forControlEvents: .ValueChanged) + } + + public override func update() { + super.update() + + if let maximumValue = rowDescriptor.configuration[FormRowDescriptor.Configuration.MaximumValue] as? Double { + stepperView.maximumValue = maximumValue + } + + if let minimumValue = rowDescriptor.configuration[FormRowDescriptor.Configuration.MinimumValue] as? Double { + stepperView.minimumValue = minimumValue + } + + if let steps = rowDescriptor.configuration[FormRowDescriptor.Configuration.Steps] as? Double { + stepperView.stepValue = steps + } + + titleLabel.text = rowDescriptor.title + + if rowDescriptor.value != nil { + stepperView.value = rowDescriptor.value as! Double + } + else { + stepperView.value = stepperView.minimumValue + rowDescriptor.value = stepperView.minimumValue + } + + countLabel.text = rowDescriptor.value.description + } + + public override func constraintsViews() -> [String : UIView] { + return ["titleLabel" : titleLabel, "countLabel" : countLabel, "stepperView" : stepperView] + } + + public override func defaultVisualConstraints() -> [String] { + var constraints: [String] = [] + + constraints.append("V:|[titleLabel]|") + constraints.append("V:|[countLabel]|") + + constraints.append("H:|-16-[titleLabel][countLabel]-[stepperView]-16-|") + return constraints + } + + /// MARK: Actions + + internal func valueChanged(_: UISwitch) { + rowDescriptor.value = stepperView.value + countLabel.text = rowDescriptor.value.description + } +} diff --git a/Frameworks/SwiftForms/cells/FormSwitchCell.swift b/Frameworks/SwiftForms/cells/FormSwitchCell.swift new file mode 100755 index 0000000..75bbf14 --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormSwitchCell.swift @@ -0,0 +1,49 @@ +// +// FormSwitchCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 21/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormSwitchCell: FormTitleCell { + + /// MARK: Cell views + + public let switchView = UISwitch() + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + selectionStyle = .None + + switchView.addTarget(self, action: "valueChanged:", forControlEvents: .ValueChanged) + accessoryView = switchView + } + + public override func update() { + super.update() + + titleLabel.text = rowDescriptor.title + + if rowDescriptor.value != nil { + switchView.on = rowDescriptor.value as! Bool + } + else { + switchView.on = false + rowDescriptor.value = false + } + } + + /// MARK: Actions + + internal func valueChanged(_: UISwitch) { + if switchView.on != rowDescriptor.value { + rowDescriptor.value = switchView.on as Bool + } + } +} diff --git a/Frameworks/SwiftForms/cells/FormTextFieldCell.swift b/Frameworks/SwiftForms/cells/FormTextFieldCell.swift new file mode 100755 index 0000000..fa546d3 --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormTextFieldCell.swift @@ -0,0 +1,153 @@ +// +// FormTextFieldCell.swift +// SwiftForms +// +// Created by Miguel Ángel Ortuño Ortuño on 20/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormTextFieldCell: FormBaseCell { + + /// MARK: Cell views + + public let titleLabel = UILabel() + public let textField = UITextField() + + /// MARK: Properties + + private var customConstraints: [AnyObject]! + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + selectionStyle = .None + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + textField.setTranslatesAutoresizingMaskIntoConstraints(false) + + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + textField.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + + contentView.addSubview(titleLabel) + contentView.addSubview(textField) + + titleLabel.setContentHuggingPriority(500, forAxis: .Horizontal) + titleLabel.setContentCompressionResistancePriority(1000, forAxis: .Horizontal) + + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .Height, relatedBy: .Equal, toItem: contentView, attribute: .Height, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Height, relatedBy: .Equal, toItem: contentView, attribute: .Height, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + + textField.addTarget(self, action: "editingChanged:", forControlEvents: .EditingChanged) + } + + public override func update() { + super.update() + + if let showsInputToolbar = rowDescriptor.configuration[FormRowDescriptor.Configuration.ShowsInputToolbar] as? Bool { + if showsInputToolbar && textField.inputAccessoryView == nil { + textField.inputAccessoryView = inputAccesoryView() + } + } + + titleLabel.text = rowDescriptor.title + textField.text = rowDescriptor.value as? String + textField.placeholder = rowDescriptor.configuration[FormRowDescriptor.Configuration.Placeholder] as? String + + textField.secureTextEntry = false + textField.clearButtonMode = .WhileEditing + + switch rowDescriptor.rowType { + case .Text: + textField.autocorrectionType = .Default + textField.autocapitalizationType = .Sentences + textField.keyboardType = .Default + case .Number: + textField.keyboardType = .NumberPad + case .NumbersAndPunctuation: + textField.keyboardType = .NumbersAndPunctuation + case .Decimal: + textField.keyboardType = .DecimalPad + case .Name: + textField.autocorrectionType = .No + textField.autocapitalizationType = .Words + textField.keyboardType = .Default + case .Phone: + textField.keyboardType = .PhonePad + case .NamePhone: + textField.autocorrectionType = .No + textField.autocapitalizationType = .Words + textField.keyboardType = .NamePhonePad + case .URL: + textField.autocorrectionType = .No + textField.autocapitalizationType = .None + textField.keyboardType = .URL + case .Twitter: + textField.autocorrectionType = .No + textField.autocapitalizationType = .None + textField.keyboardType = .Twitter + case .Email: + textField.autocorrectionType = .No + textField.autocapitalizationType = .None + textField.keyboardType = .EmailAddress + case .ASCIICapable: + textField.autocorrectionType = .No + textField.autocapitalizationType = .None + textField.keyboardType = .ASCIICapable + case .Password: + textField.secureTextEntry = true + textField.clearsOnBeginEditing = false + default: + break + } + } + + public override func constraintsViews() -> [String : UIView] { + var views = ["titleLabel" : titleLabel, "textField" : textField] + if self.imageView!.image != nil { + views["imageView"] = imageView + } + return views + } + + public override func defaultVisualConstraints() -> [String] { + + if self.imageView!.image != nil { + + if titleLabel.text != nil && count(titleLabel.text!) > 0 { + return ["H:[imageView]-[titleLabel]-[textField]-16-|"] + } + else { + return ["H:[imageView]-[textField]-16-|"] + } + } + else { + if titleLabel.text != nil && count(titleLabel.text!) > 0 { + return ["H:|-16-[titleLabel]-[textField]-16-|"] + } + else { + return ["H:|-16-[textField]-16-|"] + } + } + } + + public override func firstResponderElement() -> UIResponder? { + return textField + } + + public override class func formRowCanBecomeFirstResponder() -> Bool { + return true + } + + /// MARK: Actions + + internal func editingChanged(sender: UITextField) { + let trimmedText = sender.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + rowDescriptor.value = count(trimmedText) > 0 ? trimmedText : nil + } +} diff --git a/Frameworks/SwiftForms/cells/FormTextViewCell.swift b/Frameworks/SwiftForms/cells/FormTextViewCell.swift new file mode 100755 index 0000000..e3874ee --- /dev/null +++ b/Frameworks/SwiftForms/cells/FormTextViewCell.swift @@ -0,0 +1,99 @@ +// +// FormTextViewCell.swift +// SwiftForms +// +// Created by Joey Padot on 12/6/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormTextViewCell : FormBaseCell, UITextViewDelegate { + + /// MARK: Cell views + + public let titleLabel = UILabel() + public let textField = UITextView() + + /// MARK: Properties + + private var customConstraints: [AnyObject]! + + /// MARK: Class Funcs + public override class func formRowCellHeight() -> CGFloat { + return 110.0 + } + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + selectionStyle = .None + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + textField.setTranslatesAutoresizingMaskIntoConstraints(false) + + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + textField.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + + contentView.addSubview(titleLabel) + contentView.addSubview(textField) + + titleLabel.setContentHuggingPriority(500, forAxis: .Horizontal) + + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .Height, relatedBy: .Equal, toItem: contentView, attribute: .Height, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Top, relatedBy: .Equal, toItem: contentView, attribute: .Top, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: textField, attribute: .Bottom, relatedBy: .Equal, toItem: contentView, attribute: .Bottom, multiplier: 1.0, constant: 0.0)) + + textField.delegate = self + } + + public override func update() { + + titleLabel.text = rowDescriptor.title + textField.text = rowDescriptor.value as? String + + textField.secureTextEntry = false + textField.autocorrectionType = .Default + textField.autocapitalizationType = .Sentences + textField.keyboardType = .Default + } + + public override func constraintsViews() -> [String : UIView] { + var views = ["titleLabel" : titleLabel, "textField" : textField] + if self.imageView!.image != nil { + views["imageView"] = imageView + } + return views + } + + public override func defaultVisualConstraints() -> [String] { + + if self.imageView!.image != nil { + + if titleLabel.text != nil && count(titleLabel.text!) > 0 { + return ["H:[imageView]-[titleLabel]-[textField]-16-|"] + } + else { + return ["H:[imageView]-[textField]-16-|"] + } + } + else { + if titleLabel.text != nil && count(titleLabel.text!) > 0 { + return ["H:|-16-[titleLabel]-[textField]-16-|"] + } + else { + return ["H:|-16-[textField]-16-|"] + } + } + } + + /// MARK: UITextViewDelegate + + public func textViewDidChange(textView: UITextView) { + let trimmedText = textView.text.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + rowDescriptor.value = count(trimmedText) > 0 ? trimmedText : nil + } +} diff --git a/Frameworks/SwiftForms/cells/base/FormBaseCell.swift b/Frameworks/SwiftForms/cells/base/FormBaseCell.swift new file mode 100755 index 0000000..26a4983 --- /dev/null +++ b/Frameworks/SwiftForms/cells/base/FormBaseCell.swift @@ -0,0 +1,121 @@ +// +// FormBaseCell.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 20/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormBaseCell: UITableViewCell { + + /// MARK: Properties + + var rowDescriptor: FormRowDescriptor! { + didSet { + self.update() + } + } + + public weak var formViewController: FormViewController! + + private var customConstraints: [AnyObject] = [] + + /// MARK: Init + + public required override init(style: UITableViewCellStyle, reuseIdentifier: String!) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + /// MARK: Public interface + + public func configure() { + /// override + } + + public func update() { + /// override + } + + public func defaultVisualConstraints() -> [String] { + /// override + return [] + } + + public func constraintsViews() -> [String : UIView] { + /// override + return [:] + } + + public func firstResponderElement() -> UIResponder? { + /// override + return nil + } + + public func inputAccesoryView() -> UIToolbar { + + let actionBar = UIToolbar() + actionBar.translucent = true + actionBar.sizeToFit() + actionBar.barStyle = .Default + + let doneButton = UIBarButtonItem(title: NSLocalizedString("Done", comment: ""), style: .Done, target: self, action: "handleDoneAction:") + + let flexible = UIBarButtonItem(barButtonSystemItem: .FlexibleSpace, target: nil, action: nil) + actionBar.items = [flexible, doneButton] + + return actionBar + } + + internal func handleDoneAction(_: UIBarButtonItem) { + firstResponderElement()?.resignFirstResponder() + } + + public class func formRowCellHeight() -> CGFloat { + return 44.0 + } + + public class func formRowCanBecomeFirstResponder() -> Bool { + return false + } + + public class func formViewController(formViewController: FormViewController, didSelectRow: FormBaseCell) { + } + + /// MARK: Constraints + + public override func updateConstraints() { + + if customConstraints.count > 0 { + contentView.removeConstraints(customConstraints) + } + + var views = constraintsViews() + + customConstraints.removeAll() + + var visualConstraints: NSArray! + + if let visualConstraintsClosure = rowDescriptor.configuration[FormRowDescriptor.Configuration.VisualConstraintsClosure] as? VisualConstraintsClosure { + visualConstraints = visualConstraintsClosure(self) + } + else { + visualConstraints = self.defaultVisualConstraints() + } + + for visualConstraint in visualConstraints { + let constraints = NSLayoutConstraint.constraintsWithVisualFormat(visualConstraint as! String, options: NSLayoutFormatOptions(0), metrics: nil, views: views) + for constraint in constraints { + customConstraints.append(constraint) + } + } + + contentView.addConstraints(customConstraints) + super.updateConstraints() + } +} diff --git a/Frameworks/SwiftForms/cells/base/FormTitleCell.swift b/Frameworks/SwiftForms/cells/base/FormTitleCell.swift new file mode 100755 index 0000000..2217e20 --- /dev/null +++ b/Frameworks/SwiftForms/cells/base/FormTitleCell.swift @@ -0,0 +1,38 @@ +// +// FormTitleCell.swift +// SwiftForms +// +// Created by Miguel Ángel Ortuño Ortuño on 13/11/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormTitleCell: FormBaseCell { + + /// MARK: Cell views + + public let titleLabel = UILabel() + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + + // apply constant constraints + contentView.addSubview(titleLabel) + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .Height, relatedBy: .Equal, toItem: contentView, attribute: .Height, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + } + + public override func constraintsViews() -> [String : UIView] { + return ["titleLabel" : titleLabel] + } + + public override func defaultVisualConstraints() -> [String] { + return ["H:|-16-[titleLabel]-16-|"] + } +} diff --git a/Frameworks/SwiftForms/cells/base/FormValueCell.swift b/Frameworks/SwiftForms/cells/base/FormValueCell.swift new file mode 100755 index 0000000..6953c34 --- /dev/null +++ b/Frameworks/SwiftForms/cells/base/FormValueCell.swift @@ -0,0 +1,70 @@ +// +// FormValueCell.swift +// SwiftForms +// +// Created by Miguel Ángel Ortuño Ortuño on 13/11/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormValueCell: FormBaseCell { + + /// MARK: Cell views + + public let titleLabel = UILabel() + public let valueLabel = UILabel() + + /// MARK: Properties + + private var customConstraints: [AnyObject]! + + /// MARK: FormBaseCell + + public override func configure() { + super.configure() + + accessoryType = .DisclosureIndicator + + titleLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + valueLabel.setTranslatesAutoresizingMaskIntoConstraints(false) + + titleLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + valueLabel.font = UIFont.preferredFontForTextStyle(UIFontTextStyleBody) + + valueLabel.textColor = UIColor.lightGrayColor() + valueLabel.textAlignment = .Right + + contentView.addSubview(titleLabel) + contentView.addSubview(valueLabel) + + titleLabel.setContentHuggingPriority(500, forAxis: .Horizontal) + titleLabel.setContentCompressionResistancePriority(1000, forAxis: .Horizontal) + + // apply constant constraints + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .Height, relatedBy: .Equal, toItem: contentView, attribute: .Height, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: valueLabel, attribute: .Height, relatedBy: .Equal, toItem: contentView, attribute: .Height, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: titleLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + contentView.addConstraint(NSLayoutConstraint(item: valueLabel, attribute: .CenterY, relatedBy: .Equal, toItem: contentView, attribute: .CenterY, multiplier: 1.0, constant: 0.0)) + } + + public override func constraintsViews() -> [String : UIView] { + return ["titleLabel" : titleLabel, "valueLabel" : valueLabel] + } + + public override func defaultVisualConstraints() -> [String] { + + // apply default constraints + var rightPadding = 0 + if accessoryType == .None { + rightPadding = 16 + } + + if titleLabel.text != nil && count(titleLabel.text!) > 0 { + return ["H:|-16-[titleLabel]-[valueLabel]-\(rightPadding)-|"] + } + else { + return ["H:|-16-[valueLabel]-\(rightPadding)-|"] + } + } +} diff --git a/Frameworks/SwiftForms/controllers/FormOptionsSelectorController.swift b/Frameworks/SwiftForms/controllers/FormOptionsSelectorController.swift new file mode 100755 index 0000000..d609a69 --- /dev/null +++ b/Frameworks/SwiftForms/controllers/FormOptionsSelectorController.swift @@ -0,0 +1,150 @@ +// +// FormOptionsSelectorController.swift +// SwiftForms +// +// Created by Miguel Ángel Ortuño Ortuño on 23/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormOptionsSelectorController: UITableViewController, FormSelector { + + /// MARK: FormSelector + + public var formCell: FormBaseCell! + + /// MARK: Init + + public init() { + super.init(style: .Grouped) + } + + public required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + } + + public override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.title = formCell.rowDescriptor.title + } + + /// MARK: UITableViewDataSource + + public override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return 1 + } + + public override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + if let options = formCell.rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + return options.count + } + return 0 + } + + public override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { + return 0.1 + } + + public override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + + let reuseIdentifier = NSStringFromClass(self.dynamicType) + + var cell = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as? UITableViewCell + if cell == nil { + cell = UITableViewCell(style: .Default, reuseIdentifier: reuseIdentifier) + } + + let options = formCell.rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as! NSArray + let optionValue = options[indexPath.row] as! NSObject + + cell!.textLabel!.text = formCell.rowDescriptor.titleForOptionValue(optionValue) + + if let selectedOptions = formCell.rowDescriptor.value as? [NSObject] { + if (find(selectedOptions, optionValue as NSObject) != nil) { + + if let checkMarkAccessoryView = formCell.rowDescriptor.configuration[FormRowDescriptor.Configuration.CheckmarkAccessoryView] as? UIView { + cell!.accessoryView = checkMarkAccessoryView + } + else { + cell!.accessoryType = .Checkmark + } + } + else { + cell!.accessoryType = .None + } + } + else if let selectedOption = formCell.rowDescriptor.value { + if optionValue == selectedOption { + cell!.accessoryType = .Checkmark + } + else { + cell!.accessoryType = .None + } + } + return cell! + } + + /// MARK: UITableViewDelegate + + public override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + + let cell = tableView.cellForRowAtIndexPath(indexPath) + + var allowsMultipleSelection = false + if let allowsMultipleSelectionValue = formCell.rowDescriptor.configuration[FormRowDescriptor.Configuration.AllowsMultipleSelection] as? Bool { + allowsMultipleSelection = allowsMultipleSelectionValue + } + + let options = formCell.rowDescriptor.configuration[FormRowDescriptor.Configuration.Options] as! NSArray + let optionValue = options[indexPath.row] as! NSObject + + if allowsMultipleSelection { + + if formCell.rowDescriptor.value == nil { + formCell.rowDescriptor.value = NSMutableArray() + } + + if var selectedOptions = formCell.rowDescriptor.value as? NSMutableArray { + + if selectedOptions.containsObject(optionValue) { + selectedOptions.removeObject(optionValue) + cell?.accessoryType = .None + } + else { + selectedOptions.addObject(optionValue) + + if let checkmarkAccessoryView = formCell.rowDescriptor.configuration[FormRowDescriptor.Configuration.CheckmarkAccessoryView] as? UIView { + cell?.accessoryView = checkmarkAccessoryView + } + else { + cell?.accessoryType = .Checkmark + } + } + + if selectedOptions.count > 0 { + formCell.rowDescriptor.value = selectedOptions + } + else { + formCell.rowDescriptor.value = nil + } + } + } + else { + formCell.rowDescriptor.value = NSMutableArray(object: optionValue) + } + + formCell.update() + + if allowsMultipleSelection { + tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + else { + self.navigationController?.popViewControllerAnimated(true) + } + } +} diff --git a/Frameworks/SwiftForms/controllers/FormSelector.swift b/Frameworks/SwiftForms/controllers/FormSelector.swift new file mode 100755 index 0000000..96fc88e --- /dev/null +++ b/Frameworks/SwiftForms/controllers/FormSelector.swift @@ -0,0 +1,13 @@ +// +// FormSelector.swift +// SwiftForms +// +// Created by Miguel Ángel Ortuño Ortuño on 23/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +@objc public protocol FormSelector: NSObjectProtocol { + var formCell: FormBaseCell! { get set } +} diff --git a/Frameworks/SwiftForms/controllers/FormViewController.swift b/Frameworks/SwiftForms/controllers/FormViewController.swift new file mode 100755 index 0000000..1cd7edc --- /dev/null +++ b/Frameworks/SwiftForms/controllers/FormViewController.swift @@ -0,0 +1,218 @@ +// +// FormViewController.swift +// SwiftForms +// +// Created by Miguel Angel Ortuño on 20/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormViewController : UITableViewController { + + /// MARK: Types + + private struct Static { + static var onceDefaultCellClass: dispatch_once_t = 0 + static var defaultCellClasses: [FormRowType : FormBaseCell.Type] = [:] + } + + /// MARK: Properties + + public var form: FormDescriptor! + + /// MARK: Init + + public convenience init() { + self.init(style: .Grouped) + } + + public convenience init(form: FormDescriptor) { + self.init() + self.form = form + } + + public override init(style: UITableViewStyle) { + super.init(style: style) + } + + public override init(nibName nibNameOrNil: String!, bundle nibBundleOrNil: NSBundle!) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + baseInit() + } + + public required init(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + baseInit() + } + + private func baseInit() { + } + + /// MARK: View life cycle + + public override func viewDidLoad() { + super.viewDidLoad() + assert(form != nil, "self.form property MUST be assigned!") + navigationItem.title = form.title + } + + /// MARK: Public interface + + public func valueForTag(tag: String) -> NSObject! { + for section in form.sections { + for row in section.rows { + if row.tag == tag { + return row.value + } + } + } + return nil + } + + public func setValue(value: NSObject, forTag tag: String) { + + var sectionIndex = 0 + var rowIndex = 0 + + for section in form.sections { + for row in section.rows { + if row.tag == tag { + row.value = value + if let cell = self.tableView.cellForRowAtIndexPath(NSIndexPath(forRow: rowIndex, inSection: sectionIndex)) as? FormBaseCell { + cell.update() + } + return + } + ++rowIndex + } + ++sectionIndex + } + } + + /// MARK: UITableViewDataSource + + public override func numberOfSectionsInTableView(tableView: UITableView) -> Int { + return form.sections.count + } + + public override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return form.sections[section].rows.count + } + + public override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { + + let rowDescriptor = formRowDescriptorAtIndexPath(indexPath) + + var formBaseCellClass = formBaseCellClassFromRowDescriptor(rowDescriptor) + + let reuseIdentifier = NSStringFromClass(formBaseCellClass) + + var cell: FormBaseCell? = tableView.dequeueReusableCellWithIdentifier(reuseIdentifier) as? FormBaseCell + if cell == nil { + + cell = formBaseCellClass(style: .Default, reuseIdentifier: reuseIdentifier) + cell?.formViewController = self + cell?.configure() + } + + cell?.rowDescriptor = rowDescriptor + + // apply cell custom design + if let cellConfiguration = rowDescriptor.configuration[FormRowDescriptor.Configuration.CellConfiguration] as? NSDictionary { + for (keyPath, value) in cellConfiguration { + cell?.setValue(value, forKeyPath: keyPath as! String) + } + } + return cell! + } + + public override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + return form.sections[section].headerTitle + } + + public override func tableView(tableView: UITableView, titleForFooterInSection section: Int) -> String? { + return form.sections[section].footerTitle + } + + /// MARK: UITableViewDelegate + + public override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { + + let rowDescriptor = formRowDescriptorAtIndexPath(indexPath) + + if let formBaseCellClass = formBaseCellClassFromRowDescriptor(rowDescriptor) { + return formBaseCellClass.formRowCellHeight() + } + return super.tableView(tableView, heightForRowAtIndexPath: indexPath) + } + + public override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { + + let rowDescriptor = formRowDescriptorAtIndexPath(indexPath) + + if let selectedRow = tableView.cellForRowAtIndexPath(indexPath) as? FormBaseCell { + if let formBaseCellClass = formBaseCellClassFromRowDescriptor(rowDescriptor) { + formBaseCellClass.formViewController(self, didSelectRow: selectedRow) + } + } + + if let didSelectClosure = rowDescriptor.configuration[FormRowDescriptor.Configuration.DidSelectClosure] as? DidSelectClosure { + didSelectClosure() + } + + tableView.deselectRowAtIndexPath(indexPath, animated: true) + } + + private class func defaultCellClassForRowType(rowType: FormRowType) -> FormBaseCell.Type { + dispatch_once(&Static.onceDefaultCellClass) { + Static.defaultCellClasses[FormRowType.Text] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Number] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.NumbersAndPunctuation] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Decimal] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Name] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Phone] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.URL] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Twitter] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.NamePhone] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Email] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.ASCIICapable] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Password] = FormTextFieldCell.self + Static.defaultCellClasses[FormRowType.Button] = FormButtonCell.self + Static.defaultCellClasses[FormRowType.BooleanSwitch] = FormSwitchCell.self + Static.defaultCellClasses[FormRowType.BooleanCheck] = FormCheckCell.self + Static.defaultCellClasses[FormRowType.SegmentedControl] = FormSegmentedControlCell.self + Static.defaultCellClasses[FormRowType.Picker] = FormPickerCell.self + Static.defaultCellClasses[FormRowType.Date] = FormDateCell.self + Static.defaultCellClasses[FormRowType.Time] = FormDateCell.self + Static.defaultCellClasses[FormRowType.DateAndTime] = FormDateCell.self + Static.defaultCellClasses[FormRowType.Stepper] = FormStepperCell.self + Static.defaultCellClasses[FormRowType.Slider] = FormSliderCell.self + Static.defaultCellClasses[FormRowType.MultipleSelector] = FormSelectorCell.self + Static.defaultCellClasses[FormRowType.MultilineText] = FormTextViewCell.self + } + return Static.defaultCellClasses[rowType]! + } + + private func formRowDescriptorAtIndexPath(indexPath: NSIndexPath!) -> FormRowDescriptor { + let section = form.sections[indexPath.section] + let rowDescriptor = section.rows[indexPath.row] + return rowDescriptor + } + + private func formBaseCellClassFromRowDescriptor(rowDescriptor: FormRowDescriptor) -> FormBaseCell.Type! { + + var formBaseCellClass: FormBaseCell.Type! + + if let cellClass: AnyClass = rowDescriptor.configuration[FormRowDescriptor.Configuration.CellClass] as? AnyClass { + formBaseCellClass = cellClass as? FormBaseCell.Type + } + else { + formBaseCellClass = FormViewController.defaultCellClassForRowType(rowDescriptor.rowType) + } + + assert(formBaseCellClass != nil, "FormRowDescriptor.Configuration.CellClass must be a FormBaseCell derived class value.") + + return formBaseCellClass + } +} diff --git a/Frameworks/SwiftForms/descriptors/FormDescriptor.swift b/Frameworks/SwiftForms/descriptors/FormDescriptor.swift new file mode 100755 index 0000000..3fdaa54 --- /dev/null +++ b/Frameworks/SwiftForms/descriptors/FormDescriptor.swift @@ -0,0 +1,62 @@ +// +// FormDescriptor.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 20/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormDescriptor: NSObject { + + /// MARK: Properties + + public var title: String! + + public var sections: [FormSectionDescriptor] = [] + + /// MARK: Public + + public func addSection(section: FormSectionDescriptor) { + sections.append(section) + } + + public func removeSection(section: FormSectionDescriptor) { + if let index = find(sections, section) { + sections.removeAtIndex(index) + } + } + + public func formValues() -> NSDictionary { + + var formValues = NSMutableDictionary() + + for section in sections { + for row in section.rows { + if row.tag != nil && row.rowType != .Button { + if row.value != nil { + formValues[row.tag!] = row.value! + } + else { + formValues[row.tag!] = NSNull() + } + } + } + } + return formValues.copy() as! NSDictionary + } + + public func validateForm() -> FormRowDescriptor! { + for section in sections { + for row in section.rows { + if let required = row.configuration[FormRowDescriptor.Configuration.Required] as? Bool { + if required && row.value == nil { + return row + } + } + } + } + return nil + } +} diff --git a/Frameworks/SwiftForms/descriptors/FormRowDescriptor.swift b/Frameworks/SwiftForms/descriptors/FormRowDescriptor.swift new file mode 100755 index 0000000..e72a463 --- /dev/null +++ b/Frameworks/SwiftForms/descriptors/FormRowDescriptor.swift @@ -0,0 +1,142 @@ +// +// FormRowDescriptor.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 20/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public enum FormRowType { + case Unknown + case Text + case URL + case Number + case NumbersAndPunctuation + case Decimal + case Name + case Phone + case NamePhone + case Email + case Twitter + case ASCIICapable + case Password + case Button + case BooleanSwitch + case BooleanCheck + case SegmentedControl + case Picker + case Date + case Time + case DateAndTime + case Stepper + case Slider + case MultipleSelector + case MultilineText +} + +public typealias DidSelectClosure = (Void) -> Void +public typealias UpdateClosure = (FormRowDescriptor) -> Void +public typealias TitleFormatterClosure = (NSObject) -> String! +public typealias VisualConstraintsClosure = (FormBaseCell) -> NSArray + +public class FormRowDescriptor: NSObject { + + /// MARK: Types + + public struct Configuration { + public static let Required = "FormRowDescriptorConfigurationRequired" + + public static let CellClass = "FormRowDescriptorConfigurationCellClass" + public static let CheckmarkAccessoryView = "FormRowDescriptorConfigurationCheckmarkAccessoryView" + public static let CellConfiguration = "FormRowDescriptorConfigurationCellConfiguration" + + public static let Placeholder = "FormRowDescriptorConfigurationPlaceholder" + + public static let WillUpdateClosure = "FormRowDescriptorConfigurationWillUpdateClosure" + public static let DidUpdateClosure = "FormRowDescriptorConfigurationDidUpdateClosure" + + public static let MaximumValue = "FormRowDescriptorConfigurationMaximumValue" + public static let MinimumValue = "FormRowDescriptorConfigurationMinimumValue" + public static let Steps = "FormRowDescriptorConfigurationSteps" + + public static let Continuous = "FormRowDescriptorConfigurationContinuous" + + public static let DidSelectClosure = "FormRowDescriptorConfigurationDidSelectClosure" + + public static let VisualConstraintsClosure = "FormRowDescriptorConfigurationVisualConstraintsClosure" + + public static let Options = "FormRowDescriptorConfigurationOptions" + + public static let TitleFormatterClosure = "FormRowDescriptorConfigurationTitleFormatterClosure" + + public static let SelectorControllerClass = "FormRowDescriptorConfigurationSelectorControllerClass" + + public static let AllowsMultipleSelection = "FormRowDescriptorConfigurationSelectorControllerClass" + + public static let ShowsInputToolbar = "FormRowDescriptorConfigurationShowsInputToolbar" + + public static let DateFormatter = "FormRowDescriptorConfigurationDateFormatter" + } + + /// MARK: Properties + + public var title: String! + public var rowType: FormRowType = .Unknown + public var tag: String! + + public var value: NSObject! { + willSet { + if let willUpdateBlock = self.configuration[Configuration.WillUpdateClosure] as? UpdateClosure { + willUpdateBlock(self) + } + } + didSet { + if let didUpdateBlock = self.configuration[Configuration.DidUpdateClosure] as? UpdateClosure { + didUpdateBlock(self) + } + } + } + + public var configuration: [NSObject : Any] = [:] + + /// MARK: Init + + public override init() { + super.init() + configuration[Configuration.Required] = true + configuration[Configuration.AllowsMultipleSelection] = false + configuration[Configuration.ShowsInputToolbar] = false + } + + public convenience init(tag: String, rowType: FormRowType, title: String, placeholder: String! = nil) { + self.init() + self.tag = tag + self.rowType = rowType + self.title = title + + if placeholder != nil { + configuration[FormRowDescriptor.Configuration.Placeholder] = placeholder + } + } + + /// MARK: Public interface + + public func titleForOptionAtIndex(index: Int) -> String! { + if let options = configuration[FormRowDescriptor.Configuration.Options] as? NSArray { + return titleForOptionValue(options[index] as! NSObject) + } + return nil + } + + public func titleForOptionValue(optionValue: NSObject) -> String! { + if let titleFormatter = configuration[FormRowDescriptor.Configuration.TitleFormatterClosure] as? TitleFormatterClosure { + return titleFormatter(optionValue) + } + else if optionValue is String { + return optionValue as! String + } + return "\(optionValue)" + } +} diff --git a/Frameworks/SwiftForms/descriptors/FormSectionDescriptor.swift b/Frameworks/SwiftForms/descriptors/FormSectionDescriptor.swift new file mode 100755 index 0000000..a5fe165 --- /dev/null +++ b/Frameworks/SwiftForms/descriptors/FormSectionDescriptor.swift @@ -0,0 +1,31 @@ +// +// FormSectionDescriptor.swift +// SwiftForms +// +// Created by Miguel Angel Ortuno on 20/08/14. +// Copyright (c) 2014 Miguel Angel Ortuño. All rights reserved. +// + +import UIKit + +public class FormSectionDescriptor: NSObject { + + /// MARK: Properties + + public var headerTitle: String! + public var footerTitle: String! + + public var rows: [FormRowDescriptor] = [] + + /// MARK: Public interface + + public func addRow(row: FormRowDescriptor) { + rows.append(row) + } + + public func removeRow(row: FormRowDescriptor) { + if let index = find(rows, row) { + rows.removeAtIndex(index) + } + } +} diff --git a/Frameworks/SwiftNotice.swift b/Frameworks/SwiftNotice.swift new file mode 100755 index 0000000..31aac06 --- /dev/null +++ b/Frameworks/SwiftNotice.swift @@ -0,0 +1,325 @@ +// +// SwiftNotice.swift +// SwiftNotice +// +// Created by JohnLui on 15/4/15. +// Copyright (c) 2015年 com.lvwenhan. All rights reserved. +// + +import Foundation +import UIKit + +extension UIViewController { + func noticeTop(text: String) { + SwiftNotice.noticeOnSatusBar(text, autoClear: true) + } + func noticeTop(text: String, autoClear: Bool) { + SwiftNotice.noticeOnSatusBar(text, autoClear: autoClear) + } + func successNotice(text: String) { + SwiftNotice.showNoticeWithText(NoticeType.success, text: text, autoClear: true) + } + func successNotice(text: String, autoClear: Bool) { + SwiftNotice.showNoticeWithText(NoticeType.success, text: text, autoClear: autoClear) + } + func errorNotice(text: String) { + SwiftNotice.showNoticeWithText(NoticeType.error, text: text, autoClear: true) + } + func errorNotice(text: String, autoClear: Bool) { + SwiftNotice.showNoticeWithText(NoticeType.error, text: text, autoClear: autoClear) + } + func infoNotice(text: String) { + SwiftNotice.showNoticeWithText(NoticeType.info, text: text, autoClear: true) + } + func infoNotice(text: String, autoClear: Bool) { + SwiftNotice.showNoticeWithText(NoticeType.info, text: text, autoClear: autoClear) + } + func notice(text: String, type: NoticeType, autoClear: Bool) { + SwiftNotice.showNoticeWithText(type, text: text, autoClear: autoClear) + } + func pleaseWait() { + SwiftNotice.wait() + } + func noticeOnlyText(text: String) { + SwiftNotice.showText(text) + } + func clearAllNotice() { + SwiftNotice.clear() + } + + // my customization + func interestedNotice(text: String, autoClear: Bool) { + SwiftNotice.showInterestedNotice(text, autoClear: autoClear) + } +} + +enum NoticeType{ + case success + case error + case info +} + +class SwiftNotice: NSObject { + + static var windows = Array() + static let rv = UIApplication.sharedApplication().keyWindow?.subviews.first as! UIView + + static func clear() { + for i in windows { + i.hidden = true + } + } + + static func noticeOnSatusBar(text: String, autoClear: Bool) { + let frame = UIApplication.sharedApplication().statusBarFrame + let window = UIWindow(frame: frame) + let view = UIView(frame: frame) + view.backgroundColor = UIColor(red: 0x6a/0x100, green: 0xb4/0x100, blue: 0x9f/0x100, alpha: 1) + + let label = UILabel(frame: frame) + label.textAlignment = NSTextAlignment.Center + label.font = UIFont.systemFontOfSize(12) + label.textColor = UIColor.whiteColor() + label.text = text + view.addSubview(label) + + window.windowLevel = UIWindowLevelStatusBar + window.hidden = false + window.addSubview(view) + windows.append(window) + + if autoClear { + let selector = Selector("hideNotice:") + self.performSelector(selector, withObject: view, afterDelay: 1) + } + } + static func wait() { + let frame = CGRectMake(0, 0, 78, 78) + let window = UIWindow(frame: frame) + let mainView = UIView(frame: frame) + mainView.layer.cornerRadius = 12 + mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.8) + + let ai = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge) + ai.frame = CGRectMake(21, 21, 36, 36) + ai.startAnimating() + mainView.addSubview(ai) + + window.windowLevel = UIWindowLevelAlert + window.center = rv.center + window.hidden = false + window.addSubview(mainView) + windows.append(window) + } + static func showText(text: String) { + let window = UIWindow() + let mainView = UIView() + mainView.layer.cornerRadius = 12 + mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.8) + + let label = UILabel() + label.text = text + label.numberOfLines = 0 + label.font = UIFont(name: "American Typerwriter", size: 12) + label.textAlignment = NSTextAlignment.Center + label.textColor = UIColor.whiteColor() + label.sizeToFit() + mainView.addSubview(label) + + let superFrame = CGRectMake(0, 0, label.frame.width + 50 , label.frame.height + 30) + window.frame = superFrame + mainView.frame = superFrame + + label.center = mainView.center + + window.windowLevel = UIWindowLevelAlert + window.center = rv.center + window.hidden = false + window.addSubview(mainView) + windows.append(window) + } + + static func showNoticeWithText(type: NoticeType,text: String, autoClear: Bool) { + let frame = CGRectMake(0, 0, 90, 90) + let window = UIWindow(frame: frame) + let mainView = UIView(frame: frame) + mainView.layer.cornerRadius = 10 + mainView.backgroundColor = UIColor(red:0, green:0, blue:0, alpha: 0.7) + + var image = UIImage() + switch type { + case .success: + image = SwiftNoticeSDK.imageOfCheckmark + case .error: + image = SwiftNoticeSDK.imageOfCross + case .info: + image = SwiftNoticeSDK.imageOfInfo + default: + break + } + let checkmarkView = UIImageView(image: image) + checkmarkView.frame = CGRectMake(27, 15, 36, 36) + mainView.addSubview(checkmarkView) + + let label = UILabel(frame: CGRectMake(0, 60, 90, 16)) + label.font = UIFont.systemFontOfSize(13) + label.textColor = UIColor.whiteColor() + label.text = text + label.textAlignment = NSTextAlignment.Center + mainView.addSubview(label) + + window.windowLevel = UIWindowLevelAlert + window.center = rv.center + window.hidden = false + window.addSubview(mainView) + windows.append(window) + + if autoClear { + let selector = Selector("hideNotice:") + self.performSelector(selector, withObject: mainView, afterDelay: 3) + } + } + + static func hideNotice(sender: AnyObject) { + if sender is UIView { + sender.removeFromSuperview() + } + } + + // my customization + + static func showInterestedNotice(text: String, autoClear: Bool) { + let frame = CGRectMake(0, 0, 90, 90) + let window = UIWindow(frame: frame) + let mainView = UIView(frame: frame) + mainView.layer.cornerRadius = 15 + mainView.layer.borderColor = UIColor.lightGrayColor().CGColor + mainView.layer.borderWidth = 0.35 + mainView.backgroundColor = UIColor.whiteColor() + mainView.alpha = 0.95 + + /* + // add blur view + var blurEffect = UIBlurEffect(style: UIBlurEffectStyle.Dark) + var blurView = UIVisualEffectView(effect: blurEffect) + blurView.frame = mainView.bounds + blurView.layer.cornerRadius = 10 + mainView.addSubview(blurView) + */ + + var image = UIImage(named: "interested icon") + let iconView = UIImageView(image: image) + iconView.frame = CGRectMake(20, 15, 50, 50) + mainView.addSubview(iconView) + + let label = UILabel(frame: CGRectMake(0, 60, 90, 20)) + label.font = UIFont(name: "American Typewriter", size: 16) + label.textColor = UIColor.grayColor() + label.text = text + label.textAlignment = NSTextAlignment.Center + mainView.addSubview(label) + + window.windowLevel = UIWindowLevelAlert + window.center = rv.center + window.hidden = false + window.addSubview(mainView) + windows.append(window) + + if autoClear { + UIView.animateWithDuration(1, delay: 1, options: UIViewAnimationOptions.CurveEaseOut, animations: { + mainView.alpha = 0.0 + }, completion: nil) + let selector = Selector("hideNotice:") + self.performSelector(selector, withObject: mainView, afterDelay: 2) + } + } +} + +class SwiftNoticeSDK { + struct Cache { + static var imageOfCheckmark: UIImage? + static var imageOfCross: UIImage? + static var imageOfInfo: UIImage? + } + class func draw(type: NoticeType) { + var checkmarkShapePath = UIBezierPath() + + // draw circle + checkmarkShapePath.moveToPoint(CGPointMake(36, 18)) + checkmarkShapePath.addArcWithCenter(CGPointMake(18, 18), radius: 17.5, startAngle: 0, endAngle: CGFloat(M_PI*2), clockwise: true) + checkmarkShapePath.closePath() + + switch type { + case .success: // draw checkmark + checkmarkShapePath.moveToPoint(CGPointMake(10, 18)) + checkmarkShapePath.addLineToPoint(CGPointMake(16, 24)) + checkmarkShapePath.addLineToPoint(CGPointMake(27, 13)) + checkmarkShapePath.moveToPoint(CGPointMake(10, 18)) + checkmarkShapePath.closePath() + case .error: // draw X + checkmarkShapePath.moveToPoint(CGPointMake(10, 10)) + checkmarkShapePath.addLineToPoint(CGPointMake(26, 26)) + checkmarkShapePath.moveToPoint(CGPointMake(10, 26)) + checkmarkShapePath.addLineToPoint(CGPointMake(26, 10)) + checkmarkShapePath.moveToPoint(CGPointMake(10, 10)) + checkmarkShapePath.closePath() + case .info: + checkmarkShapePath.moveToPoint(CGPointMake(18, 6)) + checkmarkShapePath.addLineToPoint(CGPointMake(18, 22)) + checkmarkShapePath.moveToPoint(CGPointMake(18, 6)) + checkmarkShapePath.closePath() + + UIColor.whiteColor().setStroke() + checkmarkShapePath.stroke() + + var checkmarkShapePath = UIBezierPath() + checkmarkShapePath.moveToPoint(CGPointMake(18, 27)) + checkmarkShapePath.addArcWithCenter(CGPointMake(18, 27), radius: 1, startAngle: 0, endAngle: CGFloat(M_PI*2), clockwise: true) + checkmarkShapePath.closePath() + + UIColor.whiteColor().setFill() + checkmarkShapePath.fill() + default: + break + } + + UIColor.whiteColor().setStroke() + checkmarkShapePath.stroke() + } + class var imageOfCheckmark: UIImage { + if (Cache.imageOfCheckmark != nil) { + return Cache.imageOfCheckmark! + } + UIGraphicsBeginImageContextWithOptions(CGSizeMake(36, 36), false, 0) + + SwiftNoticeSDK.draw(NoticeType.success) + + Cache.imageOfCheckmark = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return Cache.imageOfCheckmark! + } + class var imageOfCross: UIImage { + if (Cache.imageOfCross != nil) { + return Cache.imageOfCross! + } + UIGraphicsBeginImageContextWithOptions(CGSizeMake(36, 36), false, 0) + + SwiftNoticeSDK.draw(NoticeType.error) + + Cache.imageOfCross = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return Cache.imageOfCross! + } + class var imageOfInfo: UIImage { + if (Cache.imageOfInfo != nil) { + return Cache.imageOfInfo! + } + UIGraphicsBeginImageContextWithOptions(CGSizeMake(36, 36), false, 0) + + SwiftNoticeSDK.draw(NoticeType.info) + + Cache.imageOfInfo = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + return Cache.imageOfInfo! + } +}