Skip to content

Commit

Permalink
Merge pull request #6 from khalid-asad/develop
Browse files Browse the repository at this point in the history
Improve UI
  • Loading branch information
khalid-asad authored May 13, 2021
2 parents dc9748e + 86eba89 commit ce17e10
Show file tree
Hide file tree
Showing 13 changed files with 194 additions and 87 deletions.
4 changes: 4 additions & 0 deletions CardReader.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */
19B45F61264B8A5C00B33163 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B45F60264B8A5C00B33163 /* Color+Extensions.swift */; };
19B45F69264B919400B33163 /* CreditCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B45F68264B919400B33163 /* CreditCardView.swift */; };
19B45F82264CCA3A00B33163 /* UIApplication+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19B45F81264CCA3A00B33163 /* UIApplication+Extensions.swift */; };
19DC60D02643524C00E29843 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DC60CF2643524C00E29843 /* AppDelegate.swift */; };
19DC60D22643524C00E29843 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DC60D12643524C00E29843 /* SceneDelegate.swift */; };
19DC60D92643524D00E29843 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19DC60D82643524D00E29843 /* Assets.xcassets */; };
Expand Down Expand Up @@ -42,6 +43,7 @@
/* Begin PBXFileReference section */
19B45F60264B8A5C00B33163 /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = "<group>"; };
19B45F68264B919400B33163 /* CreditCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditCardView.swift; sourceTree = "<group>"; };
19B45F81264CCA3A00B33163 /* UIApplication+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIApplication+Extensions.swift"; sourceTree = "<group>"; };
19DC60CC2643524C00E29843 /* CardReader.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CardReader.app; sourceTree = BUILT_PRODUCTS_DIR; };
19DC60CF2643524C00E29843 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
19DC60D12643524C00E29843 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -90,6 +92,7 @@
isa = PBXGroup;
children = (
19B45F60264B8A5C00B33163 /* Color+Extensions.swift */,
19B45F81264CCA3A00B33163 /* UIApplication+Extensions.swift */,
);
path = Extensions;
sourceTree = "<group>";
Expand Down Expand Up @@ -320,6 +323,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
19B45F82264CCA3A00B33163 /* UIApplication+Extensions.swift in Sources */,
19DC62A82644EAA600E29843 /* CardFormView.swift in Sources */,
19DC610B2643527200E29843 /* CardReaderView.swift in Sources */,
19DC60D02643524C00E29843 /* AppDelegate.swift in Sources */,
Expand Down
Binary file not shown.
16 changes: 16 additions & 0 deletions CardReader/Assets.xcassets/scan.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "scan-icon-15.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 8 additions & 1 deletion CardReader/Extensions/Color+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
import Foundation
import SwiftUI

public extension UIColor {

static var darkGrayColor: UIColor {
UIColor(red: 40.0/255.0, green: 40.0/255.0, blue: 40.0/255.0, alpha: 1.0)
}
}

