Skip to content

Commit

Permalink
Merge pull request #16 from g-liu/game-setup-redesign
Browse files Browse the repository at this point in the history
Redo the game setup
  • Loading branch information
g-liu authored Mar 7, 2022
2 parents d31e849 + 44cd207 commit 884ef6e
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 84 deletions.
4 changes: 4 additions & 0 deletions WordleWithFriends.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
6C94887827D0AAD9005252F1 /* LetterState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C94887727D0AAD9005252F1 /* LetterState.swift */; };
6C94887C27D0AB15005252F1 /* LetterStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C94887B27D0AB15005252F1 /* LetterStateTests.swift */; };
6C94887E27D0B4E4005252F1 /* KeyboardRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C94887D27D0B4E4005252F1 /* KeyboardRow.swift */; };
6C94F50227D5C23D00C19D43 /* Array+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C94F50127D5C23D00C19D43 /* Array+Extension.swift */; };
6CBBCECF279BDC7D00875C30 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBBCECE279BDC7D00875C30 /* Double+Extension.swift */; };
6CBCC3CD2797565D005EB254 /* DismissableAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBCC3CC2797565D005EB254 /* DismissableAlertController.swift */; };
6CBCC3D1279764FF005EB254 /* CGPoint+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6CBCC3D0279764FF005EB254 /* CGPoint+Extension.swift */; };
Expand Down Expand Up @@ -152,6 +153,7 @@
6C94887727D0AAD9005252F1 /* LetterState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterState.swift; sourceTree = "<group>"; };
6C94887B27D0AB15005252F1 /* LetterStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LetterStateTests.swift; sourceTree = "<group>"; };
6C94887D27D0B4E4005252F1 /* KeyboardRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardRow.swift; sourceTree = "<group>"; };
6C94F50127D5C23D00C19D43 /* Array+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+Extension.swift"; sourceTree = "<group>"; };
6CBBCECE279BDC7D00875C30 /* Double+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Double+Extension.swift"; sourceTree = "<group>"; };
6CBCC3CC2797565D005EB254 /* DismissableAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableAlertController.swift; sourceTree = "<group>"; };
6CBCC3D0279764FF005EB254 /* CGPoint+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGPoint+Extension.swift"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -336,6 +338,7 @@
6CBCC3D22797657B005EB254 /* CGSize+Extension.swift */,
6C834C8F279C897F0024CB13 /* IndexPath+Extension.swift */,
6C889A1127D33CA2001AC677 /* UIViewController+Extension.swift */,
6C94F50127D5C23D00C19D43 /* Array+Extension.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -568,6 +571,7 @@
6C78656327D2069C001C9F58 /* CGFloat+Extension.swift in Sources */,
6C94887327D08598005252F1 /* WordleKeyboardKey.swift in Sources */,
6C94887627D098C7005252F1 /* WeakRef.swift in Sources */,
6C94F50227D5C23D00C19D43 /* Array+Extension.swift in Sources */,
60D948012793A46700086C51 /* GameEndDelegate.swift in Sources */,
6C94887E27D0B4E4005252F1 /* KeyboardRow.swift in Sources */,
6CBCC3D1279764FF005EB254 /* CGPoint+Extension.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ final class GameMessagingViewController: UIViewController {

switch gamemode {
case .human:
mainMenuButton.setValue("Play again", forKeyPath: "title")
mainMenuButton.setValue("Main menu", forKeyPath: "title")
case .computer:
mainMenuButton.setValue("Main menu", forKeyPath: "title")
alertController.addAction(newClueButton)
Expand Down
8 changes: 7 additions & 1 deletion WordleWithFriends/ClueGuessViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class ClueGuessViewController: UIViewController {
}()

private lazy var wordleKeyboard: WordleKeyboardInputView = {
let inputView = WordleKeyboardInputView()
let inputView = WordleKeyboardInputView(gamemode: gameGuessesModel.gamemode)
inputView.delegate = self
return inputView
}()
Expand Down Expand Up @@ -103,6 +103,8 @@ final class ClueGuessViewController: UIViewController {
if gameGuessesModel.gamemode != .infinite {
navigationItem.rightBarButtonItem = shareButton
}

navigationItem.setHidesBackButton(true, animated: true)
}

override func viewWillDisappear(_ animated: Bool) {
Expand Down Expand Up @@ -380,4 +382,8 @@ extension ClueGuessViewController: KeyTapDelegate {
func didForfeit() {
forceLoss()
}

func didTapMainMenu() {
navigationController?.popViewController(animated: true)
}
}
12 changes: 12 additions & 0 deletions WordleWithFriends/Extensions/Array+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Array+Extension.swift
// WordleWithFriends
//
// Created by Geoffrey Liu on 3/6/22.
//

extension Array {
mutating func prepend(_ newElement: Element) {
insert(newElement, at: 0)
}
}
131 changes: 102 additions & 29 deletions WordleWithFriends/GameSetupViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,41 +10,77 @@ import AudioToolbox

final class GameSetupViewController: UIViewController {

private var selectedGamemode: GameMode? {
didSet {
switch selectedGamemode {
case .some(.human):
// WHY THIS SO LAGGY???
humanInstructionsTextLabel.isHidden = false
clueTextField.isHidden = false
clueTextField.becomeFirstResponder()
startGameButton.isHidden = false
versusHumanButton.isHidden = true
versusComputerButton.isHidden = true
infiniteModeButton.isHidden = true
switchGamemodeButton.isHidden = false
case .none,
.some(.computer),
.some(.infinite):
humanInstructionsTextLabel.isHidden = true
startGameButton.isHidden = true
clueTextField.isHidden = true
clueTextField.resignFirstResponder()
versusHumanButton.isHidden = false
versusComputerButton.isHidden = false
infiniteModeButton.isHidden = false
switchGamemodeButton.isHidden = true
}
}
}

private lazy var settingsButton: UIBarButtonItem = {
let button = UIBarButtonItem(title: "", style: .plain, target: self, action: #selector(openSettings))
button.accessibilityLabel = "Game settings"

return button
}()

private lazy var instructionsTextLabel: UILabel = {
private lazy var welcomeTextLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.text = "Welcome to Wordle With Friends!"
label.font = UIFont.boldSystemFont(ofSize: 24.0) // TODO: Dynamic font sizes

return label
}()

private lazy var startGameButton: UIButton = {
private lazy var humanInstructionsTextLabel: UILabel = {
let label = UILabel()
label.numberOfLines = 0
label.translatesAutoresizingMaskIntoConstraints = false
label.textAlignment = .center
label.isHidden = true

return label
}()

private lazy var versusHumanButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Start", for: .normal)
button.setTitleColor(.systemGreen, for: .normal)
button.addTarget(self, action: #selector(checkAndInitiateGame), for: .touchUpInside)
button.setTitle("Play vs. human", for: .normal)
button.addTarget(self, action: #selector(promptForClue), for: .touchUpInside)
button.titleLabel?.font = .boldSystemFont(ofSize: 16.0)
button.setTitleColor(.systemGray, for: .disabled)
button.isEnabled = false

return button
}()

private lazy var randomWordButton: UIButton = {
private lazy var versusComputerButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Random word", for: .normal)
button.setTitleColor(.systemOrange, for: .normal)
button.addTarget(self, action: #selector(initiateGameWithRandomWord), for: .touchUpInside)
button.setTitle("Play vs. computer", for: .normal)
button.addTarget(self, action: #selector(initiateGameVersusComputer), for: .touchUpInside)
button.titleLabel?.font = .boldSystemFont(ofSize: 16.0)

return button
Expand All @@ -54,18 +90,43 @@ final class GameSetupViewController: UIViewController {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Infinite mode", for: .normal)
button.setTitleColor(.systemRed, for: .normal)
button.addTarget(self, action: #selector(initiateGameOnInfiniteMode), for: .touchUpInside)
button.titleLabel?.font = .boldSystemFont(ofSize: 16.0)

return button
}()

private lazy var startGameButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Start", for: .normal)
button.addTarget(self, action: #selector(checkAndInitiateGame), for: .touchUpInside)
button.titleLabel?.font = .boldSystemFont(ofSize: 16.0)
button.setTitleColor(.systemGray, for: .disabled)
button.isEnabled = false
button.isHidden = true

return button
}()

private lazy var switchGamemodeButton: UIButton = {
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.setTitle("Switch gamemode", for: .normal)
button.addTarget(self, action: #selector(resetGamemode), for: .touchUpInside)
button.titleLabel?.font = .boldSystemFont(ofSize: 16.0)
button.setTitleColor(.systemGray, for: .disabled)
button.isHidden = true

return button
}()

private lazy var clueTextField: UITextField = {
let textField = WordInputTextField()
textField.translatesAutoresizingMaskIntoConstraints = false
textField.delegate = self
textField.accessibilityIdentifier = "GameSetupViewController.clueTextField"
textField.isHidden = true

return textField
}()
Expand All @@ -85,13 +146,19 @@ final class GameSetupViewController: UIViewController {
stackView.spacing = 8.0

updateScreen()
stackView.addArrangedSubview(instructionsTextLabel)
stackView.addArrangedSubview(welcomeTextLabel)
stackView.addArrangedSubview(humanInstructionsTextLabel)
stackView.addArrangedSubview(clueTextField)
stackView.addArrangedSubview(startGameButton)
stackView.addArrangedSubview(randomWordButton)
stackView.addArrangedSubview(switchGamemodeButton)
stackView.addArrangedSubview(versusHumanButton)
stackView.addArrangedSubview(versusComputerButton)
stackView.addArrangedSubview(infiniteModeButton)
view.addSubview(stackView)

stackView.setCustomSpacing(32.0, after: welcomeTextLabel)
stackView.setCustomSpacing(16.0, after: humanInstructionsTextLabel)

let maxWidth = LayoutUtility.size(screenWidthPercentage: 85.0, maxWidth: 300)

NSLayoutConstraint.activate([
Expand All @@ -101,7 +168,7 @@ final class GameSetupViewController: UIViewController {
clueTextField.widthAnchor.constraint(equalToConstant: CGFloat(maxWidth)),
])

clueTextField.becomeFirstResponder()
updateScreen()
}

override func viewWillDisappear(_ animated: Bool) {
Expand All @@ -110,17 +177,13 @@ final class GameSetupViewController: UIViewController {
startGameButton.isEnabled = false

NotificationCenter.default.removeObserver(self, name: UITextField.textDidChangeNotification, object: nil)

clueTextField.resignFirstResponder()
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
startGameButton.isEnabled = false

NotificationCenter.default.addObserver(self, selector: #selector(textFieldDidUpdate), name: UITextField.textDidChangeNotification, object: nil)

clueTextField.becomeFirstResponder()
}

@objc private func openSettings() {
Expand All @@ -130,12 +193,17 @@ final class GameSetupViewController: UIViewController {
}

func updateScreen() {
let clueLength = GameSettings.clueLength.readIntValue()
instructionsTextLabel.text = "Welcome to Wordle with Friends.\nTo get started, enter a \(clueLength.spelledOut ?? "??")-letter English word below."
let clueLength = GameSettings.clueLength.readIntValue().spelledOut ?? " "
humanInstructionsTextLabel.text = "Enter your \(GameSettings.clueLength.readIntValue().spelledOut ?? " ")-letter clue below:"

clueTextField.accessibilityLabel = "Enter a \(clueLength)-letter word here."
}

@objc private func promptForClue() {
// TODO: Ensure this stays uptodate
selectedGamemode = .human
}

@objc private func textFieldDidUpdate(_ notification: Notification) {
guard let textField = notification.object as? UITextField else {
return
Expand Down Expand Up @@ -170,7 +238,7 @@ final class GameSetupViewController: UIViewController {
let wordValidity = isWordValid()
let isValid = wordValidity == .valid
if isValid {
initiateGame(.human)
initiateGame()
} else {
let ctrl = UIAlertController(title: "Error", message: wordValidity.rawValue, preferredStyle: .alert)
ctrl.addAction(UIAlertAction(title: "Ok", style: .cancel, handler: nil))
Expand All @@ -180,26 +248,31 @@ final class GameSetupViewController: UIViewController {
return isValid
}

@objc private func initiateGameWithRandomWord() {
@objc private func resetGamemode() {
selectedGamemode = nil
}

@objc private func initiateGameVersusComputer() {
selectedGamemode = .computer
clueTextField.text = GameUtility.pickWord()

initiateGame(.computer)
initiateGame()
}

@objc private func initiateGameOnInfiniteMode() {
selectedGamemode = .infinite
clueTextField.text = GameUtility.pickWord()

initiateGame(.infinite)
initiateGame()
}

private func initiateGame(_ gamemode: GameMode) {
private func initiateGame() {
guard let gamemode = selectedGamemode else { return }
// start game
let clueGuessVC = ClueGuessViewController(clue: clueTextField.text?.uppercased() ?? "", gamemode: gamemode)
clueTextField.text = ""
startGameButton.isEnabled = false

clueTextField.resignFirstResponder()

navigationController?.pushViewController(clueGuessVC, animated: true)
}
}
Expand Down
39 changes: 13 additions & 26 deletions WordleWithFriends/Views/CustomKeyboard/KeyboardRow.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,36 +35,23 @@ final class KeyboardRow: UIStackView {
}

@discardableResult
func configure(keys: [Character], keyWidth: CGFloat, isLastRow: Bool = false) -> [WeakRef<WordleKeyboardKey>]{
func configure(keys: [WordleKeyboardKey], keyWidth: CGFloat) -> [WeakRef<WordleKeyboardKey>]{
var keyReferences: [WeakRef<WordleKeyboardKey>] = []

if isLastRow {
// last row must add Enter key (Submit guess)
let enterKey = WordleKeyboardKey(keyType: .submit)
enterKey.delegate = delegate
enterKey.widthAnchor.constraint(equalToConstant: keyWidth * Layout.specialKeyWidthMultiplier).isActive = true
addArrangedSubview(enterKey)
setCustomSpacing(Layout.specialKeySpacing, after: enterKey)
}

keys.enumerated().forEach { index, char in
let keyView = WordleKeyboardKey(keyType: .char(char))
keys.enumerated().forEach { index, keyView in
keyView.delegate = delegate
keyView.widthAnchor.constraint(equalToConstant: keyWidth).isActive = true
addArrangedSubview(keyView)

keyReferences.append(WeakRef(value: keyView))
}

if isLastRow {
if let lastKey = arrangedSubviews.last {
setCustomSpacing(Layout.specialKeySpacing, after: lastKey)
switch keyView.keyType {
case .char(_):
keyReferences.append(WeakRef(value: keyView))
keyView.widthAnchor.constraint(equalToConstant: keyWidth).isActive = true
case .submit, .del:
keyView.widthAnchor.constraint(equalToConstant: keyWidth * Layout.specialKeyWidthMultiplier).isActive = true
setCustomSpacing(Layout.specialKeySpacing, after: keyView)
case .forfeit(_), .mainMenu:
break
}
// last row must add Backspace key
let backspaceKey = WordleKeyboardKey(keyType: .del)
backspaceKey.delegate = delegate
backspaceKey.widthAnchor.constraint(equalToConstant: keyWidth * Layout.specialKeyWidthMultiplier).isActive = true
addArrangedSubview(backspaceKey)

addArrangedSubview(keyView)
}

heightAnchor.constraint(equalToConstant: keyWidth * Layout.heightToWidthRatio).isActive = true
Expand Down
Loading

0 comments on commit 884ef6e

Please sign in to comment.