Skip to content
This repository has been archived by the owner on Sep 23, 2021. It is now read-only.

WIP Slide menu #75

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions FlyveMDMAdminDashboard.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

/* Begin PBXBuildFile section */
0A02916720E4363D00E4DF71 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02916620E4363D00E4DF71 /* AppDelegate.swift */; };
0A02916920E4363D00E4DF71 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02916820E4363D00E4DF71 /* ViewController.swift */; };
0A02916920E4363D00E4DF71 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02916820E4363D00E4DF71 /* MainViewController.swift */; };
0A02916E20E4363D00E4DF71 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A02916D20E4363D00E4DF71 /* Assets.xcassets */; };
0A02917C20E4363D00E4DF71 /* FlyveMDMAdminDashboardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02917B20E4363D00E4DF71 /* FlyveMDMAdminDashboardTests.swift */; };
0A02918720E4363D00E4DF71 /* FlyveMDMAdminDashboardUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02918620E4363D00E4DF71 /* FlyveMDMAdminDashboardUITests.swift */; };
Expand All @@ -20,9 +20,15 @@
0A3132C721890A9D00661C82 /* segoeui.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0A3132C221890A9D00661C82 /* segoeui.ttf */; };
0A3132C821890A9D00661C82 /* segoeuisl.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0A3132C321890A9D00661C82 /* segoeuisl.ttf */; };
0A3132C921890A9D00661C82 /* seguisb.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 0A3132C421890A9D00661C82 /* seguisb.ttf */; };
0A3132CB2189F15600661C82 /* ContainerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3132CA2189F15600661C82 /* ContainerViewController.swift */; };
0A3132CD2189F3D800661C82 /* MenuViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3132CC2189F3D800661C82 /* MenuViewController.swift */; };
0A3132CF2189F81900661C82 /* MainViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3132CE2189F81900661C82 /* MainViewControllerDelegate.swift */; };
0A3132D12189FAA800661C82 /* SidePanelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3132D02189FAA800661C82 /* SidePanelViewController.swift */; };
0A3132D32189FAD800661C82 /* SidePanelViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3132D22189FAD800661C82 /* SidePanelViewControllerDelegate.swift */; };
0A3132D5218A4B1A00661C82 /* MenuItemsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A3132D4218A4B1A00661C82 /* MenuItemsCell.swift */; };
0A75316820E5799000FC5ADE /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A75316720E5799000FC5ADE /* SnapshotHelper.swift */; };
0A75316A20E5815600FC5ADE /* about.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0A75316920E5815600FC5ADE /* about.strings */; };
0A7BB6FA215E6E890074F0EA /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02916820E4363D00E4DF71 /* ViewController.swift */; };
0A7BB6FA215E6E890074F0EA /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02916820E4363D00E4DF71 /* MainViewController.swift */; };
0A7BB6FB215E6E890074F0EA /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A02916620E4363D00E4DF71 /* AppDelegate.swift */; };
0A7BB6FE215E6E890074F0EA /* about.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0A75316920E5815600FC5ADE /* about.strings */; };
0A7BB6FF215E6E890074F0EA /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A02916D20E4363D00E4DF71 /* Assets.xcassets */; };
Expand Down Expand Up @@ -62,7 +68,7 @@
044460C1BBDB4D1F7C8D88D4 /* Pods-FlyveMDMAdminDashboardUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FlyveMDMAdminDashboardUITests.debug.xcconfig"; path = "Target Support Files/Pods-FlyveMDMAdminDashboardUITests/Pods-FlyveMDMAdminDashboardUITests.debug.xcconfig"; sourceTree = "<group>"; };
0A02916320E4363D00E4DF71 /* FlyveMDMAdminDashboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FlyveMDMAdminDashboard.app; sourceTree = BUILT_PRODUCTS_DIR; };
0A02916620E4363D00E4DF71 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
0A02916820E4363D00E4DF71 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
0A02916820E4363D00E4DF71 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
0A02916D20E4363D00E4DF71 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
0A02917220E4363D00E4DF71 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0A02917720E4363D00E4DF71 /* FlyveMDMAdminDashboardTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FlyveMDMAdminDashboardTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
Expand All @@ -81,6 +87,12 @@
0A3132C221890A9D00661C82 /* segoeui.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = segoeui.ttf; path = fonts/segoeui.ttf; sourceTree = "<group>"; };
0A3132C321890A9D00661C82 /* segoeuisl.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = segoeuisl.ttf; path = fonts/segoeuisl.ttf; sourceTree = "<group>"; };
0A3132C421890A9D00661C82 /* seguisb.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = seguisb.ttf; path = fonts/seguisb.ttf; sourceTree = "<group>"; };
0A3132CA2189F15600661C82 /* ContainerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerViewController.swift; sourceTree = "<group>"; };
0A3132CC2189F3D800661C82 /* MenuViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuViewController.swift; sourceTree = "<group>"; };
0A3132CE2189F81900661C82 /* MainViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewControllerDelegate.swift; sourceTree = "<group>"; };
0A3132D02189FAA800661C82 /* SidePanelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidePanelViewController.swift; sourceTree = "<group>"; };
0A3132D22189FAD800661C82 /* SidePanelViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidePanelViewControllerDelegate.swift; sourceTree = "<group>"; };
0A3132D4218A4B1A00661C82 /* MenuItemsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuItemsCell.swift; sourceTree = "<group>"; };
0A75316720E5799000FC5ADE /* SnapshotHelper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SnapshotHelper.swift; sourceTree = "<group>"; };
0A75316920E5815600FC5ADE /* about.strings */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; path = about.strings; sourceTree = "<group>"; };
0A7BB705215E6E890074F0EA /* FlyveMDMAdminDashboard-iPad.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "FlyveMDMAdminDashboard-iPad.app"; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -186,7 +198,13 @@
isa = PBXGroup;
children = (
0A02916620E4363D00E4DF71 /* AppDelegate.swift */,
0A02916820E4363D00E4DF71 /* ViewController.swift */,
0A3132CA2189F15600661C82 /* ContainerViewController.swift */,
0A3132CC2189F3D800661C82 /* MenuViewController.swift */,
0A3132CE2189F81900661C82 /* MainViewControllerDelegate.swift */,
0A02916820E4363D00E4DF71 /* MainViewController.swift */,
0A3132D02189FAA800661C82 /* SidePanelViewController.swift */,
0A3132D22189FAD800661C82 /* SidePanelViewControllerDelegate.swift */,
0A3132D4218A4B1A00661C82 /* MenuItemsCell.swift */,
0A02916D20E4363D00E4DF71 /* Assets.xcassets */,
0A02917220E4363D00E4DF71 /* Info.plist */,
0A02919820E43EB100E4DF71 /* Localizable.strings */,
Expand Down Expand Up @@ -650,8 +668,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0A02916920E4363D00E4DF71 /* ViewController.swift in Sources */,
0A3132D12189FAA800661C82 /* SidePanelViewController.swift in Sources */,
0A3132CB2189F15600661C82 /* ContainerViewController.swift in Sources */,
0A02916920E4363D00E4DF71 /* MainViewController.swift in Sources */,
0A02916720E4363D00E4DF71 /* AppDelegate.swift in Sources */,
0A3132D32189FAD800661C82 /* SidePanelViewControllerDelegate.swift in Sources */,
0A3132D5218A4B1A00661C82 /* MenuItemsCell.swift in Sources */,
0A3132CF2189F81900661C82 /* MainViewControllerDelegate.swift in Sources */,
0A3132CD2189F3D800661C82 /* MenuViewController.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand All @@ -676,7 +700,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0A7BB6FA215E6E890074F0EA /* ViewController.swift in Sources */,
0A7BB6FA215E6E890074F0EA /* MainViewController.swift in Sources */,
0A7BB6FB215E6E890074F0EA /* AppDelegate.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down
3 changes: 2 additions & 1 deletion FlyveMDMAdminDashboard/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

window = UIWindow(frame: UIScreen.main.bounds)
window?.makeKeyAndVisible()
window?.rootViewController = UINavigationController(rootViewController: ViewController())
// window?.rootViewController = UINavigationController(rootViewController: ViewController())
window?.rootViewController = ContainerViewController()

return true
}
Expand Down
181 changes: 181 additions & 0 deletions FlyveMDMAdminDashboard/ContainerViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
/**
* LICENSE
*
* This file is part of Flyve MDM Admin Dashboard for iOS.
*
* Admin Dashboard for iOS is a subproject of Flyve MDM.
* Flyve MDM is a mobile device management software.
*
* Flyve MDM is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* Flyve MDM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* -------------------------------------------------------------------
* @author Hector Rondon - <[email protected]>
* @copyright Copyright Teclib. All rights reserved.
* @license LGPLv3 https://www.gnu.org/licenses/lgpl-3.0.html
* @link https://github.com/flyve-mdm/ios-mdm-dashboard/
* @link http://flyve.org/ios-mdm-dashboard/
* @link https://flyve-mdm.com
* ---------------------------------------------------------------------
*/

