Implement round timer functionality and add a deck reset button

This commit is contained in:
CypherPoet 2020-01-20 15:12:24 -06:00
parent 65b99570dc
commit b5cd26488c
3 changed files with 68 additions and 31 deletions

View File

@ -40,9 +40,10 @@ extension CardDeckContainerView {
@Published var cards: [Card] = [] @Published var cards: [Card] = []
@Published var timeRemaining: TimeInterval @Published var timeRemaining: TimeInterval
// MARK: - Init // MARK: - Init
init( init(
roundDuration: TimeInterval = 10.0 roundDuration: TimeInterval = 100.0
) { ) {
self.roundDuration = roundDuration self.roundDuration = roundDuration
self.timeRemaining = roundDuration self.timeRemaining = roundDuration
@ -80,10 +81,11 @@ extension CardDeckContainerView.ViewModel {
// MARK: - Computeds // MARK: - Computeds
extension CardDeckContainerView.ViewModel { extension CardDeckContainerView.ViewModel {
var timeRemainingText: String { var timeRemainingText: String {
NumberFormatters.cardCountdown.string(for: timeRemaining) ?? "" NumberFormatters.cardCountdown.string(for: timeRemaining) ?? ""
} }
var isDeckEmpty: Bool { cards.isEmpty }
} }
@ -95,6 +97,18 @@ extension CardDeckContainerView.ViewModel {
try? fetchedResultsController.performFetch() try? fetchedResultsController.performFetch()
cards = extractResults(from: fetchedResultsController) cards = extractResults(from: fetchedResultsController)
} }
func resetDeck() {
fetchCards()
self.timeRemaining = roundDuration
self.isTimerActive = true
}
func pauseRound() {
isTimerActive = false
}
} }
@ -116,7 +130,7 @@ private extension CardDeckContainerView.ViewModel {
CurrentApp.notificationCenter CurrentApp.notificationCenter
.publisher(for: UIApplication.willEnterForegroundNotification) .publisher(for: UIApplication.willEnterForegroundNotification)
.map { _ in true } .map { _ in self.isDeckEmpty == false }
.assign(to: \.isTimerActive, on: self) .assign(to: \.isTimerActive, on: self)
.store(in: &subscriptions) .store(in: &subscriptions)
} }

View File

@ -11,8 +11,6 @@ import CypherPoetSwiftUIKit
struct CardDeckContainerView { struct CardDeckContainerView {
@Environment(\.accessibilityDifferentiateWithoutColor) var differentiateWithoutColor
@ObservedObject var viewModel: ViewModel = .init() @ObservedObject var viewModel: ViewModel = .init()
} }
@ -23,8 +21,8 @@ extension CardDeckContainerView: View {
var body: some View { var body: some View {
GeometryReader { geometry in GeometryReader { geometry in
ZStack { ZStack {
VStack { VStack(spacing: 22) {
Text("Time Remaining: \(self.viewModel.timeRemaining)") Text("Time Remaining: \(self.viewModel.timeRemainingText)")
.font(.largeTitle) .font(.largeTitle)
.foregroundColor(Color.yellow) .foregroundColor(Color.yellow)
.padding(.horizontal) .padding(.horizontal)
@ -39,19 +37,22 @@ extension CardDeckContainerView: View {
onRemove: { (card, index) in self.cardRemoved(at: index) } onRemove: { (card, index) in self.cardRemoved(at: index) }
) )
.allowsHitTesting(self.viewModel.timeRemaining > 0) .allowsHitTesting(self.viewModel.timeRemaining > 0)
.padding()
} }
if self.differentiateWithoutColor { if self.viewModel.isDeckEmpty {
VStack { VStack {
Spacer() Spacer()
HStack {
self.swipeDirectionIndicators Spacer()
self.resetButton
}
} }
} }
} }
} }
.padding() .padding()
.padding()
.background(Color("CardDeckBackground")) .background(Color("CardDeckBackground"))
.edgesIgnoringSafeArea(.all) .edgesIgnoringSafeArea(.all)
} }
@ -66,24 +67,12 @@ extension CardDeckContainerView {
// MARK: - View Variables // MARK: - View Variables
extension CardDeckContainerView { extension CardDeckContainerView {
private var swipeDirectionIndicators: some View { private var resetButton: some View {
HStack { Button("Start Again", action: viewModel.resetDeck)
Image(systemName: "xmark.circle") .padding()
.padding() .background(Color.white)
.background(Color.black.opacity(0.7)) .foregroundColor(.black)
.clipShape(Circle()) .clipShape(Capsule())
Spacer()
Image(systemName: "checkmark.circle")
.padding()
.background(Color.black.opacity(0.7))
.clipShape(Circle())
}
.foregroundColor(.white)
.font(.largeTitle)
} }
} }
@ -94,6 +83,10 @@ extension CardDeckContainerView {
private extension CardDeckContainerView { private extension CardDeckContainerView {
func cardRemoved(at index: Int) { func cardRemoved(at index: Int) {
viewModel.cards.remove(at: index) viewModel.cards.remove(at: index)
if viewModel.isDeckEmpty {
viewModel.pauseRound()
}
} }
} }
@ -105,7 +98,6 @@ struct CardDeckContainerView_Previews: PreviewProvider {
static var previews: some View { static var previews: some View {
CardDeckContainerView() CardDeckContainerView()
.environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext) .environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
// .environment(\.accessibilityDifferentiateWithoutColor, .constant(true)) // .previewLayout(PreviewLayout.iPhone11Landscape)
.previewLayout(PreviewLayout.iPhone11Landscape)
} }
} }

View File

@ -10,6 +10,8 @@ import SwiftUI
struct CardDeckView { struct CardDeckView {
@Environment(\.accessibilityDifferentiateWithoutColor) var differentiateWithoutColor
var width: CGFloat var width: CGFloat
var height: CGFloat var height: CGFloat
@ -33,7 +35,36 @@ extension CardDeckView: View {
) )
.stacked(at: index + 1, outOf: deckSize, offsetMultiple: CGFloat(30 / deckSize)) .stacked(at: index + 1, outOf: deckSize, offsetMultiple: CGFloat(30 / deckSize))
} }
if self.differentiateWithoutColor {
VStack {
Spacer()
self.swipeDirectionIndicators
}
}
} }
.frame(width: width, height: height) .frame(width: width, height: height)
} }
private var swipeDirectionIndicators: some View {
HStack {
Image(systemName: "xmark.circle")
.padding()
.background(Color.black.opacity(0.7))
.clipShape(Circle())
Spacer()
Image(systemName: "checkmark.circle")
.padding()
.background(Color.black.opacity(0.7))
.clipShape(Circle())
}
.foregroundColor(.white)
.font(.largeTitle)
}
} }