Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WR-361: Payment screen settings #44

Merged
merged 3 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions WaiterRobot/Ui/Billing/BillingScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ struct BillingScreen: View {
title: localize.dialog.cancel(),
icon: nil
) {
if viewModel.state.hasSelectedItems {
if viewModel.state.hasCustomSelection {
showAbortConfirmation = true
} else {
viewModel.actual.abortBill()
Expand Down Expand Up @@ -67,7 +67,16 @@ struct BillingScreen: View {
.sheet(isPresented: $showPayDialog) {
PayDialog(viewModel: viewModel)
}
.withViewModel(viewModel, navigator)
.withViewModel(viewModel, navigator) { effect in
switch onEnum(of: effect) {
case .showPaymentSheet:
showPayDialog = true
case .toast:
break // TODO: add "toast" support
}

return true
}
}

@ViewBuilder
Expand Down Expand Up @@ -117,7 +126,7 @@ struct BillingScreen: View {
.padding()
.overlay(alignment: .bottom) {
Button {
showPayDialog = true
viewModel.actual.paySelection(paymentSheetShown: false)
} label: {
Image(systemName: "eurosign")
.font(.system(.title))
Expand Down
4 changes: 3 additions & 1 deletion WaiterRobot/Ui/Billing/PayDialog.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,11 @@ struct PayDialog: View {
dismiss()
}
}
}
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button(localize.billing.pay()) {
viewModel.actual.paySelection()
viewModel.actual.paySelection(paymentSheetShown: true)
dismiss()
}
}
Expand Down
4 changes: 2 additions & 2 deletions WaiterRobot/Ui/Core/Navigation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ extension View {
func withViewModel<State, SideEffect>(
_ viewModel: some ObservableViewModel<State, SideEffect, some AbstractViewModel<State, SideEffect>>,
_ navigator: UIPilot<Screen>,
handler _: ((SideEffect) -> Bool)? = nil
handler: ((SideEffect) -> Bool)? = nil
) -> some View where State: ViewModelState, SideEffect: ViewModelEffect {
handleSideEffects(of: viewModel, navigator)
handleSideEffects(of: viewModel, navigator, handler: handler)
.observeState(of: viewModel)
}
}
12 changes: 6 additions & 6 deletions WaiterRobot/Ui/Order/ProductListItem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,11 @@ struct ProductListItem: View {

var foregroundColor: Color {
if product.soldOut {
return .blackWhite
}

if let backgroundColor {
return backgroundColor.getContentColor(lightColorScheme: .black, darkColorScheme: .white)
.blackWhite
} else if let backgroundColor {
backgroundColor.getContentColor(lightColorScheme: .black, darkColorScheme: .white)
} else {
return Color.blackWhite
.blackWhite
}
}

Expand Down Expand Up @@ -76,6 +74,7 @@ struct ProductListItem: View {
name: "Wine",
price: Money(cents: 290),
soldOut: true,
color: nil,
allergens: [
Allergen(id: 1, name: "Egg", shortName: "E"),
Allergen(id: 2, name: "Egg2", shortName: "A"),
Expand All @@ -98,6 +97,7 @@ struct ProductListItem: View {
name: "Wine",
price: Money(cents: 290),
soldOut: false,
color: nil,
allergens: [
Allergen(id: 1, name: "Egg", shortName: "E"),
Allergen(id: 2, name: "Egg2", shortName: "A"),
Expand Down
1 change: 1 addition & 0 deletions WaiterRobot/Ui/Order/Search/ProductSearchAllTab.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ struct ProductSearchAllTab: View {
name: "Beer",
price: Money(cents: 450),
soldOut: false,
color: nil,
allergens: [],
position: 1
),
Expand Down
1 change: 1 addition & 0 deletions WaiterRobot/Ui/Order/Search/ProductSearchGroupList.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct ProductSearchGroupList: View {
name: "Beer",
price: Money(cents: 450),
soldOut: false,
color: nil,
allergens: [],
position: 1
),
Expand Down
35 changes: 30 additions & 5 deletions WaiterRobot/Ui/Settings/SettingsItem.swift
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import SwiftUI

struct SettingsItem: View {
struct SettingsItem<Action: View>: View {
let icon: String
let title: String
let subtitle: String
let action: () -> Void
@ViewBuilder let action: Action?
let onClick: () -> Void

var body: some View {
Button {
action()
onClick()
} label: {
HStack {
Image(systemName: icon)
Expand All @@ -25,25 +26,49 @@ struct SettingsItem: View {
.font(.caption)
.foregroundColor(.secondary)
}

if let action {
Spacer()
action
}
}
}
.padding([.bottom, .top], 1)
}
}

extension SettingsItem where Action == EmptyView {
init(icon: String, title: String, subtitle: String, onClick: @escaping () -> Void) {
self.icon = icon
self.title = title
self.subtitle = subtitle
action = nil
self.onClick = onClick
}
}

#Preview {
List {
SettingsItem(
icon: "rectangle.portrait.and.arrow.right",
title: "Logout",
subtitle: "Logout from this organisation",
action: {}
onClick: {}
)
SettingsItem(
icon: "person.3",
title: "Switch event",
subtitle: "My Organisation / The Event",
action: {}
onClick: {}
)
SettingsItem(
icon: "dollarsign.arrow.circlepath",
title: "Toggle",
subtitle: "Some toggle able",
action: {
Toggle(isOn: .constant(true)) {}.labelsHidden()
},
onClick: {}
)
}
}
158 changes: 117 additions & 41 deletions WaiterRobot/Ui/Settings/SettingsScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ struct SettingsScreen: View {
@EnvironmentObject var navigator: UIPilot<Screen>

@State private var showConfirmLogout = false
@State private var showConfirmSkipMoneyBackDialog = false

@StateObject private var viewModel = ObservableSettingsViewModel()

Expand All @@ -31,44 +32,12 @@ struct SettingsScreen: View {

private func content() -> some View {
List {
Section {
SettingsItem(
icon: "rectangle.portrait.and.arrow.right",
title: localize.settings.logout.action(),
subtitle: "\"\(CommonApp.shared.settings.organisationName)\" / \"\(CommonApp.shared.settings.waiterName)\"",
action: {
showConfirmLogout = true
}
)
general()

SettingsItem(
icon: "arrow.triangle.2.circlepath",
title: localize.settings.refresh.title(),
subtitle: localize.settings.refresh.desc(),
action: {
viewModel.actual.refreshAll()
}
)
payment()

SettingsItem(
icon: "person.3",
title: localize.switchEvent.title(),
subtitle: CommonApp.shared.settings.eventName,
action: {
viewModel.actual.switchEvent()
}
)
}

Section {
SwitchThemeView(
initial: viewModel.state.currentAppTheme,
onChange: viewModel.actual.switchTheme
)
}

Section {
Link(localize.settings.privacyPolicy(), destination: URL(string: CommonApp.shared.privacyPolicyUrl)!)
Section(header: Text(localize.settings.about.title())) {
Link(localize.settings.about.privacyPolicy(), destination: URL(string: CommonApp.shared.privacyPolicyUrl)!)
}

HStack {
Expand All @@ -89,12 +58,119 @@ struct SettingsScreen: View {
}
}
}
.confirmationDialog(localize.settings.logout.title(value0: CommonApp.shared.settings.organisationName), isPresented: $showConfirmLogout, titleVisibility: .visible) {
Button(localize.settings.logout.action(), role: .destructive, action: { viewModel.actual.logout() })
Button(localize.settings.keepLoggedIn(), role: .cancel, action: { showConfirmLogout = false })
.confirmationDialog(
localize.settings.general.logout.title(value0: CommonApp.shared.settings.organisationName),
isPresented: $showConfirmLogout,
titleVisibility: .visible
) {
Button(localize.settings.general.logout.action(), role: .destructive, action: { viewModel.actual.logout() })
Button(localize.settings.general.keepLoggedIn(), role: .cancel, action: { showConfirmLogout = false })
} message: {
Text(localize.settings.general.logout.desc(value0: CommonApp.shared.settings.organisationName))
}
.confirmationDialog(
localize.settings.payment.skipMoneyBackDialog.title(),
isPresented: $showConfirmSkipMoneyBackDialog,
titleVisibility: .visible
) {
Button(localize.settings.payment.skipMoneyBackDialog.confirmAction(), role: .destructive) {
viewModel.actual.toggleSkipMoneyBackDialog(value: true, confirmed: true)
}
Button(localize.dialog.cancel(), role: .cancel) {
showConfirmSkipMoneyBackDialog = false
}
} message: {
Text(localize.settings.logout.desc(value0: CommonApp.shared.settings.organisationName))
Text(localize.settings.payment.skipMoneyBackDialog.confirmDesc())
}
.withViewModel(viewModel, navigator) { effect in
switch onEnum(of: effect) {
case .confirmSkipMoneyBackDialog:
showConfirmSkipMoneyBackDialog = true
}

return true
}
}

private func general() -> some View {
Section(header: Text(localize.settings.general.title())) {
SettingsItem(
icon: "rectangle.portrait.and.arrow.right",
title: localize.settings.general.logout.action(),
subtitle: "\"\(CommonApp.shared.settings.organisationName)\" / \"\(CommonApp.shared.settings.waiterName)\"",
onClick: {
showConfirmLogout = true
}
)

SettingsItem(
icon: "person.3",
title: localize.switchEvent.title(),
subtitle: CommonApp.shared.settings.eventName,
onClick: {
viewModel.actual.switchEvent()
}
)

SwitchThemeView(
initial: viewModel.state.currentAppTheme,
onChange: viewModel.actual.switchTheme
)

SettingsItem(
icon: "arrow.triangle.2.circlepath",
title: localize.settings.general.refresh.title(),
subtitle: localize.settings.general.refresh.desc(),
onClick: {
viewModel.actual.refreshAll()
}
)
}
}

private func payment() -> some View {
Section(header: Text(localize.settings.payment.title())) {
SettingsItem(
icon: "dollarsign.arrow.circlepath",
title: localize.settings.payment.skipMoneyBackDialog.title(),
subtitle: localize.settings.payment.skipMoneyBackDialog.desc(),
action: {
Toggle(
isOn: .init(
get: { viewModel.state.skipMoneyBackDialog },
set: { newValue in
let kotlinBool = KotlinBoolean(value: newValue)
viewModel.actual.toggleSkipMoneyBackDialog(value: kotlinBool, confirmed: false)
}
),
label: {}
).labelsHidden()
},
onClick: {
viewModel.actual.toggleSkipMoneyBackDialog(value: nil, confirmed: false)
}
)

SettingsItem(
icon: "checkmark.square",
title: localize.settings.payment.selectAllProductsByDefault.title(),
subtitle: localize.settings.payment.selectAllProductsByDefault.desc(),
action: {
Toggle(
isOn: .init(
get: { viewModel.state.paymentSelectAllProductsByDefault },
set: { newValue in
let kotlinBool = KotlinBoolean(value: newValue)
viewModel.actual.togglePaymentSelectAllProductsByDefault(value: kotlinBool)
}
),
label: {}
).labelsHidden()
},
onClick: {
viewModel.actual.togglePaymentSelectAllProductsByDefault(value: nil)
}
)
}
.withViewModel(viewModel, navigator)
}
}
18 changes: 14 additions & 4 deletions WaiterRobot/Ui/Settings/SwitchThemeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,22 @@ struct SwitchThemeView: View {
}

var body: some View {
Picker(localize.settings.darkMode.title(), selection: $selectedTheme) {
ForEach(AppTheme.companion.valueList(), id: \.name) { theme in
Text(theme.settingsText()).tag(theme)
HStack {
Image(systemName: "moon")
.symbolRenderingMode(.hierarchical)
.resizable()
.scaledToFit()
.frame(maxWidth: 25)
.padding(.trailing)
.foregroundColor(.blue)

Picker(localize.settings.general.darkMode.title(), selection: $selectedTheme) {
ForEach(AppTheme.companion.valueList(), id: \.name) { theme in
Text(theme.settingsText()).tag(theme)
}
}
.onChange(of: selectedTheme, perform: onChange)
}
.onChange(of: selectedTheme, perform: onChange)
}
}

Expand Down
2 changes: 1 addition & 1 deletion project.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ fileGroups:
packages:
shared:
url: https://github.com/DatepollSystems/WaiterRobot-Shared-Android.git
version: 1.6.4
version: 1.6.7
UIPilot:
url: https://github.com/canopas/UIPilot.git
from: 1.3.1
Expand Down
Loading