import UIKit

class ContainerViewController: UIViewController {

enum SlideOutState {
case collapsed
case menuExpanded
}

var mainNavigationController: UINavigationController!
var mainViewController: MainViewController!

var menuViewController: SidePanelViewController?

let mainPanelExpandedOffset: CGFloat = 60

var currentState: SlideOutState = .collapsed {
didSet {
let shouldShowShadow = currentState != .collapsed
showShadowForCenterViewController(shouldShowShadow)
}
}

override func loadView() {
super.loadView()

mainViewController = MainViewController()
mainViewController.delegate = self

mainNavigationController = UINavigationController(rootViewController: mainViewController)
view.addSubview(mainNavigationController.view)
addChild(mainNavigationController)

mainNavigationController.didMove(toParent: self)

let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
mainNavigationController.view.addGestureRecognizer(panGestureRecognizer)
}
}

// MARK: MainViewController delegate
extension ContainerViewController: MainViewControllerDelegate {

func toggleMenuPanel() {

let notAlreadyExpanded = (currentState != .menuExpanded)

if notAlreadyExpanded {
addMenuPanelViewController()
}

animateMenuPanel(shouldExpand: notAlreadyExpanded)
}

func collapseMenuPanel() {

switch currentState {
case .menuExpanded:
toggleMenuPanel()
default:
break
}
}

func addMenuPanelViewController() {

guard menuViewController == nil else { return }

if let vc = menuViewController {
addChildSidePanelController(vc)
menuViewController = vc
}
}

func addChildSidePanelController(_ sidePanelController: SidePanelViewController) {

sidePanelController.delegate = mainViewController
view.insertSubview(sidePanelController.view, at: 0)

addChild(sidePanelController)
sidePanelController.didMove(toParent: self)
}


func animateMenuPanel(shouldExpand: Bool) {

if shouldExpand {
currentState = .menuExpanded
animateCenterPanelXPosition(targetPosition: mainNavigationController.view.frame.width - mainPanelExpandedOffset)

} else {
animateCenterPanelXPosition(targetPosition: 0) { _ in
self.currentState = .collapsed
self.menuViewController?.view.removeFromSuperview()
self.menuViewController = nil
}
}
}

func animateCenterPanelXPosition(targetPosition: CGFloat, completion: ((Bool) -> Void)? = nil) {

UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: .curveEaseInOut, animations: {
self.mainNavigationController.view.frame.origin.x = targetPosition
}, completion: completion)
}

