Adding SwiftUI keyboard view

This commit is contained in:
Selim Mustafaev 2025-02-23 22:03:36 +03:00
parent 0c4b14debf
commit 363ab9e0a0
5 changed files with 223 additions and 0 deletions

View File

@ -64,6 +64,7 @@
7A4955822D58CCF900912E66 /* HistoryFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A4955812D58CCF900912E66 /* HistoryFilter.swift */; };
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */; };
7A54BFD32D43B95E00176D6D /* DbUpdatePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A54BFD22D43B95E00176D6D /* DbUpdatePolicy.swift */; };
7A589E0F2D6B6E8E00EF3FBE /* NumberEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */; };
7A5911EE2D63226F00EC51BA /* SearchScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911ED2D63226F00EC51BA /* SearchScreen.swift */; };
7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */; };
7A5911F22D63268400EC51BA /* SearchCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7A5911F12D63268400EC51BA /* SearchCoordinator.swift */; };
@ -150,6 +151,8 @@
7AABBE3B2CF9F85600346588 /* Binding+Map.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABBE3A2CF9F85600346588 /* Binding+Map.swift */; };
7AABDE26253350C30041AFC6 /* RxSectionedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */; };
7AB0EF812C5CC0FE00291EE6 /* SwiftLocationProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */; };
7AB490292D6B1217002F39C6 /* ACKeyboardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB490282D6B1217002F39C6 /* ACKeyboardView.swift */; };
7AB4902B2D6B1446002F39C6 /* ACKeyboardButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB4902A2D6B1446002F39C6 /* ACKeyboardButton.swift */; };
7AB4E42C2D397D8E0006D052 /* VehicleCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB4E42B2D397D8E0006D052 /* VehicleCellView.swift */; };
7AB4E4332D3C21C00006D052 /* FileManagerExt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB4E4322D3C21C00006D052 /* FileManagerExt.swift */; };
7AB4E4382D3D0C5C0006D052 /* VehiclesArchive.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB4E4372D3D0C5C0006D052 /* VehiclesArchive.swift */; };
@ -341,6 +344,7 @@
7A530B7D24017FEE00CBFE6E /* VehicleCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCell.swift; sourceTree = "<group>"; };
7A530B7F2401803A00CBFE6E /* Vehicle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Vehicle.swift; sourceTree = "<group>"; };
7A54BFD22D43B95E00176D6D /* DbUpdatePolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DbUpdatePolicy.swift; sourceTree = "<group>"; };
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumberEditView.swift; sourceTree = "<group>"; };
7A5911ED2D63226F00EC51BA /* SearchScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchScreen.swift; sourceTree = "<group>"; };
7A5911EF2D63266B00EC51BA /* SearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewModel.swift; sourceTree = "<group>"; };
7A5911F12D63268400EC51BA /* SearchCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchCoordinator.swift; sourceTree = "<group>"; };
@ -432,6 +436,8 @@
7AABDE25253350C30041AFC6 /* RxSectionedDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RxSectionedDataSource.swift; sourceTree = "<group>"; };
7AAE6AD224CDDF950023860B /* VehicleEvent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleEvent.swift; sourceTree = "<group>"; };
7AB0EF802C5CC0FE00291EE6 /* SwiftLocationProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftLocationProtocol.swift; sourceTree = "<group>"; };
7AB490282D6B1217002F39C6 /* ACKeyboardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACKeyboardView.swift; sourceTree = "<group>"; };
7AB4902A2D6B1446002F39C6 /* ACKeyboardButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ACKeyboardButton.swift; sourceTree = "<group>"; };
7AB4E42B2D397D8E0006D052 /* VehicleCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehicleCellView.swift; sourceTree = "<group>"; };
7AB4E4322D3C21C00006D052 /* FileManagerExt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileManagerExt.swift; sourceTree = "<group>"; };
7AB4E4372D3D0C5C0006D052 /* VehiclesArchive.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VehiclesArchive.swift; sourceTree = "<group>"; };
@ -1143,6 +1149,9 @@
7AB4E42B2D397D8E0006D052 /* VehicleCellView.swift */,
7A5912042D648A6000EC51BA /* AutoCancellable.swift */,
7AC8B2752D6A01C700190706 /* UISearchTextField+Dumb.swift */,
7AB490282D6B1217002F39C6 /* ACKeyboardView.swift */,
7AB4902A2D6B1446002F39C6 /* ACKeyboardButton.swift */,
7A589E0E2D6B6E8E00EF3FBE /* NumberEditView.swift */,
);
path = SwiftUI;
sourceTree = "<group>";
@ -1441,6 +1450,7 @@
7AB9FE2A2D08CF35005DE374 /* EventsScreenMode.swift in Sources */,
7A96AE2D246B2B7400297C33 /* GoogleSignInController.swift in Sources */,
7A10227B2C557EE900B84627 /* LocationPickerCoordinator.swift in Sources */,
7AB490292D6B1217002F39C6 /* ACKeyboardView.swift in Sources */,
7A1090EA24A3A26300B4F0B2 /* AudioPlayer.swift in Sources */,
7A11471623FDEB2A00B424AF /* MainSplitController.swift in Sources */,
7A6DD903242BF4A5009DE740 /* PlateView.swift in Sources */,
@ -1451,6 +1461,7 @@
7A530B7E24017FEE00CBFE6E /* VehicleCell.swift in Sources */,
7A1E78F82CE900440004B740 /* ReportViewModel.swift in Sources */,
7A10226E2C551EE000B84627 /* LocationEditViewModel.swift in Sources */,
7AB4902B2D6B1446002F39C6 /* ACKeyboardButton.swift in Sources */,
7AFBE8CE2C308B53003C491D /* ACMessageView.swift in Sources */,
7A14416C2C297F2100E79018 /* NotesCoordinator.swift in Sources */,
7A9FEEC82529AB23001CA50E /* RxRealmDataSource.swift in Sources */,
@ -1483,6 +1494,7 @@
7A5911F02D63266B00EC51BA /* SearchViewModel.swift in Sources */,
7A64AE752469DFB600ABE48E /* MediaBrowserViewController.swift in Sources */,
7ABD1B4B2D044A7D00B43213 /* GalleryCoordinator.swift in Sources */,
7A589E0F2D6B6E8E00EF3FBE /* NumberEditView.swift in Sources */,
7A64AE732469DFB600ABE48E /* DismissAnimationController.swift in Sources */,
7ADF6C97250F41B000F237B2 /* PNKeyboard.swift in Sources */,
7A1022702C551EFD00B84627 /* LocationEditCoordinator.swift in Sources */,

