Implement DiceRollHistoryListView and related functionality

This commit is contained in:
CypherPoet 2020-02-13 16:18:56 -06:00
parent fb09172539
commit 00cd52d5b5
14 changed files with 364 additions and 20 deletions

View File

@ -7,6 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
F321F76D23F5AD3C0059D5E9 /* DiceRollHistoryContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321F76C23F5AD3C0059D5E9 /* DiceRollHistoryContainerView.swift */; };
F321F76F23F5B1F00059D5E9 /* DiceRollHistoryListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321F76E23F5B1F00059D5E9 /* DiceRollHistoryListView.swift */; };
F321F77123F5B7990059D5E9 /* DiceRoll+FetchHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321F77023F5B7990059D5E9 /* DiceRoll+FetchHelpers.swift */; };
F321F77423F5E8410059D5E9 /* DateFormatters.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321F77323F5E8410059D5E9 /* DateFormatters.swift */; };
F321F77623F5E8770059D5E9 /* DiceRollListItemSummaryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321F77523F5E8770059D5E9 /* DiceRollListItemSummaryView.swift */; };
F397601823E742E000813BD8 /* PreviewData+AppStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F397601723E742E000813BD8 /* PreviewData+AppStore.swift */; };
F3CFFC6023E749A2001A2E19 /* DiceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3CFFC5F23E749A2001A2E19 /* DiceView.swift */; };
F3CFFC6223E74A37001A2E19 /* DiceGeneratorContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3CFFC6123E74A37001A2E19 /* DiceGeneratorContainerView.swift */; };
@ -37,6 +42,11 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
F321F76C23F5AD3C0059D5E9 /* DiceRollHistoryContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiceRollHistoryContainerView.swift; sourceTree = "<group>"; };
F321F76E23F5B1F00059D5E9 /* DiceRollHistoryListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiceRollHistoryListView.swift; sourceTree = "<group>"; };
F321F77023F5B7990059D5E9 /* DiceRoll+FetchHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DiceRoll+FetchHelpers.swift"; sourceTree = "<group>"; };
F321F77323F5E8410059D5E9 /* DateFormatters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DateFormatters.swift; sourceTree = "<group>"; };
F321F77523F5E8770059D5E9 /* DiceRollListItemSummaryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiceRollListItemSummaryView.swift; sourceTree = "<group>"; };
F397601723E742E000813BD8 /* PreviewData+AppStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PreviewData+AppStore.swift"; sourceTree = "<group>"; };
F3CFFC5F23E749A2001A2E19 /* DiceView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DiceView.swift; sourceTree = "<group>"; };
F3CFFC6123E74A37001A2E19 /* DiceGeneratorContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiceGeneratorContainerView.swift; sourceTree = "<group>"; };
@ -79,12 +89,30 @@
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
F321F76B23F5AD170059D5E9 /* Dice Roll History */ = {
isa = PBXGroup;
children = (
F321F76C23F5AD3C0059D5E9 /* DiceRollHistoryContainerView.swift */,
F321F76E23F5B1F00059D5E9 /* DiceRollHistoryListView.swift */,
);
path = "Dice Roll History";
sourceTree = "<group>";
};
F321F77223F5E8380059D5E9 /* Formatters */ = {
isa = PBXGroup;
children = (
F321F77323F5E8410059D5E9 /* DateFormatters.swift */,
);
path = Formatters;
sourceTree = "<group>";
};
F397601423E73E6A00813BD8 /* Views */ = {
isa = PBXGroup;
children = (
F3CFFC5F23E749A2001A2E19 /* DiceView.swift */,
F3CFFC6723E77E02001A2E19 /* VerticalDiceRollView.swift */,
F3CFFC6923E77E22001A2E19 /* HorizontalDiceRollView.swift */,
F321F77523F5E8770059D5E9 /* DiceRollListItemSummaryView.swift */,
);
path = Views;
sourceTree = "<group>";
@ -132,6 +160,7 @@
F3D4FD4C23E5EF46000CF606 /* Scenes */ = {
isa = PBXGroup;
children = (
F321F76B23F5AD170059D5E9 /* Dice Roll History */,
F3D4FD8423E705FD000CF606 /* Dice Generator */,
);
path = Scenes;
@ -161,6 +190,7 @@
F3D4FD4F23E5EF58000CF606 /* Reusables */ = {
isa = PBXGroup;
children = (
F321F77223F5E8380059D5E9 /* Formatters */,
F397601423E73E6A00813BD8 /* Views */,
);
path = Reusables;
@ -215,6 +245,7 @@
children = (
F3D4FD6C23E60076000CF606 /* DiceRoll+CoreDataClass.swift */,
F3D4FD6D23E60076000CF606 /* DiceRoll+CoreDataProperties.swift */,
F321F77023F5B7990059D5E9 /* DiceRoll+FetchHelpers.swift */,
F3D4FD7423E60166000CF606 /* DiceRoll+Computeds.swift */,
);
path = DiceRoll;
@ -324,6 +355,7 @@
F3D4FD6E23E60076000CF606 /* DiceRoll+CoreDataClass.swift in Sources */,
F3D4FD5823E5F016000CF606 /* PreviewData.swift in Sources */,
F3D4FD3923E5E688000CF606 /* AppDelegate.swift in Sources */,
F321F77123F5B7990059D5E9 /* DiceRoll+FetchHelpers.swift in Sources */,
F3D4FD6523E5F14D000CF606 /* Dicey.xcdatamodeld in Sources */,
F3CFFC6823E77E02001A2E19 /* VerticalDiceRollView.swift in Sources */,
F3D4FD7523E60166000CF606 /* DiceRoll+Computeds.swift in Sources */,
@ -331,15 +363,19 @@
F3D4FD3B23E5E688000CF606 /* SceneDelegate.swift in Sources */,
F3D4FD7223E60115000CF606 /* Dice.swift in Sources */,
F3D4FD7723E60359000CF606 /* Dice+Computeds.swift in Sources */,
F321F77623F5E8770059D5E9 /* DiceRollListItemSummaryView.swift in Sources */,
F3D4FD8623E70657000CF606 /* DiceGeneratorView.swift in Sources */,
F3CFFC6023E749A2001A2E19 /* DiceView.swift in Sources */,
F3D4FD8023E6FC51000CF606 /* AppState.swift in Sources */,
F3CFFC6C23E85963001A2E19 /* PreviewData+DiceRolls.swift in Sources */,
F321F77423F5E8410059D5E9 /* DateFormatters.swift in Sources */,
F321F76D23F5AD3C0059D5E9 /* DiceRollHistoryContainerView.swift in Sources */,
F3D4FD5623E5EFDE000CF606 /* CurrentApplication.swift in Sources */,
F3D4FD6123E5F120000CF606 /* CoreDataManager+Utils.swift in Sources */,
F397601823E742E000813BD8 /* PreviewData+AppStore.swift in Sources */,
F3D4FD6F23E60076000CF606 /* DiceRoll+CoreDataProperties.swift in Sources */,
F3CFFC6A23E77E22001A2E19 /* HorizontalDiceRollView.swift in Sources */,
F321F76F23F5B1F00059D5E9 /* DiceRollHistoryListView.swift in Sources */,
F3CFFC6423E74D43001A2E19 /* DiceGeneratorView+ViewModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View File

@ -37,6 +37,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
let entryView = DiceGeneratorContainerView()
.environment(\.managedObjectContext, context)
.environmentObject(store)
.accentColor(.purple)
window.rootViewController = UIHostingController(rootView: entryView)

View File

@ -21,4 +21,8 @@ extension DiceRoll {
accumulated + Int(current.rawValue)
}
}
var listFormattedDateString: String {
DateFormatters.diceRollListItem.string(from: createdAt)
}
}

View File

@ -12,11 +12,6 @@ import CoreData
extension DiceRoll {
@nonobjc public class func fetchRequest() -> NSFetchRequest<DiceRoll> {
return NSFetchRequest<DiceRoll>(entityName: "DiceRoll")
}
@NSManaged public var createdAt: Date
@NSManaged public var diceValues: [Int16]
}

View File

@ -0,0 +1,39 @@
//
// DiceRoll+FetchHelpers.swift
// Dicey
//
// Created by CypherPoet on 2/13/20.
//
//
import Foundation
import CoreData
extension DiceRoll {
@nonobjc public class func fetchRequest() -> NSFetchRequest<DiceRoll> {
return NSFetchRequest<DiceRoll>(entityName: "DiceRoll")
}
public enum SortDescriptors {
static let mostRecent = NSSortDescriptor(keyPath: \DiceRoll.createdAt, ascending: false)
}
public enum Predicates {
}
public enum FetchRequests {
static let `default`: NSFetchRequest<DiceRoll> = {
let fetchRequest: NSFetchRequest<DiceRoll> = DiceRoll.fetchRequest()
fetchRequest.sortDescriptors = [DiceRoll.SortDescriptors.mostRecent]
fetchRequest.predicate = nil
return fetchRequest
}()
}
}

View File

@ -1,8 +1,13 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="15702" systemVersion="19C57" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="15702" systemVersion="19D76" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="DiceRoll" representedClassName="DiceRoll" syncable="YES">
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="diceValues" attributeType="Transformable" valueTransformerName="NSSecureUnarchiveFromData" customClassName="[Int16]"/>
<uniquenessConstraints>
<uniquenessConstraint>
<constraint value="createdAt"/>
</uniquenessConstraint>
</uniquenessConstraints>
</entity>
<elements>
<element name="DiceRoll" positionX="-63" positionY="-18" width="128" height="73"/>

View File

@ -21,5 +21,15 @@ extension PreviewData {
return diceRoll
}()
static let sixDice: DiceRoll = {
let diceRoll = DiceRoll(context: CurrentApp.coreDataManager.mainContext)
diceRoll.diceValues = [1, 2, 3, 4, 5, 6]
diceRoll.createdAt = Date().advanced(by: 1000)
return diceRoll
}()
}
}

View File

@ -13,6 +13,19 @@ import CoreData
enum PreviewData {
static func setupSimulatorPreviewData(in context: NSManagedObjectContext) {
(1...10).map { day in
let diceRoll = DiceRoll(context: context)
diceRoll.diceValues = [
Dice.allCases.randomElement()!.rawValue,
Dice.allCases.randomElement()!.rawValue,
Dice.allCases.randomElement()!.rawValue,
Dice.allCases.randomElement()!.rawValue,
]
diceRoll.createdAt = Date.init(timeIntervalSince1970: 60 * 60 * 24 * Double(day))
}
_ = CurrentApp.coreDataManager.save(context)
}
}

View File

@ -0,0 +1,21 @@
//
// DateFormatters.swift
// Dicey
//
// Created by CypherPoet on 2/13/20.
//
//
import Foundation
enum DateFormatters {
static let diceRollListItem: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter
}()
}

View File

@ -0,0 +1,73 @@
//
// DiceRollListItemSummaryView.swift
// Dicey
//
// Created by CypherPoet on 2/13/20.
//
//
import SwiftUI
struct DiceRollListItemSummaryView {
var diceRoll: DiceRoll
}
// MARK: - View
extension DiceRollListItemSummaryView: View {
var body: some View {
GeometryReader { geometry in
HStack(spacing: 0) {
ForEach(
Array(self.diceRoll.diceArray.enumerated()), id: \.offset
) { (index, dice) in
Group {
RoundedRectangle(cornerRadius: geometry.size.height * 0.1)
.fill(Color.accentColor.opacity(0.8))
.frame(
width: geometry.size.height * 0.86,
height: geometry.size.height * 0.86
)
.overlay(
Text("\(dice.rawValue)")
.foregroundColor(.white)
)
.padding(.horizontal, geometry.size.height * 0.1)
if index < (self.diceRoll.diceArray.count - 1) {
RoundedRectangle(cornerRadius: .infinity)
.fill(Color.secondary)
.frame(
width: geometry.size.height * 0.2,
height: geometry.size.height * 0.0667
)
}
}
}
}
}
}
}
// MARK: - View Variables
extension DiceRollListItemSummaryView {
}
// MARK: - Preview
struct DiceRollListItemSummaryView_Previews: PreviewProvider {
static var previews: some View {
List {
DiceRollListItemSummaryView(
diceRoll: PreviewData.DiceRolls.sixDice
)
}
}
}

View File

@ -10,6 +10,7 @@ import SwiftUI
struct DiceGeneratorContainerView {
@Environment(\.managedObjectContext) private var managedObjectContext
@EnvironmentObject private var store: AppStore
@State private var isShowingRollHistory = false
@ -20,15 +21,21 @@ struct DiceGeneratorContainerView {
extension DiceGeneratorContainerView: View {
var body: some View {
DiceGeneratorView(
viewModel: .init(
diceCount: store.state.diceGeneratorState.rollSize,
diceCollection: store.state.diceGeneratorState.latestRoll?.diceArray
),
onDiceRolled: onDiceRolled(_:)
)
NavigationView {
DiceGeneratorView(
viewModel: .init(
diceCount: store.state.diceGeneratorState.rollSize,
diceCollection: store.state.diceGeneratorState.latestRoll?.diceArray
),
onDiceRolled: onDiceRolled(_:)
)
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(trailing: historyButton)
}
.sheet(isPresented: $isShowingRollHistory) {
Text("Roll History")
DiceRollHistoryContainerView()
.environment(\.managedObjectContext, self.managedObjectContext)
.accentColor(.purple)
}
}
}
@ -42,6 +49,14 @@ extension DiceGeneratorContainerView {
// MARK: - View Variables
extension DiceGeneratorContainerView {
private var historyButton: some View {
Button(action: {
self.isShowingRollHistory = true
}) {
Text("History")
}
}
}

View File

@ -192,11 +192,15 @@ private extension DiceGeneratorView {
struct DiceGeneratorView_Previews: PreviewProvider {
static var previews: some View {
DiceGeneratorView(
viewModel: .init(
diceCount: 2
),
onDiceRolled: { _ in }
)
NavigationView {
DiceGeneratorView(
viewModel: .init(
diceCount: 2
),
onDiceRolled: { _ in }
)
.navigationBarTitle("", displayMode: .inline)
.navigationBarItems(trailing: Text("History"))
}
}
}

View File

@ -0,0 +1,62 @@
//
// DiceRollHistoryContainerView.swift
// Dicey
//
// Created by CypherPoet on 2/13/20.
//
//
import SwiftUI
struct DiceRollHistoryContainerView {
@Environment(\.managedObjectContext) private var managedObjectContext
@Environment(\.presentationMode) private var presentationMode
}
// MARK: - View
extension DiceRollHistoryContainerView: View {
var body: some View {
NavigationView {
DiceRollHistoryListView()
.navigationBarItems(trailing: doneButton)
.navigationBarTitle(Text("Dice Rolls"), displayMode: .inline)
}
}
}
// MARK: - Computeds
extension DiceRollHistoryContainerView {
}
// MARK: - View Variables
extension DiceRollHistoryContainerView {
private var doneButton: some View {
Button(action: {
self.presentationMode.wrappedValue.dismiss()
}) {
Text("Done")
}
}
}
// MARK: - Private Helpers
private extension DiceRollHistoryContainerView {
}
// MARK: - Preview
struct DiceRollHistoryContainerView_Previews: PreviewProvider {
static var previews: some View {
DiceRollHistoryContainerView()
.environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
}
}

View File

@ -0,0 +1,66 @@
//
// DiceRollHistoryListView.swift
// Dicey
//
// Created by CypherPoet on 2/13/20.
//
//
import SwiftUI
struct DiceRollHistoryListView {
@Environment(\.managedObjectContext) private var managedObjectContext
@FetchRequest(
fetchRequest: DiceRoll.FetchRequests.default, animation: nil
) private var diceRolls: FetchedResults<DiceRoll>
}
// MARK: - View
extension DiceRollHistoryListView: View {
var body: some View {
List(diceRolls) { diceRoll in
VStack {
DiceRollListItemSummaryView(diceRoll: diceRoll)
.frame(height: 40)
Text(diceRoll.listFormattedDateString)
.multilineTextAlignment(.leading)
.font(.subheadline)
.foregroundColor(.secondary)
.lineLimit(2)
}
}
}
}
// MARK: - Computeds
extension DiceRollHistoryListView {
}
// MARK: - View Variables
extension DiceRollHistoryListView {
}
// MARK: - Private Helpers
private extension DiceRollHistoryListView {
}
// MARK: - Preview
struct DiceRollHistoryListView_Previews: PreviewProvider {
static var previews: some View {
PreviewData.setupSimulatorPreviewData(in: CurrentApp.coreDataManager.mainContext)
return DiceRollHistoryListView()
.environment(\.managedObjectContext, CurrentApp.coreDataManager.mainContext)
}
}