Skip to content

Commit 358f0ab

Browse files
[CM-1318] Add key command for navigation (#7)
* rebase * [UPDATE] review comments resolved * [UPDATE] resolved review comment * [UPDATE] added test file
1 parent 6da3f5b commit 358f0ab

File tree

7 files changed

+161
-2
lines changed

7 files changed

+161
-2
lines changed

Package.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import PackageDescription
44

55
let package = Package(
66
name: "YCarousel",
7+
defaultLocalization: "en",
78
platforms: [
89
.iOS(.v14)
910
],
@@ -16,7 +17,7 @@ let package = Package(
1617
dependencies: [
1718
.package(
1819
url: "https://github.com/yml-org/YCoreUI.git",
19-
from: "1.5.0"
20+
from: "1.6.0"
2021
)
2122
],
2223
targets: [
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/*
2+
Localizable.strings
3+
4+
5+
Created by Sahil Saini on 05/04/23.
6+
7+
*/
8+
"Previous_Arrow_Button" = "Previous";
9+
"Next_Arrow_Button" = "Next";

Sources/YCarousel/CarouselView.swift

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class CarouselView: UIView {
5050
}
5151
}
5252
}
53-
53+
5454
private let pageControlBottomSpacing: CGFloat = 16
5555
private var viewProvider: CarouselViewProvider?
5656

@@ -118,6 +118,16 @@ public class CarouselView: UIView {
118118
}
119119
return nil
120120
}
121+
122+
/// Load view at index
123+
/// - Parameter index: index of view to load
124+
public func loadView(at index: Int) {
125+
guard 0..<numberOfPages ~= index else {
126+
return
127+
}
128+
currentPage = index
129+
gotoPage(at: index)
130+
}
121131
}
122132

