- Added the network library with proper versioning
- Made the network adapter - Made the config file to hold the url auth
This commit is contained in:
5
Podfile
5
Podfile
@@ -6,8 +6,13 @@ target 'WOKA' do
|
||||
use_frameworks!
|
||||
|
||||
pod 'IQKeyboardManagerSwift', '~> 7.0.2'
|
||||
|
||||
# GIF Animations
|
||||
pod 'lottie-ios'
|
||||
|
||||
#Network call
|
||||
pod 'Alamofire' , '~> 5.9.6'
|
||||
|
||||
# Bottom line is for removing IPHONEOS_DEPLOYMENT_TARGET
|
||||
post_install do |installer|
|
||||
installer.generated_projects.each do |project|
|
||||
|
||||
@@ -19,6 +19,21 @@
|
||||
523ED27F2BDA2BC900CFED02 /* WOKAUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 523ED27E2BDA2BC900CFED02 /* WOKAUITests.swift */; };
|
||||
523ED2812BDA2BC900CFED02 /* WOKAUITestsLaunchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 523ED2802BDA2BC900CFED02 /* WOKAUITestsLaunchTests.swift */; };
|
||||
5257B2652BDFB6F50086D79B /* CheckPhoneHomeBtnOrNotch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5257B2642BDFB6F50086D79B /* CheckPhoneHomeBtnOrNotch.swift */; };
|
||||
525953CF2BE8B28F00191286 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525953CE2BE8B28F00191286 /* Utilities.swift */; };
|
||||
525953D12BE8B2B200191286 /* LLSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525953D02BE8B2B200191286 /* LLSpinner.swift */; };
|
||||
525953D42BE8B2DF00191286 /* UIApplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525953D32BE8B2DF00191286 /* UIApplication.swift */; };
|
||||
525954102BE8B72900191286 /* FontCustom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5259540F2BE8B72900191286 /* FontCustom.swift */; };
|
||||
525954122BE8C84900191286 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954112BE8C84900191286 /* Toast.swift */; };
|
||||
525954142BE8C87300191286 /* ExtensionVCToastAlert.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954132BE8C87300191286 /* ExtensionVCToastAlert.swift */; };
|
||||
525954172BE8CAD300191286 /* NetworkManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954162BE8CAD300191286 /* NetworkManager.swift */; };
|
||||
525954192BE8CC3400191286 /* ConstantString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954182BE8CC3400191286 /* ConstantString.swift */; };
|
||||
5259541B2BE8D6F900191286 /* NetworkReachibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5259541A2BE8D6F900191286 /* NetworkReachibility.swift */; };
|
||||
5259541D2BE8D94400191286 /* QueueHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5259541C2BE8D94400191286 /* QueueHelper.swift */; };
|
||||
5259541F2BE8E93500191286 /* Config.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 5259541E2BE8E93500191286 /* Config.xcconfig */; };
|
||||
525954212BE8EB7900191286 /* APIEndPoints.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954202BE8EB7900191286 /* APIEndPoints.swift */; };
|
||||
525954232BE8F00400191286 /* BaseResponseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954222BE8F00400191286 /* BaseResponseModel.swift */; };
|
||||
525954252BE8F01600191286 /* ValueWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954242BE8F01600191286 /* ValueWrapper.swift */; };
|
||||
525954272BE9178F00191286 /* UserDataDM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 525954262BE9178F00191286 /* UserDataDM.swift */; };
|
||||
52663FF52BDFAB830001D8CE /* TextFieldErrorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52663FF42BDFAB830001D8CE /* TextFieldErrorView.swift */; };
|
||||
52663FF72BDFACF60001D8CE /* ShadowView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52663FF62BDFACF60001D8CE /* ShadowView.swift */; };
|
||||
52663FF92BDFAF110001D8CE /* EmailVM.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52663FF82BDFAF110001D8CE /* EmailVM.swift */; };
|
||||
@@ -121,6 +136,21 @@
|
||||
523ED27E2BDA2BC900CFED02 /* WOKAUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WOKAUITests.swift; sourceTree = "<group>"; };
|
||||
523ED2802BDA2BC900CFED02 /* WOKAUITestsLaunchTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WOKAUITestsLaunchTests.swift; sourceTree = "<group>"; };
|
||||
5257B2642BDFB6F50086D79B /* CheckPhoneHomeBtnOrNotch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckPhoneHomeBtnOrNotch.swift; sourceTree = "<group>"; };
|
||||
525953CE2BE8B28F00191286 /* Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = "<group>"; };
|
||||
525953D02BE8B2B200191286 /* LLSpinner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LLSpinner.swift; sourceTree = "<group>"; };
|
||||
525953D32BE8B2DF00191286 /* UIApplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplication.swift; sourceTree = "<group>"; };
|
||||
5259540F2BE8B72900191286 /* FontCustom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FontCustom.swift; sourceTree = "<group>"; };
|
||||
525954112BE8C84900191286 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = "<group>"; };
|
||||
525954132BE8C87300191286 /* ExtensionVCToastAlert.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionVCToastAlert.swift; sourceTree = "<group>"; };
|
||||
525954162BE8CAD300191286 /* NetworkManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkManager.swift; sourceTree = "<group>"; };
|
||||
525954182BE8CC3400191286 /* ConstantString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConstantString.swift; sourceTree = "<group>"; };
|
||||
5259541A2BE8D6F900191286 /* NetworkReachibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkReachibility.swift; sourceTree = "<group>"; };
|
||||
5259541C2BE8D94400191286 /* QueueHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueueHelper.swift; sourceTree = "<group>"; };
|
||||
5259541E2BE8E93500191286 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
|
||||
525954202BE8EB7900191286 /* APIEndPoints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIEndPoints.swift; sourceTree = "<group>"; };
|
||||
525954222BE8F00400191286 /* BaseResponseModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseResponseModel.swift; sourceTree = "<group>"; };
|
||||
525954242BE8F01600191286 /* ValueWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValueWrapper.swift; sourceTree = "<group>"; };
|
||||
525954262BE9178F00191286 /* UserDataDM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataDM.swift; sourceTree = "<group>"; };
|
||||
52663FF42BDFAB830001D8CE /* TextFieldErrorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextFieldErrorView.swift; sourceTree = "<group>"; };
|
||||
52663FF62BDFACF60001D8CE /* ShadowView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShadowView.swift; sourceTree = "<group>"; };
|
||||
52663FF82BDFAF110001D8CE /* EmailVM.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmailVM.swift; sourceTree = "<group>"; };
|
||||
@@ -272,6 +302,7 @@
|
||||
523ED25C2BDA2BC700CFED02 /* WOKA */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
525954152BE8CAC900191286 /* Network Adapter */,
|
||||
9CBCB2A62BE5104F007D7934 /* Home */,
|
||||
52C6E01F2BE3ADD800E22D59 /* Default Enum */,
|
||||
9C56E83E2BDBE4FB00E4CA14 /* Authentication */,
|
||||
@@ -283,6 +314,7 @@
|
||||
523ED2932BDA3D0100CFED02 /* Assets */,
|
||||
523ED2682BDA2BC900CFED02 /* LaunchScreen.storyboard */,
|
||||
523ED26B2BDA2BC900CFED02 /* Info.plist */,
|
||||
5259541E2BE8E93500191286 /* Config.xcconfig */,
|
||||
);
|
||||
path = WOKA;
|
||||
sourceTree = "<group>";
|
||||
@@ -373,10 +405,43 @@
|
||||
9C56E8332BDBC3EF00E4CA14 /* Exo2-Regular.ttf */,
|
||||
9C56E8302BDBC3EF00E4CA14 /* Exo2-SemiBold.ttf */,
|
||||
9C56E8312BDBC3EF00E4CA14 /* Exo2-Thin.ttf */,
|
||||
5259540F2BE8B72900191286 /* FontCustom.swift */,
|
||||
);
|
||||
path = Fonts;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
525953CD2BE8B28100191286 /* ActivityToast&Indicator */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
525953CE2BE8B28F00191286 /* Utilities.swift */,
|
||||
525953D02BE8B2B200191286 /* LLSpinner.swift */,
|
||||
525954112BE8C84900191286 /* Toast.swift */,
|
||||
525954132BE8C87300191286 /* ExtensionVCToastAlert.swift */,
|
||||
);
|
||||
path = "ActivityToast&Indicator";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
525953D22BE8B2CD00191286 /* UIApplication */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
525953D32BE8B2DF00191286 /* UIApplication.swift */,
|
||||
);
|
||||
path = UIApplication;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
525954152BE8CAC900191286 /* Network Adapter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
525954162BE8CAD300191286 /* NetworkManager.swift */,
|
||||
5259541A2BE8D6F900191286 /* NetworkReachibility.swift */,
|
||||
5259541C2BE8D94400191286 /* QueueHelper.swift */,
|
||||
525954202BE8EB7900191286 /* APIEndPoints.swift */,
|
||||
525954222BE8F00400191286 /* BaseResponseModel.swift */,
|
||||
525954242BE8F01600191286 /* ValueWrapper.swift */,
|
||||
);
|
||||
path = "Network Adapter";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
52C6E01F2BE3ADD800E22D59 /* Default Enum */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@@ -388,6 +453,8 @@
|
||||
52C8B0512BDA4B51003B51D0 /* Helpers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
525953D22BE8B2CD00191286 /* UIApplication */,
|
||||
525953CD2BE8B28100191286 /* ActivityToast&Indicator */,
|
||||
5202AAFF2BDFA7860043B7BD /* Validations */,
|
||||
52C8B06A2BDA6E7A003B51D0 /* Localized */,
|
||||
52C8B0522BDA4B58003B51D0 /* UIElements Helper */,
|
||||
@@ -426,6 +493,7 @@
|
||||
9C27E1642BDB6FBC00EC1DA9 /* StoryBoardID.swift */,
|
||||
9C27E16C2BDB852F00EC1DA9 /* GVar.swift */,
|
||||
9C27E16E2BDB866500EC1DA9 /* CellIdentifier.swift */,
|
||||
525954182BE8CC3400191286 /* ConstantString.swift */,
|
||||
);
|
||||
path = "Constants K";
|
||||
sourceTree = "<group>";
|
||||
@@ -480,6 +548,7 @@
|
||||
9C56E83F2BDBE50200E4CA14 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
525954262BE9178F00191286 /* UserDataDM.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
@@ -666,6 +735,7 @@
|
||||
52C8B05B2BDA5924003B51D0 /* WokaSplashSound.m4a in Resources */,
|
||||
523ED2652BDA2BC700CFED02 /* Base in Resources */,
|
||||
52C6E01C2BE383C000E22D59 /* YourIntrestCell.xib in Resources */,
|
||||
5259541F2BE8E93500191286 /* Config.xcconfig in Resources */,
|
||||
9C56E8392BDBC3F000E4CA14 /* Exo2-Regular.ttf in Resources */,
|
||||
52C6E0262BE3B46A00E22D59 /* SelectAvatarCell.xib in Resources */,
|
||||
52C8B0712BDA7512003B51D0 /* PassingCloud.json in Resources */,
|
||||
@@ -738,18 +808,23 @@
|
||||
files = (
|
||||
52D774EF2BDFC50D001D87DE /* StringValidations.swift in Sources */,
|
||||
5272FCE32BDFDB05000ECB1D /* UserDetailsRegisterVC.swift in Sources */,
|
||||
525954102BE8B72900191286 /* FontCustom.swift in Sources */,
|
||||
5202AAFE2BDF90590043B7BD /* TextFieldImage.swift in Sources */,
|
||||
52C6E0232BE3B3E300E22D59 /* SelectAvatarVC.swift in Sources */,
|
||||
52C8B06C2BDA6E87003B51D0 /* LocalizedString.swift in Sources */,
|
||||
525953D42BE8B2DF00191286 /* UIApplication.swift in Sources */,
|
||||
52CC38C32BDF812F00B74C3E /* LocalisedElements.swift in Sources */,
|
||||
52CA28FC2BE11A0400708B49 /* UserIntrestVM.swift in Sources */,
|
||||
9C27E1602BDB6ECA00EC1DA9 /* UserDefaultsStruct.swift in Sources */,
|
||||
5259541D2BE8D94400191286 /* QueueHelper.swift in Sources */,
|
||||
525954232BE8F00400191286 /* BaseResponseModel.swift in Sources */,
|
||||
9C27E1692BDB76F200EC1DA9 /* OnBoardVM.swift in Sources */,
|
||||
523ED2622BDA2BC700CFED02 /* SplashVC.swift in Sources */,
|
||||
9CDC343C2BDBBC6B00093089 /* SelectAgeVC.swift in Sources */,
|
||||
52C8B0542BDA4BD1003B51D0 /* RoundCorner.swift in Sources */,
|
||||
52C8B0572BDA57DB003B51D0 /* Constant.swift in Sources */,
|
||||
5202AB012BDFA7900043B7BD /* EmailValidation.swift in Sources */,
|
||||
525954192BE8CC3400191286 /* ConstantString.swift in Sources */,
|
||||
52D774EB2BDFC0BF001D87DE /* OTPVC.swift in Sources */,
|
||||
9C27E16F2BDB866500EC1DA9 /* CellIdentifier.swift in Sources */,
|
||||
9C27E1632BDB6F1900EC1DA9 /* AuthFunc.swift in Sources */,
|
||||
@@ -757,6 +832,7 @@
|
||||
52C8B0592BDA57FA003B51D0 /* StaticFilesString.swift in Sources */,
|
||||
52C8B05D2BDA5AA7003B51D0 /* ApplyGradrient.swift in Sources */,
|
||||
52C6E01B2BE383C000E22D59 /* YourIntrestCell.swift in Sources */,
|
||||
525954142BE8C87300191286 /* ExtensionVCToastAlert.swift in Sources */,
|
||||
523ED25E2BDA2BC700CFED02 /* AppDelegate.swift in Sources */,
|
||||
52D774ED2BDFC13F001D87DE /* OTPVM.swift in Sources */,
|
||||
9CBCB2A32BE50C95007D7934 /* ResetPassUserNameVC.swift in Sources */,
|
||||
@@ -766,17 +842,24 @@
|
||||
9C56E83B2BDBC6E600E4CA14 /* SelectAgeVM.swift in Sources */,
|
||||
52CA28FA2BE119F500708B49 /* UserIntrestVC.swift in Sources */,
|
||||
9C27E16B2BDB774D00EC1DA9 /* CarouselData.swift in Sources */,
|
||||
525954212BE8EB7900191286 /* APIEndPoints.swift in Sources */,
|
||||
523ED2602BDA2BC700CFED02 /* SceneDelegate.swift in Sources */,
|
||||
9CBCB2AA2BE51A52007D7934 /* HomeVC.swift in Sources */,
|
||||
52D774E92BDFBDA4001D87DE /* AuthenticationStringConstant.swift in Sources */,
|
||||
5259541B2BE8D6F900191286 /* NetworkReachibility.swift in Sources */,
|
||||
9C27E1672BDB706700EC1DA9 /* StoryBoard.swift in Sources */,
|
||||
52C8B0692BDA6E1E003B51D0 /* LocalizedEnum.swift in Sources */,
|
||||
525954122BE8C84900191286 /* Toast.swift in Sources */,
|
||||
525954172BE8CAD300191286 /* NetworkManager.swift in Sources */,
|
||||
525954252BE8F01600191286 /* ValueWrapper.swift in Sources */,
|
||||
52C6E01E2BE3847F00E22D59 /* BorderView.swift in Sources */,
|
||||
52C8B0742BDA7626003B51D0 /* OnBoardVC.swift in Sources */,
|
||||
525953CF2BE8B28F00191286 /* Utilities.swift in Sources */,
|
||||
9CBCB2A12BE4E50A007D7934 /* TextFieldPassword.swift in Sources */,
|
||||
9C56E8482BDBEFAB00E4CA14 /* AssetColor.swift in Sources */,
|
||||
9CBCB29D2BE4D6BB007D7934 /* LoginVM.swift in Sources */,
|
||||
5272FCE52BDFDC8C000ECB1D /* UserDetailsRegisterVM.swift in Sources */,
|
||||
525954272BE9178F00191286 /* UserDataDM.swift in Sources */,
|
||||
9C27E1652BDB6FBC00EC1DA9 /* StoryBoardID.swift in Sources */,
|
||||
9C27E1722BDB86B600EC1DA9 /* OnBoardCell.swift in Sources */,
|
||||
52C8B05F2BDA5AFA003B51D0 /* SplashVM.swift in Sources */,
|
||||
@@ -790,6 +873,7 @@
|
||||
9C56E8462BDBEE6400E4CA14 /* EmailVC.swift in Sources */,
|
||||
52663FFB2BDFB1700001D8CE /* TextFieldShadow.swift in Sources */,
|
||||
52C6E0212BE3ADE300E22D59 /* GenderEnum.swift in Sources */,
|
||||
525953D12BE8B2B200191286 /* LLSpinner.swift in Sources */,
|
||||
52C6E0272BE3B46A00E22D59 /* SelectAvatarCell.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@@ -869,6 +953,7 @@
|
||||
/* Begin XCBuildConfiguration section */
|
||||
523ED2822BDA2BC900CFED02 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 5259541E2BE8E93500191286 /* Config.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
@@ -933,6 +1018,7 @@
|
||||
};
|
||||
523ED2832BDA2BC900CFED02 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
baseConfigurationReference = 5259541E2BE8E93500191286 /* Config.xcconfig */;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||
|
||||
@@ -1,8 +1,26 @@
|
||||
//
|
||||
// FontCusto.swift
|
||||
// FontCustom.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
enum FontsCustomEnum : String{
|
||||
case Exo2_Bold = "Exo2-Bold"
|
||||
case Exo2_ExtraBold = "Exo2-ExtraBold"
|
||||
case Exo2_Medium = "Exo2-Medium"
|
||||
case Exo2_Regular = "Exo2-Regular"
|
||||
case Exo2_SemiBold = "Exo2-SemiBold"
|
||||
case Exo2_Thin = "Exo2-Thin"
|
||||
}
|
||||
|
||||
final class FontCustom{
|
||||
|
||||
static let shareInstance = FontCustom()
|
||||
|
||||
func customFont(fontName : FontsCustomEnum , size : CGFloat = 16.0)-> UIFont{
|
||||
UIFont(name: fontName.rawValue, size: size)!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ class EmailVC: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func nextBtnTapped(_ sender: LocalisedElementsButton) {
|
||||
Utilities.startProgressHUD()
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else{return}
|
||||
//validate email fiirst
|
||||
@@ -45,22 +46,43 @@ class EmailVC: UIViewController {
|
||||
if emailValidate != .isCorrect{
|
||||
enterEmailTF.rightView?.isHidden = false
|
||||
enterEmailTF.setError(emailValidate.rawValue, show: true)
|
||||
Utilities.dismissProgressHUD()
|
||||
return
|
||||
}
|
||||
|
||||
let sb = UIStoryboard(name: K.StoryBoard.authenticationSB, bundle: nil)
|
||||
let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Authentication.oTPVC) as! OTPVC
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
vm.checkEmail()
|
||||
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.authenticationSB, bundle: nil)
|
||||
// let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Authentication.oTPVC) as! OTPVC
|
||||
// self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - TextField Delegate
|
||||
|
||||
extension EmailVC : UITextFieldDelegate{
|
||||
|
||||
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool{
|
||||
|
||||
return true
|
||||
switch textField{
|
||||
case enterEmailTF:
|
||||
if let rightView = textField.rightView {
|
||||
// Hide the right view
|
||||
rightView.isHidden = true
|
||||
|
||||
// Check if the right view is hidden
|
||||
if rightView.isHidden {
|
||||
// If hidden, hide the associated error view
|
||||
if let errorView = errorViews.object(forKey: enterEmailTF) {
|
||||
errorView.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ValidatorClass.sharedInstanec.limitCharacter(length: 255,textField, shouldChangeCharactersIn: range, replacementString: string)
|
||||
default:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ class LoginVC: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func loginBtnTapped(_ sender: LocalisedElementsButton) {
|
||||
vm.loginUser()
|
||||
}
|
||||
|
||||
@IBAction func createAccountBtnTapped(_ sender: LocalisedElementsButton) {
|
||||
|
||||
@@ -6,3 +6,62 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - UserDataDM
|
||||
struct UserDataDM: Codable {
|
||||
let result: Result?
|
||||
|
||||
// MARK: - Result
|
||||
struct Result: Codable {
|
||||
let id: Int?
|
||||
let username, fullname: String?
|
||||
let gender: Gender?
|
||||
let birthdate, email: String?
|
||||
let avtar: String?
|
||||
let userType: String?
|
||||
let languageMasterID: Int?
|
||||
let isActive: String?
|
||||
let deletedAt: String?
|
||||
let lastLogin, rememberToken: String?
|
||||
let childDetail: String?
|
||||
let language: Language?
|
||||
let alreadyLoggedIn: Bool?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id, username, fullname, gender, birthdate, email, avtar
|
||||
case userType = "user_type"
|
||||
case languageMasterID = "language_master_id"
|
||||
case isActive = "is_active"
|
||||
case deletedAt = "deleted_at"
|
||||
case lastLogin = "last_login"
|
||||
case rememberToken = "remember_token"
|
||||
case childDetail = "child_detail"
|
||||
case language
|
||||
case alreadyLoggedIn = "already_logged_in"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Gender
|
||||
struct Gender: Codable {
|
||||
let id: Int?
|
||||
let genderName: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case genderName = "gender_name"
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Language
|
||||
struct Language: Codable {
|
||||
let id: Int?
|
||||
let languageName: String?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case id
|
||||
case languageName = "language_name"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Alamofire
|
||||
|
||||
class EmailVM{
|
||||
|
||||
@@ -36,7 +37,7 @@ class EmailVM{
|
||||
vc.enterEmailTF.placeholder = K.AuthenticationStringConstant.enterParentsEmail.localized(loc: K.GVar.localized)
|
||||
vc.beSafeLabel.text = K.AuthenticationStringConstant.safeBelow.localized(loc: K.GVar.localized)
|
||||
vc.emailLabel.text = K.AuthenticationStringConstant.emailBelow.localized(loc: K.GVar.localized)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to handle tap on validation icon
|
||||
@@ -46,4 +47,59 @@ class EmailVM{
|
||||
errorView.isHidden.toggle()
|
||||
}
|
||||
}
|
||||
|
||||
func checkEmail(){
|
||||
let params: Parameters = [
|
||||
"email": vc.enterEmailTF.text!,
|
||||
"user_type": "2"
|
||||
]
|
||||
NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Auth.check_exist_email, method: .post ,parameters: params) {(result : Result<BaseResponseModel<UserDataDM>, NetworkManager.APIError>) in
|
||||
switch result{
|
||||
case .success(let data):
|
||||
// print(data.message)
|
||||
switch data.success{
|
||||
case 0:
|
||||
Utilities.dismissProgressHUD()
|
||||
self.vc.toast(msg: data.message ?? "Unrecognised error" , time: 2)
|
||||
case 1:
|
||||
Utilities.dismissProgressHUD()
|
||||
self.vc.toast(msg: data.message ?? "Unrecognised error" , time: 2)
|
||||
default:
|
||||
break
|
||||
}
|
||||
// switch data.errorCode{
|
||||
// case 0: // this means no error
|
||||
// Utilities.dismissProgressHUD()
|
||||
// if let data = data.result {
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.geoFencing, bundle: nil)
|
||||
// let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.GeoFencing.geoFencingMapVC) as! GeoFencingMapVC
|
||||
// vcPush.vm.patientLocationLink = data
|
||||
// self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
// self.navigationController?.pushViewController(vcPush, animated: true)
|
||||
// }else{
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.geoFencing, bundle: nil)
|
||||
// let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.GeoFencing.geoFencingMapVC) as! GeoFencingMapVC
|
||||
// self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
// self.navigationController?.pushViewController(vcPush, animated: true)
|
||||
// }
|
||||
// case 1: // handle error
|
||||
// Utilities.dismissProgressHUD()
|
||||
// self.toast(msg: data.message ?? "Unrecognised error" , time: 2)
|
||||
// default:
|
||||
// Utilities.dismissProgressHUD()
|
||||
// break
|
||||
// }
|
||||
case .failure(let error):
|
||||
Utilities.dismissProgressHUD()
|
||||
print(error)
|
||||
// Utilities.dismissProgressHUD()
|
||||
// switch error {
|
||||
// case .noNetwork(let message) , .custom(let message), .unknown(let message):
|
||||
// Utilities.alertWithBtn(title: "", msgBody: message, okBtnStr: "OK", vc: self)
|
||||
// default:
|
||||
// self.toast(msg: String(describing: error) , time: 2)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Alamofire
|
||||
|
||||
class LoginVM{
|
||||
|
||||
@@ -37,4 +38,60 @@ class LoginVM{
|
||||
vc.passwordTF.isSecureTextEntry.toggle()
|
||||
}
|
||||
|
||||
func loginUser(){
|
||||
let params: Parameters = [
|
||||
"username": vc.userNameTF.text!,
|
||||
"password": vc.passwordTF.text!
|
||||
]
|
||||
let header : HTTPHeaders = ["device-id" : "12345"]
|
||||
|
||||
Utilities.startProgressHUD()
|
||||
NetworkManager.shareInstance.apiRequest(url: APIEndPoints.Auth.login, method: .post ,parameters: params, headers: header) {(result : Result<BaseResponseModel<UserDataDM?>, NetworkManager.APIError>) in
|
||||
switch result{
|
||||
case .success(let data):
|
||||
switch data.success{
|
||||
case 0:
|
||||
Utilities.dismissProgressHUD()
|
||||
self.vc.toast(msg: data.message ?? "Unrecognised error" , time: 2)
|
||||
case 1:
|
||||
Utilities.dismissProgressHUD()
|
||||
self.vc.toast(msg: data.message ?? "Unrecognised error" , time: 2)
|
||||
default:
|
||||
break
|
||||
}
|
||||
// switch data.errorCode{
|
||||
// case 0: // this means no error
|
||||
// Utilities.dismissProgressHUD()
|
||||
// if let data = data.result {
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.geoFencing, bundle: nil)
|
||||
// let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.GeoFencing.geoFencingMapVC) as! GeoFencingMapVC
|
||||
// vcPush.vm.patientLocationLink = data
|
||||
// self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
// self.navigationController?.pushViewController(vcPush, animated: true)
|
||||
// }else{
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.geoFencing, bundle: nil)
|
||||
// let vcPush = sb.instantiateViewController(withIdentifier: K.StoryBoardID.GeoFencing.geoFencingMapVC) as! GeoFencingMapVC
|
||||
// self.navigationController?.setNavigationBarHidden(false, animated: true)
|
||||
// self.navigationController?.pushViewController(vcPush, animated: true)
|
||||
// }
|
||||
// case 1: // handle error
|
||||
// Utilities.dismissProgressHUD()
|
||||
// self.toast(msg: data.message ?? "Unrecognised error" , time: 2)
|
||||
// default:
|
||||
// Utilities.dismissProgressHUD()
|
||||
// break
|
||||
// }
|
||||
case .failure(let error):
|
||||
Utilities.dismissProgressHUD()
|
||||
print(error)
|
||||
// Utilities.dismissProgressHUD()
|
||||
// switch error {
|
||||
// case .noNetwork(let message) , .custom(let message), .unknown(let message):
|
||||
// Utilities.alertWithBtn(title: "", msgBody: message, okBtnStr: "OK", vc: self)
|
||||
// default:
|
||||
// self.toast(msg: String(describing: error) , time: 2)
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,3 +7,7 @@
|
||||
|
||||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
API_KEY_ID = "admin"
|
||||
API_KEY_PASS = "Woka@1234"
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// ConstantString.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
@@ -14,7 +14,7 @@ extension K{
|
||||
|
||||
static let passRequirement = "- Be at least 8 characters in length. \n- Contain both upper and lowercase alphabetic characters (e.g. A-Z, a-z). \n- Have at least one numerical character (e.g. 0-9). \n- Have at least one special character (e.g. ~!@#$%^&*()_-+=)."
|
||||
|
||||
static let unRecognised = "Unreccognised error"
|
||||
static let unRecognised = "Unrecognised error"
|
||||
|
||||
static let noInternet = "Make sure you are connected to the internet!"
|
||||
|
||||
|
||||
@@ -5,4 +5,17 @@
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
extension UIViewController{
|
||||
|
||||
func toast(msg : String , time : CGFloat, completionBlock: (() -> ())? = nil){
|
||||
self.view.endEditing(true)
|
||||
self.view.isUserInteractionEnabled = false
|
||||
self.view.makeToast(msg, duration: time, point: CGPoint(x: self.view.frame.width / 2, y: self.view.frame.height - 60), title: nil, image: nil, completion: {didTap in
|
||||
self.view.isUserInteractionEnabled = true
|
||||
completionBlock?()
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// LLSpinner.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
@@ -8,30 +8,68 @@
|
||||
import UIKit
|
||||
|
||||
open class LLSpinner {
|
||||
|
||||
// Spinner view
|
||||
internal static var spinnerView: UIActivityIndicatorView?
|
||||
// Background view behind spinner
|
||||
internal static var backgroundView: UIView?
|
||||
// Background view covering entire frame
|
||||
internal static var frameTintView: UIView?
|
||||
// Label to display text
|
||||
internal static var label: UILabel?
|
||||
|
||||
// Default spinner style and background color
|
||||
public static var style: UIActivityIndicatorView.Style = .large
|
||||
public static var backgroundColor: UIColor = UIColor(white: 0, alpha: 0.6)
|
||||
|
||||
public static var backgroundColor: UIColor = UIColor.black.withAlphaComponent(0.3)
|
||||
|
||||
// Touch handler closure
|
||||
internal static var touchHandler: (() -> Void)?
|
||||
|
||||
public static func spin(style: UIActivityIndicatorView.Style = style, backgroundColor: UIColor = backgroundColor, touchHandler: (() -> Void)? = nil) {
|
||||
// Function to show spinner
|
||||
public static func spin(style: UIActivityIndicatorView.Style = style,
|
||||
backgroundColor: UIColor = backgroundColor,
|
||||
text: String? = nil,
|
||||
touchHandler: (() -> Void)? = nil) {
|
||||
if spinnerView == nil,
|
||||
let window = UIApplication.shared.mainKeyWindow {
|
||||
let frame = UIScreen.main.bounds
|
||||
|
||||
spinnerView = UIActivityIndicatorView(frame: frame)
|
||||
spinnerView?.center = CGPoint(x: window.frame.size.width / 2,
|
||||
y: window.frame.size.height / 2)
|
||||
spinnerView!.backgroundColor = backgroundColor
|
||||
spinnerView!.style = style
|
||||
spinnerView!.color = .white
|
||||
// Add background view covering entire frame
|
||||
frameTintView = UIView(frame: frame)
|
||||
frameTintView?.center = CGPoint(x: window.frame.size.width / 2,
|
||||
y: window.frame.size.height / 2)
|
||||
frameTintView?.backgroundColor = backgroundColor
|
||||
frameTintView?.layer.cornerRadius = 10
|
||||
window.addSubview(frameTintView!)
|
||||
|
||||
// Add background view behind spinner
|
||||
backgroundView = UIView(frame: CGRect(x: 0, y: 0, width: 180, height: 120))
|
||||
backgroundView?.center = CGPoint(x: window.frame.size.width / 2,
|
||||
y: window.frame.size.height / 2 - 20) // Adjust vertical position
|
||||
backgroundView?.backgroundColor = .white
|
||||
backgroundView?.layer.cornerRadius = 10
|
||||
window.addSubview(backgroundView!)
|
||||
|
||||
// Create and add spinner view
|
||||
spinnerView = UIActivityIndicatorView(style: style)
|
||||
spinnerView!.center = CGPoint(x: backgroundView!.center.x,
|
||||
y: backgroundView!.center.y - 10) // Move spinner up
|
||||
spinnerView!.color = UIColor.appColor(.TextDarkBlue)
|
||||
window.addSubview(spinnerView!)
|
||||
spinnerView!.startAnimating()
|
||||
|
||||
// Add label if text is provided
|
||||
if let text = text {
|
||||
label = UILabel(frame: CGRect(x: 0, y: spinnerView!.frame.maxY + 10, width: window.frame.size.width, height: 20))
|
||||
label?.font = FontCustom().customFont(fontName: .Exo2_Bold, size: 16)
|
||||
label?.textColor = UIColor.appColor(.TextDarkBlue)
|
||||
label?.text = text
|
||||
label?.textAlignment = .center
|
||||
window.addSubview(label!)
|
||||
}
|
||||
}
|
||||
|
||||
// Attach touch handler if provided
|
||||
if touchHandler != nil {
|
||||
self.touchHandler = touchHandler
|
||||
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(runTouchHandler))
|
||||
@@ -39,17 +77,38 @@ open class LLSpinner {
|
||||
}
|
||||
}
|
||||
|
||||
// Run touch handler
|
||||
@objc internal static func runTouchHandler() {
|
||||
if touchHandler != nil {
|
||||
touchHandler!()
|
||||
}
|
||||
}
|
||||
|
||||
// Function to stop spinner
|
||||
public static func stop() {
|
||||
// Remove spinner view
|
||||
if let _ = spinnerView {
|
||||
spinnerView!.stopAnimating()
|
||||
spinnerView!.removeFromSuperview()
|
||||
spinnerView = nil
|
||||
}
|
||||
|
||||
// Remove background view behind spinner
|
||||
if let _ = backgroundView {
|
||||
backgroundView!.removeFromSuperview()
|
||||
backgroundView = nil
|
||||
}
|
||||
|
||||
// Remove label
|
||||
if let _ = label {
|
||||
label!.removeFromSuperview()
|
||||
label = nil
|
||||
}
|
||||
|
||||
// Remove background view covering entire frame
|
||||
if let _ = frameTintView {
|
||||
frameTintView!.removeFromSuperview()
|
||||
frameTintView = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,760 @@
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import ObjectiveC
|
||||
|
||||
/**
|
||||
Toast is a Swift extension that adds toast notifications to the `UIView` object class.
|
||||
It is intended to be simple, lightweight, and easy to use. Most toast notifications
|
||||
can be triggered with a single line of code.
|
||||
|
||||
The `makeToast` methods create a new view and then display it as toast.
|
||||
|
||||
The `showToast` methods display any view as toast.
|
||||
|
||||
*/
|
||||
public extension UIView {
|
||||
|
||||
/**
|
||||
Keys used for associated objects.
|
||||
*/
|
||||
private struct ToastKeys {
|
||||
static var timer = "com.toast-swift.timer"
|
||||
static var duration = "com.toast-swift.duration"
|
||||
static var point = "com.toast-swift.point"
|
||||
static var completion = "com.toast-swift.completion"
|
||||
static var activeToasts = "com.toast-swift.activeToasts"
|
||||
static var activityView = "com.toast-swift.activityView"
|
||||
static var queue = "com.toast-swift.queue"
|
||||
}
|
||||
|
||||
/**
|
||||
Swift closures can't be directly associated with objects via the
|
||||
Objective-C runtime, so the (ugly) solution is to wrap them in a
|
||||
class that can be used with associated objects.
|
||||
*/
|
||||
private class ToastCompletionWrapper {
|
||||
let completion: ((Bool) -> Void)?
|
||||
|
||||
init(_ completion: ((Bool) -> Void)?) {
|
||||
self.completion = completion
|
||||
}
|
||||
}
|
||||
|
||||
private enum ToastError: Error {
|
||||
case missingParameters
|
||||
}
|
||||
|
||||
private var activeToasts: NSMutableArray {
|
||||
get {
|
||||
if let activeToasts = objc_getAssociatedObject(self, &ToastKeys.activeToasts) as? NSMutableArray {
|
||||
return activeToasts
|
||||
} else {
|
||||
let activeToasts = NSMutableArray()
|
||||
objc_setAssociatedObject(self, &ToastKeys.activeToasts, activeToasts, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
return activeToasts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var queue: NSMutableArray {
|
||||
get {
|
||||
if let queue = objc_getAssociatedObject(self, &ToastKeys.queue) as? NSMutableArray {
|
||||
return queue
|
||||
} else {
|
||||
let queue = NSMutableArray()
|
||||
objc_setAssociatedObject(self, &ToastKeys.queue, queue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
return queue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Make Toast Methods
|
||||
|
||||
/**
|
||||
Creates and presents a new toast view.
|
||||
|
||||
@param message The message to be displayed
|
||||
@param duration The toast duration
|
||||
@param position The toast's position
|
||||
@param title The title
|
||||
@param image The image
|
||||
@param style The style. The shared style will be used when nil
|
||||
@param completion The completion closure, executed after the toast view disappears.
|
||||
didTap will be `true` if the toast view was dismissed from a tap.
|
||||
*/
|
||||
func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, title: String? = nil, image: UIImage? = nil, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)? = nil) {
|
||||
do {
|
||||
let toast = try toastViewForMessage(message, title: title, image: image, style: style)
|
||||
showToast(toast, duration: duration, position: position, completion: completion)
|
||||
} catch ToastError.missingParameters {
|
||||
print("Error: message, title, and image are all nil")
|
||||
} catch {}
|
||||
}
|
||||
|
||||
/**
|
||||
Creates a new toast view and presents it at a given center point.
|
||||
|
||||
@param message The message to be displayed
|
||||
@param duration The toast duration
|
||||
@param point The toast's center point
|
||||
@param title The title
|
||||
@param image The image
|
||||
@param style The style. The shared style will be used when nil
|
||||
@param completion The completion closure, executed after the toast view disappears.
|
||||
didTap will be `true` if the toast view was dismissed from a tap.
|
||||
*/
|
||||
func makeToast(_ message: String?, duration: TimeInterval = ToastManager.shared.duration, point: CGPoint, title: String?, image: UIImage?, style: ToastStyle = ToastManager.shared.style, completion: ((_ didTap: Bool) -> Void)?) {
|
||||
do {
|
||||
let toast = try toastViewForMessage(message, title: title, image: image, style: style)
|
||||
showToast(toast, duration: duration, point: point, completion: completion)
|
||||
} catch ToastError.missingParameters {
|
||||
print("Error: message, title, and image cannot all be nil")
|
||||
} catch {}
|
||||
}
|
||||
|
||||
// MARK: - Show Toast Methods
|
||||
|
||||
/**
|
||||
Displays any view as toast at a provided position and duration. The completion closure
|
||||
executes when the toast view completes. `didTap` will be `true` if the toast view was
|
||||
dismissed from a tap.
|
||||
|
||||
@param toast The view to be displayed as toast
|
||||
@param duration The notification duration
|
||||
@param position The toast's position
|
||||
@param completion The completion block, executed after the toast view disappears.
|
||||
didTap will be `true` if the toast view was dismissed from a tap.
|
||||
*/
|
||||
func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, position: ToastPosition = ToastManager.shared.position, completion: ((_ didTap: Bool) -> Void)? = nil) {
|
||||
let point = position.centerPoint(forToast: toast, inSuperview: self)
|
||||
showToast(toast, duration: duration, point: point, completion: completion)
|
||||
}
|
||||
|
||||
/**
|
||||
Displays any view as toast at a provided center point and duration. The completion closure
|
||||
executes when the toast view completes. `didTap` will be `true` if the toast view was
|
||||
dismissed from a tap.
|
||||
|
||||
@param toast The view to be displayed as toast
|
||||
@param duration The notification duration
|
||||
@param point The toast's center point
|
||||
@param completion The completion block, executed after the toast view disappears.
|
||||
didTap will be `true` if the toast view was dismissed from a tap.
|
||||
*/
|
||||
func showToast(_ toast: UIView, duration: TimeInterval = ToastManager.shared.duration, point: CGPoint, completion: ((_ didTap: Bool) -> Void)? = nil) {
|
||||
objc_setAssociatedObject(toast, &ToastKeys.completion, ToastCompletionWrapper(completion), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
if ToastManager.shared.isQueueEnabled, activeToasts.count > 0 {
|
||||
objc_setAssociatedObject(toast, &ToastKeys.duration, NSNumber(value: duration), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
objc_setAssociatedObject(toast, &ToastKeys.point, NSValue(cgPoint: point), .OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
|
||||
queue.add(toast)
|
||||
} else {
|
||||
showToast(toast, duration: duration, point: point)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Hide Toast Methods
|
||||
|
||||
/**
|
||||
Hides the active toast. If there are multiple toasts active in a view, this method
|
||||
hides the oldest toast (the first of the toasts to have been presented).
|
||||
|
||||
@see `hideAllToasts()` to remove all active toasts from a view.
|
||||
|
||||
@warning This method has no effect on activity toasts. Use `hideToastActivity` to
|
||||
hide activity toasts.
|
||||
|
||||
*/
|
||||
func hideToast() {
|
||||
guard let activeToast = activeToasts.firstObject as? UIView else { return }
|
||||
hideToast(activeToast)
|
||||
}
|
||||
|
||||
/**
|
||||
Hides an active toast.
|
||||
|
||||
@param toast The active toast view to dismiss. Any toast that is currently being displayed
|
||||
on the screen is considered active.
|
||||
|
||||
@warning this does not clear a toast view that is currently waiting in the queue.
|
||||
*/
|
||||
func hideToast(_ toast: UIView) {
|
||||
guard activeToasts.contains(toast) else { return }
|
||||
hideToast(toast, fromTap: false)
|
||||
}
|
||||
|
||||
/**
|
||||
Hides all toast views.
|
||||
|
||||
@param includeActivity If `true`, toast activity will also be hidden. Default is `false`.
|
||||
@param clearQueue If `true`, removes all toast views from the queue. Default is `true`.
|
||||
*/
|
||||
func hideAllToasts(includeActivity: Bool = false, clearQueue: Bool = true) {
|
||||
if clearQueue {
|
||||
clearToastQueue()
|
||||
}
|
||||
|
||||
activeToasts.compactMap { $0 as? UIView }
|
||||
.forEach { hideToast($0) }
|
||||
|
||||
if includeActivity {
|
||||
hideToastActivity()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Removes all toast views from the queue. This has no effect on toast views that are
|
||||
active. Use `hideAllToasts(clearQueue:)` to hide the active toasts views and clear
|
||||
the queue.
|
||||
*/
|
||||
func clearToastQueue() {
|
||||
queue.removeAllObjects()
|
||||
}
|
||||
|
||||
// MARK: - Activity Methods
|
||||
|
||||
/**
|
||||
Creates and displays a new toast activity indicator view at a specified position.
|
||||
|
||||
@warning Only one toast activity indicator view can be presented per superview. Subsequent
|
||||
calls to `makeToastActivity(position:)` will be ignored until `hideToastActivity()` is called.
|
||||
|
||||
@warning `makeToastActivity(position:)` works independently of the `showToast` methods. Toast
|
||||
activity views can be presented and dismissed while toast views are being displayed.
|
||||
`makeToastActivity(position:)` has no effect on the queueing behavior of the `showToast` methods.
|
||||
|
||||
@param position The toast's position
|
||||
*/
|
||||
// func makeToastActivity(_ position: ToastPosition) {
|
||||
// // sanity
|
||||
// guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return }
|
||||
//
|
||||
// let toast = createToastActivityView()
|
||||
// let point = position.centerPoint(forToast: toast, inSuperview: self)
|
||||
// makeToastActivity(toast, point: point)
|
||||
// }
|
||||
|
||||
/**
|
||||
Creates and displays a new toast activity indicator view at a specified position.
|
||||
|
||||
@warning Only one toast activity indicator view can be presented per superview. Subsequent
|
||||
calls to `makeToastActivity(position:)` will be ignored until `hideToastActivity()` is called.
|
||||
|
||||
@warning `makeToastActivity(position:)` works independently of the `showToast` methods. Toast
|
||||
activity views can be presented and dismissed while toast views are being displayed.
|
||||
`makeToastActivity(position:)` has no effect on the queueing behavior of the `showToast` methods.
|
||||
|
||||
@param point The toast's center point
|
||||
*/
|
||||
// func makeToastActivity(_ point: CGPoint) {
|
||||
// // sanity
|
||||
// guard objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView == nil else { return }
|
||||
//
|
||||
// let toast = createToastActivityView()
|
||||
// makeToastActivity(toast, point: point)
|
||||
// }
|
||||
|
||||
/**
|
||||
Dismisses the active toast activity indicator view.
|
||||
*/
|
||||
func hideToastActivity() {
|
||||
if let toast = objc_getAssociatedObject(self, &ToastKeys.activityView) as? UIView {
|
||||
UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: {
|
||||
toast.alpha = 0.0
|
||||
}) { _ in
|
||||
toast.removeFromSuperview()
|
||||
objc_setAssociatedObject(self, &ToastKeys.activityView, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private Activity Methods
|
||||
|
||||
private func makeToastActivity(_ toast: UIView, point: CGPoint) {
|
||||
toast.alpha = 0.0
|
||||
toast.center = point
|
||||
|
||||
objc_setAssociatedObject(self, &ToastKeys.activityView, toast, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
|
||||
self.addSubview(toast)
|
||||
|
||||
UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: .curveEaseOut, animations: {
|
||||
toast.alpha = 1.0
|
||||
})
|
||||
}
|
||||
|
||||
// private func createToastActivityView() -> UIView {
|
||||
// let style = ToastManager.shared.style
|
||||
//
|
||||
// let activityView = UIView(frame: CGRect(x: 0.0, y: 0.0, width: style.activitySize.width, height: style.activitySize.height))
|
||||
// activityView.backgroundColor = style.activityBackgroundColor
|
||||
// activityView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
|
||||
// activityView.layer.cornerRadius = style.cornerRadius
|
||||
//
|
||||
// if style.displayShadow {
|
||||
// activityView.layer.shadowColor = style.shadowColor.cgColor
|
||||
// activityView.layer.shadowOpacity = style.shadowOpacity
|
||||
// activityView.layer.shadowRadius = style.shadowRadius
|
||||
// activityView.layer.shadowOffset = style.shadowOffset
|
||||
// }
|
||||
//
|
||||
// let activityIndicatorView = UIActivityIndicatorView(style: .whiteLarge)
|
||||
// activityIndicatorView.center = CGPoint(x: activityView.bounds.size.width / 2.0, y: activityView.bounds.size.height / 2.0)
|
||||
// activityView.addSubview(activityIndicatorView)
|
||||
// activityIndicatorView.color = style.activityIndicatorColor
|
||||
// activityIndicatorView.startAnimating()
|
||||
//
|
||||
// return activityView
|
||||
// }
|
||||
|
||||
// MARK: - Private Show/Hide Methods
|
||||
|
||||
private func showToast(_ toast: UIView, duration: TimeInterval, point: CGPoint) {
|
||||
toast.center = point
|
||||
toast.alpha = 0.0
|
||||
|
||||
if ToastManager.shared.isTapToDismissEnabled {
|
||||
let recognizer = UITapGestureRecognizer(target: self, action: #selector(UIView.handleToastTapped(_:)))
|
||||
toast.addGestureRecognizer(recognizer)
|
||||
toast.isUserInteractionEnabled = true
|
||||
toast.isExclusiveTouch = true
|
||||
}
|
||||
|
||||
activeToasts.add(toast)
|
||||
self.addSubview(toast)
|
||||
|
||||
UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseOut, .allowUserInteraction], animations: {
|
||||
toast.alpha = 1.0
|
||||
}) { _ in
|
||||
let timer = Timer(timeInterval: duration, target: self, selector: #selector(UIView.toastTimerDidFinish(_:)), userInfo: toast, repeats: false)
|
||||
RunLoop.main.add(timer, forMode: .common)
|
||||
objc_setAssociatedObject(toast, &ToastKeys.timer, timer, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
|
||||
private func hideToast(_ toast: UIView, fromTap: Bool) {
|
||||
if let timer = objc_getAssociatedObject(toast, &ToastKeys.timer) as? Timer {
|
||||
timer.invalidate()
|
||||
}
|
||||
|
||||
UIView.animate(withDuration: ToastManager.shared.style.fadeDuration, delay: 0.0, options: [.curveEaseIn, .beginFromCurrentState], animations: {
|
||||
toast.alpha = 0.0
|
||||
}) { _ in
|
||||
toast.removeFromSuperview()
|
||||
self.activeToasts.remove(toast)
|
||||
|
||||
if let wrapper = objc_getAssociatedObject(toast, &ToastKeys.completion) as? ToastCompletionWrapper, let completion = wrapper.completion {
|
||||
completion(fromTap)
|
||||
}
|
||||
|
||||
if let nextToast = self.queue.firstObject as? UIView, let duration = objc_getAssociatedObject(nextToast, &ToastKeys.duration) as? NSNumber, let point = objc_getAssociatedObject(nextToast, &ToastKeys.point) as? NSValue {
|
||||
self.queue.removeObject(at: 0)
|
||||
self.showToast(nextToast, duration: duration.doubleValue, point: point.cgPointValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Events
|
||||
|
||||
@objc
|
||||
private func handleToastTapped(_ recognizer: UITapGestureRecognizer) {
|
||||
guard let toast = recognizer.view else { return }
|
||||
hideToast(toast, fromTap: true)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func toastTimerDidFinish(_ timer: Timer) {
|
||||
guard let toast = timer.userInfo as? UIView else { return }
|
||||
hideToast(toast)
|
||||
}
|
||||
|
||||
// MARK: - Toast Construction
|
||||
|
||||
/**
|
||||
Creates a new toast view with any combination of message, title, and image.
|
||||
The look and feel is configured via the style. Unlike the `makeToast` methods,
|
||||
this method does not present the toast view automatically. One of the `showToast`
|
||||
methods must be used to present the resulting view.
|
||||
|
||||
@warning if message, title, and image are all nil, this method will throw
|
||||
`ToastError.missingParameters`
|
||||
|
||||
@param message The message to be displayed
|
||||
@param title The title
|
||||
@param image The image
|
||||
@param style The style. The shared style will be used when nil
|
||||
@throws `ToastError.missingParameters` when message, title, and image are all nil
|
||||
@return The newly created toast view
|
||||
*/
|
||||
func toastViewForMessage(_ message: String?, title: String?, image: UIImage?, style: ToastStyle) throws -> UIView {
|
||||
// sanity
|
||||
guard message != nil || title != nil || image != nil else {
|
||||
throw ToastError.missingParameters
|
||||
}
|
||||
|
||||
var messageLabel: UILabel?
|
||||
var titleLabel: UILabel?
|
||||
var imageView: UIImageView?
|
||||
|
||||
let wrapperView = UIView()
|
||||
wrapperView.backgroundColor = style.backgroundColor
|
||||
wrapperView.autoresizingMask = [.flexibleLeftMargin, .flexibleRightMargin, .flexibleTopMargin, .flexibleBottomMargin]
|
||||
wrapperView.layer.cornerRadius = style.cornerRadius
|
||||
|
||||
if style.displayShadow {
|
||||
wrapperView.layer.shadowColor = UIColor.black.cgColor
|
||||
wrapperView.layer.shadowOpacity = style.shadowOpacity
|
||||
wrapperView.layer.shadowRadius = style.shadowRadius
|
||||
wrapperView.layer.shadowOffset = style.shadowOffset
|
||||
}
|
||||
|
||||
if let image = image {
|
||||
imageView = UIImageView(image: image)
|
||||
imageView?.contentMode = .scaleAspectFit
|
||||
imageView?.frame = CGRect(x: style.horizontalPadding, y: style.verticalPadding, width: style.imageSize.width, height: style.imageSize.height)
|
||||
}
|
||||
|
||||
var imageRect = CGRect.zero
|
||||
|
||||
if let imageView = imageView {
|
||||
imageRect.origin.x = style.horizontalPadding
|
||||
imageRect.origin.y = style.verticalPadding
|
||||
imageRect.size.width = imageView.bounds.size.width
|
||||
imageRect.size.height = imageView.bounds.size.height
|
||||
}
|
||||
|
||||
if let title = title {
|
||||
titleLabel = UILabel()
|
||||
titleLabel?.numberOfLines = style.titleNumberOfLines
|
||||
titleLabel?.font = style.titleFont
|
||||
titleLabel?.textAlignment = style.titleAlignment
|
||||
titleLabel?.lineBreakMode = .byTruncatingTail
|
||||
titleLabel?.textColor = style.titleColor
|
||||
titleLabel?.backgroundColor = UIColor.clear
|
||||
titleLabel?.text = title;
|
||||
|
||||
let maxTitleSize = CGSize(width: (self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, height: self.bounds.size.height * style.maxHeightPercentage)
|
||||
let titleSize = titleLabel?.sizeThatFits(maxTitleSize)
|
||||
if let titleSize = titleSize {
|
||||
titleLabel?.frame = CGRect(x: 0.0, y: 0.0, width: titleSize.width, height: titleSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
if let message = message {
|
||||
messageLabel = UILabel()
|
||||
messageLabel?.text = message
|
||||
messageLabel?.numberOfLines = style.messageNumberOfLines
|
||||
messageLabel?.font = style.messageFont
|
||||
messageLabel?.textAlignment = style.messageAlignment
|
||||
messageLabel?.lineBreakMode = .byTruncatingTail;
|
||||
messageLabel?.textColor = style.messageColor
|
||||
messageLabel?.backgroundColor = UIColor.clear
|
||||
|
||||
let maxMessageSize = CGSize(width: (self.bounds.size.width * style.maxWidthPercentage) - imageRect.size.width, height: self.bounds.size.height * style.maxHeightPercentage)
|
||||
let messageSize = messageLabel?.sizeThatFits(maxMessageSize)
|
||||
if let messageSize = messageSize {
|
||||
let actualWidth = min(messageSize.width, maxMessageSize.width)
|
||||
let actualHeight = min(messageSize.height, maxMessageSize.height)
|
||||
messageLabel?.frame = CGRect(x: 0.0, y: 0.0, width: actualWidth, height: actualHeight)
|
||||
}
|
||||
}
|
||||
|
||||
var titleRect = CGRect.zero
|
||||
|
||||
if let titleLabel = titleLabel {
|
||||
titleRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding
|
||||
titleRect.origin.y = style.verticalPadding
|
||||
titleRect.size.width = titleLabel.bounds.size.width
|
||||
titleRect.size.height = titleLabel.bounds.size.height
|
||||
}
|
||||
|
||||
var messageRect = CGRect.zero
|
||||
|
||||
if let messageLabel = messageLabel {
|
||||
messageRect.origin.x = imageRect.origin.x + imageRect.size.width + style.horizontalPadding
|
||||
messageRect.origin.y = titleRect.origin.y + titleRect.size.height + style.verticalPadding
|
||||
messageRect.size.width = messageLabel.bounds.size.width
|
||||
messageRect.size.height = messageLabel.bounds.size.height
|
||||
}
|
||||
|
||||
let longerWidth = max(titleRect.size.width, messageRect.size.width)
|
||||
let longerX = max(titleRect.origin.x, messageRect.origin.x)
|
||||
let wrapperWidth = max((imageRect.size.width + (style.horizontalPadding * 2.0)), (longerX + longerWidth + style.horizontalPadding))
|
||||
let wrapperHeight = max((messageRect.origin.y + messageRect.size.height + style.verticalPadding), (imageRect.size.height + (style.verticalPadding * 2.0)))
|
||||
|
||||
wrapperView.frame = CGRect(x: 0.0, y: 0.0, width: wrapperWidth, height: wrapperHeight)
|
||||
|
||||
if let titleLabel = titleLabel {
|
||||
titleRect.size.width = longerWidth
|
||||
titleLabel.frame = titleRect
|
||||
wrapperView.addSubview(titleLabel)
|
||||
}
|
||||
|
||||
if let messageLabel = messageLabel {
|
||||
messageRect.size.width = longerWidth
|
||||
messageLabel.frame = messageRect
|
||||
wrapperView.addSubview(messageLabel)
|
||||
}
|
||||
|
||||
if let imageView = imageView {
|
||||
wrapperView.addSubview(imageView)
|
||||
}
|
||||
|
||||
return wrapperView
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Toast Style
|
||||
|
||||
/**
|
||||
`ToastStyle` instances define the look and feel for toast views created via the
|
||||
`makeToast` methods as well for toast views created directly with
|
||||
`toastViewForMessage(message:title:image:style:)`.
|
||||
|
||||
@warning `ToastStyle` offers relatively simple styling options for the default
|
||||
toast view. If you require a toast view with more complex UI, it probably makes more
|
||||
sense to create your own custom UIView subclass and present it with the `showToast`
|
||||
methods.
|
||||
*/
|
||||
public struct ToastStyle {
|
||||
|
||||
public init() {}
|
||||
|
||||
/**
|
||||
The background color. Default is `.black` at 80% opacity.
|
||||
*/
|
||||
public var backgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8)
|
||||
|
||||
/**
|
||||
The title color. Default is `UIColor.whiteColor()`.
|
||||
*/
|
||||
public var titleColor: UIColor = .white
|
||||
|
||||
/**
|
||||
The message color. Default is `.white`.
|
||||
*/
|
||||
public var messageColor: UIColor = .white
|
||||
|
||||
/**
|
||||
A percentage value from 0.0 to 1.0, representing the maximum width of the toast
|
||||
view relative to it's superview. Default is 0.8 (80% of the superview's width).
|
||||
*/
|
||||
public var maxWidthPercentage: CGFloat = 0.8 {
|
||||
didSet {
|
||||
maxWidthPercentage = max(min(maxWidthPercentage, 1.0), 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
A percentage value from 0.0 to 1.0, representing the maximum height of the toast
|
||||
view relative to it's superview. Default is 0.8 (80% of the superview's height).
|
||||
*/
|
||||
public var maxHeightPercentage: CGFloat = 0.8 {
|
||||
didSet {
|
||||
maxHeightPercentage = max(min(maxHeightPercentage, 1.0), 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The spacing from the horizontal edge of the toast view to the content. When an image
|
||||
is present, this is also used as the padding between the image and the text.
|
||||
Default is 10.0.
|
||||
|
||||
*/
|
||||
public var horizontalPadding: CGFloat = 10.0
|
||||
|
||||
/**
|
||||
The spacing from the vertical edge of the toast view to the content. When a title
|
||||
is present, this is also used as the padding between the title and the message.
|
||||
Default is 10.0. On iOS11+, this value is added added to the `safeAreaInset.top`
|
||||
and `safeAreaInsets.bottom`.
|
||||
*/
|
||||
public var verticalPadding: CGFloat = 10.0
|
||||
|
||||
/**
|
||||
The corner radius. Default is 10.0.
|
||||
*/
|
||||
public var cornerRadius: CGFloat = 10.0;
|
||||
|
||||
/**
|
||||
The title font. Default is `.boldSystemFont(16.0)`.
|
||||
*/
|
||||
public var titleFont: UIFont = .boldSystemFont(ofSize: 16.0)
|
||||
|
||||
/**
|
||||
The message font. Default is `.systemFont(ofSize: 16.0)`.
|
||||
*/
|
||||
public var messageFont: UIFont = .systemFont(ofSize: 16.0)
|
||||
|
||||
/**
|
||||
The title text alignment. Default is `NSTextAlignment.Left`.
|
||||
*/
|
||||
public var titleAlignment: NSTextAlignment = .left
|
||||
|
||||
/**
|
||||
The message text alignment. Default is `NSTextAlignment.Left`.
|
||||
*/
|
||||
public var messageAlignment: NSTextAlignment = .left
|
||||
|
||||
/**
|
||||
The maximum number of lines for the title. The default is 0 (no limit).
|
||||
*/
|
||||
public var titleNumberOfLines = 0
|
||||
|
||||
/**
|
||||
The maximum number of lines for the message. The default is 0 (no limit).
|
||||
*/
|
||||
public var messageNumberOfLines = 0
|
||||
|
||||
/**
|
||||
Enable or disable a shadow on the toast view. Default is `false`.
|
||||
*/
|
||||
public var displayShadow = false
|
||||
|
||||
/**
|
||||
The shadow color. Default is `.black`.
|
||||
*/
|
||||
public var shadowColor: UIColor = .black
|
||||
|
||||
/**
|
||||
A value from 0.0 to 1.0, representing the opacity of the shadow.
|
||||
Default is 0.8 (80% opacity).
|
||||
*/
|
||||
public var shadowOpacity: Float = 0.8 {
|
||||
didSet {
|
||||
shadowOpacity = max(min(shadowOpacity, 1.0), 0.0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
The shadow radius. Default is 6.0.
|
||||
*/
|
||||
public var shadowRadius: CGFloat = 6.0
|
||||
|
||||
/**
|
||||
The shadow offset. The default is 4 x 4.
|
||||
*/
|
||||
public var shadowOffset = CGSize(width: 4.0, height: 4.0)
|
||||
|
||||
/**
|
||||
The image size. The default is 80 x 80.
|
||||
*/
|
||||
public var imageSize = CGSize(width: 80.0, height: 80.0)
|
||||
|
||||
/**
|
||||
The size of the toast activity view when `makeToastActivity(position:)` is called.
|
||||
Default is 100 x 100.
|
||||
*/
|
||||
public var activitySize = CGSize(width: 100.0, height: 100.0)
|
||||
|
||||
/**
|
||||
The fade in/out animation duration. Default is 0.2.
|
||||
*/
|
||||
public var fadeDuration: TimeInterval = 0.2
|
||||
|
||||
/**
|
||||
Activity indicator color. Default is `.white`.
|
||||
*/
|
||||
public var activityIndicatorColor: UIColor = .white
|
||||
|
||||
/**
|
||||
Activity background color. Default is `.black` at 80% opacity.
|
||||
*/
|
||||
public var activityBackgroundColor: UIColor = UIColor.black.withAlphaComponent(0.8)
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Toast Manager
|
||||
|
||||
/**
|
||||
`ToastManager` provides general configuration options for all toast
|
||||
notifications. Backed by a singleton instance.
|
||||
*/
|
||||
public class ToastManager {
|
||||
|
||||
/**
|
||||
The `ToastManager` singleton instance.
|
||||
|
||||
*/
|
||||
public static let shared = ToastManager()
|
||||
|
||||
/**
|
||||
The shared style. Used whenever toastViewForMessage(message:title:image:style:) is called
|
||||
with with a nil style.
|
||||
|
||||
*/
|
||||
public var style = ToastStyle()
|
||||
|
||||
/**
|
||||
Enables or disables tap to dismiss on toast views. Default is `true`.
|
||||
|
||||
*/
|
||||
public var isTapToDismissEnabled = true
|
||||
|
||||
/**
|
||||
Enables or disables queueing behavior for toast views. When `true`,
|
||||
toast views will appear one after the other. When `false`, multiple toast
|
||||
views will appear at the same time (potentially overlapping depending
|
||||
on their positions). This has no effect on the toast activity view,
|
||||
which operates independently of normal toast views. Default is `false`.
|
||||
|
||||
*/
|
||||
public var isQueueEnabled = false
|
||||
|
||||
/**
|
||||
The default duration. Used for the `makeToast` and
|
||||
`showToast` methods that don't require an explicit duration.
|
||||
Default is 3.0.
|
||||
|
||||
*/
|
||||
public var duration: TimeInterval = 3.0
|
||||
|
||||
/**
|
||||
Sets the default position. Used for the `makeToast` and
|
||||
`showToast` methods that don't require an explicit position.
|
||||
Default is `ToastPosition.Bottom`.
|
||||
|
||||
*/
|
||||
public var position: ToastPosition = .bottom
|
||||
|
||||
}
|
||||
|
||||
// MARK: - ToastPosition
|
||||
|
||||
public enum ToastPosition {
|
||||
case top
|
||||
case center
|
||||
case bottom
|
||||
|
||||
fileprivate func centerPoint(forToast toast: UIView, inSuperview superview: UIView) -> CGPoint {
|
||||
let topPadding: CGFloat = ToastManager.shared.style.verticalPadding + superview.csSafeAreaInsets.top
|
||||
let bottomPadding: CGFloat = ToastManager.shared.style.verticalPadding + superview.csSafeAreaInsets.bottom
|
||||
|
||||
switch self {
|
||||
case .top:
|
||||
return CGPoint(x: superview.bounds.size.width / 2.0, y: (toast.frame.size.height / 2.0) + topPadding)
|
||||
case .center:
|
||||
return CGPoint(x: superview.bounds.size.width / 2.0, y: superview.bounds.size.height / 2.0)
|
||||
case .bottom:
|
||||
return CGPoint(x: superview.bounds.size.width / 2.0, y: (superview.bounds.size.height - (toast.frame.size.height / 2.0)) - bottomPadding)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private UIView Extensions
|
||||
|
||||
private extension UIView {
|
||||
|
||||
var csSafeAreaInsets: UIEdgeInsets {
|
||||
if #available(iOS 11.0, *) {
|
||||
return self.safeAreaInsets
|
||||
} else {
|
||||
return .zero
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class Utilities{
|
||||
// }
|
||||
|
||||
static func startProgressHUD(progress: Float? = nil) {
|
||||
LLSpinner.spin()
|
||||
LLSpinner.spin(text: "Please wait...")
|
||||
// if let progress = progress {
|
||||
// SVProgressHUD.showProgress(progress)
|
||||
// } else {
|
||||
@@ -54,7 +54,7 @@ class Utilities{
|
||||
alert.setValue(messageMutableString, forKey: "attributedMessage")
|
||||
|
||||
let okAction = UIAlertAction(title: okBtnStr ?? "OK", style: .default, handler: nil)
|
||||
okAction.setValue(UIColor.appColor(.AppBaseBlueColor), forKey: "titleTextColor")
|
||||
okAction.setValue(UIColor.appColor(.TextDarkBlue), forKey: "titleTextColor")
|
||||
|
||||
alert.addAction(okAction)
|
||||
|
||||
@@ -70,7 +70,7 @@ class Utilities{
|
||||
let messageAttributes = [NSAttributedString.Key.font: UIFont(name: "Nunito-Regular", size: 18)!, NSAttributedString.Key.foregroundColor: UIColor.black]
|
||||
let messageString = NSAttributedString(string: msgBody, attributes: messageAttributes)
|
||||
|
||||
okAction.setValue(UIColor.appColor(.AppBaseBlueColor), forKey: "titleTextColor")
|
||||
okAction.setValue(UIColor.appColor(.TextDarkBlue), forKey: "titleTextColor")
|
||||
|
||||
alert.addAction(okAction)
|
||||
alert.setValue(messageString, forKey: "attributedMessage")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// UIApplication.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Y6W-OH-hqX">
|
||||
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
|
||||
@@ -2,6 +2,12 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>STAGING_URL</key>
|
||||
<string>$(STAGING_URL)</string>
|
||||
<key>API_KEY_ID</key>
|
||||
<string>$(API_KEY_ID)</string>
|
||||
<key>API_KEY_PASS</key>
|
||||
<string>$(API_KEY_PASS)</string>
|
||||
<key>UIUserInterfaceStyle</key>
|
||||
<string>Light</string>
|
||||
<key>UIApplicationSceneManifest</key>
|
||||
|
||||
@@ -18,9 +18,14 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
IQKeyboardManager.shared.enable = true
|
||||
IQKeyboardManager.shared.resignOnTouchOutside = true
|
||||
// IQKeyboardManager.shared.enableAutoToolbar = false
|
||||
|
||||
// IQKeyboardManager.shared.layoutIfNeededOnUpdate = true
|
||||
|
||||
// Set the authentication ID Pass after app starts
|
||||
AuthFunc.shareInstance.setAuthIDPass()
|
||||
|
||||
// Set the toast defaults
|
||||
setupToast()
|
||||
|
||||
//Lottie Config to handle rendering
|
||||
LottieConfiguration.shared.renderingEngine = .mainThread
|
||||
return true
|
||||
@@ -43,3 +48,24 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
|
||||
|
||||
}
|
||||
|
||||
extension AppDelegate {
|
||||
// MARK: - Toast Setup
|
||||
|
||||
private func setupToast(){
|
||||
var style = ToastStyle()
|
||||
style.displayShadow = true
|
||||
style.messageColor = UIColor.white
|
||||
style.backgroundColor = UIColor.appColor(.TextDarkBlue)!
|
||||
style.messageFont = FontCustom.shareInstance.customFont(fontName: .Exo2_Medium, size: 16)
|
||||
style.titleAlignment = .center
|
||||
style.messageAlignment = .center
|
||||
style.cornerRadius = 10
|
||||
ToastManager.shared.style = style
|
||||
|
||||
// toggle "tap to dismiss" functionality
|
||||
ToastManager.shared.isTapToDismissEnabled = true
|
||||
|
||||
// toggle queueing behavior
|
||||
ToastManager.shared.isQueueEnabled = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,12 +14,27 @@ class AuthFunc{
|
||||
This is not for external use!
|
||||
This should only be used for login, registration, Auth Process process & userData Extraction.
|
||||
*/
|
||||
|
||||
var player: AVQueuePlayer?
|
||||
var playerLooper: AVPlayerLooper?
|
||||
var userType = UserType.adult
|
||||
|
||||
var authID = String()
|
||||
var authPass = String()
|
||||
|
||||
static let shareInstance = AuthFunc()
|
||||
|
||||
|
||||
func setAuthIDPass(){
|
||||
if let id = Bundle.main.infoDictionary?["API_KEY_ID"] as? String{
|
||||
authID = id
|
||||
}
|
||||
|
||||
if let pass = Bundle.main.infoDictionary?["API_KEY_PASS"] as? String{
|
||||
authPass = pass
|
||||
}
|
||||
}
|
||||
|
||||
func playStartUpsound(){
|
||||
guard let path = Bundle.main.path(forResource: K.StaticFilesString.onBoardMainSound, ofType:"m4a") else {
|
||||
return }
|
||||
|
||||
@@ -6,3 +6,44 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// enum to check envirnments
|
||||
enum EnvironmentCheck{
|
||||
case staging
|
||||
case production
|
||||
}
|
||||
|
||||
struct APIEndPoints {
|
||||
|
||||
struct BaseURL {
|
||||
static let staging = "https://wokaland.com/admin/api/"
|
||||
static let production = "https://simplitend.com"
|
||||
}
|
||||
|
||||
struct Auth {
|
||||
static let check_exist_email = makeURL(path: "check_exist_email")
|
||||
static let login = makeURL(path: "login")
|
||||
static let login_proceed = makeURL(path: "login_proceed")
|
||||
}
|
||||
|
||||
// Other endpoint categories...
|
||||
struct Links {
|
||||
static let privacyPolicy = "https://www.simplitend.com/privacy-policy"
|
||||
static let termsAndCondition = "https://www.simplitend.com/terms-and-conditions"
|
||||
// Other links...
|
||||
}
|
||||
|
||||
// Helper method to construct full URL from base URL and path
|
||||
private static func makeURL(path: String) -> URL {
|
||||
guard let baseURL = baseURLForCurrentEnvironment() else {
|
||||
fatalError("Base URL not configured for current environment")
|
||||
}
|
||||
return baseURL.appendingPathComponent(path)
|
||||
}
|
||||
|
||||
// Helper method to get base URL based on current environment
|
||||
private static func baseURLForCurrentEnvironment() -> URL? {
|
||||
// Determine environment (e.g., staging, production) and return appropriate base URL
|
||||
return URL(string: BaseURL.staging)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,3 +6,18 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - BaseResponseModel
|
||||
|
||||
class BaseResponseModel<T: Codable> : Codable {
|
||||
//class BaseResponseModel: Codable {
|
||||
let success: Int?
|
||||
let message: String?
|
||||
let result: T?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case success
|
||||
case message
|
||||
case result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ class NetworkManager{
|
||||
// Execute the request on the specified queue
|
||||
queue.async {
|
||||
AF.request(url, method: method, parameters: parameters, encoding: encoding, headers: headers, requestModifier: { $0.timeoutInterval = 30 })
|
||||
.authenticate(username: "admin", password: "Woka@1234")
|
||||
.validate(statusCode: 200..<300)
|
||||
.responseDecodable(of: T.self) { response in
|
||||
switch response.result {
|
||||
@@ -105,69 +106,4 @@ class NetworkManager{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// func handleAFError(error: Error)-> Int? {
|
||||
// if let afError = error as? AFError {
|
||||
// // This error is of type AFError, and you can access its properties.
|
||||
// let errorCode = afError.responseCode
|
||||
// return errorCode
|
||||
// } else {
|
||||
// // Handle other types of errors or unsupported cases
|
||||
// return nil
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func uploadFormData<T: Codable>(
|
||||
// url: URLConvertible,
|
||||
// method: HTTPMethod,
|
||||
// headers: HTTPHeaders? = nil,
|
||||
// params : [String : Any]?,
|
||||
// image : UIImage?,
|
||||
// formData: [MultipartFormData],
|
||||
// completionHandler: @escaping (Result<T, AFError>) -> Void
|
||||
// ) {
|
||||
//
|
||||
// let imageData = image?.jpegData(compressionQuality: 0.4)!
|
||||
// let imageKey = "contact_photo" // Change me
|
||||
// AF.upload(multipartFormData: { multiPart in
|
||||
// for (key, value) in (params ?? [:]) {
|
||||
// if let arrayObj = value as? [Any] {
|
||||
// for index in 0..<arrayObj.count {
|
||||
// if key != "contact_photo"{
|
||||
// multiPart.append("\(arrayObj[index])".data(using: .utf8)!, withName: "\(key)[\(index)]")
|
||||
// }
|
||||
// }
|
||||
// } else {
|
||||
// if key != "contact_photo"{
|
||||
// multiPart.append("\(value)".data(using: .utf8)!, withName: key)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if let imageData{
|
||||
// multiPart.append(imageData, withName: imageKey, fileName: "file.jpg", mimeType: "image/jpg")
|
||||
// }
|
||||
// }, to: url, headers: headers).responseDecodable { (response: DataResponse<T,AFError>) in
|
||||
// switch response.result {
|
||||
// case .success(let value):
|
||||
// completionHandler(.success(value))
|
||||
// case .failure(let error):
|
||||
// if let statusCode = response.response?.statusCode {
|
||||
// switch statusCode {
|
||||
// case 400..<500:
|
||||
// // Handle client-side errors (4xx)
|
||||
// completionHandler(.failure(.custom(message: "Client-side error: \(statusCode)")))
|
||||
// case 500..<600:
|
||||
// // Handle server-side errors (5xx)
|
||||
// completionHandler(.failure(.custom(message: "Server-side error: \(statusCode)")))
|
||||
// default:
|
||||
// completionHandler(.failure(.unknown))
|
||||
// }
|
||||
// } else {
|
||||
// completionHandler(.failure(.unknown))
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// QueueHelper.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
@@ -13,8 +13,8 @@ import Foundation
|
||||
*/
|
||||
|
||||
class QueueHelper {
|
||||
static let queue = DispatchQueue(label: "com.simpliTend")
|
||||
static let queueHome = DispatchQueue(label: "com.simpliTend.home")
|
||||
static let queue = DispatchQueue(label: "com.woka")
|
||||
static let queueHome = DispatchQueue(label: "com.woka.home")
|
||||
static let group = DispatchGroup()
|
||||
static let group2 = DispatchGroup()
|
||||
static let group3 = DispatchGroup()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//
|
||||
// File.swift
|
||||
// ValueWrapper.swift
|
||||
// WOKA
|
||||
//
|
||||
// Created by MacBook Pro on 06/05/24.
|
||||
|
||||
@@ -29,9 +29,6 @@ class SplashVC: UIViewController {
|
||||
}
|
||||
|
||||
@IBAction func languageBtnTapped(_ sender: UIButton) {
|
||||
// let sb = UIStoryboard(name: K.StoryBoard.authenticationSB, bundle: nil)
|
||||
// let vc = sb.instantiateViewController(withIdentifier: K.StoryBoardID.Authentication.loginVC) as! LoginVC
|
||||
// self.navigationController?.pushViewController(vc, animated: true)
|
||||
switch sender{
|
||||
case hindiBtn:
|
||||
K.GVar.localized = K.LocalizedEnum.hindi
|
||||
|
||||
Reference in New Issue
Block a user