View File

@ -0,0 +1,81 @@
//
// ACKeyboardButton.swift
// AutoCat
//
// Created by Selim Mustafaev on 23.02.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct ACKeyboardButton: View {
let type: PNButtonType
let onTap: (PNButtonType) -> Void
init(type: PNButtonType, onTap: @escaping (PNButtonType) -> Void) {
self.type = type
self.onTap = onTap
}
var body: some View {
Button {
onTap(type)
} label: {
title
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center)
.foregroundColor(.primary)
.background {
RoundedRectangle(cornerRadius: 6)
.fill(backgroundColor)
.padding(4)
}
}
}
@ViewBuilder
var title: some View {
switch type {
case .symbol(let s):
Text(s)
.font(.custom("RoadNumbers", size: 36 - 2*sizeDelta))
.offset(y: sizeDelta/2)
case .backspace:
Image(systemName: "delete.left")
case .done:
Image(systemName: "arrow.turn.down.left")
}
}
var backgroundColor: Color {
switch type {
case .symbol: Color("KeyBackground")
case .backspace: Color("DarkKeyBackground")
case .done: .blue
}
}
var sizeDelta: CGFloat {
guard case let .symbol(title) = type else {
return 0
}
if let character = title.first {
return character.isNumber ? 3 : 0
} else {
return 0
}
}
}
#Preview {
HStack(spacing: 0) {
ACKeyboardButton(type: .symbol("A")) { _ in }
ACKeyboardButton(type: .symbol("1")) { _ in }
ACKeyboardButton(type: .backspace) { _ in }
ACKeyboardButton(type: .done) { _ in }
}
.frame(height: 50)
}

View File

@ -0,0 +1,68 @@
//
// ACKeyboardView.swift
// AutoCat
//
// Created by Selim Mustafaev on 23.02.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
struct ACKeyboardView: View {
let buttonPressed: (PNButtonType) -> Void
var body: some View {
HStack(spacing: 16) {
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
GridRow {
ACKeyboardButton(type: .symbol("A"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("B"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("E"), onTap: buttonPressed)
}
GridRow {
ACKeyboardButton(type: .symbol("K"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("M"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("H"), onTap: buttonPressed)
}
GridRow {
ACKeyboardButton(type: .symbol("O"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("P"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("C"), onTap: buttonPressed)
}
GridRow {
ACKeyboardButton(type: .symbol("T"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("Y"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("X"), onTap: buttonPressed)
}
}
Grid(horizontalSpacing: 0, verticalSpacing: 0) {
GridRow {
ACKeyboardButton(type: .symbol("1"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("2"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("3"), onTap: buttonPressed)
}
GridRow {
ACKeyboardButton(type: .symbol("4"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("5"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("6"), onTap: buttonPressed)
}
GridRow {
ACKeyboardButton(type: .symbol("7"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("8"), onTap: buttonPressed)
ACKeyboardButton(type: .symbol("9"), onTap: buttonPressed)
}
GridRow {
ACKeyboardButton(type: .symbol("0"), onTap: buttonPressed)
ACKeyboardButton(type: .backspace, onTap: buttonPressed)
ACKeyboardButton(type: .done, onTap: buttonPressed)
}
}
}
}
}
#Preview {
ACKeyboardView { _ in }
.frame(height: 240)
}

View File

@ -0,0 +1,60 @@
//
// NumberEditView.swift
// AutoCat
//
// Created by Selim Mustafaev on 23.02.2025.
// Copyright © 2025 Selim Mustafaev. All rights reserved.
//
import SwiftUI
import AutoCatCore
struct NumberEditView: View {
let onCheck: (String) -> Void
@State var number = PlateNumber("")
var body: some View {
VStack(spacing: 16) {
HStack(spacing: 16) {
LicensePlateView(number: number, foreground: .primary)
.layoutPriority(1)
.frame(height: 50)
Button {
} label: {
Text("Check")
.foregroundColor(.primary)
.padding(16)
.background {
RoundedRectangle(cornerRadius: 6)
.fill(.blue)
}
}
.layoutPriority(0)
.frame(height: 50)
}
ACKeyboardView(buttonPressed: buttonPressed)
.frame(height: 220)
}
.padding(16)
}
func buttonPressed(type: PNButtonType) {
switch type {
case .symbol(let s):
number.insertText(s)
case .backspace:
number.deleteBackward()
case .done:
onCheck(number.asString())
}
}
}
#Preview {
NumberEditView() { _ in }
}

View File

@ -44,6 +44,7 @@ public class PlateNumber {
}
// Returns true if number was changed
@discardableResult
public func insertText(_ text: String) -> Bool {
guard number.count < maxLength, text.count == 1 else {
return false
@ -61,6 +62,7 @@ public class PlateNumber {
return true
}
@discardableResult
public func deleteBackward() -> Bool {
guard !number.isEmpty else {
return false