123133
internal extension CarouselView {

Sources/YCarousel/CarouselViewController.swift

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import UIKit
1212
public class CarouselViewController: UIViewController, CarouselViewDelegate, CarouselViewDataSource {
1313
private let pages: [CarouselPage]
1414

15+
/// Enables keyboard navigation. Default is `true`.
16+
public var isKeyboardNavigationEnabled: Bool = true
17+
1518
/// The carousel view managed by this controller
1619
public var carouselView: CarouselView! { view as? CarouselView }
1720

@@ -37,6 +40,7 @@ public class CarouselViewController: UIViewController, CarouselViewDelegate, Car
3740
carouselView.dataSource = self
3841
carouselView.delegate = self
3942
self.view = carouselView
43+
configureKeys()
4044
}
4145

4246
// MARK: - CarouselViewDelegate
@@ -95,3 +99,32 @@ public class CarouselViewController: UIViewController, CarouselViewDelegate, Car
9599
/// - Returns: UIView
96100
public func carouselView(pageAt index: Int) -> UIView { pages[index].view }
97101
}
102+
103+
// MARK: - UIKeyCommand
104+
105+
internal extension CarouselViewController {
106+
func configureKeys() {
107+
let rightArrow = UIKeyCommand(
108+
title: CarouselViewController.Strings.next.localized,
109+
action: #selector(rightArrowKeyPressed),
110+
input: UIKeyCommand.inputRightArrow
111+
)
112+
let leftArrow = UIKeyCommand(
113+
title: CarouselViewController.Strings.previous.localized,
114+
action: #selector(leftArrowKeyPressed),
115+
input: UIKeyCommand.inputLeftArrow
116+
)
117+
addKeyCommand(leftArrow)
118+
addKeyCommand(rightArrow)
119+
}
120+
121+
@objc func leftArrowKeyPressed() {
122+
guard isKeyboardNavigationEnabled else { return }
123+
carouselView.loadView(at: carouselView.currentPage - 1)
124+
}
125+
126+
@objc func rightArrowKeyPressed() {
127+
guard isKeyboardNavigationEnabled else { return }
128+
carouselView.loadView(at: carouselView.currentPage + 1)
129+
}
130+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//
2+
// CarouselViewController+Strings.swift
3+
// YCarousel
4+
//
5+
// Created by Sahil Saini on 05/04/23.
6+
// Copyright © 2023 Y Media Labs. All rights reserved.
7+
//
8+
9+
import Foundation
10+
import YCoreUI
11+
12+
extension CarouselViewController {
13+
/// Strings
14+
enum Strings: String, Localizable, CaseIterable {
15+
/// Buttons
16+
case previous = "Previous_Arrow_Button"
17+
case next = "Next_Arrow_Button"
18+
19+
/// Bundle
20+
static var bundle: Bundle { .module }
21+
}
22+
}

Tests/YCarouselTests/CarouselViewControllerTests.swift

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,67 @@ final class CarouselViewControllerTests: XCTestCase {
8282
XCTAssertTrue(sut.pageWillUnload)
8383
XCTAssertTrue(sut.pageWillUnload)
8484
}
85+
86+
func test_pressKeyboardLeft_deliversPreviousPage() {
87+
// Given
88+
let sut = makeSUT(withViews: [UIView(), UIView()])
89+
sut.carouselView.loadPage(at: 1)
90+
// When
91+
sut.leftArrowKeyPressed()
92+
// Then
93+
XCTAssertEqual(sut.carouselView.currentPage, 0)
94+
}
95+
96+
func test_pressKeyboardLeftOnFirstPage_deliversNothing() {
97+
// Given
98+
let sut = makeSUT(withViews: [UIView(), UIView()])
99+
XCTAssertEqual(sut.carouselView.currentPage, 0)
100+
// When
101+
sut.leftArrowKeyPressed()
102+
// Then
103+
XCTAssertEqual(sut.carouselView.currentPage, 0)
104+
}
105+
106+
func test_pressKeyboardRight_deliversNextPage() {
107+
// Given
108+
let sut = makeSUT(withViews: [UIView(), UIView()])
109+
XCTAssertEqual(sut.carouselView.currentPage, 0)
110+
// When
111+
sut.rightArrowKeyPressed()
112+
// Then
113+
XCTAssertEqual(sut.carouselView.currentPage, 1)
114+
}
115+
116+
func test_pressKeyboardRightFromLastPage_deliversNothing() {
117+
// Given
118+
let sut = makeSUT(withViews: [UIView(), UIView()])
119+
sut.carouselView.loadView(at: 1)
120+
// When
121+
sut.rightArrowKeyPressed()
122+
// Then
123+
XCTAssertEqual(sut.carouselView.currentPage, 1)
124+
}
125+
126+
func test_pressKeyboardLeftWhenDisabled_deliversNothing() {
127+
// Given
128+
let sut = makeSUT(withViews: [UIView(), UIView()])
129+
sut.carouselView.loadView(at: 1)
130+
sut.isKeyboardNavigationEnabled = false
131+
// When
132+
sut.leftArrowKeyPressed()
133+
// Then
134+
XCTAssertEqual(sut.carouselView.currentPage, 1)
135+
}
136+
137+
func test_pressKeyboardRightWhenDisabled_deliversNothing() {
138+
// Given
139+
let sut = makeSUT(withViews: [UIView(), UIView()])
140+
sut.isKeyboardNavigationEnabled = false
141+
// When
142+
sut.rightArrowKeyPressed()
143+
// Then
144+
XCTAssertEqual(sut.carouselView.currentPage, 0)
145+
}
85146
}
86147

87148
private extension CarouselViewControllerTests {
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//
2+
// CarouselViewController+StringsTests.swift
3+
// YCarousel
4+
//
5+
// Created by Sahil Saini on 07/04/23.
6+
// Copyright © 2023 Y Media Labs. All rights reserved.
7+
//
8+
9+
import XCTest
10+
@testable import YCarousel
11+
12+
final class CarouselViewControllerStringsTests: XCTestCase {
13+
func testLoadStrings() {
14+
CarouselViewController.Strings.allCases.forEach {
15+
// Given a localized string constant
16+
let string = $0.localized
17+
// should not be empty
18+
XCTAssertFalse(string.isEmpty)
19+
// should not equal its key
20+
XCTAssertNotEqual($0.rawValue, string)
21+
}
22+
}
23+
}

0 commit comments

Comments
 (0)