func showShadowForCenterViewController(_ shouldShowShadow: Bool) {
if shouldShowShadow {
mainNavigationController.view.layer.shadowOpacity = 0.8
} else {
mainNavigationController.view.layer.shadowOpacity = 0.0
}
}
}

// MARK: Gesture recognizer

extension ContainerViewController: UIGestureRecognizerDelegate {

@objc func handlePanGesture(_ recognizer: UIPanGestureRecognizer) {

let gestureIsDraggingFromLeftToRight = (recognizer.velocity(in: view).x > 0)

switch recognizer.state {

case .began:
if currentState == .collapsed {
if gestureIsDraggingFromLeftToRight {
addMenuPanelViewController()
}

showShadowForCenterViewController(true)
}

case .changed:
if let rview = recognizer.view {
rview.center.x = rview.center.x + recognizer.translation(in: view).x
recognizer.setTranslation(CGPoint.zero, in: view)
}

case .ended:
if let _ = menuViewController,
let rview = recognizer.view {
// animate the side panel open or closed based on whether the view has moved more or less than halfway
let hasMovedGreaterThanHalfway = rview.center.x > view.bounds.size.width
animateMenuPanel(shouldExpand: hasMovedGreaterThanHalfway)

}

default:
break
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@

import UIKit

class ViewController: UIViewController {
class MainViewController: UIViewController {

var imageView: UIImageView!
var titleLabel: UILabel!

var delegate: MainViewControllerDelegate?

override func viewDidLoad() {
super.viewDidLoad()
Expand Down Expand Up @@ -65,11 +70,20 @@ class ViewController: UIViewController {
print("open menu")
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
// MARK: Button actions
func menuTapped(_ sender: Any) {
delegate?.toggleMenuPanel?()
}
}


// MARK: - SidePanelViewControllerDelegate
extension MainViewController: SidePanelViewControllerDelegate {

func didSelectMenuItem(_ menuItem: AnyObject) {
imageView.image = menuItem.image
titleLabel.text = menuItem.title

delegate?.collapseSidePanels?()
}
}

34 changes: 34 additions & 0 deletions FlyveMDMAdminDashboard/MainViewControllerDelegate.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* LICENSE
*
* This file is part of Flyve MDM Admin Dashboard for iOS.
*
* Admin Dashboard for iOS is a subproject of Flyve MDM.
* Flyve MDM is a mobile device management software.
*
* Flyve MDM is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* Flyve MDM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* -------------------------------------------------------------------
* @author Hector Rondon - <[email protected]>
* @copyright Copyright Teclib. All rights reserved.
* @license LGPLv3 https://www.gnu.org/licenses/lgpl-3.0.html
* @link https://github.com/flyve-mdm/ios-mdm-dashboard/
* @link http://flyve.org/ios-mdm-dashboard/
* @link https://flyve-mdm.com
* ---------------------------------------------------------------------
*/

import UIKit

@objc
protocol MainViewControllerDelegate {
@objc optional func toggleMenuPanel()
@objc optional func collapseSidePanels()
}
39 changes: 39 additions & 0 deletions FlyveMDMAdminDashboard/MenuItemsCell.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* LICENSE
*
* This file is part of Flyve MDM Admin Dashboard for iOS.
*
* Admin Dashboard for iOS is a subproject of Flyve MDM.
* Flyve MDM is a mobile device management software.
*
* Flyve MDM is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 3
* of the License, or (at your option) any later version.
*
* Flyve MDM is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* -------------------------------------------------------------------
* @author Hector Rondon - <[email protected]>
* @copyright Copyright Teclib. All rights reserved.
* @license LGPLv3 https://www.gnu.org/licenses/lgpl-3.0.html
* @link https://github.com/flyve-mdm/ios-mdm-dashboard/
* @link http://flyve.org/ios-mdm-dashboard/
* @link https://flyve-mdm.com
* ---------------------------------------------------------------------
*/

import UIKit

class MenuItemsCell: UITableViewCell {

var imageMenu: UIImageView!
var imageNameLabel: UILabel!

func configureForItem(_ item: AnyObject) {
imageMenu.image = (item as AnyObject).image
imageNameLabel.text = (item as AnyObject).title
}
}
Loading