Skip to content

Commit

Permalink
POC: Show warning banner on map when user is about to approach the th…
Browse files Browse the repository at this point in the history
…reshold for maximum allowed cities to save

This in accordance to #12

Also see https://iafisher.com/projects/cities/faqs
  • Loading branch information
Geoffrey Liu committed May 22, 2022
1 parent 28146c3 commit 554418f
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 0 deletions.
4 changes: 4 additions & 0 deletions HowManyCities.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
6C0EB7A3282C4AFB00E95F6B /* UIDismissableAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0EB7A2282C4AFB00E95F6B /* UIDismissableAlertController.swift */; };
6C0EB7A5282C6B3B00E95F6B /* CityinfoViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0EB7A4282C6B3B00E95F6B /* CityinfoViewModel.swift */; };
6C0EB7A7282C84EB00E95F6B /* WarningBannerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C0EB7A6282C84EB00E95F6B /* WarningBannerView.swift */; };
6C7C8D9828161AA60091E09F /* NormalizedCountryNames.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6C7C8D9728161AA60091E09F /* NormalizedCountryNames.plist */; };
6C7C8D9B2817BFE60091E09F /* OrderedCollections in Frameworks */ = {isa = PBXBuildFile; productRef = 6C7C8D9A2817BFE60091E09F /* OrderedCollections */; };
6C7C8D9E2817C1330091E09F /* MapGuessModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6C7C8D9D2817C1330091E09F /* MapGuessModelTests.swift */; };
Expand Down Expand Up @@ -115,6 +116,7 @@
5E08EA20EB451FE21A3BAC71 /* Pods_HowManyCities.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HowManyCities.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6C0EB7A2282C4AFB00E95F6B /* UIDismissableAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDismissableAlertController.swift; sourceTree = "<group>"; };
6C0EB7A4282C6B3B00E95F6B /* CityinfoViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CityinfoViewModel.swift; sourceTree = "<group>"; };
6C0EB7A6282C84EB00E95F6B /* WarningBannerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WarningBannerView.swift; sourceTree = "<group>"; };
6C7C8D9728161AA60091E09F /* NormalizedCountryNames.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = NormalizedCountryNames.plist; sourceTree = "<group>"; };
6C7C8D9D2817C1330091E09F /* MapGuessModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapGuessModelTests.swift; sourceTree = "<group>"; };
6C7F4D9B2814F52000F90FDE /* State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -477,6 +479,7 @@
6CAD802827F3C1140057A41E /* CityAnnotationView.swift */,
6CAD802E27F3D2C20057A41E /* MapGuessStatsBar.swift */,
6C9C42AB281219D0006529E9 /* MapToast.swift */,
6C0EB7A6282C84EB00E95F6B /* WarningBannerView.swift */,
);
path = Views;
sourceTree = "<group>";
Expand Down Expand Up @@ -805,6 +808,7 @@
6CC3C5802804FB6C00AE5C50 /* NSLayoutConstraint+Extension.swift in Sources */,
6CAD7FE827F381DF0057A41E /* AppDelegate.swift in Sources */,
6C9F60662825AAB90035B0FA /* StateTotalPopulationRenderer.swift in Sources */,
6C0EB7A7282C84EB00E95F6B /* WarningBannerView.swift in Sources */,
6C9C42B528122999006529E9 /* MKOverlayRenderer+Extension.swift in Sources */,
6CBBD5DA2821F7DB002D9FC2 /* CLLocation+Extension.swift in Sources */,
6C82DBE127F569F80084159F /* MKCoordinateRegion+Extension.swift in Sources */,
Expand Down
14 changes: 14 additions & 0 deletions HowManyCities/MapGuessViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ final class MapGuessViewController: UIViewController {
return button
}()

private lazy var warningBanner: WarningBannerView = {
let view = WarningBannerView().autolayoutEnabled

return view
}()

private lazy var guessStackView: UIStackView = {
let stackView = UIStackView(arrangedSubviews: [cityInputTextField, countryDropdownButton]).autolayoutEnabled
stackView.axis = .horizontal
Expand Down Expand Up @@ -145,6 +151,8 @@ final class MapGuessViewController: UIViewController {

view.backgroundColor = .systemBackground

mapView.addSubview(warningBanner)

view.addSubview(mapView)
view.addSubview(resetButton)
view.addSubview(finishButton)
Expand All @@ -161,6 +169,10 @@ final class MapGuessViewController: UIViewController {
view.addSubview(moreStatsButton)

NSLayoutConstraint.activate([
warningBanner.topAnchor.constraint(equalTo: mapView.topAnchor),
warningBanner.leadingAnchor.constraint(equalTo: mapView.leadingAnchor),
warningBanner.trailingAnchor.constraint(equalTo: mapView.trailingAnchor),

mapView.topAnchor.constraint(equalTo: view.topAnchor),
mapView.bottomAnchor.constraint(equalTo: view.centerYAnchor, constant: -64),
mapView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
Expand Down Expand Up @@ -220,6 +232,8 @@ final class MapGuessViewController: UIViewController {
guessStats.updateNumCitiesGuessed(viewModel.numCitiesGuessed)
guessStats.updatePercentageTotalPopulation(viewModel.percentageTotalPopulationGuessed)

warningBanner.setState(viewModel.cityLimitWarning)

return annotations
}

Expand Down
17 changes: 17 additions & 0 deletions HowManyCities/Models/MapGuessViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ protocol MapGuessDelegate: AnyObject {
func didChangeGuessMode(_ mode: GuessMode)
}

enum CityLimitWarning {
case none
case warning(_ remaining: Int)
case unableToSave(_ surplus: Int)
}

final class MapGuessViewModel: NSObject {
var delegate: MapGuessDelegate?

Expand All @@ -41,6 +47,17 @@ final class MapGuessViewModel: NSObject {
var populationGuessed: Int { model.populationGuessed }
var percentageTotalPopulationGuessed: Double { model.percentageTotalPopulationGuessed }

var cityLimitWarning: CityLimitWarning {
// TODO: Thresholds depend on game mode
if numCitiesGuessed > 7500 {
return .unableToSave(numCitiesGuessed - 7500)
} else if numCitiesGuessed >= 7000 {
return .warning(7500 - numCitiesGuessed)
} else {
return .none
}
}

init(cities: Cities? = nil) {
super.init()
let decoder = JSONDecoder()
Expand Down
47 changes: 47 additions & 0 deletions HowManyCities/Views/WarningBannerView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//
// WarningBannerView.swift
// HowManyCities
//
// Created by Geoffrey Liu on 5/11/22.
//

import UIKit

final class WarningBannerView: UIView {
private lazy var label: UILabel = {
let label = UILabel().autolayoutEnabled
label.numberOfLines = 2

return label
}()

override init(frame: CGRect) {
super.init(frame: frame)

isHidden = true
addSubview(label)
label.pin(to: safeAreaLayoutGuide, margins: .init(top: 0, left: 16, bottom: 8, right: 16))
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

func setState(_ state: CityLimitWarning) {
switch state {
case .none:
isHidden = true
backgroundColor = .clear
label.text = nil
case .warning(let remaining):
isHidden = false
backgroundColor = .systemYellow
label.text = "You're approaching the limit (\(remaining) cities left)"
case .unableToSave(let surplus):
isHidden = false
backgroundColor = .systemRed
label.text = "Unable to save now, you're over the limit by \(surplus) cities"

}
}
}

0 comments on commit 554418f

Please sign in to comment.