public extension Color {

static var isDarkInterfaceStyle: Bool {
Expand All @@ -19,7 +26,7 @@ public extension Color {
}

static var backgroundColor: Color {
Color(UIColor { $0.userInterfaceStyle == .dark ? .darkGray : .white })
Color(UIColor { $0.userInterfaceStyle == .dark ? .darkGrayColor : .white })
}

static var grayColor: Color {
Expand Down
16 changes: 16 additions & 0 deletions CardReader/Extensions/UIApplication+Extensions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// UIApplication+Extensions.swift
// CardReader
//
// Created by Khalid Asad on 2021-05-12.
//

import Foundation
import UIKit

extension UIApplication {

func endEditing() {
sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
8 changes: 5 additions & 3 deletions CardReader/Models/CardDetails.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ import SwiftUI

public struct CardDetails: Hashable, Identifiable {
public var number: String?
public var expiryDate: String?
public var name: String?
public var expiryDate: String?
public var cvcNumber: String?
public var type: CardType
public var industry: CardIndustry

public init(numberWithDelimiters: String? = nil, expiryDate: String? = nil, name: String? = nil) {
public init(numberWithDelimiters: String? = nil, name: String? = nil, expiryDate: String? = nil, cvcNumber: String? = nil) {
self.number = numberWithDelimiters
self.expiryDate = expiryDate
self.name = name
self.expiryDate = expiryDate
self.cvcNumber = cvcNumber
self.type = CardType(number: numberWithDelimiters?.replacingOccurrences(of: " ", with: ""))
self.industry = .init(firstDigit: numberWithDelimiters?.first)
}
Expand Down
2 changes: 1 addition & 1 deletion CardReader/Models/ImageTextRecognizable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,6 @@ public extension ImageTextRecognizable {
CardType.allCases.map { $0.rawValue.uppercased() }
let name = recognizedText.filter({ !wordsToAvoid.contains($0) }).last

return CardDetails(numberWithDelimiters: creditCardNumber, expiryDate: expiryDate, name: name)
return CardDetails(numberWithDelimiters: creditCardNumber, name: name, expiryDate: expiryDate)
}
}
2 changes: 1 addition & 1 deletion CardReader/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: CardFormView())
window.rootViewController = UIHostingController(rootView: CardFormView(completion: { _ in }))
self.window = window
window.makeKeyAndVisible()
}
Expand Down
81 changes: 42 additions & 39 deletions CardReader/Views/CardForm/CardFormField.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ public struct CardFormField: View {
var isCreditCardNumber: Bool
var isExpiryDate: Bool

init(fieldTitle: String, text: Binding<String>, isSecure: Bool = false, autocapitalizationType: UITextAutocapitalizationType = .none, onEdit: (() -> Void)? = nil, isCreditCardNumber: Bool = false, isExpiryDate: Bool = false) {
init(
fieldTitle: String,
text: Binding<String>,
isSecure: Bool = false,
autocapitalizationType: UITextAutocapitalizationType = .none,
onEdit: (() -> Void)? = nil,
isCreditCardNumber: Bool = false,
isExpiryDate: Bool = false
) {
self.fieldTitle = fieldTitle
self._text = text
self.isSecure = isSecure
Expand All @@ -35,50 +43,45 @@ public struct CardFormField: View {
public var body: some View {
VStack(alignment: .leading) {
Text(fieldTitle)
.font(.system(size: 16))
.font(.system(size: 16, weight: .bold, design: .rounded))
.foregroundColor(isEditing ? .red : .primaryColor)

if isSecure {
SecureField("", text: $text, onCommit: { onEdit?() })
.font(.system(size: 20))
.foregroundColor(.black)
.autocapitalization(autocapitalizationType)
.disableAutocorrection(true)
.border(Color(UIColor.separator))
.padding(.all, 4)
.background(Color.grayColor)
.cornerRadius(5)
} else {
TextField(
"",
text: $text,
onEditingChanged: { isEditing in
self.isEditing = isEditing
if !isEditing { onEdit?() }
})
.font(.largeTitle)
.foregroundColor(.black)
.autocapitalization(autocapitalizationType)
.disableAutocorrection(true)
.padding(.all, 4)
.background(Color.grayColor)
.cornerRadius(5)
// .onReceive(Just(text), perform: { newValue in
// if isCreditCardNumber {
// if [3, 8, 13].contains(text.count) && [4, 9, 15].contains(newValue.count) {
// self.text = newValue + " "
// } else if [5, 0, 15].contains(newValue.count) && [6, 11, 16].contains(text.count) {
// self.text = String(newValue.dropLast(1))
Group {
if isSecure {
SecureField("", text: $text, onCommit: { onEdit?() })
} else {
TextField(
"",
text: $text,
onEditingChanged: { isEditing in
self.isEditing = isEditing
if !isEditing { onEdit?() }
}
)
// .onReceive(Just(text), perform: { newValue in
// if isCreditCardNumber {
// if [3, 8, 13].contains(text.count) && [4, 9, 15].contains(newValue.count) {
// self.text = newValue + " "
// } else if [5, 0, 15].contains(newValue.count) && [6, 11, 16].contains(text.count) {
// self.text = String(newValue.dropLast(1))
// } else {
// self.text = newValue
// }
// } else if isExpiryDate {
// self.text = newValue
// } else {
// self.text = newValue
// }
// } else if isExpiryDate {
// self.text = newValue
// } else {
// self.text = newValue
// }
// })
// })
}
}
.font(.system(size: 20, weight: .bold, design: .monospaced))
.foregroundColor(.black)
.autocapitalization(autocapitalizationType)
.disableAutocorrection(true)
.padding(.all, 6)
.background(Color.grayColor)
.cornerRadius(5)
}
}
}
Expand Down
108 changes: 81 additions & 27 deletions CardReader/Views/CardForm/CardFormView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,99 @@ public struct CardFormView: View {

@State private var isShowingSheet = false
@State private var cardNumber: String = ""
@State private var cardExpiryDate: String = ""
@State private var cardName: String = ""
@State private var cardExpiryDate: String = ""
@State private var cvcNumber: String = ""

public var completion: ((CardDetails) -> Void)

private var colors: [Color]
private var formattedCardNumber: String { cardNumber == "" ? "4111 2222 3333 4444" : cardNumber }
private var cardIndustry: CardIndustry { .init(firstDigit: formattedCardNumber.first) }

public init(colors: [Color] = [.green, .blue, .black], completion: @escaping ((CardDetails) -> Void )) {
self.colors = colors
self.completion = completion
}

public var body: some View {
ScrollView(.vertical) {
VStack {
CreditCardView(backgroundColors: [.blue, .black], cardNumber: $cardNumber, cardExpiryDate: $cardExpiryDate, cardName: $cardName)
CreditCardView(backgroundColors: colors, cardNumber: $cardNumber, cardExpiryDate: $cardExpiryDate, cardName: $cardName)
.shadow(color: .primaryColor, radius: 5)
.padding(.top, 30)

Spacer(minLength: 30)

.padding(.top, 60)

if cardIndustry != .unknown {
Text(cardIndustry.rawValue)
.font(.system(size: 14))
.foregroundColor(.primaryColor)
.padding(.top, 10)
}

VStack(alignment: .leading) {
CardFormField(fieldTitle: "Card Number", text: $cardNumber, isCreditCardNumber: true)
.keyboardType(.numberPad)

CardFormField(fieldTitle: "Card Expiry Date", text: $cardExpiryDate, isExpiryDate: true)
.keyboardType(.numberPad)

CardFormField(fieldTitle: "Card Name", text: $cardName, autocapitalizationType: .words)
.keyboardType(.alphabet)

Button {
isShowingSheet.toggle()
} label: {
Text("Scan card instead?")
.font(.title)
.fontWeight(.bold)
.multilineTextAlignment(.leading)
Button(action: {
isShowingSheet.toggle()
}) {
VStack(alignment: .center) {
Image("scan")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)

Text("Scan Card")
.font(.system(size: 26, weight: .bold, design: .monospaced))
}
.foregroundColor(.primaryColor)
.padding(.all, 12)
.overlay(RoundedRectangle(cornerRadius: 16).stroke(Color.primaryColor, lineWidth: 1))
}
.padding(.top, 30)

VStack(alignment: .center) {
VStack(alignment: .leading, spacing: 10) {
CardFormField(fieldTitle: "Card Number", text: $cardNumber, isCreditCardNumber: true)
.keyboardType(.numberPad)

CardFormField(fieldTitle: "Card Name", text: $cardName, autocapitalizationType: .words)
.keyboardType(.alphabet)

HStack(spacing: 20) {
CardFormField(fieldTitle: "Card Expiry Date", text: $cardExpiryDate, isExpiryDate: true)
.keyboardType(.numberPad)

CardFormField(fieldTitle: "CVC #", text: $cvcNumber)
.keyboardType(.numberPad)
}
}

Button(action: {
let cardInfo = CardDetails(
numberWithDelimiters: cardNumber,
name: cardName,
expiryDate: cardExpiryDate,
cvcNumber: cvcNumber
)
completion(cardInfo)
}) {
HStack(alignment: .center) {
Image(systemName: "bookmark.fill")
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)

Text("Save")
.font(.system(size: 26, weight: .bold, design: .monospaced))
}
.foregroundColor(Color.white)
.padding(.all, 12)
.background(colors.first)
.cornerRadius(16)
.overlay(RoundedRectangle(cornerRadius: 16).stroke(Color.primaryColor, lineWidth: 1))
}
.padding(.top, 20)
.padding(.top, 26)
}
.sheet(isPresented: $isShowingSheet) {
CardReaderView() { cardDetails in
print(cardDetails)
print(cardDetails ?? "")
cardNumber = cardDetails?.number ?? ""
cardExpiryDate = cardDetails?.expiryDate ?? ""
cardName = cardDetails?.name ?? ""
Expand All @@ -64,15 +113,20 @@ public struct CardFormView: View {
.edgesIgnoringSafeArea(.all)
}
.padding(.horizontal, 15)
.padding(.top, 50)
.padding(.top, 10)
}
}
.onTapGesture {
UIApplication.shared.endEditing()
}
.background(Color.backgroundColor)
.edgesIgnoringSafeArea(.all)
}
}

struct MainView_Previews: PreviewProvider {

static var previews: some View {
CardFormView()
CardFormView(completion: { _ in })
}
}
Loading

0 comments on commit ce17e10

Please sign in to comment.