Issue #276 - [Scaffold] Drawer for the Home Screen
Drawer + transactions history clean up
This commit is contained in:
parent
a15596b3aa
commit
1a16282899
|
@ -96,6 +96,7 @@
|
|||
9E2DF99E27CF704D00649636 /* ImportWalletView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2DF99B27CF704D00649636 /* ImportWalletView.swift */; };
|
||||
9E2F1C8228095AFE004E65FE /* Int64+Zcash.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8128095AFE004E65FE /* Int64+Zcash.swift */; };
|
||||
9E2F1C842809B606004E65FE /* DebugMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C832809B606004E65FE /* DebugMenu.swift */; };
|
||||
9E2F1C8F280EDE09004E65FE /* Drawer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E2F1C8E280EDE09004E65FE /* Drawer.swift */; };
|
||||
9E37A2B827C8F59F00AE57B3 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 9E37A2B727C8F59F00AE57B3 /* Localizable.strings */; };
|
||||
9E4DC6E027C409A100E657F4 /* NeumorphicDesignModifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */; };
|
||||
9E4DC6E227C4C6B700E657F4 /* SecantButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */; };
|
||||
|
@ -257,6 +258,7 @@
|
|||
9E2DF99B27CF704D00649636 /* ImportWalletView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImportWalletView.swift; sourceTree = "<group>"; };
|
||||
9E2F1C8128095AFE004E65FE /* Int64+Zcash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Int64+Zcash.swift"; sourceTree = "<group>"; };
|
||||
9E2F1C832809B606004E65FE /* DebugMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebugMenu.swift; sourceTree = "<group>"; };
|
||||
9E2F1C8E280EDE09004E65FE /* Drawer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Drawer.swift; sourceTree = "<group>"; };
|
||||
9E37A2B727C8F59F00AE57B3 /* Localizable.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Localizable.strings; sourceTree = "<group>"; };
|
||||
9E4DC6DF27C409A100E657F4 /* NeumorphicDesignModifier.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NeumorphicDesignModifier.swift; sourceTree = "<group>"; };
|
||||
9E4DC6E127C4C6B700E657F4 /* SecantButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecantButtonStyles.swift; sourceTree = "<group>"; };
|
||||
|
@ -515,6 +517,7 @@
|
|||
0DA13C9126C15E1900E3B610 /* UIComponents */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E2F1C8D280EDDEF004E65FE /* Drawer */,
|
||||
2E35F99027B28E6800EB79CD /* TextFields */,
|
||||
0D0781C5278776B90083ACD7 /* Shapes */,
|
||||
0D8A43C2272AEEA7005A6414 /* FontStyles */,
|
||||
|
@ -765,6 +768,14 @@
|
|||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9E2F1C8D280EDDEF004E65FE /* Drawer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
9E2F1C8E280EDE09004E65FE /* Drawer.swift */,
|
||||
);
|
||||
path = Drawer;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
9EAFEB802805791400199FC9 /* AppReducer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -1208,6 +1219,7 @@
|
|||
0D5D16F526E24CCF00AD33D1 /* AppError.swift in Sources */,
|
||||
0D18581B272728D60046B928 /* PhraseChip.swift in Sources */,
|
||||
0DF482BA2787ADA800EB37D6 /* ConditionalModifier.swift in Sources */,
|
||||
9E2F1C8F280EDE09004E65FE /* Drawer.swift in Sources */,
|
||||
665C963F272C26E600BC04FB /* CircularFrameBackground.swift in Sources */,
|
||||
9EAFEB882806E5AE00199FC9 /* CombineSynchronizer.swift in Sources */,
|
||||
0DB8AA81271DC7520035BC9D /* DesignGuide.swift in Sources */,
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.271",
|
||||
"green" : "0.125",
|
||||
"red" : "0.075"
|
||||
"blue" : "0x45",
|
||||
"green" : "0x1F",
|
||||
"red" : "0x13"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.100",
|
||||
"blue" : "0.000",
|
||||
"green" : "0.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x45",
|
||||
"green" : "0x1F",
|
||||
"red" : "0x13"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -9,13 +9,16 @@ struct AppView: View {
|
|||
WithViewStore(store) { viewStore in
|
||||
switch viewStore.route {
|
||||
case .home:
|
||||
HomeView(
|
||||
store: store.scope(
|
||||
state: \.homeState,
|
||||
action: AppAction.home
|
||||
NavigationView {
|
||||
HomeView(
|
||||
store: store.scope(
|
||||
state: \.homeState,
|
||||
action: AppAction.home
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
.navigationViewStyle(StackNavigationViewStyle())
|
||||
|
||||
case .sandbox:
|
||||
NavigationView {
|
||||
SandboxView(
|
||||
|
|
|
@ -2,15 +2,20 @@ import ComposableArchitecture
|
|||
import SwiftUI
|
||||
|
||||
struct HomeState: Equatable {
|
||||
var totalBalance: Double
|
||||
var verifiedBalance: Double
|
||||
var arePublishersPrepared = false
|
||||
|
||||
var drawerOverlay: DrawerOverlay
|
||||
var totalBalance: Double
|
||||
var transactionHistoryState: TransactionHistoryState
|
||||
var verifiedBalance: Double
|
||||
}
|
||||
|
||||
enum HomeAction: Equatable {
|
||||
case debugMenuStartup
|
||||
case preparePublishers
|
||||
case transactionHistory(TransactionHistoryAction)
|
||||
case updateBalance(Balance)
|
||||
case updateDrawer(DrawerOverlay)
|
||||
}
|
||||
|
||||
struct HomeEnvironment {
|
||||
|
@ -43,6 +48,16 @@ extension HomeReducer {
|
|||
|
||||
case .debugMenuStartup:
|
||||
return .none
|
||||
|
||||
case .updateDrawer(let drawerOverlay):
|
||||
state.drawerOverlay = drawerOverlay
|
||||
return .none
|
||||
|
||||
case .transactionHistory(let historyAction):
|
||||
return TransactionHistoryReducer
|
||||
.default
|
||||
.run(&state.transactionHistoryState, historyAction, ())
|
||||
.map(HomeAction.transactionHistory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -51,11 +66,36 @@ extension HomeReducer {
|
|||
|
||||
typealias HomeStore = Store<HomeState, HomeAction>
|
||||
|
||||
extension HomeStore {
|
||||
func historyStore() -> TransactionHistoryStore {
|
||||
self.scope(
|
||||
state: \.transactionHistoryState,
|
||||
action: HomeAction.transactionHistory
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - HomeViewStore
|
||||
|
||||
typealias HomeViewStore = ViewStore<HomeState, HomeAction>
|
||||
|
||||
extension HomeViewStore {
|
||||
func bindingForDrawer() -> Binding<DrawerOverlay> {
|
||||
self.binding(
|
||||
get: { $0.drawerOverlay },
|
||||
send: { .updateDrawer($0) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: PlaceHolders
|
||||
|
||||
extension HomeState {
|
||||
static var placeholder: Self {
|
||||
.init(
|
||||
drawerOverlay: .partial,
|
||||
totalBalance: 0.0,
|
||||
transactionHistoryState: .placeHolder,
|
||||
verifiedBalance: 0.0
|
||||
)
|
||||
}
|
||||
|
|
|
@ -6,12 +6,29 @@ struct HomeView: View {
|
|||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
VStack(alignment: .center, spacing: 30.0) {
|
||||
Text("totalBalance \(viewStore.totalBalance)")
|
||||
Text("verifiedBalance \(viewStore.verifiedBalance)")
|
||||
.accessDebugMenuWithHiddenGesture {
|
||||
viewStore.send(.debugMenuStartup)
|
||||
GeometryReader { proxy in
|
||||
ZStack {
|
||||
VStack {
|
||||
Text("totalBalance \(viewStore.totalBalance)")
|
||||
Text("verifiedBalance \(viewStore.verifiedBalance)")
|
||||
.accessDebugMenuWithHiddenGesture {
|
||||
viewStore.send(.debugMenuStartup)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Drawer(overlay: viewStore.bindingForDrawer(), maxHeight: proxy.size.height) {
|
||||
VStack {
|
||||
TransactionHistoryView(store: store.historyStore())
|
||||
.padding(.top, 10)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.applyScreenBackground()
|
||||
}
|
||||
}
|
||||
.applyScreenBackground()
|
||||
}
|
||||
.onAppear(perform: { viewStore.send(.preparePublishers) })
|
||||
}
|
||||
|
|
|
@ -6,18 +6,15 @@ struct TransactionHistoryView: View {
|
|||
|
||||
var body: some View {
|
||||
WithViewStore(store) { viewStore in
|
||||
List {
|
||||
ForEach(viewStore.transactions) { transaction in
|
||||
WithStateBinding(binding: viewStore.bindingForSelectingTransaction(transaction)) {
|
||||
Text("Show Transaction \(transaction.id)")
|
||||
.navigationLink(
|
||||
isActive: $0,
|
||||
destination: { TransactionDetailView(transaction: transaction) }
|
||||
)
|
||||
}
|
||||
ForEach(viewStore.transactions) { transaction in
|
||||
WithStateBinding(binding: viewStore.bindingForSelectingTransaction(transaction)) {
|
||||
Text("Show Transaction \(transaction.id)")
|
||||
.navigationLink(
|
||||
isActive: $0,
|
||||
destination: { TransactionDetailView(transaction: transaction) }
|
||||
)
|
||||
}
|
||||
}
|
||||
.navigationTitle(Text("Transactions"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@ internal enum Asset {
|
|||
internal static let redGradientStart = ColorAsset(name: "redGradientStart")
|
||||
}
|
||||
internal enum Shadow {
|
||||
internal static let drawerShadow = ColorAsset(name: "drawerShadow")
|
||||
internal static let emptyChipInnerShadow = ColorAsset(name: "emptyChipInnerShadow")
|
||||
internal static let numberedTextShadow = ColorAsset(name: "numberedTextShadow")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
//
|
||||
// Drawer.swift
|
||||
// secant-testnet
|
||||
//
|
||||
// Created by Lukáš Korba on 19.04.2022.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
enum DrawerOverlay {
|
||||
case full
|
||||
case partial
|
||||
case bottom
|
||||
}
|
||||
|
||||
struct Drawer<Content: View>: View {
|
||||
@GestureState private var translation: CGFloat = 0
|
||||
@Binding var overlay: DrawerOverlay
|
||||
|
||||
let maxHeight: CGFloat
|
||||
let content: Content
|
||||
|
||||
private var offset: CGFloat {
|
||||
switch overlay {
|
||||
case .full: return 70.0
|
||||
case .partial: return maxHeight * 0.75
|
||||
case .bottom: return maxHeight
|
||||
}
|
||||
}
|
||||
|
||||
init(overlay: Binding<DrawerOverlay>, maxHeight: CGFloat, @ViewBuilder content: () -> Content) {
|
||||
self._overlay = overlay
|
||||
self.maxHeight = maxHeight
|
||||
self.content = content()
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
GeometryReader { proxy in
|
||||
ZStack {
|
||||
VStack {
|
||||
RoundedRectangle(cornerRadius: 16.0)
|
||||
.fill(Color.secondary)
|
||||
.opacity(0.2)
|
||||
.frame(
|
||||
width: 50,
|
||||
height: 6
|
||||
)
|
||||
.padding(.top, 10)
|
||||
|
||||
content
|
||||
}
|
||||
}
|
||||
.frame(width: proxy.size.width, height: maxHeight, alignment: .top)
|
||||
.applyScreenBackground()
|
||||
.background(Color(.secondarySystemBackground))
|
||||
.cornerRadius(16.0)
|
||||
.frame(height: proxy.size.height, alignment: .bottom)
|
||||
.offset(y: max(offset + translation, 0))
|
||||
.animation(.interactiveSpring())
|
||||
.gesture(
|
||||
DragGesture().updating($translation) { value, state, _ in
|
||||
state = value.translation.height
|
||||
}
|
||||
.onEnded { value in
|
||||
let snapDistanceFull = maxHeight * 0.55
|
||||
let snapDistancePartial = maxHeight * 0.8
|
||||
|
||||
if value.location.y <= snapDistanceFull {
|
||||
overlay = .full
|
||||
} else if value.location.y > snapDistanceFull && value.location.y <= snapDistancePartial {
|
||||
overlay = .partial
|
||||
} else {
|
||||
overlay = .bottom
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
.shadow(color: Asset.Colors.Shadow.drawerShadow.color, radius: 15.0, x: 0.0, y: -4.0)
|
||||
}
|
||||
}
|
||||
|
||||
struct Drawer_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
@State var overlay: DrawerOverlay = .partial
|
||||
|
||||
return Drawer(overlay: $overlay, maxHeight: 800.0) {
|
||||
VStack {
|
||||
Text("Transaction History")
|
||||
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue