Commit 880d9eeb authored by Imam Aly's avatar Imam Aly
Browse files

add coordinator pattern and login view controller

parent 60c71313
Showing with 368 additions and 19 deletions
+368 -19
......@@ -3,10 +3,17 @@
archiveVersion = 1;
classes = {
};
objectVersion = 56;
objectVersion = 55;
objects = {
/* Begin PBXBuildFile section */
18D0350C9339A7856CBE294E /* Pods_sss_app.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 173D9717995C49EBDE82A112 /* Pods_sss_app.framework */; };
9F3207C22A7A45930022BD0E /* AppCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3207C12A7A45930022BD0E /* AppCoordinator.swift */; };
9F3207C52A7A49590022BD0E /* BaseCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3207C42A7A49590022BD0E /* BaseCoordinator.swift */; };
9F3207C82A7A4D310022BD0E /* AppConstant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3207C72A7A4D310022BD0E /* AppConstant.swift */; };
9F3207CC2A7A4E100022BD0E /* LoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3207CA2A7A4E100022BD0E /* LoginViewController.swift */; };
9F3207CD2A7A4E100022BD0E /* LoginViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9F3207CB2A7A4E100022BD0E /* LoginViewController.xib */; };
9F3207D02A7A4EA80022BD0E /* LoginCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F3207CF2A7A4EA80022BD0E /* LoginCoordinator.swift */; };
9FBD1E4F2A78FB0C0061FDBB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD1E4E2A78FB0C0061FDBB /* AppDelegate.swift */; };
9FBD1E512A78FB0C0061FDBB /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD1E502A78FB0C0061FDBB /* SceneDelegate.swift */; };
9FBD1E532A78FB0C0061FDBB /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9FBD1E522A78FB0C0061FDBB /* ViewController.swift */; };
......@@ -16,6 +23,15 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
173D9717995C49EBDE82A112 /* Pods_sss_app.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_sss_app.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6116A36C31AFE561943E0A8C /* Pods-sss-app.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sss-app.debug.xcconfig"; path = "Target Support Files/Pods-sss-app/Pods-sss-app.debug.xcconfig"; sourceTree = "<group>"; };
9C56F6F9E87474D96E26F212 /* Pods-sss-app.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-sss-app.release.xcconfig"; path = "Target Support Files/Pods-sss-app/Pods-sss-app.release.xcconfig"; sourceTree = "<group>"; };
9F3207C12A7A45930022BD0E /* AppCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppCoordinator.swift; sourceTree = "<group>"; };
9F3207C42A7A49590022BD0E /* BaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = "<group>"; };
9F3207C72A7A4D310022BD0E /* AppConstant.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppConstant.swift; sourceTree = "<group>"; };
9F3207CA2A7A4E100022BD0E /* LoginViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginViewController.swift; sourceTree = "<group>"; };
9F3207CB2A7A4E100022BD0E /* LoginViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LoginViewController.xib; sourceTree = "<group>"; };
9F3207CF2A7A4EA80022BD0E /* LoginCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginCoordinator.swift; sourceTree = "<group>"; };
9FBD1E4B2A78FB0C0061FDBB /* sss-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sss-app.app"; sourceTree = BUILT_PRODUCTS_DIR; };
9FBD1E4E2A78FB0C0061FDBB /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
9FBD1E502A78FB0C0061FDBB /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
......@@ -31,17 +47,61 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
18D0350C9339A7856CBE294E /* Pods_sss_app.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
7A8AD802ADF0D01590E52315 /* Frameworks */ = {
isa = PBXGroup;
children = (
173D9717995C49EBDE82A112 /* Pods_sss_app.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
9F3207C32A7A49450022BD0E /* Base */ = {
isa = PBXGroup;
children = (
9F3207C42A7A49590022BD0E /* BaseCoordinator.swift */,
);
path = Base;
sourceTree = "<group>";
};
9F3207C62A7A4D240022BD0E /* Constant */ = {
isa = PBXGroup;
children = (
9F3207C72A7A4D310022BD0E /* AppConstant.swift */,
);
path = Constant;
sourceTree = "<group>";
};
9F3207C92A7A4DBE0022BD0E /* ViewController */ = {
isa = PBXGroup;
children = (
9F3207CA2A7A4E100022BD0E /* LoginViewController.swift */,
9F3207CB2A7A4E100022BD0E /* LoginViewController.xib */,
);
path = ViewController;
sourceTree = "<group>";
};
9F3207CE2A7A4E980022BD0E /* Coordinator */ = {
isa = PBXGroup;
children = (
9F3207CF2A7A4EA80022BD0E /* LoginCoordinator.swift */,
);
path = Coordinator;
sourceTree = "<group>";
};
9FBD1E422A78FB0C0061FDBB = {
isa = PBXGroup;
children = (
9FBD1E4D2A78FB0C0061FDBB /* sss-app */,
9FBD1E4C2A78FB0C0061FDBB /* Products */,
F377F4ACDE347F01F909F27F /* Pods */,
7A8AD802ADF0D01590E52315 /* Frameworks */,
);
sourceTree = "<group>";
};
......@@ -56,7 +116,12 @@
9FBD1E4D2A78FB0C0061FDBB /* sss-app */ = {
isa = PBXGroup;
children = (
9F3207CE2A7A4E980022BD0E /* Coordinator */,
9F3207C32A7A49450022BD0E /* Base */,
9F3207C62A7A4D240022BD0E /* Constant */,
9F3207C92A7A4DBE0022BD0E /* ViewController */,
9FBD1E4E2A78FB0C0061FDBB /* AppDelegate.swift */,
9F3207C12A7A45930022BD0E /* AppCoordinator.swift */,
9FBD1E502A78FB0C0061FDBB /* SceneDelegate.swift */,
9FBD1E522A78FB0C0061FDBB /* ViewController.swift */,
9FBD1E542A78FB0C0061FDBB /* Main.storyboard */,
......@@ -67,6 +132,15 @@
path = "sss-app";
sourceTree = "<group>";
};
F377F4ACDE347F01F909F27F /* Pods */ = {
isa = PBXGroup;
children = (
6116A36C31AFE561943E0A8C /* Pods-sss-app.debug.xcconfig */,
9C56F6F9E87474D96E26F212 /* Pods-sss-app.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
......@@ -74,6 +148,7 @@
isa = PBXNativeTarget;
buildConfigurationList = 9FBD1E5F2A78FB0E0061FDBB /* Build configuration list for PBXNativeTarget "sss-app" */;
buildPhases = (
AE69E672B645C52741A1C88B /* [CP] Check Pods Manifest.lock */,
9FBD1E472A78FB0C0061FDBB /* Sources */,
9FBD1E482A78FB0C0061FDBB /* Frameworks */,
9FBD1E492A78FB0C0061FDBB /* Resources */,
......@@ -103,7 +178,7 @@
};
};
buildConfigurationList = 9FBD1E462A78FB0C0061FDBB /* Build configuration list for PBXProject "sss-app" */;
compatibilityVersion = "Xcode 14.0";
compatibilityVersion = "Xcode 13.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
......@@ -125,6 +200,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9F3207CD2A7A4E100022BD0E /* LoginViewController.xib in Resources */,
9FBD1E5B2A78FB0E0061FDBB /* LaunchScreen.storyboard in Resources */,
9FBD1E582A78FB0E0061FDBB /* Assets.xcassets in Resources */,
9FBD1E562A78FB0C0061FDBB /* Main.storyboard in Resources */,
......@@ -133,13 +209,43 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
AE69E672B645C52741A1C88B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-sss-app-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
9FBD1E472A78FB0C0061FDBB /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
9F3207CC2A7A4E100022BD0E /* LoginViewController.swift in Sources */,
9F3207C52A7A49590022BD0E /* BaseCoordinator.swift in Sources */,
9F3207C22A7A45930022BD0E /* AppCoordinator.swift in Sources */,
9FBD1E532A78FB0C0061FDBB /* ViewController.swift in Sources */,
9F3207C82A7A4D310022BD0E /* AppConstant.swift in Sources */,
9FBD1E4F2A78FB0C0061FDBB /* AppDelegate.swift in Sources */,
9F3207D02A7A4EA80022BD0E /* LoginCoordinator.swift in Sources */,
9FBD1E512A78FB0C0061FDBB /* SceneDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
......@@ -282,6 +388,7 @@
};
9FBD1E602A78FB0E0061FDBB /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 6116A36C31AFE561943E0A8C /* Pods-sss-app.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
......@@ -309,6 +416,7 @@
};
9FBD1E612A78FB0E0061FDBB /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 9C56F6F9E87474D96E26F212 /* Pods-sss-app.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
......
......@@ -7,7 +7,7 @@
<key>sss-app.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
<integer>1</integer>
</dict>
</dict>
</dict>
......
//
// AppCoordinator.swift
// sss-app
//
// Created by Imam Aly on 02/08/23.
//
import Foundation
import UIKit
class AppCoordinator: BaseCoordinator {
weak var navigationController: UINavigationController?
init(navigationController: UINavigationController) {
super.init()
self.navigationController = navigationController
}
override func start() {
super.start()
routeName(name: .login)
}
}
protocol AppCoordinatorRouteDelegate: AnyObject {
func routeName(name: RouteName)
}
extension AppCoordinator: AppCoordinatorRouteDelegate {
func routeName(name: RouteName) {
switch name {
case .home:
let coordinator = LoginCoordinator(navigationController: self.navigationController)
coordinator.delegate = self
self.add(coordinator)
coordinator.start()
break
case .login:
break
}
}
}
......@@ -7,18 +7,16 @@
import UIKit
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
@UIApplicationMain
@objc 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.
......@@ -30,7 +28,5 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// 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.
}
}
{
"images" : [
{
"filename" : "Mask Group 10.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Mask Group 10@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
sss-app/Assets.xcassets/auth_background.imageset/Mask Group 10.png

205 KB

sss-app/Assets.xcassets/auth_background.imageset/Mask Group 10@2x.png

603 KB

//
// BaseCoordinator.swift
// sss-app
//
// Created by Imam Aly on 02/08/23.
//
import Foundation
import UIKit
protocol Coordinator: AnyObject {
var childCoordinators: [Coordinator] { get }
func add(_ coordinator: Coordinator)
func remove(_ coordinator: Coordinator)
func removeAll()
func start()
}
class BaseCoordinator: Coordinator {
private var _childCoordinators: [Coordinator] = []
var childCoordinators: [Coordinator] {
return self._childCoordinators
}
init() {
guard type(of: self) != BaseCoordinator.self else {
fatalError("BaseCoordinator cannot be instantiated")
}
}
func add(_ coordinator: Coordinator) {
self._childCoordinators.append(coordinator)
}
func remove(_ coordinator: Coordinator) {
self._childCoordinators = self.childCoordinators.filter { $0 !== coordinator }
}
func removeAll() {
self._childCoordinators.removeAll()
}
func start() {}
}
//
// AppConstant.swift
// sss-app
//
// Created by Imam Aly on 02/08/23.
//
enum RouteName {
case login
case home
}
//
// LoginCoordinator.swift
// sss-app
//
// Created by Imam Aly on 02/08/23.
//
import Foundation
import UIKit
final class LoginCoordinator: BaseCoordinator {
weak var navigationController: UINavigationController?
weak var delegate: AppCoordinatorRouteDelegate?
override func start() {
super.start()
let vc = LoginViewController(nibName: "LoginViewController", bundle: nil)
vc.delegate = self
navigationController?.pushViewController(vc, animated: false)
}
init(navigationController: UINavigationController?) {
super.init()
self.navigationController = navigationController
}
}
protocol LoginCoordinatorDelegate {
func back()
}
extension LoginCoordinator: LoginCoordinatorDelegate {
func back() {
}
}
......@@ -8,15 +8,28 @@
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
private var mainCoordinator: AppCoordinator?
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).
guard let _ = (scene as? UIWindowScene) else { return }
/// 1. Capture the scene
guard let windowScene = (scene as? UIWindowScene) else { return }
/// 2. Create a new UIWindow using the windowScene constructor which takes in a window scene.
let window = UIWindow(windowScene: windowScene)
/// 3. Create a view hierarchy programmatically
let viewController = LoginViewController()
let navigation = UINavigationController(rootViewController: viewController)
/// 4. Set the root view controller of the window with your view controller
window.rootViewController = navigation
/// 5. Set the window and call makeKeyAndVisible()
self.window = window
mainCoordinator = AppCoordinator(navigationController: navigation)
mainCoordinator?.start()
window.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene) {
......
......@@ -13,7 +13,5 @@ class ViewController: UIViewController {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
}
//
// LoginViewController.swift
// sss-app
//
// Created by Imam Aly on 02/08/23.
//
import UIKit
class LoginViewController: UIViewController {
var delegate: LoginCoordinatorDelegate?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destination.
// Pass the selected object to the new view controller.
}
*/
}
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LoginViewController" customModule="sss_app" customModuleProvider="target">
<connections>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="auth_background" translatesAutoresizingMaskIntoConstraints="NO" id="CgW-Tj-zvg">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Republic of the Philipines" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ej6-fc-lok">
<rect key="frame" x="101.00000000000001" y="109" width="191.33333333333337" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="fnl-2z-Ty3"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="ej6-fc-lok" firstAttribute="top" secondItem="fnl-2z-Ty3" secondAttribute="top" constant="50" id="4al-VB-mcS"/>
<constraint firstItem="CgW-Tj-zvg" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" id="6Wi-RG-Mfb"/>
<constraint firstAttribute="bottom" secondItem="CgW-Tj-zvg" secondAttribute="bottom" id="7li-5c-TlY"/>
<constraint firstItem="ej6-fc-lok" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="96g-gL-Rmy"/>
<constraint firstItem="CgW-Tj-zvg" firstAttribute="leading" secondItem="fnl-2z-Ty3" secondAttribute="leading" id="DQe-m6-rF2"/>
<constraint firstItem="fnl-2z-Ty3" firstAttribute="trailing" secondItem="CgW-Tj-zvg" secondAttribute="trailing" id="eyC-c1-YGw"/>
</constraints>
<point key="canvasLocation" x="28" y="20"/>
</view>
</objects>
<resources>
<image name="auth_background" width="393" height="852"/>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment