Complete Challenge 2
> Add a settings screen that has a single option: Whether or not a card goes back into deck if it was answered incorrectly.
This commit is contained in:
parent
934e328595
commit
c9bf108b51
|
@ -44,6 +44,12 @@
|
|||
F378AA2523D7B91E00296A76 /* CardDeck+Computeds.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA2423D7B91E00296A76 /* CardDeck+Computeds.swift */; };
|
||||
F378AA3023D8909C00296A76 /* KeyboardAvoider in Frameworks */ = {isa = PBXBuildFile; productRef = F378AA2F23D8909C00296A76 /* KeyboardAvoider */; };
|
||||
F378AA3223D8A6EA00296A76 /* Card+FetchHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA3123D8A6EA00296A76 /* Card+FetchHelpers.swift */; };
|
||||
F378AA3623D91B5100296A76 /* AppState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA3523D91B5100296A76 /* AppState.swift */; };
|
||||
F378AA3823D91B8C00296A76 /* SettingsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA3723D91B8C00296A76 /* SettingsState.swift */; };
|
||||
F378AA3B23D91BD900296A76 /* Burritos in Frameworks */ = {isa = PBXBuildFile; productRef = F378AA3A23D91BD900296A76 /* Burritos */; };
|
||||
F378AA3E23D91DFE00296A76 /* SettingsFormView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA3D23D91DFE00296A76 /* SettingsFormView.swift */; };
|
||||
F378AA4023D91E1500296A76 /* SettingsContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA3F23D91E1500296A76 /* SettingsContainerView.swift */; };
|
||||
F378AA4223D9215400296A76 /* PreviewData+AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F378AA4123D9215400296A76 /* PreviewData+AppStore.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
|
@ -82,6 +88,11 @@
|
|||
F378AA2123D7B8D900296A76 /* CardDeck+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+CoreDataProperties.swift"; sourceTree = "<group>"; };
|
||||
F378AA2423D7B91E00296A76 /* CardDeck+Computeds.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CardDeck+Computeds.swift"; sourceTree = "<group>"; };
|
||||
F378AA3123D8A6EA00296A76 /* Card+FetchHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Card+FetchHelpers.swift"; sourceTree = "<group>"; };
|
||||
F378AA3523D91B5100296A76 /* AppState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppState.swift; sourceTree = "<group>"; };
|
||||
F378AA3723D91B8C00296A76 /* SettingsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsState.swift; sourceTree = "<group>"; };
|
||||
F378AA3D23D91DFE00296A76 /* SettingsFormView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsFormView.swift; sourceTree = "<group>"; };
|
||||
F378AA3F23D91E1500296A76 /* SettingsContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsContainerView.swift; sourceTree = "<group>"; };
|
||||
F378AA4123D9215400296A76 /* PreviewData+AppStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreviewData+AppStore.swift"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
|
@ -90,6 +101,7 @@
|
|||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
F378A9EB23D43C3200296A76 /* CypherPoetSwiftUIKit in Frameworks */,
|
||||
F378AA3B23D91BD900296A76 /* Burritos in Frameworks */,
|
||||
F378A9EE23D43C5600296A76 /* CypherPoetCoreDataKit in Frameworks */,
|
||||
F378AA3023D8909C00296A76 /* KeyboardAvoider in Frameworks */,
|
||||
F378A9F123D43C6F00296A76 /* CypherPoetSwiftUIAnimationKit in Frameworks */,
|
||||
|
@ -152,6 +164,7 @@
|
|||
F378A9D623D438D900296A76 /* Scenes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F378AA3C23D91D9700296A76 /* Settings */,
|
||||
F378A9D923D4393100296A76 /* RootView.swift */,
|
||||
F378AA0023D48CA900296A76 /* Card Deck */,
|
||||
);
|
||||
|
@ -191,6 +204,8 @@
|
|||
F378A9DC23D4395D00296A76 /* State */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F378AA3523D91B5100296A76 /* AppState.swift */,
|
||||
F378AA3723D91B8C00296A76 /* SettingsState.swift */,
|
||||
);
|
||||
path = State;
|
||||
sourceTree = "<group>";
|
||||
|
@ -210,6 +225,7 @@
|
|||
children = (
|
||||
F378A9E323D43A1700296A76 /* PreviewData.swift */,
|
||||
F378A9F223D43CA900296A76 /* PreviewData+Cards.swift */,
|
||||
F378AA4123D9215400296A76 /* PreviewData+AppStore.swift */,
|
||||
);
|
||||
path = "Preview Data";
|
||||
sourceTree = "<group>";
|
||||
|
@ -300,6 +316,15 @@
|
|||
path = "Card Deck";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
F378AA3C23D91D9700296A76 /* Settings */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F378AA3D23D91DFE00296A76 /* SettingsFormView.swift */,
|
||||
F378AA3F23D91E1500296A76 /* SettingsContainerView.swift */,
|
||||
);
|
||||
path = Settings;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
|
@ -321,6 +346,7 @@
|
|||
F378A9ED23D43C5600296A76 /* CypherPoetCoreDataKit */,
|
||||
F378A9F023D43C6F00296A76 /* CypherPoetSwiftUIAnimationKit */,
|
||||
F378AA2F23D8909C00296A76 /* KeyboardAvoider */,
|
||||
F378AA3A23D91BD900296A76 /* Burritos */,
|
||||
);
|
||||
productName = Flashzilla;
|
||||
productReference = F378A9BB23D438AE00296A76 /* Flashzilla.app */;
|
||||
|
@ -355,6 +381,7 @@
|
|||
F378A9EC23D43C5600296A76 /* XCRemoteSwiftPackageReference "CypherPoetCoreDataKit" */,
|
||||
F378A9EF23D43C6E00296A76 /* XCRemoteSwiftPackageReference "CypherPoetSwiftUIAnimationKit" */,
|
||||
F378AA2E23D8909C00296A76 /* XCRemoteSwiftPackageReference "KeyboardAvoider" */,
|
||||
F378AA3923D91BD900296A76 /* XCRemoteSwiftPackageReference "Burritos" */,
|
||||
);
|
||||
productRefGroup = F378A9BC23D438AE00296A76 /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -391,6 +418,7 @@
|
|||
F378AA0C23D4A5D300296A76 /* View+Stacked.swift in Sources */,
|
||||
F378A9F723D44E3900296A76 /* Card+CoreDataProperties.swift in Sources */,
|
||||
F378A9E823D43B6A00296A76 /* CurrentApplication.swift in Sources */,
|
||||
F378AA3823D91B8C00296A76 /* SettingsState.swift in Sources */,
|
||||
F378AA2323D7B8D900296A76 /* CardDeck+CoreDataProperties.swift in Sources */,
|
||||
F378A9FD23D47E1000296A76 /* CardView+ViewModel.swift in Sources */,
|
||||
F378A9E423D43A1700296A76 /* PreviewData.swift in Sources */,
|
||||
|
@ -400,11 +428,14 @@
|
|||
F378AA1323D63AA700296A76 /* NumberFormatters.swift in Sources */,
|
||||
F378A9C423D438AE00296A76 /* Flashzilla.xcdatamodeld in Sources */,
|
||||
F378AA0E23D4CC6400296A76 /* DraggableCardView.swift in Sources */,
|
||||
F378AA3E23D91DFE00296A76 /* SettingsFormView.swift in Sources */,
|
||||
F378A9BF23D438AE00296A76 /* AppDelegate.swift in Sources */,
|
||||
F378A9E623D43A6900296A76 /* CoreDataManager+Utils.swift in Sources */,
|
||||
F378AA1023D5BAD500296A76 /* CardDeckView.swift in Sources */,
|
||||
F378AA1723D733EF00296A76 /* EditDeckView.swift in Sources */,
|
||||
F378AA1523D7156200296A76 /* Card+AnswerState.swift in Sources */,
|
||||
F378AA3623D91B5100296A76 /* AppState.swift in Sources */,
|
||||
F378AA4023D91E1500296A76 /* SettingsContainerView.swift in Sources */,
|
||||
F378AA1923D7359B00296A76 /* EditDeckView+ViewModel.swift in Sources */,
|
||||
F378A9F323D43CAA00296A76 /* PreviewData+Cards.swift in Sources */,
|
||||
F378AA0223D48CB900296A76 /* CardDeckContainerView.swift in Sources */,
|
||||
|
@ -412,6 +443,7 @@
|
|||
F378A9FB23D47DD900296A76 /* CardView.swift in Sources */,
|
||||
F378AA0723D4985200296A76 /* FetchedResultsControlling.swift in Sources */,
|
||||
F378A9C123D438AE00296A76 /* SceneDelegate.swift in Sources */,
|
||||
F378AA4223D9215400296A76 /* PreviewData+AppStore.swift in Sources */,
|
||||
F378AA2523D7B91E00296A76 /* CardDeck+Computeds.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -640,6 +672,14 @@
|
|||
minimumVersion = 1.0.1;
|
||||
};
|
||||
};
|
||||
F378AA3923D91BD900296A76 /* XCRemoteSwiftPackageReference "Burritos" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/guillermomuntaner/Burritos.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 0.0.3;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
|
@ -663,6 +703,11 @@
|
|||
package = F378AA2E23D8909C00296A76 /* XCRemoteSwiftPackageReference "KeyboardAvoider" */;
|
||||
productName = KeyboardAvoider;
|
||||
};
|
||||
F378AA3A23D91BD900296A76 /* Burritos */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = F378AA3923D91BD900296A76 /* XCRemoteSwiftPackageReference "Burritos" */;
|
||||
productName = Burritos;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
|
|
|
@ -1,6 +1,15 @@
|
|||
{
|
||||
"object": {
|
||||
"pins": [
|
||||
{
|
||||
"package": "Burritos",
|
||||
"repositoryURL": "https://github.com/guillermomuntaner/Burritos.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "309dbe1b5b3af8839ca6a7ebb2ad6ddf041bf420",
|
||||
"version": "0.0.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "CypherPoetCoreDataKit",
|
||||
"repositoryURL": "https://github.com/CypherPoet/CypherPoetCoreDataKit.git",
|
||||
|
|
|
@ -30,10 +30,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
PreviewData.setupSimulatorPreviewData(in: context)
|
||||
#endif
|
||||
|
||||
let store = AppStore(initialState: .init(), appReducer: appReducer)
|
||||
|
||||
// Create the SwiftUI view and set the context as the value for the managedObjectContext environment keyPath.
|
||||
// Add `@Environment(\.managedObjectContext)` in the views that will need the context.
|
||||
let entryView = RootView()
|
||||
.environment(\.managedObjectContext, context)
|
||||
.environmentObject(store)
|
||||
|
||||
window.rootViewController = UIHostingController(rootView: entryView)
|
||||
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// AppState.swift
|
||||
// Flashzilla
|
||||
//
|
||||
// Created by CypherPoet on 1/22/20.
|
||||
// ✌️
|
||||
//
|
||||
|
||||
|
||||
import Foundation
|
||||
import CypherPoetSwiftUIKit_DataFlowUtils
|
||||
|
||||
|
||||
struct AppState {
|
||||
var settingsState = SettingsState()
|
||||
}
|
||||
|
||||
|
||||
|
||||
//enum AppSideEffect: SideEffect {}
|
||||
|
||||
|
||||
enum AppAction {
|
||||
case settings(_ action: SettingsAction)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Reducer
|
||||
let appReducer = Reducer<AppState, AppAction> { appState, action in
|
||||
switch action {
|
||||
case .settings(let action):
|
||||
settingsReducer.reduce(&appState.settingsState, action)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
typealias AppStore = Store<AppState, AppAction>
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// SettingsState.swift
|
||||
// Flashzilla
|
||||
//
|
||||
// Created by CypherPoet on 1/22/20.
|
||||
// ✌️
|
||||
//
|
||||
|
||||
|
||||
import CypherPoetSwiftUIKit_DataFlowUtils
|
||||
import UserDefault
|
||||
import Combine
|
||||
|
||||
|
||||
struct SettingsState {
|
||||
@UserDefault("settings-state-restacks-incorrect-cards", defaultValue: false)
|
||||
var restacksIncorrectCards: Bool
|
||||
}
|
||||
|
||||
|
||||
enum SettingsAction {
|
||||
case restacksIncorrectCardsSet(Bool)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Reducer
|
||||
let settingsReducer: Reducer<SettingsState, SettingsAction> = Reducer(
|
||||
reduce: { state, action in
|
||||
switch action {
|
||||
case .restacksIncorrectCardsSet(let value):
|
||||
state.restacksIncorrectCards = value
|
||||
}
|
||||
}
|
||||
)
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// PreviewData+AppStore.swift
|
||||
// Flashzilla
|
||||
//
|
||||
// Created by CypherPoet on 1/22/20.
|
||||
// ✌️
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
extension PreviewData {
|
||||
|
||||
enum AppStores {
|
||||
|
||||
static let `default`: AppStore = {
|
||||
AppStore(initialState: .init(), appReducer: appReducer)
|
||||
}()
|
||||
}
|
||||
}
|
|
@ -63,7 +63,8 @@ extension CardView {
|
|||
|
||||
private var cardContent: some View {
|
||||
Group {
|
||||
if isAccessibilityEnabled {
|
||||
// if isAccessibilityEnabled { // 📝 This appears to become true whenever a sheet is presented and dismissed over the deck view (Xcode 11.3.1)
|
||||
if false {
|
||||
Text(isShowingAnswer ? viewModel.cardAnswerText : viewModel.cardPromptText)
|
||||
.font(.largeTitle)
|
||||
} else {
|
||||
|
|
|
@ -42,11 +42,16 @@ extension DraggableCardView: View {
|
|||
.clipShape(
|
||||
RoundedRectangle(cornerRadius: min(geometry.size.width, geometry.size.height) * 0.08)
|
||||
)
|
||||
|
||||
.animation(.easeIn(duration: 0.25))
|
||||
)
|
||||
.animation(nil)
|
||||
.rotationEffect(self.cardRotation)
|
||||
.offset(self.cardOffset)
|
||||
|
||||
// TODO: We'd need to manually animate this back into position if we don't
|
||||
// want to have to cancel the animations before it. (Look into using @State instead
|
||||
// of @GestureState -- since the latter automatically handles resettting on end)
|
||||
.animation(.spring())
|
||||
.gesture(self.dragGesture)
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ extension CardDeckContainerView {
|
|||
|
||||
var isTimerActive = false
|
||||
var roundDuration: TimeInterval
|
||||
|
||||
var settingsState: SettingsState
|
||||
|
||||
// MARK: - Published Outputs
|
||||
@Published var cards: [Card] = []
|
||||
|
@ -40,11 +40,13 @@ extension CardDeckContainerView {
|
|||
// MARK: - Init
|
||||
init(
|
||||
cardDeck: CardDeck,
|
||||
roundDuration: TimeInterval = 100.0
|
||||
roundDuration: TimeInterval = 100.0,
|
||||
settingsState: SettingsState = .init()
|
||||
) {
|
||||
self.cardDeck = cardDeck
|
||||
self.roundDuration = roundDuration
|
||||
self.timeRemaining = roundDuration
|
||||
self.settingsState = settingsState
|
||||
|
||||
super.init()
|
||||
|
||||
|
@ -79,10 +81,21 @@ extension CardDeckContainerView.ViewModel {
|
|||
|
||||
|
||||
private var visibleCardsPublisher: AnyPublisher<[Card], Never> {
|
||||
$cards
|
||||
.map { $0.filter { $0.answerState == .unanswered } }
|
||||
.print("visibleCardsPublisher")
|
||||
.eraseToAnyPublisher()
|
||||
Publishers.CombineLatest(
|
||||
$cards,
|
||||
CurrentValueSubject(settingsState)
|
||||
)
|
||||
.map { (cards, settingsState) in
|
||||
cards.filter { card in
|
||||
let answerState = card.answerState
|
||||
|
||||
// An optimization here would be to include sorting logic that accounted
|
||||
// for the answer state. That way, incorrect cards could slide to the back.
|
||||
return answerState == .unanswered ||
|
||||
(settingsState.restacksIncorrectCards && answerState == .incorrect)
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,7 +122,7 @@ extension CardDeckContainerView.ViewModel {
|
|||
var unansweredCountText: String {
|
||||
let count = cardDeck.unansweredCount
|
||||
|
||||
return "\(count) \(count == 1 ? "Card" : "Cards") Unattempted"
|
||||
return "\(count) \(count == 1 ? "Card" : "Cards") Unanswered"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,7 +159,6 @@ extension CardDeckContainerView.ViewModel {
|
|||
|
||||
func record(_ answerState: Card.AnswerState, forCardAt index: Int) {
|
||||
let card = visibleCards[index]
|
||||
|
||||
guard let managedObjectContext = card.managedObjectContext else { fatalError() }
|
||||
|
||||
card.answerState = answerState
|
||||
|
|
|
@ -11,6 +11,7 @@ import CypherPoetSwiftUIKit
|
|||
|
||||
|
||||
struct CardDeckContainerView {
|
||||
@EnvironmentObject var store: AppStore
|
||||
@ObservedObject var viewModel: ViewModel
|
||||
|
||||
@State private var isShowingEditView = false
|
||||
|
@ -64,11 +65,11 @@ extension CardDeckContainerView: View {
|
|||
self.editDeckButton
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.padding()
|
||||
.padding()
|
||||
.background(Color("CardDeckBackground"))
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.sheet(
|
||||
|
@ -82,6 +83,13 @@ extension CardDeckContainerView: View {
|
|||
viewModel: .init(currentDeck: self.viewModel.cardDeck)
|
||||
)
|
||||
}
|
||||
.sheet(
|
||||
isPresented: self.$isShowingSettingsView,
|
||||
onDismiss: viewModel.resumeRound
|
||||
) {
|
||||
SettingsContainerView()
|
||||
.environmentObject(self.store)
|
||||
}
|
||||
.onAppear {
|
||||
self.viewModel.isTimerActive = true
|
||||
}
|
||||
|
@ -172,6 +180,7 @@ struct CardDeckContainerView_Previews: PreviewProvider {
|
|||
viewModel: .init(cardDeck: PreviewData.CardDecks.default)
|
||||
)
|
||||
.environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
|
||||
.environmentObject(PreviewData.AppStores.default)
|
||||
// .previewLayout(PreviewLayout.iPhone11Landscape)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,5 +49,6 @@ struct RootView_Previews: PreviewProvider {
|
|||
static var previews: some View {
|
||||
RootView()
|
||||
.environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
|
||||
.environmentObject(PreviewData.AppStores.default)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// SettingsContainerView.swift
|
||||
// Flashzilla
|
||||
//
|
||||
// Created by CypherPoet on 1/22/20.
|
||||
// ✌️
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
|
||||
struct SettingsContainerView: View {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Body
|
||||
extension SettingsContainerView {
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
SettingsFormView()
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Computeds
|
||||
extension SettingsContainerView {
|
||||
}
|
||||
|
||||
|
||||
// MARK: - View Variables
|
||||
extension SettingsContainerView {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Preview
|
||||
struct SettingsContainerView_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
SettingsContainerView()
|
||||
.environmentObject(PreviewData.AppStores.default)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// SettingsFormView.swift
|
||||
// Flashzilla
|
||||
//
|
||||
// Created by CypherPoet on 1/22/20.
|
||||
// ✌️
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
|
||||
struct SettingsFormView {
|
||||
@Environment(\.presentationMode) private var presentationMode
|
||||
@EnvironmentObject var store: AppStore
|
||||
|
||||
|
||||
private var restacksIncorrectCards: Binding<Bool> {
|
||||
store.binding(for: \.settingsState.restacksIncorrectCards) {
|
||||
.settings(.restacksIncorrectCardsSet($0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - View
|
||||
extension SettingsFormView: View {
|
||||
|
||||
var body: some View {
|
||||
Form {
|
||||
Section {
|
||||
Toggle(isOn: restacksIncorrectCards) {
|
||||
Text("Restack After Wrong Answers")
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarItems(trailing: doneButton)
|
||||
.navigationBarTitle("Settings")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Computeds
|
||||
extension SettingsFormView {
|
||||
var settingsState: SettingsState { store.state.settingsState }
|
||||
}
|
||||
|
||||
|
||||
// MARK: - View Variables
|
||||
extension SettingsFormView {
|
||||
|
||||
private var doneButton: some View {
|
||||
Button(action: {
|
||||
self.presentationMode.wrappedValue.dismiss()
|
||||
}) {
|
||||
Text("Done")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Private Helpers
|
||||
private extension SettingsFormView {
|
||||
}
|
||||
|
||||
|
||||
|
||||
// MARK: - Preview
|
||||
struct SettingsFormView_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
SettingsFormView()
|
||||
.environmentObject(PreviewData.AppStores.default)
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue