Skip to content

Commit

Permalink
Working demo with full keyboard shortcut support
Browse files Browse the repository at this point in the history
  • Loading branch information
emcro committed May 7, 2020
1 parent 80fbf6b commit 13f03c7
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 83 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "5A84FCF7-0C19-4C03-B92A-E539209537A8"
type = "1"
version = "2.0">
</Bucket>
68 changes: 46 additions & 22 deletions SwiftUIKeyboardDemo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,52 @@ import UIKit

@UIApplicationMain
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)
let store = Store()

override var keyCommands: [UIKeyCommand]? {
var commands: [UIKeyCommand] = []

if store.isModalPresented {
commands += [
UIKeyCommand(title: "Close", action: #selector(handleKeyCommand(sender:)), input: "`", propertyList: "closeModal"),
UIKeyCommand(title: "", action: #selector(handleKeyCommand(sender:)), input: UIKeyCommand.inputEscape, propertyList: "closeModal"),
UIKeyCommand(title: "", action: #selector(handleKeyCommand(sender:)), input: "W", modifierFlags: .command, propertyList: "closeModal")
]
} else {
commands += [
UIKeyCommand(title: "First View", action: #selector(handleKeyCommand(sender:)), input: "1", modifierFlags: .command, propertyList: 1),

UIKeyCommand(title: "Second View", action: #selector(handleKeyCommand(sender:)), input: "2", modifierFlags: .command, propertyList: 2)
]

// Add an Open Modal shortcut just when the second view is on screen
if store.currentView == "Second View" {
commands.append(UIKeyCommand(title: "Open Modal", action: #selector(handleKeyCommand(sender:)), input: "O", modifierFlags: .command, propertyList: "openModal"))
}
}

return commands
}

func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
// 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.

@objc func handleKeyCommand(sender: UIKeyCommand) {
if let tabTag = sender.propertyList as? Int {
NotificationCenter.default.post(name: .init("switchTabs"), object: tabTag)
return
}

if let propertyList = sender.propertyList as? String {
switch propertyList {
case "openModal":
self.store.openSecondViewModal = true
return

case "closeModal":
self.store.dismissModal = true
return

default:
return
}
}
}


}

110 changes: 89 additions & 21 deletions SwiftUIKeyboardDemo/ContentView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,34 +9,102 @@
import SwiftUI

struct ContentView: View {
@State private var selection = 0

@EnvironmentObject var store: Store
@State private var selection = 1

var body: some View {
TabView(selection: $selection){
Text("First View")
.font(.title)
.tabItem {
VStack {
Image("first")
Text("First")
}
FirstView().tabItem {
VStack {
Image("first")
Text("First")
}
.tag(0)
Text("Second View")
.font(.title)
.tabItem {
VStack {
Image("second")
Text("Second")
}
}
.tag(1)

SecondView().tabItem {
VStack {
Image("second")
Text("Second")
}
.tag(1)
}
.tag(2)
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("switchTabs"))) { notification in
if let tabTag = notification.object as? Int {
self.selection = tabTag
}
}
}
}

struct FirstView: View {
@EnvironmentObject var store: Store

let title = "First View"

var body: some View {
VStack {
Text(title)
Text("Hold down ⌘ to see keyboard shortcuts")
}
.onAppear {
self.store.currentView = self.title
}
}
}

struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
struct SecondView: View {
@EnvironmentObject var store: Store
@State private var isPresented = false

let title = "Second View"

var body: some View {
VStack {
Text(title)

Button("Open Modal by tapping here or hitting ⌘-O") {
self.store.openSecondViewModal.toggle()
}
}
.onAppear {
self.store.currentView = self.title
}
.sheet(isPresented: self.$store.openSecondViewModal, content: {
ModalView().environmentObject(self.store)
})
}
}

struct ModalView: View {
@EnvironmentObject var store: Store
@Environment(\.presentationMode) var presentationMode

var body: some View {
VStack {
Text("Modal View")
Text("Hit ⌘-W, ⌘-., or Esc to close")
Text("Note that two of the commands are hidden, thanks to empty titles")
}
.onAppear {
self.store.isModalPresented = true
}
.onDisappear {
self.store.isModalPresented = false
}
.onReceive(store.$dismissModal, perform: { dismissModal in
if dismissModal {
self.presentationMode.wrappedValue.dismiss()
self.store.dismissModal = false
}
})
}
}

final class Store: ObservableObject {
@Published var isModalPresented: Bool = false
@Published var openSecondViewModal: Bool = false
@Published var dismissModal: Bool = false
@Published var currentView: String = ""
}
51 changes: 11 additions & 40 deletions SwiftUIKeyboardDemo/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,52 +13,23 @@ 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).

// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()

// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
if let delegate = UIApplication.shared.delegate as? AppDelegate {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView().environmentObject(delegate.store)

// Use a UIHostingController as window root view controller.
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
}
}
}

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 neccessarily 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.
}


}

0 comments on commit 13f03c7

Please sign in to comment.