ConstValue.swift
//
// ConstValue.swift
// BarcodeScanner
//
// Created by akira ohmachi on 2021/04/17.
//
import SwiftUI
class ConstValue: ObservableObject {
//background
static let colorBg: Color = Color.init(red: 241 / 255, green: 226 / 255, blue: 244 / 255)
//button color
/*
static let colorTitle: Color = Color.init(red: 61 / 255, green: 196 / 255, blue: 99 / 255)
static let colorScan: Color = Color.init(red: 101 / 255, green: 196 / 255, blue: 74 / 255)
static let colorContinuousScan: Color = Color.init(red: 138 / 255, green: 196 / 255, blue: 74 / 255)
static let colorShareAll: Color = Color.init(red: 172 / 255, green: 196 / 255, blue: 74 / 255)
static let colorClearAll: Color = Color.init(red: 196 / 255, green: 180 / 255, blue: 74 / 255)
static let colorShareLatest: Color = Color.init(red: 196 / 255, green: 164 / 255, blue: 74 / 255)
static let colorBrowserLatest: Color = Color.init(red: 196 / 255, green: 142 / 255, blue: 74 / 255)
static let colorClearLatest: Color = Color.init(red: 196 / 255, green: 117 / 255, blue: 74 / 255)
*/
static let colorTitle: Color = Color.init(red: 66 / 255, green: 46 / 255, blue: 195 / 255)
static let colorScan: Color = Color.init(red: 79 / 255, green: 46 / 255, blue: 195 / 255)
static let colorContinuousScan: Color = Color.init(red: 96 / 255, green: 46 / 255, blue: 195 / 255)
static let colorShareAll: Color = Color.init(red: 114 / 255, green: 46 / 255, blue: 195 / 255)
static let colorClearAll: Color = Color.init(red: 131 / 255, green: 47 / 255, blue: 195 / 255)
static let colorShareLatest: Color = Color.init(red: 151 / 255, green: 47 / 255, blue: 195 / 255)
static let colorBrowserLatest: Color = Color.init(red: 165 / 255, green: 47 / 255, blue: 195 / 255)
static let colorClearLatest: Color = Color.init(red: 180 / 255, green: 47 / 255, blue: 195 / 255)
}
ContentView.swift
//
// ContentView.swift
// BarcodeScanner
//
// Created by akira ohmachi on 2021/04/17.
//
import SwiftUI
import GoogleMobileAds
//import CodeScanner
//import MobileCoreServices //clipboard access
struct ContentView: View {
@EnvironmentObject var pub: PublicManager
@State private var destroyFlag: Bool = false
@State private var isShowingScanner: Bool = false //barcode
@State private var isShowingScannerContinuous: Bool = false //barcode
private let dateFormatter: DateFormatter = DateFormatter()
private let dateFormatString: String = "yyyyMMdd_HHmmss"
@State private var resultTextPadding: CGFloat = 5.0
@State private var isAlertClipboardAll: Bool = false
@State private var isShareAll: Bool = false
@State private var isAlertClearAll: Bool = false
@State private var isAlertClipboardLatest: Bool = false
@State private var isShareLatest: Bool = false
@State private var isAlertBrowserLatest: Bool = false
@State private var isAlertClearLatest: Bool = false
@State private var buttonHeightDiv1: CGFloat = 8
@State private var buttonHeightDiv2: CGFloat = 14
//
var body: some View {
NavigationView {
GeometryReader { bodyView in
ZStack(alignment: .bottom) {
ScrollView {
VStack(spacing: 0) {
VStack(spacing: 0) {
Text("title")
.padding(5)
.frame(width:bodyView.size.width, alignment: .center)
.background(ConstValue.colorTitle)
.foregroundColor(Color.white)
Rectangle().fill(Color.white).frame(width:bodyView.size.width, height:1)
}
VStack(spacing: 0) {
Button(action:{
self.isShowingScanner = true
}){
HStack {
Image(systemName: "camera.circle")
Text("scan")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv1, alignment: .center)
.background(ConstValue.colorScan)
.foregroundColor(Color.white)
}.sheet(isPresented: self.$isShowingScanner) {
CodeScannerView(codeTypes: [.qr,.aztec,.code128,.code39,.code39Mod43,.code93,.dataMatrix,.ean13,.ean8,.itf14,.pdf417,.upce], simulatedData: "https://www.aosystem.co.jp/", completion: self.handleScan)
}
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
VStack(spacing: 0) {
Button(action:{
self.isShowingScannerContinuous = true
}){
HStack {
Image(systemName: "camera.circle.fill")
Text("continuousScan")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv1, alignment: .center)
.background(ConstValue.colorContinuousScan)
.foregroundColor(Color.white)
}.sheet(isPresented: self.$isShowingScannerContinuous) {
CodeScannerView(codeTypes: [.qr,.aztec,.code128,.code39,.code39Mod43,.code93,.dataMatrix,.ean13,.ean8,.itf14,.pdf417,.upce], simulatedData: "https://www.aosystem.co.jp/", completion: self.handleScanContinuous)
}
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
/*
VStack(spacing: 0) {
Button(action:{
self.isAlertClipboardAll = true
}){
Text("clipboardAll")
.frame(width:bodyView.size.width, height: bodyView.size.height / 10, alignment: .center)
.background(ConstValue.colorSetting)
.foregroundColor(Color.white)
}.alert(isPresented: self.$isAlertClipboardAll, content: self.clipboardAll)
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
*/
VStack(spacing: 0) {
Button(action:{
self.isShareAll = true
}){
HStack {
Image(systemName: "square.and.arrow.up.fill")
Text("shareAll")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv2, alignment: .center)
.background(ConstValue.colorShareAll)
.foregroundColor(Color.white)
}.sheet(isPresented: self.$isShareAll) {
ActivityView(
activityItems: [self.pub.csv],
applicationActivities: nil
)
}
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
VStack(spacing: 0) {
Button(action:{
self.isAlertClearAll = true
}){
HStack {
Image(systemName: "clear.fill")
Text("clearAll")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv2, alignment: .center)
.background(ConstValue.colorClearAll)
.foregroundColor(Color.white)
}.alert(isPresented: self.$isAlertClearAll, content: self.clearAll)
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
/*
VStack(spacing: 0) {
Button(action:{
self.isAlertClipboardLatest = true
}){
Text("clipboardLatest")
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv2, alignment: .center)
.background(ConstValue.colorSetting)
.foregroundColor(Color.white)
}.alert(isPresented: self.$isAlertClipboardLatest, content: self.clipboardLatest)
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
*/
VStack(spacing: 0) {
Button(action:{
self.isShareLatest = true
}){
HStack {
Image(systemName: "square.and.arrow.up")
Text("shareLatest")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv2, alignment: .center)
.background(ConstValue.colorShareLatest)
.foregroundColor(Color.white)
}.sheet(isPresented: self.$isShareLatest) {
ActivityView(
activityItems: [self.latestResult()],
applicationActivities: nil
)
}
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
VStack(spacing: 0) {
Button(action:{
self.isAlertBrowserLatest = true
}){
HStack {
Image(systemName: "arrow.up.square")
Text("browserLatest")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv2, alignment: .center)
.background(ConstValue.colorBrowserLatest)
.foregroundColor(Color.white)
}.alert(isPresented: self.$isAlertBrowserLatest, content: self.browserLatest)
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
VStack(spacing: 0) {
Button(action:{
self.isAlertClearLatest = true
}){
HStack {
Image(systemName: "clear")
Text("clearLatest")
}
.frame(width:bodyView.size.width, height: bodyView.size.height / self.buttonHeightDiv2, alignment: .center)
.background(ConstValue.colorClearLatest)
.foregroundColor(Color.white)
}.alert(isPresented: self.$isAlertClearLatest, content: self.clearLatest)
Rectangle().fill(Color.white).frame(width: bodyView.size.width,height: 1)
}
VStack(spacing: 0) {
HStack {
Text(self.pub.csv)
.foregroundColor(Color.black)
.lineLimit(nil)
.padding(self.resultTextPadding)
Spacer()
}
.frame(width: bodyView.size.width)
.background(Color.white)
}
Spacer(minLength: 150)
}
}
HStack(spacing: 0) {
Spacer(minLength: 0)
PublicManager.AdView().frame(maxWidth: bodyView.size.width, maxHeight: 50)
Spacer(minLength: 0)
}.background(Color(red:0.2,green:0.2,blue:0.2))
}
.background(ConstValue.colorBg)
//.navigationBarTitle("")
.navigationBarHidden(true)
}
}
.navigationViewStyle(StackNavigationViewStyle())
.onAppear { //アプリ起動時に実行
self.dateFormatter.dateFormat = self.dateFormatString
}
.onDisappear { //アプリ終了時
self.destroyFlag = true
}
}
func handleScan(result: Result<String, CodeScannerView.ScanError>) {
self.isShowingScanner = false
switch result {
case .success(let code):
let dateStr: String = self.dateFormatter.string(from: Date())
self.pub.csv += "\"" + dateStr + "\",\"" + self.safetyCode(str: code) + "\"\n"
self.refreshResultText()
case .failure( _):
//print("Scanning failed")
break
}
}
func handleScanContinuous(result: Result<String, CodeScannerView.ScanError>) {
self.isShowingScannerContinuous = false
switch result {
case .success(let code):
let dateStr: String = self.dateFormatter.string(from: Date())
self.pub.csv += "\"" + dateStr + "\",\"" + self.safetyCode(str: code) + "\"\n"
self.refreshResultText()
self.nextScanContinuous()
case .failure( _):
//print("Scanning failed")
break
}
}
private func safetyCode(str: String) -> String {
let str1: String = str.replacingOccurrences(of: "\n", with: "\\n")
let str2: String = str1.replacingOccurrences(of: "\"", with: "\\\"")
return str2
}
private func nextScanContinuous() {
withAnimation {
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 1.0)
DispatchQueue.main.sync {
if self.destroyFlag == false {
self.isShowingScannerContinuous = true
}
}
}
}
}
//リフレッシュされないのでこの処理を入れてリフレッシュさせる
private func refreshResultText() {
let tmpResultTextPadding: CGFloat = self.resultTextPadding
self.resultTextPadding = 0
withAnimation {
DispatchQueue.global().async {
Thread.sleep(forTimeInterval: 0.1)
DispatchQueue.main.sync {
if self.destroyFlag == false {
self.resultTextPadding = tmpResultTextPadding
}
}
}
}
}
/*
private func clipboardAll() -> Alert {
return Alert(title: Text("clipboardAll"),
message: Text("clipboardAll1"),
primaryButton: .cancel(Text("cancel")),
secondaryButton: .destructive(
Text("copy"),
action: {
UIPasteboard.general.setValue(self.pub.csv, forPasteboardType: kUTTypePlainText as String)
}
)
)
}
*/
private func clearAll() -> Alert {
return Alert(title: Text("clearAll"),
message: Text("clearAll1"),
primaryButton: .cancel(Text("cancel")),
secondaryButton: .destructive(
Text("clear"),
action: {
self.pub.csv = ""
self.refreshResultText()
}
)
)
}
/*
private func clipboardLatest() -> Alert {
let resultStr: String = self.latestResult()
return Alert(title: Text("clipboardLatest"),
message: Text(resultStr),
primaryButton: .cancel(Text("cancel")),
secondaryButton: .destructive(
Text("copy"),
action: {
UIPasteboard.general.setValue(resultStr, forPasteboardType: kUTTypePlainText as String)
}
)
)
}
*/
private func browserLatest() -> Alert {
let resultStr: String = self.latestResult()
return Alert(title: Text("browserLatest"),
message: Text(resultStr),
primaryButton: .cancel(Text("cancel")),
secondaryButton: .destructive(
Text("send"),
action: {
if resultStr != "" {
if let url = URL(string: resultStr) {
UIApplication.shared.open(url)
}
}
}
)
)
}
private func clearLatest() -> Alert {
let resultStr: String = self.latestResult()
return Alert(title: Text("clearLatest"),
message: Text(resultStr),
primaryButton: .cancel(Text("cancel")),
secondaryButton: .destructive(
Text("clear"),
action: {
self.pub.csv = self.exceptlatestCsv()
self.refreshResultText()
}
)
)
}
private func latestResult() -> String {
if self.pub.csv == "" {
return ""
}
let ary1: Array<Substring> = (self.pub.csv).split(separator: "\n")
if ary1.count == 0 {
return ""
}
let ary2: Array<Substring> = ary1[ary1.count - 1].split(separator: ",")
var str1: Substring = ""
for i in 1 ..< ary2.count { //文字列の中にカンマが含まれている場合があるので最後まで繋げる
str1 += ary2[i]
}
if str1.count < 2 { //2文字より少ない場合は不正
return ""
}
let str2: Substring = str1.suffix(str1.count - 1) //先頭文字を削除"\""
let str3: Substring = str2.prefix(str2.count - 1) //後尾文字を削除"\""
return String(str3)
}
private func exceptlatestCsv() -> String {
if self.pub.csv == "" {
return ""
}
let ary1: Array<Substring> = (self.pub.csv).split(separator: "\n")
if ary1.count == 0 {
return ""
}
var resultCsv: String = ""
for i in 0 ..< (ary1.count - 1) {
resultCsv += ary1[i] + "\n"
}
return String(resultCsv)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView().environmentObject(PublicManager())
}
}
}
struct ActivityView: UIViewControllerRepresentable {
let activityItems: [Any]
let applicationActivities: [UIActivity]?
func makeUIViewController(context: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
return UIActivityViewController(
activityItems: activityItems,
applicationActivities: applicationActivities
)
}
func updateUIViewController(
_ uiViewController: UIActivityViewController,
context: UIViewControllerRepresentableContext<ActivityView>
) {
// Nothing to do
}
}