diff --git a/WaiterRobot/Core/Mvi/KotlinArrayWrapper.swift b/WaiterRobot/Core/Mvi/KotlinArrayWrapper.swift index d977d68..3f481c8 100644 --- a/WaiterRobot/Core/Mvi/KotlinArrayWrapper.swift +++ b/WaiterRobot/Core/Mvi/KotlinArrayWrapper.swift @@ -1,37 +1,47 @@ import Foundation import shared -@objc public class KotlinIteratorImpl: NSObject, KotlinIterator, IteratorProtocol { - public typealias Element = KotlinInt - - var iterator: KotlinIterator - - init(iterator: KotlinIterator) { - self.iterator = iterator - } - - public func next() -> Any? { - if hasNext() { - iterator.next() - } else { nil } - } - - public func next() -> KotlinInt? { - if hasNext() { - (iterator.next() as! KotlinInt?) - } else { nil } - } - - public func hasNext() -> Bool { - iterator.hasNext() - } -} - -extension KotlinArray: Sequence { - @objc public func makeIterator() -> KotlinIteratorImpl { - KotlinIteratorImpl(iterator: iterator()) - } -} +// public class KotlinIteratorImpl: NSObject, KotlinIterator, IteratorProtocol { +// public typealias Element = T +// +// var iterator: KotlinIterator +// +// init(iterator: KotlinIterator) { +// self.iterator = iterator +// } +// +// public func next() -> Any? { +// if hasNext() { +// iterator.next() +// } else { +// nil +// } +// } +// +// public func next() -> T? { +// if hasNext() { +// (iterator.next() as! T?) +// } else { +// nil +// } +// } +// +// public func hasNext() -> Bool { +// iterator.hasNext() +// } +// } + +// extension KotlinArray where T: AnyObject { +// var array: Array { +// Array(self) +// } +// } + +// extension KotlinArray: Sequence { +// @objc public func makeIterator() -> KotlinIteratorImpl { +// KotlinIteratorImpl(iterator: iterator()) +// } +// } extension Array where Element: AnyObject { init(_ kotlinArray: KotlinArray) { diff --git a/WaiterRobot/MainView.swift b/WaiterRobot/MainView.swift index f5e9664..3eec142 100644 --- a/WaiterRobot/MainView.swift +++ b/WaiterRobot/MainView.swift @@ -40,7 +40,7 @@ struct MainView: View { case let screen as Screen.OrderScreen: OrderScreen(table: screen.table, initialItemId: screen.initialItemId) case let screen as Screen.BillingScreen: BillingScreen(table: screen.table) default: - Text("No view defined for \(route.description)") // TODO: + Text("No view defined for \(route.description)") // TODO: fix Button { navigator.pop() } label: { diff --git a/WaiterRobot/Ui/Billing/PayDialog.swift b/WaiterRobot/Ui/Billing/PayDialog.swift index e7a0518..d9da588 100644 --- a/WaiterRobot/Ui/Billing/PayDialog.swift +++ b/WaiterRobot/Ui/Billing/PayDialog.swift @@ -14,7 +14,8 @@ struct PayDialog: View { return } - isInputInvalid = viewModel.state.changeText == "NaN" || viewModel.state.changeText.hasPrefix("-") || regex.firstMatch(in: moneyGiven, options: [], range: range) == nil + // TODO: fix +// isInputInvalid = viewModel.state.change == "NaN" || viewModel.state.changeText.hasPrefix("-") || regex.firstMatch(in: moneyGiven, options: [], range: range) == nil } } @@ -47,8 +48,11 @@ struct PayDialog: View { Text(localize.billing.change() + ":") .font(.title2) Spacer() - Text(viewModel.state.changeText) - .font(.title2) + + if let change = viewModel.state.change?.amount { + Text(change.description()) // TODO: check if correct + .font(.title2) + } } Spacer() diff --git a/WaiterRobot/Ui/Core/ScreenContainer.swift b/WaiterRobot/Ui/Core/ScreenContainer.swift index 3982f6b..195ee17 100644 --- a/WaiterRobot/Ui/Core/ScreenContainer.swift +++ b/WaiterRobot/Ui/Core/ScreenContainer.swift @@ -11,6 +11,7 @@ struct ScreenContainer: View { } var body: some View { + // onEnum(of: ) switch state.viewState { case is ViewState.Loading: ProgressView() diff --git a/WaiterRobot/Ui/Login/LoginScannerScreen.swift b/WaiterRobot/Ui/Login/LoginScannerScreen.swift index fe43a90..c4a0861 100644 --- a/WaiterRobot/Ui/Login/LoginScannerScreen.swift +++ b/WaiterRobot/Ui/Login/LoginScannerScreen.swift @@ -8,7 +8,7 @@ struct LoginScannerScreen: View { @StateObject private var viewModel = ObservableLoginScannerViewModel() - private let simulatedData = "https://lava.kellner.team/ml/signIn?token=w7wF6pgYA6Ssm3VBH-rSFL6if70&purpose=SIGN_IN" + private let simulatedData = "https://lava.kellner.team/ml/signIn?purpose=SIGN_IN&token=xWEP33DuYhJzUvQ6clywKPCM_Oa5NymihpJk4-_EGHV3D_f10YSKL_2hOYV3" var body: some View { ScreenContainer(viewModel.state) { diff --git a/WaiterRobot/Ui/Order/ProductListItem.swift b/WaiterRobot/Ui/Order/ProductListItem.swift index d4ad357..85fbbaa 100644 --- a/WaiterRobot/Ui/Order/ProductListItem.swift +++ b/WaiterRobot/Ui/Order/ProductListItem.swift @@ -12,7 +12,7 @@ struct ProductListItem: View { self.onClick = onClick var allergens = "" - self.product.allergens.forEach { allergen in + for allergen in self.product.allergens { allergens += "\(allergen.shortName), " } diff --git a/WaiterRobot/Ui/Order/Search/ProductSearch.swift b/WaiterRobot/Ui/Order/Search/ProductSearch.swift index e2312fa..81ffb98 100644 --- a/WaiterRobot/Ui/Order/Search/ProductSearch.swift +++ b/WaiterRobot/Ui/Order/Search/ProductSearch.swift @@ -15,59 +15,83 @@ struct ProductSearch: View { var body: some View { NavigationView { - if viewModel.state.productGroups.isEmpty { - Text(localize.productSearch.noProductFound()) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .padding() - } else { - VStack { - ProducSearchTabBarHeader(currentTab: $selectedTab, tabBarOptions: getGroupNames(viewModel.state.productGroups)) + switch onEnum(of: viewModel.state.productGroups) { + case let .loading(resource): + ProgressView() + case let .error(resource): + productGroupsError() + case let .success(resource): + if let productGroups = resource.data { + productsGroupsList(productGroups: productGroups) + } else { + productGroupsError() + } + } + } + } - TabView(selection: $selectedTab) { - ProductSearchAllTab( - productGroups: viewModel.state.productGroups, - columns: layout, - onProductClick: { - viewModel.actual.addItem(product: $0, amount: 1) - dismiss() - } - ) - .tag(0) - .padding() + @ViewBuilder + private func productsGroupsList(productGroups: KotlinArray) -> some View { + let productGroups = Array(productGroups) + + if productGroups.isEmpty { + Text(localize.productSearch.noProductFound()) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity) + .padding() - ForEach(Array(viewModel.state.productGroups.enumerated()), id: \.element.id) { index, groupWithProducts in - ScrollView { - LazyVGrid(columns: layout, spacing: 0) { - ProductSearchGroupList( - products: groupWithProducts.products, - onProductClick: { - viewModel.actual.addItem(product: $0, amount: 1) - dismiss() - } - ) - Spacer() - } - .padding() + } else { + VStack { + ProducSearchTabBarHeader(currentTab: $selectedTab, tabBarOptions: getGroupNames(productGroups)) + + TabView(selection: $selectedTab) { + ProductSearchAllTab( + productGroups: productGroups, + columns: layout, + onProductClick: { + viewModel.actual.addItem(product: $0, amount: 1) + dismiss() + } + ) + .tag(0) + .padding() + + let enumeratedProductGroups = Array(productGroups.enumerated()) + ForEach(enumeratedProductGroups, id: \.element.id) { index, groupWithProducts in + ScrollView { + LazyVGrid(columns: layout, spacing: 0) { + ProductSearchGroupList( + products: groupWithProducts.products, + onProductClick: { + viewModel.actual.addItem(product: $0, amount: 1) + dismiss() + } + ) + Spacer() } - .tag(index + 1) + .padding() } + .tag(index + 1) } } - .tabViewStyle(.page(indexDisplayMode: .never)) - .searchable(text: $search, placement: .navigationBarDrawer(displayMode: .always)) - .onChange(of: search, perform: { viewModel.actual.filterProducts(filter: $0) }) - .toolbar { - ToolbarItem(placement: .navigationBarLeading) { - Button(localize.dialog.cancel()) { - dismiss() - } + } + .tabViewStyle(.page(indexDisplayMode: .never)) + .searchable(text: $search, placement: .navigationBarDrawer(displayMode: .always)) + .onChange(of: search, perform: { viewModel.actual.filterProducts(filter: $0) }) + .toolbar { + ToolbarItem(placement: .navigationBarLeading) { + Button(localize.dialog.cancel()) { + dismiss() } } } } } + private func productGroupsError() -> some View { + Text("Something went wrong") // TODO: fix + } + private func getGroupNames(_ productGroups: [ProductGroup]) -> [String] { var groupNames = productGroups.map { productGroup in productGroup.name diff --git a/WaiterRobot/Ui/TableDetail/TableDetailScreen.swift b/WaiterRobot/Ui/TableDetail/TableDetailScreen.swift index d0517dc..9d5d724 100644 --- a/WaiterRobot/Ui/TableDetail/TableDetailScreen.swift +++ b/WaiterRobot/Ui/TableDetail/TableDetailScreen.swift @@ -10,49 +10,74 @@ struct TableDetailScreen: View { init(table: shared.Table) { self.table = table - _viewModel = StateObject(wrappedValue: ObservableTableDetailViewModel(table: table)) + _viewModel = StateObject( + wrappedValue: ObservableTableDetailViewModel(table: table) + ) } var body: some View { - let resource = onEnum(of: viewModel.state.orderedItemsResource) - let orderedItems = viewModel.state.orderedItemsResource.data as? [OrderedItem] + content() + .navigationTitle(localize.tableDetail.title(value0: table.number.description, value1: table.groupName)) + .handleSideEffects(of: viewModel, navigator) + } + private func content() -> some View { // TODO: add refreshing and loading indicator (also check android) ZStack { - VStack { - if case let .error(value) = resource { - Text(value.exception.getLocalizedUserMessage()) - } - if orderedItems?.isEmpty == true { - Text(localize.tableDetail.noOrder(value0: table.number.description, value1: table.groupName)) - .multilineTextAlignment(.center) - .frame(maxWidth: .infinity) - .padding() - } else if let orderedItems { - List { - ForEach(orderedItems, id: \.id) { item in - OrderedItemView(item: item) { - viewModel.actual.openOrderScreen(initialItemId: item.id.toKotlinLong()) - } - } - } - } - } + tableDetails() EmbeddedFloatingActionButton(icon: "plus") { viewModel.actual.openOrderScreen(initialItemId: nil) } } - .navigationTitle(localize.tableDetail.title(value0: table.number.description, value1: table.groupName)) - .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { - Button { - viewModel.actual.openBillingScreen() - } label: { - Image(systemName: "creditcard") - }.disabled(orderedItems?.isEmpty != false) + } + + func tableDetails() -> some View { + VStack { + switch onEnum(of: viewModel.state.orderedItemsResource) { + case let .loading(resource): + ProgressView() + + case let .error(error): + tableDetailsError(error) + + case let .success(resource): + // TODO: we need KotlinArray here in shared + if let orderedItems = resource.data as? [OrderedItem] { + VStack { + if orderedItems.isEmpty { + Text(localize.tableDetail.noOrder(value0: table.number.description, value1: table.groupName)) + .multilineTextAlignment(.center) + .frame(maxWidth: .infinity) + .padding() + } else { + List { + ForEach(orderedItems, id: \.id) { item in + OrderedItemView(item: item) { + viewModel.actual.openOrderScreen(initialItemId: item.id.toKotlinLong()) + } + } + } + } + } + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button { + viewModel.actual.openBillingScreen() + } label: { + Image(systemName: "creditcard") + } + .disabled(orderedItems.isEmpty) + } + } + } else { + Text("Something went wrong") + } } } - .handleSideEffects(of: viewModel, navigator) + } + + func tableDetailsError(_ error: ResourceError) -> some View { + Text(error.userMessage) } } diff --git a/WaiterRobot/Ui/TableList/TableListFilterRow.swift b/WaiterRobot/Ui/TableList/TableListFilterRow.swift index 8dbe893..d779865 100644 --- a/WaiterRobot/Ui/TableList/TableListFilterRow.swift +++ b/WaiterRobot/Ui/TableList/TableListFilterRow.swift @@ -35,7 +35,6 @@ struct TableListFilterRow: View { Image(systemName: "checkmark") } .padding(.trailing) - .disabled(tableGroups.allSatisfy { !$0.hidden }) } } diff --git a/WaiterRobot/Ui/TableList/TableListScreen.swift b/WaiterRobot/Ui/TableList/TableListScreen.swift index a633cd5..a952c48 100644 --- a/WaiterRobot/Ui/TableList/TableListScreen.swift +++ b/WaiterRobot/Ui/TableList/TableListScreen.swift @@ -40,7 +40,7 @@ struct TableListScreen: View { Spacer() HStack { - Text("Test me") + Text(resource.userMessage) .padding() Spacer() diff --git a/project.yml b/project.yml index 0421331..05b5018 100644 --- a/project.yml +++ b/project.yml @@ -15,7 +15,7 @@ fileGroups: packages: shared: url: https://github.com/DatepollSystems/WaiterRobot-Shared-Android.git - version: "1.3.1" + version: 1.4.1 UIPilot: url: https://github.com/canopas/UIPilot.git from: 1.3.1