From 2d33f7f71fbd40069f349aca9b65d10f30f671be Mon Sep 17 00:00:00 2001 From: Uday-iOS Date: Wed, 10 May 2023 10:35:06 +0530 Subject: [PATCH] --- added api call using url session, display list of pages in tableview. --- WisdomTask.xcodeproj/project.pbxproj | 635 ++++++++++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + WisdomTask/AppDelegate/AppDelegate.swift | 36 + WisdomTask/AppDelegate/SceneDelegate.swift | 64 ++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 13 + WisdomTask/Assets.xcassets/Contents.json | 6 + WisdomTask/BaseStack/APIError.swift | 68 ++ WisdomTask/BaseStack/AlertModel.swift | 38 ++ WisdomTask/BaseStack/BaseDynamic.swift | 30 + .../BaseStack/BaseLoaderController.swift | 62 ++ WisdomTask/BaseStack/BaseModel.swift | 61 ++ WisdomTask/BaseStack/BaseNav.swift | 20 + WisdomTask/BaseStack/BaseViewController.swift | 87 +++ WisdomTask/BaseStack/Helper.swift | 52 ++ WisdomTask/BaseStack/LoaderView.swift | 42 ++ WisdomTask/BaseStack/LoaderViewStatus.swift | 35 + WisdomTask/BaseStack/RowViewModel.swift | 13 + WisdomTask/BaseStack/UserDefaults.swift | 50 ++ WisdomTask/Constants/APIConstants.swift | 22 + WisdomTask/Constants/Gateway.swift | 38 ++ .../WisdomeList/Shared/WisdomResponder.swift | 13 + .../WisdomeList/Shared/WisdomeSharedNav.swift | 55 ++ .../Shared/WisdomeSharedViewModel.swift | 35 + .../WisdomeList/WisdomListController.swift | 61 ++ .../WisdomeList/WisdomListViewModel.swift | 84 +++ WisdomTask/Info.plist | 30 + WisdomTask/Models/WisdomeListModel.swift | 18 + .../NetworkHandlers/Common/AppGateway.plist | 11 + .../Common/ImageNetworkHandler.swift | 30 + .../Common/ImageNetworking.swift | 48 ++ .../Common/Network+Utils.swift | 19 + .../Common/NetworkConfiguration.swift | 33 + .../Common/NetworkHandler.swift | 188 ++++++ .../NetworkHandlers/Common/Reachability.swift | 399 +++++++++++ .../WisdomList/WisdomListHandler.swift | 37 + .../WisdomList/WisdomListRouter.swift | 48 ++ .../Base.lproj/LaunchScreen.storyboard | 25 + .../StoryBoards/Base.lproj/Main.storyboard | 106 +++ .../WisdomeList/WisdomeListCell.swift | 29 + .../WisdomeListCellViewModel.swift | 45 ++ WisdomTask/Utils/Data+Util.swift | 31 + WisdomTask/Utils/Dictionary+Util.swift | 21 + WisdomTask/Utils/ImageCache+Util.swift | 67 ++ WisdomTask/Utils/NotificationName+Util.swift | 17 + WisdomTask/Utils/Storyboard.Util.swift | 33 + WisdomTask/Utils/String.Util.swift | 24 + .../Utils/UIViewController+ViewStatus.swift | 101 +++ WisdomTask/Utils/ViewController.Util.swift | 33 + 50 files changed, 3039 insertions(+) create mode 100644 WisdomTask.xcodeproj/project.pbxproj create mode 100644 WisdomTask.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 WisdomTask.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 WisdomTask/AppDelegate/AppDelegate.swift create mode 100644 WisdomTask/AppDelegate/SceneDelegate.swift create mode 100644 WisdomTask/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 WisdomTask/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 WisdomTask/Assets.xcassets/Contents.json create mode 100644 WisdomTask/BaseStack/APIError.swift create mode 100644 WisdomTask/BaseStack/AlertModel.swift create mode 100644 WisdomTask/BaseStack/BaseDynamic.swift create mode 100644 WisdomTask/BaseStack/BaseLoaderController.swift create mode 100644 WisdomTask/BaseStack/BaseModel.swift create mode 100644 WisdomTask/BaseStack/BaseNav.swift create mode 100644 WisdomTask/BaseStack/BaseViewController.swift create mode 100644 WisdomTask/BaseStack/Helper.swift create mode 100644 WisdomTask/BaseStack/LoaderView.swift create mode 100644 WisdomTask/BaseStack/LoaderViewStatus.swift create mode 100644 WisdomTask/BaseStack/RowViewModel.swift create mode 100644 WisdomTask/BaseStack/UserDefaults.swift create mode 100644 WisdomTask/Constants/APIConstants.swift create mode 100644 WisdomTask/Constants/Gateway.swift create mode 100644 WisdomTask/Features/WisdomeList/Shared/WisdomResponder.swift create mode 100644 WisdomTask/Features/WisdomeList/Shared/WisdomeSharedNav.swift create mode 100644 WisdomTask/Features/WisdomeList/Shared/WisdomeSharedViewModel.swift create mode 100644 WisdomTask/Features/WisdomeList/WisdomListController.swift create mode 100644 WisdomTask/Features/WisdomeList/WisdomListViewModel.swift create mode 100644 WisdomTask/Info.plist create mode 100644 WisdomTask/Models/WisdomeListModel.swift create mode 100644 WisdomTask/NetworkHandlers/Common/AppGateway.plist create mode 100644 WisdomTask/NetworkHandlers/Common/ImageNetworkHandler.swift create mode 100644 WisdomTask/NetworkHandlers/Common/ImageNetworking.swift create mode 100755 WisdomTask/NetworkHandlers/Common/Network+Utils.swift create mode 100644 WisdomTask/NetworkHandlers/Common/NetworkConfiguration.swift create mode 100644 WisdomTask/NetworkHandlers/Common/NetworkHandler.swift create mode 100755 WisdomTask/NetworkHandlers/Common/Reachability.swift create mode 100644 WisdomTask/NetworkHandlers/WisdomList/WisdomListHandler.swift create mode 100644 WisdomTask/NetworkHandlers/WisdomList/WisdomListRouter.swift create mode 100644 WisdomTask/StoryBoards/Base.lproj/LaunchScreen.storyboard create mode 100644 WisdomTask/StoryBoards/Base.lproj/Main.storyboard create mode 100644 WisdomTask/TableviewCells/WisdomeList/WisdomeListCell.swift create mode 100644 WisdomTask/TableviewCells/WisdomeList/WisdomeListCellViewModel.swift create mode 100644 WisdomTask/Utils/Data+Util.swift create mode 100755 WisdomTask/Utils/Dictionary+Util.swift create mode 100644 WisdomTask/Utils/ImageCache+Util.swift create mode 100644 WisdomTask/Utils/NotificationName+Util.swift create mode 100644 WisdomTask/Utils/Storyboard.Util.swift create mode 100644 WisdomTask/Utils/String.Util.swift create mode 100644 WisdomTask/Utils/UIViewController+ViewStatus.swift create mode 100644 WisdomTask/Utils/ViewController.Util.swift diff --git a/WisdomTask.xcodeproj/project.pbxproj b/WisdomTask.xcodeproj/project.pbxproj new file mode 100644 index 0000000..cd7358d --- /dev/null +++ b/WisdomTask.xcodeproj/project.pbxproj @@ -0,0 +1,635 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 56; + objects = { + +/* Begin PBXBuildFile section */ + 48B2B02A2A0AAF4500C64039 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0292A0AAF4500C64039 /* AppDelegate.swift */; }; + 48B2B02C2A0AAF4500C64039 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B02B2A0AAF4500C64039 /* SceneDelegate.swift */; }; + 48B2B02E2A0AAF4500C64039 /* WisdomListController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B02D2A0AAF4500C64039 /* WisdomListController.swift */; }; + 48B2B0312A0AAF4500C64039 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 48B2B02F2A0AAF4500C64039 /* Main.storyboard */; }; + 48B2B0332A0AAF4700C64039 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 48B2B0322A0AAF4700C64039 /* Assets.xcassets */; }; + 48B2B0362A0AAF4700C64039 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 48B2B0342A0AAF4700C64039 /* LaunchScreen.storyboard */; }; + 48B2B0472A0AB02D00C64039 /* NetworkHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0452A0AB02D00C64039 /* NetworkHandler.swift */; }; + 48B2B0482A0AB02D00C64039 /* NetworkConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0462A0AB02D00C64039 /* NetworkConfiguration.swift */; }; + 48B2B05B2A0AB06800C64039 /* APIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B04B2A0AB06800C64039 /* APIError.swift */; }; + 48B2B05C2A0AB06800C64039 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B04C2A0AB06800C64039 /* BaseViewController.swift */; }; + 48B2B05D2A0AB06800C64039 /* BaseNav.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B04D2A0AB06800C64039 /* BaseNav.swift */; }; + 48B2B0602A0AB06800C64039 /* AlertModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0512A0AB06800C64039 /* AlertModel.swift */; }; + 48B2B0612A0AB06800C64039 /* BaseModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0522A0AB06800C64039 /* BaseModel.swift */; }; + 48B2B0622A0AB06800C64039 /* RowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0532A0AB06800C64039 /* RowViewModel.swift */; }; + 48B2B0632A0AB06800C64039 /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0542A0AB06800C64039 /* UserDefaults.swift */; }; + 48B2B0642A0AB06800C64039 /* LoaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0552A0AB06800C64039 /* LoaderView.swift */; }; + 48B2B0662A0AB06800C64039 /* BaseLoaderController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0572A0AB06800C64039 /* BaseLoaderController.swift */; }; + 48B2B0672A0AB06800C64039 /* Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0582A0AB06800C64039 /* Helper.swift */; }; + 48B2B0682A0AB06800C64039 /* LoaderViewStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0592A0AB06800C64039 /* LoaderViewStatus.swift */; }; + 48B2B0692A0AB06800C64039 /* BaseDynamic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B05A2A0AB06800C64039 /* BaseDynamic.swift */; }; + 48B2B06B2A0AB15800C64039 /* ImageCache+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B06A2A0AB15800C64039 /* ImageCache+Util.swift */; }; + 48B2B06D2A0AB17A00C64039 /* Reachability.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B06C2A0AB17A00C64039 /* Reachability.swift */; }; + 48B2B06F2A0AB19600C64039 /* Network+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B06E2A0AB19500C64039 /* Network+Utils.swift */; }; + 48B2B0712A0AB1B000C64039 /* Dictionary+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0702A0AB1B000C64039 /* Dictionary+Util.swift */; }; + 48B2B0732A0AB1DC00C64039 /* NotificationName+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0722A0AB1DC00C64039 /* NotificationName+Util.swift */; }; + 48B2B0772A0AB43000C64039 /* APIConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0762A0AB43000C64039 /* APIConstants.swift */; }; + 48B2B0792A0AB4A800C64039 /* Gateway.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0782A0AB4A800C64039 /* Gateway.swift */; }; + 48B2B07B2A0AB55F00C64039 /* AppGateway.plist in Resources */ = {isa = PBXBuildFile; fileRef = 48B2B07A2A0AB55E00C64039 /* AppGateway.plist */; }; + 48B2B07D2A0AB5AF00C64039 /* WisdomListRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B07C2A0AB5AF00C64039 /* WisdomListRouter.swift */; }; + 48B2B07F2A0AB5B900C64039 /* WisdomListHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B07E2A0AB5B900C64039 /* WisdomListHandler.swift */; }; + 48B2B0822A0AB73200C64039 /* WisdomeListModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0812A0AB73200C64039 /* WisdomeListModel.swift */; }; + 48B2B0842A0ABBCA00C64039 /* WisdomListViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0832A0ABBCA00C64039 /* WisdomListViewModel.swift */; }; + 48B2B0872A0ABC5000C64039 /* WisdomResponder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0862A0ABC5000C64039 /* WisdomResponder.swift */; }; + 48B2B0892A0ABCD700C64039 /* UIViewController+ViewStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0882A0ABCD700C64039 /* UIViewController+ViewStatus.swift */; }; + 48B2B08D2A0ABFE400C64039 /* WisdomeListCellViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B08C2A0ABFE400C64039 /* WisdomeListCellViewModel.swift */; }; + 48B2B0902A0AC21D00C64039 /* WisdomeListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B08F2A0AC21D00C64039 /* WisdomeListCell.swift */; }; + 48B2B0942A0AC51900C64039 /* WisdomeSharedNav.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0932A0AC51900C64039 /* WisdomeSharedNav.swift */; }; + 48B2B0962A0AC52500C64039 /* WisdomeSharedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0952A0AC52500C64039 /* WisdomeSharedViewModel.swift */; }; + 48B2B0982A0AC69900C64039 /* ViewController.Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0972A0AC69900C64039 /* ViewController.Util.swift */; }; + 48B2B09A2A0AC6C100C64039 /* Storyboard.Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0992A0AC6C100C64039 /* Storyboard.Util.swift */; }; + 48B2B09C2A0AC75E00C64039 /* String.Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B09B2A0AC75E00C64039 /* String.Util.swift */; }; + 48B2B09E2A0ACB9500C64039 /* ImageNetworkHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B09D2A0ACB9500C64039 /* ImageNetworkHandler.swift */; }; + 48B2B0A02A0AD20C00C64039 /* Data+Util.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B09F2A0AD20C00C64039 /* Data+Util.swift */; }; + 48B2B0A22A0AD4B400C64039 /* ImageNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B2B0A12A0AD4B400C64039 /* ImageNetworking.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 48B2B0262A0AAF4500C64039 /* WisdomTask.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WisdomTask.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 48B2B0292A0AAF4500C64039 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 48B2B02B2A0AAF4500C64039 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; + 48B2B02D2A0AAF4500C64039 /* WisdomListController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomListController.swift; sourceTree = ""; }; + 48B2B0302A0AAF4500C64039 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 48B2B0322A0AAF4700C64039 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 48B2B0352A0AAF4700C64039 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 48B2B0372A0AAF4700C64039 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 48B2B0452A0AB02D00C64039 /* NetworkHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkHandler.swift; sourceTree = ""; }; + 48B2B0462A0AB02D00C64039 /* NetworkConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkConfiguration.swift; sourceTree = ""; }; + 48B2B04B2A0AB06800C64039 /* APIError.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = APIError.swift; sourceTree = ""; }; + 48B2B04C2A0AB06800C64039 /* BaseViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; + 48B2B04D2A0AB06800C64039 /* BaseNav.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseNav.swift; sourceTree = ""; }; + 48B2B0512A0AB06800C64039 /* AlertModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AlertModel.swift; sourceTree = ""; }; + 48B2B0522A0AB06800C64039 /* BaseModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseModel.swift; sourceTree = ""; }; + 48B2B0532A0AB06800C64039 /* RowViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RowViewModel.swift; sourceTree = ""; }; + 48B2B0542A0AB06800C64039 /* UserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserDefaults.swift; sourceTree = ""; }; + 48B2B0552A0AB06800C64039 /* LoaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoaderView.swift; sourceTree = ""; }; + 48B2B0572A0AB06800C64039 /* BaseLoaderController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseLoaderController.swift; sourceTree = ""; }; + 48B2B0582A0AB06800C64039 /* Helper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Helper.swift; sourceTree = ""; }; + 48B2B0592A0AB06800C64039 /* LoaderViewStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoaderViewStatus.swift; sourceTree = ""; }; + 48B2B05A2A0AB06800C64039 /* BaseDynamic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BaseDynamic.swift; sourceTree = ""; }; + 48B2B06A2A0AB15800C64039 /* ImageCache+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ImageCache+Util.swift"; sourceTree = ""; }; + 48B2B06C2A0AB17A00C64039 /* Reachability.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reachability.swift; sourceTree = ""; }; + 48B2B06E2A0AB19500C64039 /* Network+Utils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Network+Utils.swift"; sourceTree = ""; }; + 48B2B0702A0AB1B000C64039 /* Dictionary+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Dictionary+Util.swift"; sourceTree = ""; }; + 48B2B0722A0AB1DC00C64039 /* NotificationName+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NotificationName+Util.swift"; sourceTree = ""; }; + 48B2B0762A0AB43000C64039 /* APIConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIConstants.swift; sourceTree = ""; }; + 48B2B0782A0AB4A800C64039 /* Gateway.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Gateway.swift; sourceTree = ""; }; + 48B2B07A2A0AB55E00C64039 /* AppGateway.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppGateway.plist; sourceTree = ""; }; + 48B2B07C2A0AB5AF00C64039 /* WisdomListRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomListRouter.swift; sourceTree = ""; }; + 48B2B07E2A0AB5B900C64039 /* WisdomListHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomListHandler.swift; sourceTree = ""; }; + 48B2B0812A0AB73200C64039 /* WisdomeListModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomeListModel.swift; sourceTree = ""; }; + 48B2B0832A0ABBCA00C64039 /* WisdomListViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomListViewModel.swift; sourceTree = ""; }; + 48B2B0862A0ABC5000C64039 /* WisdomResponder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomResponder.swift; sourceTree = ""; }; + 48B2B0882A0ABCD700C64039 /* UIViewController+ViewStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewController+ViewStatus.swift"; sourceTree = ""; }; + 48B2B08C2A0ABFE400C64039 /* WisdomeListCellViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomeListCellViewModel.swift; sourceTree = ""; }; + 48B2B08F2A0AC21D00C64039 /* WisdomeListCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomeListCell.swift; sourceTree = ""; }; + 48B2B0932A0AC51900C64039 /* WisdomeSharedNav.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomeSharedNav.swift; sourceTree = ""; }; + 48B2B0952A0AC52500C64039 /* WisdomeSharedViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WisdomeSharedViewModel.swift; sourceTree = ""; }; + 48B2B0972A0AC69900C64039 /* ViewController.Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.Util.swift; sourceTree = ""; }; + 48B2B0992A0AC6C100C64039 /* Storyboard.Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Storyboard.Util.swift; sourceTree = ""; }; + 48B2B09B2A0AC75E00C64039 /* String.Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = String.Util.swift; sourceTree = ""; }; + 48B2B09D2A0ACB9500C64039 /* ImageNetworkHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageNetworkHandler.swift; sourceTree = ""; }; + 48B2B09F2A0AD20C00C64039 /* Data+Util.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Util.swift"; sourceTree = ""; }; + 48B2B0A12A0AD4B400C64039 /* ImageNetworking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageNetworking.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 48B2B0232A0AAF4500C64039 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 48B2B01D2A0AAF4500C64039 = { + isa = PBXGroup; + children = ( + 48B2B0282A0AAF4500C64039 /* WisdomTask */, + 48B2B0272A0AAF4500C64039 /* Products */, + ); + sourceTree = ""; + }; + 48B2B0272A0AAF4500C64039 /* Products */ = { + isa = PBXGroup; + children = ( + 48B2B0262A0AAF4500C64039 /* WisdomTask.app */, + ); + name = Products; + sourceTree = ""; + }; + 48B2B0282A0AAF4500C64039 /* WisdomTask */ = { + isa = PBXGroup; + children = ( + 48B2B08E2A0AC20000C64039 /* TableviewCells */, + 48B2B0802A0AB71D00C64039 /* Models */, + 48B2B0752A0AB42400C64039 /* Constants */, + 48B2B04A2A0AB06800C64039 /* BaseStack */, + 48B2B0422A0AAFE600C64039 /* StoryBoards */, + 48B2B0402A0AAFBF00C64039 /* NetworkHandlers */, + 48B2B03F2A0AAFBC00C64039 /* Utils */, + 48B2B03E2A0AAFBA00C64039 /* AppDelegate */, + 48B2B03D2A0AAFAB00C64039 /* Features */, + 48B2B0322A0AAF4700C64039 /* Assets.xcassets */, + 48B2B0372A0AAF4700C64039 /* Info.plist */, + ); + path = WisdomTask; + sourceTree = ""; + }; + 48B2B03D2A0AAFAB00C64039 /* Features */ = { + isa = PBXGroup; + children = ( + 48B2B0432A0AB00100C64039 /* WisdomeList */, + ); + path = Features; + sourceTree = ""; + }; + 48B2B03E2A0AAFBA00C64039 /* AppDelegate */ = { + isa = PBXGroup; + children = ( + 48B2B0292A0AAF4500C64039 /* AppDelegate.swift */, + 48B2B02B2A0AAF4500C64039 /* SceneDelegate.swift */, + ); + path = AppDelegate; + sourceTree = ""; + }; + 48B2B03F2A0AAFBC00C64039 /* Utils */ = { + isa = PBXGroup; + children = ( + 48B2B09F2A0AD20C00C64039 /* Data+Util.swift */, + 48B2B09B2A0AC75E00C64039 /* String.Util.swift */, + 48B2B0992A0AC6C100C64039 /* Storyboard.Util.swift */, + 48B2B0972A0AC69900C64039 /* ViewController.Util.swift */, + 48B2B0882A0ABCD700C64039 /* UIViewController+ViewStatus.swift */, + 48B2B0722A0AB1DC00C64039 /* NotificationName+Util.swift */, + 48B2B0702A0AB1B000C64039 /* Dictionary+Util.swift */, + 48B2B06A2A0AB15800C64039 /* ImageCache+Util.swift */, + ); + path = Utils; + sourceTree = ""; + }; + 48B2B0402A0AAFBF00C64039 /* NetworkHandlers */ = { + isa = PBXGroup; + children = ( + 48B2B0742A0AB24600C64039 /* WisdomList */, + 48B2B0442A0AB02D00C64039 /* Common */, + ); + path = NetworkHandlers; + sourceTree = ""; + }; + 48B2B0422A0AAFE600C64039 /* StoryBoards */ = { + isa = PBXGroup; + children = ( + 48B2B0342A0AAF4700C64039 /* LaunchScreen.storyboard */, + 48B2B02F2A0AAF4500C64039 /* Main.storyboard */, + ); + path = StoryBoards; + sourceTree = ""; + }; + 48B2B0432A0AB00100C64039 /* WisdomeList */ = { + isa = PBXGroup; + children = ( + 48B2B0852A0ABC3A00C64039 /* Shared */, + 48B2B02D2A0AAF4500C64039 /* WisdomListController.swift */, + 48B2B0832A0ABBCA00C64039 /* WisdomListViewModel.swift */, + ); + path = WisdomeList; + sourceTree = ""; + }; + 48B2B0442A0AB02D00C64039 /* Common */ = { + isa = PBXGroup; + children = ( + 48B2B07A2A0AB55E00C64039 /* AppGateway.plist */, + 48B2B0452A0AB02D00C64039 /* NetworkHandler.swift */, + 48B2B06C2A0AB17A00C64039 /* Reachability.swift */, + 48B2B06E2A0AB19500C64039 /* Network+Utils.swift */, + 48B2B0462A0AB02D00C64039 /* NetworkConfiguration.swift */, + 48B2B09D2A0ACB9500C64039 /* ImageNetworkHandler.swift */, + 48B2B0A12A0AD4B400C64039 /* ImageNetworking.swift */, + ); + path = Common; + sourceTree = ""; + }; + 48B2B04A2A0AB06800C64039 /* BaseStack */ = { + isa = PBXGroup; + children = ( + 48B2B04C2A0AB06800C64039 /* BaseViewController.swift */, + 48B2B04B2A0AB06800C64039 /* APIError.swift */, + 48B2B04D2A0AB06800C64039 /* BaseNav.swift */, + 48B2B0512A0AB06800C64039 /* AlertModel.swift */, + 48B2B0522A0AB06800C64039 /* BaseModel.swift */, + 48B2B0532A0AB06800C64039 /* RowViewModel.swift */, + 48B2B0542A0AB06800C64039 /* UserDefaults.swift */, + 48B2B0552A0AB06800C64039 /* LoaderView.swift */, + 48B2B0572A0AB06800C64039 /* BaseLoaderController.swift */, + 48B2B0582A0AB06800C64039 /* Helper.swift */, + 48B2B0592A0AB06800C64039 /* LoaderViewStatus.swift */, + 48B2B05A2A0AB06800C64039 /* BaseDynamic.swift */, + ); + path = BaseStack; + sourceTree = ""; + }; + 48B2B0742A0AB24600C64039 /* WisdomList */ = { + isa = PBXGroup; + children = ( + 48B2B07C2A0AB5AF00C64039 /* WisdomListRouter.swift */, + 48B2B07E2A0AB5B900C64039 /* WisdomListHandler.swift */, + ); + path = WisdomList; + sourceTree = ""; + }; + 48B2B0752A0AB42400C64039 /* Constants */ = { + isa = PBXGroup; + children = ( + 48B2B0762A0AB43000C64039 /* APIConstants.swift */, + 48B2B0782A0AB4A800C64039 /* Gateway.swift */, + ); + path = Constants; + sourceTree = ""; + }; + 48B2B0802A0AB71D00C64039 /* Models */ = { + isa = PBXGroup; + children = ( + 48B2B0812A0AB73200C64039 /* WisdomeListModel.swift */, + ); + path = Models; + sourceTree = ""; + }; + 48B2B0852A0ABC3A00C64039 /* Shared */ = { + isa = PBXGroup; + children = ( + 48B2B0862A0ABC5000C64039 /* WisdomResponder.swift */, + 48B2B0932A0AC51900C64039 /* WisdomeSharedNav.swift */, + 48B2B0952A0AC52500C64039 /* WisdomeSharedViewModel.swift */, + ); + path = Shared; + sourceTree = ""; + }; + 48B2B08B2A0ABFCD00C64039 /* WisdomeList */ = { + isa = PBXGroup; + children = ( + 48B2B08F2A0AC21D00C64039 /* WisdomeListCell.swift */, + 48B2B08C2A0ABFE400C64039 /* WisdomeListCellViewModel.swift */, + ); + path = WisdomeList; + sourceTree = ""; + }; + 48B2B08E2A0AC20000C64039 /* TableviewCells */ = { + isa = PBXGroup; + children = ( + 48B2B08B2A0ABFCD00C64039 /* WisdomeList */, + ); + path = TableviewCells; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 48B2B0252A0AAF4500C64039 /* WisdomTask */ = { + isa = PBXNativeTarget; + buildConfigurationList = 48B2B03A2A0AAF4700C64039 /* Build configuration list for PBXNativeTarget "WisdomTask" */; + buildPhases = ( + 48B2B0222A0AAF4500C64039 /* Sources */, + 48B2B0232A0AAF4500C64039 /* Frameworks */, + 48B2B0242A0AAF4500C64039 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = WisdomTask; + productName = WisdomTask; + productReference = 48B2B0262A0AAF4500C64039 /* WisdomTask.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 48B2B01E2A0AAF4500C64039 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1420; + LastUpgradeCheck = 1420; + TargetAttributes = { + 48B2B0252A0AAF4500C64039 = { + CreatedOnToolsVersion = 14.2; + }; + }; + }; + buildConfigurationList = 48B2B0212A0AAF4500C64039 /* Build configuration list for PBXProject "WisdomTask" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 48B2B01D2A0AAF4500C64039; + productRefGroup = 48B2B0272A0AAF4500C64039 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 48B2B0252A0AAF4500C64039 /* WisdomTask */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 48B2B0242A0AAF4500C64039 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 48B2B07B2A0AB55F00C64039 /* AppGateway.plist in Resources */, + 48B2B0362A0AAF4700C64039 /* LaunchScreen.storyboard in Resources */, + 48B2B0332A0AAF4700C64039 /* Assets.xcassets in Resources */, + 48B2B0312A0AAF4500C64039 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 48B2B0222A0AAF4500C64039 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 48B2B05D2A0AB06800C64039 /* BaseNav.swift in Sources */, + 48B2B0642A0AB06800C64039 /* LoaderView.swift in Sources */, + 48B2B0772A0AB43000C64039 /* APIConstants.swift in Sources */, + 48B2B0712A0AB1B000C64039 /* Dictionary+Util.swift in Sources */, + 48B2B0902A0AC21D00C64039 /* WisdomeListCell.swift in Sources */, + 48B2B09A2A0AC6C100C64039 /* Storyboard.Util.swift in Sources */, + 48B2B0732A0AB1DC00C64039 /* NotificationName+Util.swift in Sources */, + 48B2B07D2A0AB5AF00C64039 /* WisdomListRouter.swift in Sources */, + 48B2B06D2A0AB17A00C64039 /* Reachability.swift in Sources */, + 48B2B02E2A0AAF4500C64039 /* WisdomListController.swift in Sources */, + 48B2B06F2A0AB19600C64039 /* Network+Utils.swift in Sources */, + 48B2B09E2A0ACB9500C64039 /* ImageNetworkHandler.swift in Sources */, + 48B2B0A02A0AD20C00C64039 /* Data+Util.swift in Sources */, + 48B2B0822A0AB73200C64039 /* WisdomeListModel.swift in Sources */, + 48B2B0682A0AB06800C64039 /* LoaderViewStatus.swift in Sources */, + 48B2B0672A0AB06800C64039 /* Helper.swift in Sources */, + 48B2B09C2A0AC75E00C64039 /* String.Util.swift in Sources */, + 48B2B0792A0AB4A800C64039 /* Gateway.swift in Sources */, + 48B2B0482A0AB02D00C64039 /* NetworkConfiguration.swift in Sources */, + 48B2B02A2A0AAF4500C64039 /* AppDelegate.swift in Sources */, + 48B2B0892A0ABCD700C64039 /* UIViewController+ViewStatus.swift in Sources */, + 48B2B08D2A0ABFE400C64039 /* WisdomeListCellViewModel.swift in Sources */, + 48B2B0982A0AC69900C64039 /* ViewController.Util.swift in Sources */, + 48B2B0622A0AB06800C64039 /* RowViewModel.swift in Sources */, + 48B2B0612A0AB06800C64039 /* BaseModel.swift in Sources */, + 48B2B02C2A0AAF4500C64039 /* SceneDelegate.swift in Sources */, + 48B2B07F2A0AB5B900C64039 /* WisdomListHandler.swift in Sources */, + 48B2B0A22A0AD4B400C64039 /* ImageNetworking.swift in Sources */, + 48B2B0472A0AB02D00C64039 /* NetworkHandler.swift in Sources */, + 48B2B0942A0AC51900C64039 /* WisdomeSharedNav.swift in Sources */, + 48B2B05C2A0AB06800C64039 /* BaseViewController.swift in Sources */, + 48B2B0872A0ABC5000C64039 /* WisdomResponder.swift in Sources */, + 48B2B0662A0AB06800C64039 /* BaseLoaderController.swift in Sources */, + 48B2B0692A0AB06800C64039 /* BaseDynamic.swift in Sources */, + 48B2B0602A0AB06800C64039 /* AlertModel.swift in Sources */, + 48B2B0632A0AB06800C64039 /* UserDefaults.swift in Sources */, + 48B2B06B2A0AB15800C64039 /* ImageCache+Util.swift in Sources */, + 48B2B05B2A0AB06800C64039 /* APIError.swift in Sources */, + 48B2B0962A0AC52500C64039 /* WisdomeSharedViewModel.swift in Sources */, + 48B2B0842A0ABBCA00C64039 /* WisdomListViewModel.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 48B2B02F2A0AAF4500C64039 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 48B2B0302A0AAF4500C64039 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 48B2B0342A0AAF4700C64039 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 48B2B0352A0AAF4700C64039 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 48B2B0382A0AAF4700C64039 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 48B2B0392A0AAF4700C64039 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 16.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 48B2B03B2A0AAF4700C64039 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 7VPXG96P25; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WisdomTask/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.jambav.workerlyagent; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Workerly Agent Development profile"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 48B2B03C2A0AAF4700C64039 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + CODE_SIGN_STYLE = Manual; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 7VPXG96P25; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = WisdomTask/Info.plist; + INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; + INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; + INFOPLIST_KEY_UIMainStoryboardFile = Main; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.jambav.workerlyagent; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "Workerly Agent Development profile"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 48B2B0212A0AAF4500C64039 /* Build configuration list for PBXProject "WisdomTask" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 48B2B0382A0AAF4700C64039 /* Debug */, + 48B2B0392A0AAF4700C64039 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 48B2B03A2A0AAF4700C64039 /* Build configuration list for PBXNativeTarget "WisdomTask" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 48B2B03B2A0AAF4700C64039 /* Debug */, + 48B2B03C2A0AAF4700C64039 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 48B2B01E2A0AAF4500C64039 /* Project object */; +} diff --git a/WisdomTask.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/WisdomTask.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/WisdomTask.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/WisdomTask.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/WisdomTask.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/WisdomTask.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/WisdomTask/AppDelegate/AppDelegate.swift b/WisdomTask/AppDelegate/AppDelegate.swift new file mode 100644 index 0000000..48a4c66 --- /dev/null +++ b/WisdomTask/AppDelegate/AppDelegate.swift @@ -0,0 +1,36 @@ +// +// AppDelegate.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + // MARK: UISceneSession Lifecycle + + func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { + // Called when a new scene session is being created. + // Use this method to select a configuration to create the new scene with. + return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) + } + + func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { + // Called when the user discards a scene session. + // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. + // Use this method to release any resources that were specific to the discarded scenes, as they will not return. + } + + +} + diff --git a/WisdomTask/AppDelegate/SceneDelegate.swift b/WisdomTask/AppDelegate/SceneDelegate.swift new file mode 100644 index 0000000..2c7704a --- /dev/null +++ b/WisdomTask/AppDelegate/SceneDelegate.swift @@ -0,0 +1,64 @@ +// +// SceneDelegate.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import UIKit + +class SceneDelegate: UIResponder, UIWindowSceneDelegate { + + var window: UIWindow? + + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { + // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. + // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. + // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). + let window = UIWindow(windowScene : scene as! UIWindowScene) + self.window = window + self.window?.makeKeyAndVisible() + setCustomRootViewController() + guard let _ = (scene as? UIWindowScene) else { return } + } + + func sceneDidDisconnect(_ scene: UIScene) { + // Called as the scene is being released by the system. + // This occurs shortly after the scene enters the background, or when its session is discarded. + // Release any resources associated with this scene that can be re-created the next time the scene connects. + // The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead). + } + + func sceneDidBecomeActive(_ scene: UIScene) { + // Called when the scene has moved from an inactive state to an active state. + // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. + } + + func sceneWillResignActive(_ scene: UIScene) { + // Called when the scene will move from an active state to an inactive state. + // This may occur due to temporary interruptions (ex. an incoming phone call). + } + + func sceneWillEnterForeground(_ scene: UIScene) { + // Called as the scene transitions from the background to the foreground. + // Use this method to undo the changes made on entering the background. + } + + func sceneDidEnterBackground(_ scene: UIScene) { + // Called as the scene transitions from the foreground to the background. + // Use this method to save data, release shared resources, and store enough scene-specific state information + // to restore the scene back to its current state. + } + + +} + +extension SceneDelegate { + func setCustomRootViewController(){ + let signUpVC = WisdomeSharedNav() + signUpVC.viewModel = WisdomeSharedViewModel(with: .wisdomeList) + window?.rootViewController = signUpVC + window!.makeKeyAndVisible() + } +} + diff --git a/WisdomTask/Assets.xcassets/AccentColor.colorset/Contents.json b/WisdomTask/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 0000000..eb87897 --- /dev/null +++ b/WisdomTask/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WisdomTask/Assets.xcassets/AppIcon.appiconset/Contents.json b/WisdomTask/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..13613e3 --- /dev/null +++ b/WisdomTask/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,13 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WisdomTask/Assets.xcassets/Contents.json b/WisdomTask/Assets.xcassets/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/WisdomTask/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WisdomTask/BaseStack/APIError.swift b/WisdomTask/BaseStack/APIError.swift new file mode 100644 index 0000000..3f7c062 --- /dev/null +++ b/WisdomTask/BaseStack/APIError.swift @@ -0,0 +1,68 @@ +// +// APIError.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation + +struct ErrorConstants { + struct ErrorTitles { + static let noNetwork = "Network Error" + static let serverError = "Server Error" + static let jsonError = "Internal Error" + static let badResponse = "Bad Response: Data not found" + static let noTemps = "No Temps" + } + struct ErrorMessages { + static let noNetwork = "No internet connection. Please check the network settings." + static let serverError = "Service unavailable now." + static let jsonError = "Parsing failed" + static let emotionError = "Please select your feelings." + static let badResponse = "Bad Response: Data not found" + static let noTemps = "No Temps Available" + } +} +enum APIError: Error { + case noNetwork + case serverError + case jsonError + case runtimeError(String) + case badResponse(URLResponse) + case noTemps +} +extension APIError { + var errorTitle: String { + switch self { + case .noNetwork: + return ErrorConstants.ErrorTitles.noNetwork + case .serverError: + return ErrorConstants.ErrorTitles.serverError + case .jsonError: + return ErrorConstants.ErrorTitles.jsonError + case .runtimeError(let err): + return err + case .badResponse(_): + return ErrorConstants.ErrorTitles.badResponse + case .noTemps: + return ErrorConstants.ErrorTitles.noTemps + } + } + var errorMessage: String { + switch self { + case .noNetwork: + return ErrorConstants.ErrorMessages.noNetwork + case .serverError: + return ErrorConstants.ErrorMessages.serverError + case .jsonError: + return ErrorConstants.ErrorMessages.jsonError + case .runtimeError(let err): + return err + case .noTemps: + return ErrorConstants.ErrorMessages.noTemps + case .badResponse(_): + return ErrorConstants.ErrorMessages.badResponse + } + } +} diff --git a/WisdomTask/BaseStack/AlertModel.swift b/WisdomTask/BaseStack/AlertModel.swift new file mode 100644 index 0000000..17d6d70 --- /dev/null +++ b/WisdomTask/BaseStack/AlertModel.swift @@ -0,0 +1,38 @@ +// +// AlertModel.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 06/01/23. +// + +import Foundation + +struct AlertModel { + let id: String? + let title: String? + let message: String? + let okTitle: String? + let cancelTitle: String? + let completion: (()->Void)? + + init(id: String? = nil, + title: String, + message: String, + okTitle: String? = nil, + cancelTitle: String? = nil, + completion: (()->Void)? = nil) + { + self.title = title + self.id = id + self.message = message + self.okTitle = okTitle + self.cancelTitle = cancelTitle + self.completion = completion + } +} +enum AlertPresentation { + case presentation(id: String??) + case cancel(id: String?) + case ok(id: String?) + +} diff --git a/WisdomTask/BaseStack/BaseDynamic.swift b/WisdomTask/BaseStack/BaseDynamic.swift new file mode 100644 index 0000000..5cf90a5 --- /dev/null +++ b/WisdomTask/BaseStack/BaseDynamic.swift @@ -0,0 +1,30 @@ +// +// BaseDynamic.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation + +class Dynamic { + typealias Listener = (T) -> Void + var listener: Listener? + + func bind(_ listener: Listener?) { + self.listener = listener + } + func bindAndFire(_ listener: Listener?) { + self.listener = listener + listener?(value) + } + var value: T { + didSet { + listener?(value) + } + } + init(value: T) { + self.value = value + } + +} diff --git a/WisdomTask/BaseStack/BaseLoaderController.swift b/WisdomTask/BaseStack/BaseLoaderController.swift new file mode 100644 index 0000000..3f78deb --- /dev/null +++ b/WisdomTask/BaseStack/BaseLoaderController.swift @@ -0,0 +1,62 @@ +// +// BaseLoaderController.swift +// WorkerlyAgent +// +// Created by Keerthana G on 18/01/23. +// + +import Foundation +import UIKit + +class LoadingViewController: UIViewController { + + override func viewDidLoad() { + // View Configuration + //view.backgroundColor = UIColor.black.withAlphaComponent(0.5) + blurEffectView.frame = self.view.bounds + view.insertSubview(blurEffectView, at: 0) + loadingActivityIndicator.center = CGPoint(x: view.bounds.midX, + y: view.bounds.midY) + view.addSubview(loadingActivityIndicator) + } + + var loadingActivityIndicator: UIActivityIndicatorView = { + // UIActivityIndicatorView Configuration + let indicator = UIActivityIndicatorView() + indicator.style = .medium + indicator.color = .systemGray + indicator.startAnimating() + indicator.autoresizingMask = [ + .flexibleLeftMargin, .flexibleRightMargin, + .flexibleTopMargin, .flexibleBottomMargin + ] + return indicator + }() + + var blurEffectView: UIVisualEffectView = { + // UIVisualEffectView Configuration + let blurEffect = UIBlurEffect(style: .light) + let blurEffectView = UIVisualEffectView(effect: blurEffect) + blurEffectView.alpha = 0.8 + blurEffectView.autoresizingMask = [ + .flexibleWidth, .flexibleHeight + ] + return blurEffectView + }() +// func removeSpinner() { +// //DispatchQueue.main.async { +// self.loadingActivityIndicator.stopAnimating() +// self.blurEffectView.removeFromSuperview() +// self.dismiss(animated: true) +// //} +// } +// func removeSpinner() { +// DispatchQueue.main.async { +// self.loadingActivityIndicator.stopAnimating() +// self.loadingActivityIndicator.isHidden = true +// self.blurEffectView.removeFromSuperview() +// self.blurEffectView.isHidden = true +// self.dismiss(animated: true) +// } +// } +} diff --git a/WisdomTask/BaseStack/BaseModel.swift b/WisdomTask/BaseStack/BaseModel.swift new file mode 100644 index 0000000..180ff7e --- /dev/null +++ b/WisdomTask/BaseStack/BaseModel.swift @@ -0,0 +1,61 @@ +// +// BaseModel.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation +import UIKit + +protocol noInternetProtocal{ + func networkAvailable() + func networkNotAvailable() +} +class BaseViewModel: RequestLoaderViewStatus { + + let viewStatus = Dynamic(value: .idel) + let alertModel: Dynamic = Dynamic(value: nil) + let alertPresentation = Dynamic(value: nil) + var noInternetDelegate : noInternetProtocal? + + init() { + bindAlertPresentation() + } + //MARK :- Refresh + lazy var topRefreshControl: UIRefreshControl = { + let refreshControl = UIRefreshControl() + refreshControl.tintColor = .systemGray + //refreshControl.attributedTitle = NSAttributedString(string: "Pull to Refresh") + refreshControl.sizeToFit() + refreshControl.addTarget(self, action: #selector(pullToRefresh(_:)), for: .valueChanged) + + return refreshControl + }() + +// @objc func doRefresh(){ + + // } + @objc func pullToRefresh(_ refreshControl: UIRefreshControl) { + didPullToRefresh() + } + func didPullToRefresh() { + + } + func addPullToRefreshControl(to tableView: UITableView) { + tableView.refreshControl?.endRefreshing() + tableView.refreshControl = topRefreshControl + tableView.addSubview(topRefreshControl) + } + //MARK :- Alert Handling + + func bindAlertPresentation() { + alertPresentation.bind { [weak self] indexBasedAlertPresentation in + guard let indexBasedAlertPresentation = indexBasedAlertPresentation else { return } + self?.alertAction(with: indexBasedAlertPresentation) + } + } + func alertAction(with alertPresentation: AlertPresentation) { + print("alertPresentation\(alertPresentation)") + } +} diff --git a/WisdomTask/BaseStack/BaseNav.swift b/WisdomTask/BaseStack/BaseNav.swift new file mode 100644 index 0000000..5968d27 --- /dev/null +++ b/WisdomTask/BaseStack/BaseNav.swift @@ -0,0 +1,20 @@ +// +// BaseNav.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation +import UIKit + +class BaseNavigationController: UINavigationController { + + + override func viewDidLoad() { + super.viewDidLoad() + //self.navigationBar.prefersLargeTitles = true + // Do any additional setup after loading the view. + } + +} diff --git a/WisdomTask/BaseStack/BaseViewController.swift b/WisdomTask/BaseStack/BaseViewController.swift new file mode 100644 index 0000000..b608c87 --- /dev/null +++ b/WisdomTask/BaseStack/BaseViewController.swift @@ -0,0 +1,87 @@ +// +// BaseViewController.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import UIKit + +class BaseViewController: UIViewController { + + var loader = UIActivityIndicatorView(frame: CGRect(x: 0, y: 0, width: 80, height: 80)) + override func viewDidLoad() { + super.viewDidLoad() + self.shouldShowLargeNavigationBarTitle = true + // view.addSubview(loader) + + } + var shouldShowLargeNavigationBarTitle: Bool? { + didSet { + if shouldShowLargeNavigationBarTitle ?? false { + self.navigationController?.navigationBar.prefersLargeTitles = true + self.navigationController?.navigationItem.largeTitleDisplayMode = .never + } else { + self.navigationController?.navigationBar.prefersLargeTitles = false + self.navigationController?.navigationItem.largeTitleDisplayMode = .never + } + } + } + + var shouldShowNavigationBar: Bool? { + didSet { + if shouldShowNavigationBar ?? false { + navigationController?.setNavigationBarHidden(false, animated: true) + } else { + navigationController?.setNavigationBarHidden(true, animated: true) + + } + } + } + func showIndicator(onView: UIView, withtitle: String?, and subtitle: String?){ + loader.style = .large + loader.center = onView.center + onView.isUserInteractionEnabled = false + //loader.isHidden = false + loader.startAnimating() + loader.layer.cornerCurve = .continuous + loader.layer.cornerRadius = 10 + loader.backgroundColor = UIColor(white: 0.5, alpha: 0.3) + + // loader.layer.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5).cgColor + onView.addSubview(loader) + } + func hideIndicator(onView: UIView){ + //loader.isHidden = true + onView.isUserInteractionEnabled = true + loader.stopAnimating() + loader.removeFromSuperview() + } +// var loadingActivityIndicator: UIActivityIndicatorView = { +// // UIActivityIndicatorView Configuration +// let indicator = UIActivityIndicatorView() +// indicator.backgroundColor = UIColor.black.withAlphaComponent(0.5) +// indicator.isHidden = false +// indicator.style = .large +// indicator.color = .white +// indicator.startAnimating() +// indicator.autoresizingMask = [ +// .flexibleLeftMargin, .flexibleRightMargin, +// .flexibleTopMargin, .flexibleBottomMargin +// ] +// return indicator +// }() +// +// var blurEffectView: UIVisualEffectView = { +// // UIVisualEffectView Configuration +// let blurEffect = UIBlurEffect(style: .light) +// let blurEffectView = UIVisualEffectView(effect: blurEffect) +// blurEffectView.alpha = 0.8 +// blurEffectView.autoresizingMask = [ +// .flexibleWidth, .flexibleHeight +// ] +// return blurEffectView +// }() +// + +} diff --git a/WisdomTask/BaseStack/Helper.swift b/WisdomTask/BaseStack/Helper.swift new file mode 100644 index 0000000..750ef78 --- /dev/null +++ b/WisdomTask/BaseStack/Helper.swift @@ -0,0 +1,52 @@ +// +// Helper.swift +// AgentApp_Workerly +// +// Created by Raghava Dokala on 14/10/22. +// + +import Foundation +import UIKit + +@available(iOS 13.0, *) +extension UIResponder { + @objc var scene: UIScene? { + return nil + } +} + +@available(iOS 13.0, *) +extension UIScene { + @objc override var scene: UIScene? { + return self + } +} + +@available(iOS 13.0, *) +extension UIView { + @objc override var scene: UIScene? { + if let window = self.window { + return window.windowScene + } else { + return self.next?.scene + } + } +} + +@available(iOS 13.0, *) +extension UIViewController { + @objc override var scene: UIScene? { + // Try walking the responder chain + var res = self.next?.scene + if (res == nil) { + // That didn't work. Try asking my parent view controller + res = self.parent?.scene + } + if (res == nil) { + // That didn't work. Try asking my presenting view controller + res = self.presentingViewController?.scene + } + + return res + } +} diff --git a/WisdomTask/BaseStack/LoaderView.swift b/WisdomTask/BaseStack/LoaderView.swift new file mode 100644 index 0000000..29b0804 --- /dev/null +++ b/WisdomTask/BaseStack/LoaderView.swift @@ -0,0 +1,42 @@ +// +// LoaderView.swift +// WorkerlyAgent +// +// Created by Keerthana G on 22/03/23. +// + +import Foundation +import UIKit + + var loaderView = UIView() + + let loadingActivityIndicator = UIActivityIndicatorView() + +// func showIndicator(onView: UIView, withtitle: String?, and subtitle: String?){ +// loadingActivityIndicator.isHidden = false +// loaderView.frame = onView.bounds +// // loaderView.isUserInteractionEnabled = false +// loadingActivityIndicator.style = .large +// loadingActivityIndicator.center = onView.center +// loaderView.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.3) +// //onView.addSubview(loadingActivityIndicator) +// DispatchQueue.main.async { +// //loaderView.isHidden = false +// loadingActivityIndicator.startAnimating() +// loaderView.addSubview(loadingActivityIndicator) +// onView.addSubview(loaderView) +// } +// +// } + func showDarkStyleIndicator(withtitle: String?, and subtitle: String?){ + + } +// func hideLoadingIndicator(onView : UIView){ +// DispatchQueue.main.async { +// //onView.willRemoveSubview(loaderView) +// // loaderView.isHidden = true +// loaderView.removeFromSuperview() +// } +// +// } + diff --git a/WisdomTask/BaseStack/LoaderViewStatus.swift b/WisdomTask/BaseStack/LoaderViewStatus.swift new file mode 100644 index 0000000..0bd90aa --- /dev/null +++ b/WisdomTask/BaseStack/LoaderViewStatus.swift @@ -0,0 +1,35 @@ +// +// LoaderViewStatus.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 28/12/22. +// + +import Foundation + +enum LoadingStyle { + case covering + case dark +} +enum ViewStatus { + case idel + case loading(loadStyle: LoadingStyle, title: String? = nil) + case loaded +} +protocol RequestLoaderViewStatus { + func loadingStyle() -> LoadingStyle + func loadingTitle() -> String? + func loadingSubTitle() -> String? +} + +extension RequestLoaderViewStatus { + func loadingStyle() -> LoadingStyle { + return .covering + } + func loadingTitle() -> String? { + return "Loading" + } + func loadingSubTitle() -> String? { + return nil + } +} diff --git a/WisdomTask/BaseStack/RowViewModel.swift b/WisdomTask/BaseStack/RowViewModel.swift new file mode 100644 index 0000000..03ae7ff --- /dev/null +++ b/WisdomTask/BaseStack/RowViewModel.swift @@ -0,0 +1,13 @@ +// +// RowViewModel.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 19/12/22. +// + +import Foundation + + +protocol RowViewModel { + +} diff --git a/WisdomTask/BaseStack/UserDefaults.swift b/WisdomTask/BaseStack/UserDefaults.swift new file mode 100644 index 0000000..64e677f --- /dev/null +++ b/WisdomTask/BaseStack/UserDefaults.swift @@ -0,0 +1,50 @@ +// +// UserDefaults.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation +import UIKit + +var ZWAUserDefaults = UserDefaults.standard + let APPLICATION = UIApplication.shared + let APP_DELEGATE = APPLICATION.delegate as! AppDelegate + let SCENE_DELEGATE = SceneDelegate() + var CLIENT_DETAILS = [CLIENT_CONSTS()] + + +struct CLIENT_CONSTS { + var CLIENT_ID = "1002.BJDDJGLUZ4AHD1Y2X1PMWIT0WP5F3J"//localzoho -> "1002.4DYLRPLL04HMLX1ZGF1H487QBP0JYA" + var ZSSO_URL_SCHEME = "workerlyagent" + var SCOPES = ["ZohoWorkerly.modules.ALL","ZohoWorkerly.setup.ALL","ZohoWorkerly.settings.unavailability.ALL"] + } + +struct ZWSetup{ + static let KEY_USER_OAUTH_TOKEN = "user_oauth_token" + static var OAUTH_TOKEN: String { + get { + return ZWAUserDefaults.string(forKey: ZWSetup.KEY_USER_OAUTH_TOKEN) ?? "" + }set { + ZWAUserDefaults.set(newValue, forKey: ZWSetup.KEY_USER_OAUTH_TOKEN) + } + } + static let USER_TEMP_ID = "user_temp_id" + static var TEMP_ID: String { + get { + return ZWAUserDefaults.string(forKey: ZWSetup.USER_TEMP_ID) ?? "" + }set { + ZWAUserDefaults.set(newValue, forKey: ZWSetup.USER_TEMP_ID) + } + } + static let ONB_DESCRIPTION = "Get to know the status of a job right at your fingertip!" + static var descriptionLabel : String { + get{ + return + ZWAUserDefaults.string(forKey: ZWSetup.ONB_DESCRIPTION) ?? "" + }set{ + ZWAUserDefaults.set(newValue, forKey: ZWSetup.ONB_DESCRIPTION) + } + } +} diff --git a/WisdomTask/Constants/APIConstants.swift b/WisdomTask/Constants/APIConstants.swift new file mode 100644 index 0000000..314572a --- /dev/null +++ b/WisdomTask/Constants/APIConstants.swift @@ -0,0 +1,22 @@ +// +// APIConstants.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +struct APIConstants { + static let defaultTimeOut: Double = 120.0 + + static var baseUrl: String { + get { + return AppGateway.sharedInstance.appGatewayEndPoint() + } + } +} + +extension APIConstants { + static let list = "list?" + static let image = "list?" +} diff --git a/WisdomTask/Constants/Gateway.swift b/WisdomTask/Constants/Gateway.swift new file mode 100644 index 0000000..b1f87c8 --- /dev/null +++ b/WisdomTask/Constants/Gateway.swift @@ -0,0 +1,38 @@ +// +// Gateway.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation + + +class AppGateway: NSObject { + static var sharedInstance = AppGateway() + var configs: NSDictionary! + + override init() { + let path = Bundle.main.path(forResource: PathEndPoints.config.rawValue, ofType: PathEndPoints.type.rawValue)! + configs = NSDictionary(contentsOfFile: path)!.object(forKey: ConfigEndPoint.development.rawValue) as? NSDictionary + } +} + +extension AppGateway { + func appGatewayEndPoint() -> String { + return configs.object(forKey: ApplicationGateWayEndPoint.EndPoint.rawValue) as! String + } +} + +enum ApplicationGateWayEndPoint: String { + case EndPoint = "ApplicationGateWay" +} + +enum PathEndPoints :String { + case config = "AppGateway" + case type = "plist" +} + +enum ConfigEndPoint : String { + case development = "Development" +} diff --git a/WisdomTask/Features/WisdomeList/Shared/WisdomResponder.swift b/WisdomTask/Features/WisdomeList/Shared/WisdomResponder.swift new file mode 100644 index 0000000..bb9cb6d --- /dev/null +++ b/WisdomTask/Features/WisdomeList/Shared/WisdomResponder.swift @@ -0,0 +1,13 @@ +// +// WisdomResponder.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation + +protocol WisdomResponder{ + func currentWorking() + func loaderView() +} diff --git a/WisdomTask/Features/WisdomeList/Shared/WisdomeSharedNav.swift b/WisdomTask/Features/WisdomeList/Shared/WisdomeSharedNav.swift new file mode 100644 index 0000000..99f4d1a --- /dev/null +++ b/WisdomTask/Features/WisdomeList/Shared/WisdomeSharedNav.swift @@ -0,0 +1,55 @@ +// +// WisdomeSharedNav.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +import UIKit + +class WisdomeSharedNav : BaseNavigationController{ + + var viewModel : WisdomeSharedViewModel! { + didSet{ + bindViewModel() + } + } + override func viewDidLoad() { + super.viewDidLoad() + + } +} +extension WisdomeSharedNav { + private func bindViewModel(){ + viewModel.currentWorkingSharedView.bindAndFire { view in + self.presentWIWView(view: view) + } + + } +} +extension WisdomeSharedNav{ + private func presentWIWView(view: WisdomeSharedView){ + switch view { + case .wisdomeList : + self.presentCurrentWorkingVC() + case .loader: + self.loaderView() + } + } +} +extension WisdomeSharedNav { + private func presentCurrentWorkingVC(){ + let currentWorkingVC = WisdomListController.load(from: .main) + currentWorkingVC.viewModel = WisdomListViewModel(wisdomResponder: self.viewModel) + pushViewController(currentWorkingVC, animated: true) + } + private func loaderView(){ +// let loadingVC = LoadingViewController() +// // Animate loadingVC over the existing views on screen +// loadingVC.modalPresentationStyle = .automatic +// // Animate loadingVC with a fade in animation +// loadingVC.modalTransitionStyle = .crossDissolve +// present(loadingVC, animated: true, completion: nil) + } +} diff --git a/WisdomTask/Features/WisdomeList/Shared/WisdomeSharedViewModel.swift b/WisdomTask/Features/WisdomeList/Shared/WisdomeSharedViewModel.swift new file mode 100644 index 0000000..8232716 --- /dev/null +++ b/WisdomTask/Features/WisdomeList/Shared/WisdomeSharedViewModel.swift @@ -0,0 +1,35 @@ +// +// WisdomeSharedNavViewModel.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +import UIKit + +enum WisdomeSharedView { + case wisdomeList + case loader +} +class WisdomeSharedViewModel : BaseViewModel { + let currentWorkingSharedView = Dynamic(value: .wisdomeList) + + init(with currentWorkingSharedView: WisdomeSharedView) { + super.init() + self.currentWorkingSharedView.value = currentWorkingSharedView + } + + private func changViewState(to view: WisdomeSharedView){ + currentWorkingSharedView.value = view + } +} +extension WisdomeSharedViewModel : WisdomResponder { + func currentWorking() { + changViewState(to: .wisdomeList) + } + func loaderView() { + changViewState(to: .loader) + } + +} diff --git a/WisdomTask/Features/WisdomeList/WisdomListController.swift b/WisdomTask/Features/WisdomeList/WisdomListController.swift new file mode 100644 index 0000000..12732f8 --- /dev/null +++ b/WisdomTask/Features/WisdomeList/WisdomListController.swift @@ -0,0 +1,61 @@ +// +// ViewController.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import UIKit + +class WisdomListController: BaseViewController { + @IBOutlet weak var tableView: UITableView! + + var viewModel : WisdomListViewModel? { + didSet { + configureView(with: viewModel) + bindViewModel() + } + } + + override func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + self.title = viewModel?.title + viewModel?.fetchWisdomList() +// tableView.delegate = self +// tableView.dataSource = self + + } +} + +extension WisdomListController: UITableViewDataSource, UITableViewDelegate { + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return viewModel?.numberOfRows(for: section) ?? 0 + } + func numberOfSections(in tableView: UITableView) -> Int { + return viewModel?.numberOfSections() ?? 1 + } + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let type = viewModel?.getSectionType(for: indexPath.section) + switch type{ + case .whoIsWorking: + let cell : WisdomeListCell? = tableView.dequeueReusableCell(withIdentifier: "WisdomeListCell", for: indexPath) as? WisdomeListCell + if let cellViewModel = viewModel?.getCellViewModel(for: indexPath.section, row: indexPath.row) as? WisdomeListCellRow { + cell?.cellViewModel = cellViewModel + } + return cell! + default: + return UITableViewCell() + } + } +} + +extension WisdomListController { + private func bindViewModel(){ + viewModel?.tableViewCellViewModel.bind({ [weak self] (sectionModel) in + DispatchQueue.main.async { + self?.tableView.reloadData() + } + }) + } +} diff --git a/WisdomTask/Features/WisdomeList/WisdomListViewModel.swift b/WisdomTask/Features/WisdomeList/WisdomListViewModel.swift new file mode 100644 index 0000000..1683a7b --- /dev/null +++ b/WisdomTask/Features/WisdomeList/WisdomListViewModel.swift @@ -0,0 +1,84 @@ +// +// WisdomListViewModel.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +import UIKit + +class WisdomListViewModel : BaseViewModel{ + + var title = "List" + var tableViewHeight = UITableView.automaticDimension + + var wisdomResponder : WisdomResponder + let tableViewCellViewModel = Dynamic<[WisdomeListCellViewModelBase]>(value: []) + init(wisdomResponder: WisdomResponder){ + self.wisdomResponder = wisdomResponder + super.init() + } + +} + +extension WisdomListViewModel { + func numberOfSections() -> Int { + self.tableViewCellViewModel.value.count + } + func numberOfRows(for section: Int) -> Int { + return tableViewCellViewModel.value[section].rowCount + } + func rowHeight(for indexPath: IndexPath) -> CGFloat { + return 150 + } + // func titleHeader(for section: Int) -> String { + // return tableViewCellViewModel.value[section].sectionTitle ?? "" + // } + func getSectionType(for section:Int) -> WisdomeTableSectionType{ + return tableViewCellViewModel.value[section].type + } + func getRowType(for section:Int, row:Int) -> WisdomeTableRowType { + let rowType = (tableViewCellViewModel.value[section].items?[row].rowType)! + return rowType + } + func getCellViewModel(for section:Int, row: Int) -> WisdomeListCellRow { + let sectionModel = tableViewCellViewModel.value[section] + let rowViewModel = sectionModel.items?[row] + return rowViewModel! + } + func getCurrentWorkingCellViewModel(for section:Int, row: Int) -> WisdomeListCellViewModel? { + let sectionModel = tableViewCellViewModel.value[section] as? WisdomeListCellViewModel + return sectionModel + } + +} + +extension WisdomListViewModel { + func fetchWisdomList(){ + viewStatus.value = .loading(loadStyle: .covering,title: "") + WisdomListHandler().fetchTemps { model, error in + if let err = error { + print(":- \(err.localizedDescription)") + }else{ + if let wisdome = model{ + self.buildCellViewModels(items: wisdome) { } + } + } + self.viewStatus.value = .loaded + } + } + private func buildCellViewModels(items : [WisdomeModel?], completion: @escaping () -> Void) { + var sectionTable = [WisdomeListCellViewModelBase]() + var whoIsWorkingRow = [WisdomeListCellRow]() + for item in items { + item?.url = randomString() + let row = WisdomeListCellRow(rowType: .currentWorkingTemps, item: item) + whoIsWorkingRow.append(row) + } + let whoIsWorkingSection = WisdomeListCellViewModel(items: whoIsWorkingRow, sectionTitle: "", type: .whoIsWorking) + sectionTable.append(whoIsWorkingSection) + self.tableViewCellViewModel.value = sectionTable + completion() + } +} diff --git a/WisdomTask/Info.plist b/WisdomTask/Info.plist new file mode 100644 index 0000000..c0ae0b4 --- /dev/null +++ b/WisdomTask/Info.plist @@ -0,0 +1,30 @@ + + + + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UIApplicationSceneManifest + + UIApplicationSupportsMultipleScenes + + UISceneConfigurations + + UIWindowSceneSessionRoleApplication + + + UISceneConfigurationName + Default Configuration + UISceneDelegateClassName + $(PRODUCT_MODULE_NAME).SceneDelegate + UISceneStoryboardFile + Main + + + + + + diff --git a/WisdomTask/Models/WisdomeListModel.swift b/WisdomTask/Models/WisdomeListModel.swift new file mode 100644 index 0000000..8ffcd0b --- /dev/null +++ b/WisdomTask/Models/WisdomeListModel.swift @@ -0,0 +1,18 @@ +// +// WisdomeListModel.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +typealias WisdomList = [WisdomeModel] + +class WisdomeModel: Decodable { + var id, author, url, download_url: String? + + enum CodingKeys: String, CodingKey { + case id, author, url, download_url + } +} + diff --git a/WisdomTask/NetworkHandlers/Common/AppGateway.plist b/WisdomTask/NetworkHandlers/Common/AppGateway.plist new file mode 100644 index 0000000..5be8e08 --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/AppGateway.plist @@ -0,0 +1,11 @@ + + + + + Development + + ApplicationGateWay + https://picsum.photos/v2/ + + + diff --git a/WisdomTask/NetworkHandlers/Common/ImageNetworkHandler.swift b/WisdomTask/NetworkHandlers/Common/ImageNetworkHandler.swift new file mode 100644 index 0000000..be07f34 --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/ImageNetworkHandler.swift @@ -0,0 +1,30 @@ +// +// ImageNetworkHandler.swift +// WisdomTask +// +// Created by Raghava Dokala on 10/05/23. +// + +import Foundation +import UIKit + +extension UIImageView { + func downloaded(from url: URL, contentMode mode: ContentMode = .scaleAspectFit) { + contentMode = mode + URLSession.shared.dataTask(with: url) { data, response, error in + guard + let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200, + let mimeType = response?.mimeType, mimeType.hasPrefix("image"), + let data = data, error == nil, + let image = UIImage(data: data) + else { return } + DispatchQueue.main.async() { [weak self] in + self?.image = image + } + }.resume() + } + func downloaded(from link: String, contentMode mode: ContentMode = .scaleAspectFit) { + guard let url = URL(string: link) else { return } + downloaded(from: url, contentMode: mode) + } +} diff --git a/WisdomTask/NetworkHandlers/Common/ImageNetworking.swift b/WisdomTask/NetworkHandlers/Common/ImageNetworking.swift new file mode 100644 index 0000000..4e5f110 --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/ImageNetworking.swift @@ -0,0 +1,48 @@ +// +// ImageNetworking.swift +// WisdomTask +// +// Created by Raghava Dokala on 10/05/23. +// + +import Foundation + +/// Result enum is a generic for any type of value +/// with success and failure case +public enum ImageResult { + case success(T) + case failure(Error) +} + +final class ImageNetworking: NSObject { + + // MARK: - Private functions + private static func getData(url: URL, + completion: @escaping (Data?, URLResponse?, Error?) -> ()) { + URLSession.shared.dataTask(with: url, completionHandler: completion).resume() + } + + // MARK: - Public function + + /// downloadImage function will download the thumbnail images + /// returns Result as completion handler + public static func downloadImage(url: URL, + completion: @escaping (ImageResult) -> Void) { + ImageNetworking.getData(url: url) { data, response, error in + + if let error = error { + completion(.failure(error)) + return + } + + guard let data = data, error == nil else { + return + } + + DispatchQueue.main.async() { + completion(.success(data)) + } + } + } +} + diff --git a/WisdomTask/NetworkHandlers/Common/Network+Utils.swift b/WisdomTask/NetworkHandlers/Common/Network+Utils.swift new file mode 100755 index 0000000..8d8a01d --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/Network+Utils.swift @@ -0,0 +1,19 @@ +// +// Network+Utils.swift +// HappyBeing +// +// Created by Raghava Dokala on 4/22/20. +// Copyright © 2020 RaghavaNaidu All rights reserved. +// + +import Foundation + +extension Reachability { + public static func isNetwrokReachable() -> Bool { + let connection = try? Reachability().connection + if connection == .unavailable { + return false + } + return true + } +} diff --git a/WisdomTask/NetworkHandlers/Common/NetworkConfiguration.swift b/WisdomTask/NetworkHandlers/Common/NetworkConfiguration.swift new file mode 100644 index 0000000..eb38de1 --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/NetworkConfiguration.swift @@ -0,0 +1,33 @@ +// +// NetworkConfiguration.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 15/12/22. +// + +import Foundation + +enum HTTPMethod: String { + case get = "GET" + case post = "POST" +} + +protocol NetworkConfiguration { + var baseURL: String { get } + var method: HTTPMethod { get } + var path: String? { get } + var bodyparameters: [String: Any]? { get } + var headers: [String : String]? { get } +} + +extension NetworkConfiguration { + var baseURL: String { + return APIConstants.baseUrl + } + var oAuthToken: String { + return "" + } + var timeoutInterval: TimeInterval { + return 60.0 + } +} diff --git a/WisdomTask/NetworkHandlers/Common/NetworkHandler.swift b/WisdomTask/NetworkHandlers/Common/NetworkHandler.swift new file mode 100644 index 0000000..e4cce93 --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/NetworkHandler.swift @@ -0,0 +1,188 @@ +// +// NetworkHandler.swift +// HappyBeing +// +// Created by Raghava Dokala on 4/9/20. +// Copyright © 2020 RaghavaNaidu All rights reserved. +// + +import Foundation +import Photos +import UIKit + +class NetworkHandler { + var imageCache = ImageCache.getImageCache() + + func makeAPICall(router: NetworkConfiguration, + completion: @escaping(Result<[String: Any], APIError>)-> ()) { + guard Reachability.isNetwrokReachable() else { + completion(.failure(.noNetwork)) + return + } + if let urlRequest = getURLRequest(for: router) { + URLSession(configuration: URLSessionConfiguration.default).dataTask(with: urlRequest) { (data, response, error) in + if error != nil { + // if server returns error + completion(.failure(.serverError)) + return + } + if let data = data { + // data decoding to generic dictionary + if let dataDictionary: [String: Any] = try? JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] { + completion(.success(dataDictionary)) + } else { + completion(.failure(.jsonError)) + } + } + }.resume() + } + } + func makeAPICall(router: NetworkConfiguration, + decodingType: T.Type, + decodeKeyValue:Bool = false, + completion: @escaping(Result)-> ()) { + guard Reachability.isNetwrokReachable() else { + completion(.failure(.noNetwork)) + return + } + if let urlRequest = getURLRequest(for: router) { + URLSession(configuration: URLSessionConfiguration.default).dataTask(with: urlRequest) { (data, response, error) in + if error != nil { + // if server returns error + completion(.failure(.runtimeError(error?.localizedDescription ?? ""))) + return + } + if let data = data { + // data decoding to models + if decodeKeyValue { + print("Do key value seperation. idiot") + }else{ + self.decodeObj(decodingType: T.self, data: data) { (object, err) in + guard let object = object else { + completion(.failure(.jsonError)) + return + } + completion(.success(object)) + } + } + } + }.resume() + } + } + func downlodFile(router: NetworkConfiguration, + completion: @escaping(Result)-> ()) { + guard Reachability.isNetwrokReachable() else { + completion(.failure(.noNetwork)) + return + } + + let cacheKey = self.getUrlString(for: router) + if let cacheImage = imageCache.get(forKey: cacheKey)?.jpeg { + completion(.success(Data(cacheImage))) + return + } + + if let urlRequest = getURLRequest(for: router) { + URLSession(configuration: URLSessionConfiguration.default).dataTask(with: urlRequest) { (data, response, error) in + if error != nil { + // if server returns error + completion(.failure(.runtimeError(error?.localizedDescription ?? ""))) + return + } + if let data = data, let image = data.uiImage { + self.imageCache.set(forKey: cacheKey, image: image) + completion(.success(data)) + } + }.resume() + } + } + func downlodDirect(urlString: String, id:String, completion: @escaping(Result)-> ()) { + guard Reachability.isNetwrokReachable() else { + completion(.failure(.noNetwork)) + return + } + let cacheKey = urlString + if let url = URL(string: urlString) { + let urlRequest = URLRequest(url: url) + URLSession(configuration: URLSessionConfiguration.default).dataTask(with: urlRequest) { (data, response, error) in + if error != nil { + // if server returns error + completion(.failure(.runtimeError(error?.localizedDescription ?? ""))) + return + } + if let data = data { + completion(.success(data)) + } + }.resume() + } + } + // MARK: - Private Methods + private func getURLRequest(for router: NetworkConfiguration) -> URLRequest? { + let urlString = self.getUrlString(for: router) + // retured as GET calls will not have httpBody, so appeding to the url as query parameters. + /*if router.method == .get { + if let bodyparameters = router.bodyparameters { + if let queryString = bodyparameters.queryString { + urlString.append("?\(queryString)") + } + } + }*/ + + if let url = URL(string: urlString) { + var urlRequest = URLRequest(url: url) + urlRequest.httpMethod = router.method.rawValue + urlRequest.allHTTPHeaderFields = router.headers + + if router.method == .get { + // retured as GET calls will not have httpBody + return urlRequest + } + else if let jsonData = try? JSONSerialization.data(withJSONObject: router.bodyparameters ?? [:]) { + urlRequest.httpBody = jsonData + return urlRequest + } else { + return urlRequest + } + } + return nil + } + private func getUrlString(for router: NetworkConfiguration)->String{ + let queryString = router.bodyparameters?.queryString ?? "" + let urlString = router.baseURL + (router.path ?? "") + "?\(queryString)" + return urlString + } + private func decodeObj(decodingType: T.Type, + data: Data, + decode: @escaping (Decodable?, APIError?) -> Void) { + let jsonString = String(decoding: data, as: UTF8.self) + do { + print("server response :- \(jsonString)") + let model = try JSONDecoder().decode(T.self, from: data) + decode(model, nil) + } catch { + decode(nil, .jsonError) + } + } + private func getPostString(params:[String:Any]) -> String + { + var data = [String]() + for(key, value) in params + { + data.append(key + "=\(value)") + } + return data.map { String($0) }.joined(separator: "&") + } +} + +extension Collection { + var toJson: String? { + if let theJSONData = try? JSONSerialization.data( + withJSONObject: self, + options: [.prettyPrinted]) { + let theJSONText = String(data: theJSONData, + encoding: .ascii) + return theJSONText + } + return nil + } +} diff --git a/WisdomTask/NetworkHandlers/Common/Reachability.swift b/WisdomTask/NetworkHandlers/Common/Reachability.swift new file mode 100755 index 0000000..7bad9e6 --- /dev/null +++ b/WisdomTask/NetworkHandlers/Common/Reachability.swift @@ -0,0 +1,399 @@ +/* +Copyright (c) 2014, Ashley Mills +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +import SystemConfiguration +import Foundation + +public enum ReachabilityError: Error { + case failedToCreateWithAddress(sockaddr, Int32) + case failedToCreateWithHostname(String, Int32) + case unableToSetCallback(Int32) + case unableToSetDispatchQueue(Int32) + case unableToGetFlags(Int32) +} + +public class Reachability { + + public typealias NetworkReachable = (Reachability) -> () + public typealias NetworkUnreachable = (Reachability) -> () + + @available(*, unavailable, renamed: "Connection") + public enum NetworkStatus: CustomStringConvertible { + case notReachable, reachableViaWiFi, reachableViaWWAN + public var description: String { + switch self { + case .reachableViaWWAN: return "Cellular" + case .reachableViaWiFi: return "WiFi" + case .notReachable: return "No Connection" + } + } + } + + public enum Connection: CustomStringConvertible { + @available(*, deprecated, renamed: "unavailable") + case none + case unavailable, wifi, cellular + public var description: String { + switch self { + case .cellular: return "Cellular" + case .wifi: return "WiFi" + case .unavailable: return "No Connection" + case .none: return "unavailable" + } + } + } + + public var whenReachable: NetworkReachable? + public var whenUnreachable: NetworkUnreachable? + + @available(*, deprecated, renamed: "allowsCellularConnection") + public let reachableOnWWAN: Bool = true + + /// Set to `false` to force Reachability.connection to .none when on cellular connection (default value `true`) + public var allowsCellularConnection: Bool + + // The notification center on which "reachability changed" events are being posted + public var notificationCenter: NotificationCenter = NotificationCenter.default + + @available(*, deprecated, renamed: "connection.description") + public var currentReachabilityString: String { + return "\(connection)" + } + + @available(*, unavailable, renamed: "connection") + public var currentReachabilityStatus: Connection { + return connection + } + + public var connection: Connection { + if flags == nil { + try? setReachabilityFlags() + } + + switch flags?.connection { + case .unavailable?, nil: return .unavailable + case .none?: return .unavailable + case .cellular?: return allowsCellularConnection ? .cellular : .unavailable + case .wifi?: return .wifi + } + } + + fileprivate var isRunningOnDevice: Bool = { + #if targetEnvironment(simulator) + return false + #else + return true + #endif + }() + + fileprivate(set) var notifierRunning = false + fileprivate let reachabilityRef: SCNetworkReachability + fileprivate let reachabilitySerialQueue: DispatchQueue + fileprivate let notificationQueue: DispatchQueue? + fileprivate(set) var flags: SCNetworkReachabilityFlags? { + didSet { + guard flags != oldValue else { return } + notifyReachabilityChanged() + } + } + + required public init(reachabilityRef: SCNetworkReachability, + queueQoS: DispatchQoS = .default, + targetQueue: DispatchQueue? = nil, + notificationQueue: DispatchQueue? = .main) { + self.allowsCellularConnection = true + self.reachabilityRef = reachabilityRef + self.reachabilitySerialQueue = DispatchQueue(label: "uk.co.ashleymills.reachability", qos: queueQoS, target: targetQueue) + self.notificationQueue = notificationQueue + } + + public convenience init(hostname: String, + queueQoS: DispatchQoS = .default, + targetQueue: DispatchQueue? = nil, + notificationQueue: DispatchQueue? = .main) throws { + guard let ref = SCNetworkReachabilityCreateWithName(nil, hostname) else { + throw ReachabilityError.failedToCreateWithHostname(hostname, SCError()) + } + self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue, notificationQueue: notificationQueue) + } + + public convenience init(queueQoS: DispatchQoS = .default, + targetQueue: DispatchQueue? = nil, + notificationQueue: DispatchQueue? = .main) throws { + var zeroAddress = sockaddr() + zeroAddress.sa_len = UInt8(MemoryLayout.size) + zeroAddress.sa_family = sa_family_t(AF_INET) + + guard let ref = SCNetworkReachabilityCreateWithAddress(nil, &zeroAddress) else { + throw ReachabilityError.failedToCreateWithAddress(zeroAddress, SCError()) + } + + self.init(reachabilityRef: ref, queueQoS: queueQoS, targetQueue: targetQueue, notificationQueue: notificationQueue) + } + + deinit { + stopNotifier() + } +} + +public extension Reachability { + + // MARK: - *** Notifier methods *** + func startNotifier() throws { + guard !notifierRunning else { return } + + let callback: SCNetworkReachabilityCallBack = { (reachability, flags, info) in + guard let info = info else { return } + + // `weakifiedReachability` is guaranteed to exist by virtue of our + // retain/release callbacks which we provided to the `SCNetworkReachabilityContext`. + let weakifiedReachability = Unmanaged.fromOpaque(info).takeUnretainedValue() + + // The weak `reachability` _may_ no longer exist if the `Reachability` + // object has since been deallocated but a callback was already in flight. + weakifiedReachability.reachability?.flags = flags + } + + let weakifiedReachability = ReachabilityWeakifier(reachability: self) + let opaqueWeakifiedReachability = Unmanaged.passUnretained(weakifiedReachability).toOpaque() + + var context = SCNetworkReachabilityContext( + version: 0, + info: UnsafeMutableRawPointer(opaqueWeakifiedReachability), + retain: { (info: UnsafeRawPointer) -> UnsafeRawPointer in + let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) + _ = unmanagedWeakifiedReachability.retain() + return UnsafeRawPointer(unmanagedWeakifiedReachability.toOpaque()) + }, + release: { (info: UnsafeRawPointer) -> Void in + let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) + unmanagedWeakifiedReachability.release() + }, + copyDescription: { (info: UnsafeRawPointer) -> Unmanaged in + let unmanagedWeakifiedReachability = Unmanaged.fromOpaque(info) + let weakifiedReachability = unmanagedWeakifiedReachability.takeUnretainedValue() + let description = weakifiedReachability.reachability?.description ?? "nil" + return Unmanaged.passRetained(description as CFString) + } + ) + + if !SCNetworkReachabilitySetCallback(reachabilityRef, callback, &context) { + stopNotifier() + throw ReachabilityError.unableToSetCallback(SCError()) + } + + if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef, reachabilitySerialQueue) { + stopNotifier() + throw ReachabilityError.unableToSetDispatchQueue(SCError()) + } + + // Perform an initial check + try setReachabilityFlags() + + notifierRunning = true + } + + func stopNotifier() { + defer { notifierRunning = false } + + SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil) + SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil) + } + + // MARK: - *** Connection test methods *** + @available(*, deprecated, message: "Please use `connection != .none`") + var isReachable: Bool { + return connection != .unavailable + } + + @available(*, deprecated, message: "Please use `connection == .cellular`") + var isReachableViaWWAN: Bool { + // Check we're not on the simulator, we're REACHABLE and check we're on WWAN + return connection == .cellular + } + + @available(*, deprecated, message: "Please use `connection == .wifi`") + var isReachableViaWiFi: Bool { + return connection == .wifi + } + + var description: String { + return flags?.description ?? "unavailable flags" + } +} + +fileprivate extension Reachability { + + func setReachabilityFlags() throws { + try reachabilitySerialQueue.sync { [unowned self] in + var flags = SCNetworkReachabilityFlags() + if !SCNetworkReachabilityGetFlags(self.reachabilityRef, &flags) { + self.stopNotifier() + throw ReachabilityError.unableToGetFlags(SCError()) + } + + self.flags = flags + } + } + + + func notifyReachabilityChanged() { + let notify = { [weak self] in + guard let self = self else { return } + self.connection != .unavailable ? self.whenReachable?(self) : self.whenUnreachable?(self) + self.notificationCenter.post(name: .reachabilityChanged, object: self) + } + + // notify on the configured `notificationQueue`, or the caller's (i.e. `reachabilitySerialQueue`) + notificationQueue?.async(execute: notify) ?? notify() + } +} + +extension SCNetworkReachabilityFlags { + + typealias Connection = Reachability.Connection + + var connection: Connection { + guard isReachableFlagSet else { return .unavailable } + + // If we're reachable, but not on an iOS device (i.e. simulator), we must be on WiFi + #if targetEnvironment(simulator) + return .wifi + #else + var connection = Connection.unavailable + + if !isConnectionRequiredFlagSet { + connection = .wifi + } + + if isConnectionOnTrafficOrDemandFlagSet { + if !isInterventionRequiredFlagSet { + connection = .wifi + } + } + + if isOnWWANFlagSet { + connection = .cellular + } + + return connection + #endif + } + + var isOnWWANFlagSet: Bool { + #if os(iOS) + return contains(.isWWAN) + #else + return false + #endif + } + var isReachableFlagSet: Bool { + return contains(.reachable) + } + var isConnectionRequiredFlagSet: Bool { + return contains(.connectionRequired) + } + var isInterventionRequiredFlagSet: Bool { + return contains(.interventionRequired) + } + var isConnectionOnTrafficFlagSet: Bool { + return contains(.connectionOnTraffic) + } + var isConnectionOnDemandFlagSet: Bool { + return contains(.connectionOnDemand) + } + var isConnectionOnTrafficOrDemandFlagSet: Bool { + return !intersection([.connectionOnTraffic, .connectionOnDemand]).isEmpty + } + var isTransientConnectionFlagSet: Bool { + return contains(.transientConnection) + } + var isLocalAddressFlagSet: Bool { + return contains(.isLocalAddress) + } + var isDirectFlagSet: Bool { + return contains(.isDirect) + } + var isConnectionRequiredAndTransientFlagSet: Bool { + return intersection([.connectionRequired, .transientConnection]) == [.connectionRequired, .transientConnection] + } + + var description: String { + let W = isOnWWANFlagSet ? "W" : "-" + let R = isReachableFlagSet ? "R" : "-" + let c = isConnectionRequiredFlagSet ? "c" : "-" + let t = isTransientConnectionFlagSet ? "t" : "-" + let i = isInterventionRequiredFlagSet ? "i" : "-" + let C = isConnectionOnTrafficFlagSet ? "C" : "-" + let D = isConnectionOnDemandFlagSet ? "D" : "-" + let l = isLocalAddressFlagSet ? "l" : "-" + let d = isDirectFlagSet ? "d" : "-" + + return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)" + } +} + +/** + `ReachabilityWeakifier` weakly wraps the `Reachability` class + in order to break retain cycles when interacting with CoreFoundation. + + CoreFoundation callbacks expect a pair of retain/release whenever an + opaque `info` parameter is provided. These callbacks exist to guard + against memory management race conditions when invoking the callbacks. + + #### Race Condition + + If we passed `SCNetworkReachabilitySetCallback` a direct reference to our + `Reachability` class without also providing corresponding retain/release + callbacks, then a race condition can lead to crashes when: + - `Reachability` is deallocated on thread X + - A `SCNetworkReachability` callback(s) is already in flight on thread Y + + #### Retain Cycle + + If we pass `Reachability` to CoreFoundtion while also providing retain/ + release callbacks, we would create a retain cycle once CoreFoundation + retains our `Reachability` class. This fixes the crashes and his how + CoreFoundation expects the API to be used, but doesn't play nicely with + Swift/ARC. This cycle would only be broken after manually calling + `stopNotifier()` — `deinit` would never be called. + + #### ReachabilityWeakifier + + By providing both retain/release callbacks and wrapping `Reachability` in + a weak wrapper, we: + - interact correctly with CoreFoundation, thereby avoiding a crash. + See "Memory Management Programming Guide for Core Foundation". + - don't alter the public API of `Reachability.swift` in any way + - still allow for automatic stopping of the notifier on `deinit`. + */ +private class ReachabilityWeakifier { + weak var reachability: Reachability? + init(reachability: Reachability) { + self.reachability = reachability + } +} diff --git a/WisdomTask/NetworkHandlers/WisdomList/WisdomListHandler.swift b/WisdomTask/NetworkHandlers/WisdomList/WisdomListHandler.swift new file mode 100644 index 0000000..2ff64f3 --- /dev/null +++ b/WisdomTask/NetworkHandlers/WisdomList/WisdomListHandler.swift @@ -0,0 +1,37 @@ +// +// WisdomListHandler.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +import UIKit + +class WisdomListHandler { + func fetchTemps(completion: @escaping (WisdomList?, APIError?) ->Void){ + let wisdomeListRouter = TempsApiRouter.list(page: "0") + NetworkHandler().makeAPICall(router: wisdomeListRouter, decodingType: WisdomList.self) { (result) in + switch result { + case .success(let model): + completion(model as? WisdomList, nil) + case .failure(let error): + completion(nil, error) + } + } + } + func fetchImage(url:String, id:String, completion: @escaping (UIImage?, APIError?) ->Void){ + NetworkHandler().downlodDirect(urlString: url,id: id) { (result) in + switch result { + case .success(let data): + DispatchQueue.main.async { + if let image = UIImage(data: data){ + completion(image, nil) + } + } + case .failure(let error): + completion(nil, error) + } + } + } +} diff --git a/WisdomTask/NetworkHandlers/WisdomList/WisdomListRouter.swift b/WisdomTask/NetworkHandlers/WisdomList/WisdomListRouter.swift new file mode 100644 index 0000000..055fac3 --- /dev/null +++ b/WisdomTask/NetworkHandlers/WisdomList/WisdomListRouter.swift @@ -0,0 +1,48 @@ +// +// WisdomListRouter.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation + +enum TempsApiRouter { + case list(page:String) + case image(id:String) +} + +extension TempsApiRouter: NetworkConfiguration { + var method: HTTPMethod { + switch self { + case .list: + return .get + case .image: + return .get + } + } + var path: String? { + switch self { + case .list: + return APIConstants.list + case .image: + return APIConstants.image + } + } + var headers: [String : String]? { + switch self { + case .list, .image: + return ["Content-Type":"application/json"] + } + } + var bodyparameters: [String : Any]? { + switch self { + case .list(let page): + return ["page":page, + "limit":"100"] + case .image(let id): + return ["id":id] + } + } +} + diff --git a/WisdomTask/StoryBoards/Base.lproj/LaunchScreen.storyboard b/WisdomTask/StoryBoards/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..865e932 --- /dev/null +++ b/WisdomTask/StoryBoards/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WisdomTask/StoryBoards/Base.lproj/Main.storyboard b/WisdomTask/StoryBoards/Base.lproj/Main.storyboard new file mode 100644 index 0000000..ac49913 --- /dev/null +++ b/WisdomTask/StoryBoards/Base.lproj/Main.storyboard @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WisdomTask/TableviewCells/WisdomeList/WisdomeListCell.swift b/WisdomTask/TableviewCells/WisdomeList/WisdomeListCell.swift new file mode 100644 index 0000000..c78b7f3 --- /dev/null +++ b/WisdomTask/TableviewCells/WisdomeList/WisdomeListCell.swift @@ -0,0 +1,29 @@ +// +// WisdomeListCell.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +import UIKit + +class WisdomeListCell : UITableViewCell { + + @IBOutlet weak var title : UILabel! + @IBOutlet weak var subtitle : UILabel! + @IBOutlet weak var _imageView: UIImageView! + + var cellViewModel : WisdomeListCellRow! { + didSet { + accessoryType = .none + title.text = cellViewModel.item?.author + subtitle.text = cellViewModel.item?.url + if let url = cellViewModel.item?.download_url { + DispatchQueue.main.async { + self._imageView.loadThumbnail(urlSting: url) + } + } + } + } +} diff --git a/WisdomTask/TableviewCells/WisdomeList/WisdomeListCellViewModel.swift b/WisdomTask/TableviewCells/WisdomeList/WisdomeListCellViewModel.swift new file mode 100644 index 0000000..2f10bd0 --- /dev/null +++ b/WisdomTask/TableviewCells/WisdomeList/WisdomeListCellViewModel.swift @@ -0,0 +1,45 @@ +// +// WisdomeListCellViewModel.swift +// WisdomTask +// +// Created by Raghava Dokala on 09/05/23. +// + +import Foundation +import UIKit + +enum WisdomeTableSectionType : Int { + case whoIsWorking +} +enum WisdomeTableRowType { + case currentWorkingTemps +} + +protocol WisdomeListCellViewModelBase { + var type: WisdomeTableSectionType { get } + var sectionTitle: String? { get } + var rowCount: Int { get } + var items:[WisdomeListCellRow]? {get} +} + +class WisdomeListCellViewModel : WisdomeListCellViewModelBase { + var sectionTitle: String? + var items : [WisdomeListCellRow]? + var type : WisdomeTableSectionType + var accessoryType: UITableViewCell.AccessoryType { + return .none + } + var rowCount: Int { + return items?.count ?? 0 + } + init(items: [WisdomeListCellRow]? = nil, sectionTitle: String? = "", type: WisdomeTableSectionType) { + self.items = items + self.sectionTitle = sectionTitle + self.type = type + + } +} +struct WisdomeListCellRow { + var rowType: WisdomeTableRowType? = nil + var item: WisdomeModel? = nil +} diff --git a/WisdomTask/Utils/Data+Util.swift b/WisdomTask/Utils/Data+Util.swift new file mode 100644 index 0000000..bc5e6b6 --- /dev/null +++ b/WisdomTask/Utils/Data+Util.swift @@ -0,0 +1,31 @@ +// +// Data+Util.swift +// WorkerlyAgent +// +// Created by Raghava Dokala on 30/03/23. +// + +import Foundation + +extension Data { + + func write(with folderName:String, and name: String) -> URL { + + let url = URL(fileURLWithPath: createTempDirectory(with: folderName).absoluteString).appendingPathComponent(name) + + try! write(to: url, options: .atomicWrite) + + return url + } + func createTempDirectory(with folderName:String) -> URL { + let tempDirectoryTemplate = URL(fileURLWithPath: NSTemporaryDirectory().appending(folderName)) + + let fileManager = FileManager.default + do{ + try fileManager.createDirectory(at: tempDirectoryTemplate, withIntermediateDirectories: true) + }catch { + print("Oops") + } + return tempDirectoryTemplate + } +} diff --git a/WisdomTask/Utils/Dictionary+Util.swift b/WisdomTask/Utils/Dictionary+Util.swift new file mode 100755 index 0000000..f1a0ad1 --- /dev/null +++ b/WisdomTask/Utils/Dictionary+Util.swift @@ -0,0 +1,21 @@ +// +// Dictionary+Util.swift +// ZohoWorkerly +// +// Created by Raghava Dokala on 02/07/20. +// Copyright © 2020 Raghava Dokala. All rights reserved. +// + +import Foundation + +extension Dictionary { + var queryString: String? { + var output: String = "" + for (key,value) in self { + output += "\(key)=\(value)&" + } + let urlString = output.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? output + output = String(urlString.dropLast()) + return output + } +} diff --git a/WisdomTask/Utils/ImageCache+Util.swift b/WisdomTask/Utils/ImageCache+Util.swift new file mode 100644 index 0000000..d86d2ab --- /dev/null +++ b/WisdomTask/Utils/ImageCache+Util.swift @@ -0,0 +1,67 @@ +// +// ImageCache+Util.swift +// ZohoWorkerlyAgent +// +// Created by Raghava Dokala on 26/12/22. +// + +import Foundation +import UIKit + +class ImageCache { + var cache = NSCache() + + func get(forKey: String) -> UIImage? { + return cache.object(forKey: NSString(string: forKey)) + } + + func set(forKey: String, image: UIImage) { + cache.setObject(image, forKey: NSString(string: forKey)) + } +} + +extension ImageCache { + private static var imageCache = ImageCache() + static func getImageCache() -> ImageCache { + return imageCache + } +} + +extension UIImage { + var jpeg: Data? { jpegData(compressionQuality: 1) } // QUALITY min = 0 / max = 1 + var png: Data? { pngData() } +} +extension Data { + var uiImage: UIImage? { UIImage(data: self) } +} + + + +let imageCache = NSCache() + +// MARK: - UIImageView extension +extension UIImageView { + + /// This loadThumbnail function is used to download thumbnail image using urlString + /// This method also using cache of loaded thumbnail using urlString as a key of cached thumbnail. + func loadThumbnail(urlSting: String) { + guard let url = URL(string: urlSting) else { return } + image = nil + + if let imageFromCache = imageCache.object(forKey: urlSting as AnyObject) { + image = imageFromCache as? UIImage + return + } + ImageNetworking.downloadImage(url: url) { [weak self] result in + guard let self = self else { return } + switch result { + case .success(let data): + guard let imageToCache = UIImage(data: data) else { return } + imageCache.setObject(imageToCache, forKey: urlSting as AnyObject) + self.image = UIImage(data: data) + case .failure(_): + self.image = UIImage(named: "noImage") + } + } + } +} diff --git a/WisdomTask/Utils/NotificationName+Util.swift b/WisdomTask/Utils/NotificationName+Util.swift new file mode 100644 index 0000000..0d98b6c --- /dev/null +++ b/WisdomTask/Utils/NotificationName+Util.swift @@ -0,0 +1,17 @@ +// +// ZWObservers.swift +// ZohoWorkerly +// +// Created by Raghava Dokala on 20/07/22. +// Copyright © 2022 Raghava Dokala. All rights reserved. +// + +import Foundation + +public extension Notification.Name { + static let wisdomList = Notification.Name("RefreshWisdomListPage") + static let reachabilityChanged = Notification.Name("reachabilityChanged") + + @available(*, unavailable, renamed: "Notification.Name.reachabilityChanged") + static let ReachabilityChangedNotification = NSNotification.Name("ReachabilityChangedNotification") +} diff --git a/WisdomTask/Utils/Storyboard.Util.swift b/WisdomTask/Utils/Storyboard.Util.swift new file mode 100644 index 0000000..49ff0eb --- /dev/null +++ b/WisdomTask/Utils/Storyboard.Util.swift @@ -0,0 +1,33 @@ +// +// Storyboard.Util.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation +import UIKit + +extension UIStoryboard { + enum StoryboardEnumerated: String { + case launchScreen + case main + } +} + +extension UIStoryboard.StoryboardEnumerated { + var filename: String { + return rawValue.captalizeFirstLetter + } + + var instance: UIStoryboard { + return UIStoryboard(name: filename, bundle: Bundle.main) + } + + func instantiateViewController() -> T { + guard let viewController = instance.instantiateViewController(withIdentifier: String(describing: T.self)) as? T else { + fatalError("Couldn't instantiate view controller with identifier \(T.self) ") + } + return viewController + } +} diff --git a/WisdomTask/Utils/String.Util.swift b/WisdomTask/Utils/String.Util.swift new file mode 100644 index 0000000..ea897ff --- /dev/null +++ b/WisdomTask/Utils/String.Util.swift @@ -0,0 +1,24 @@ +// +// string.Util.swift +// WorkerlyAgent(MVVM) +// +// Created by Keerthana G on 07/12/22. +// + +import Foundation + +extension String { + var captalizeFirstLetter : String { + return self.prefix(1).uppercased() + self.dropFirst() + + } +} + +func randomString() -> String { + let lower : UInt32 = 50 + let upper : UInt32 = 500 + let randomNumber = arc4random_uniform(upper - lower) + lower + + let letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + return String((0.. Self { + return storyboard.instantiateViewController() + } + func moveRootViewController(rootViewController: UIViewController, animated: Bool, completion: (() -> Void)?) { + if animated { + UIView.transition(with: SCENE_DELEGATE.window!, duration: 0.7, options: .transitionCrossDissolve, animations: { + let oldState: Bool = UIView.areAnimationsEnabled + UIView.setAnimationsEnabled(false) + SCENE_DELEGATE.window?.rootViewController = rootViewController + UIView.setAnimationsEnabled(oldState) + }, completion: { (finished: Bool) -> () in + if (completion != nil) { + completion!() + } + }) + } else { + SCENE_DELEGATE.window?.rootViewController = rootViewController + } + } + +}