copy/paste events
@ -847,7 +847,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
CURRENT_PROJECT_VERSION = 67;
|
||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
@ -870,7 +870,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = AutoCat/AutoCat.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 66;
|
||||
CURRENT_PROJECT_VERSION = 67;
|
||||
DEVELOPMENT_TEAM = 46DTTB8X4S;
|
||||
INFOPLIST_FILE = AutoCat/Info.plist;
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
|
||||
|
||||
@ -1,109 +1,109 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "wheel-40.png",
|
||||
"filename" : "wheel2-40.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-60.png",
|
||||
"filename" : "wheel2-60.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-58.png",
|
||||
"filename" : "wheel2-58.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-87.png",
|
||||
"filename" : "wheel2-87.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-80.png",
|
||||
"filename" : "wheel2-80.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-120.png",
|
||||
"filename" : "wheel2-120.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-121.png",
|
||||
"filename" : "wheel2-121.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "2x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-180.png",
|
||||
"filename" : "wheel2-180.png",
|
||||
"idiom" : "iphone",
|
||||
"scale" : "3x",
|
||||
"size" : "60x60"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-20.png",
|
||||
"filename" : "wheel2-20.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-41.png",
|
||||
"filename" : "wheel2-41.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "20x20"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-29.png",
|
||||
"filename" : "wheel2-29.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-59.png",
|
||||
"filename" : "wheel2-59.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "29x29"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-42.png",
|
||||
"filename" : "wheel2-42.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-81.png",
|
||||
"filename" : "wheel2-81.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "40x40"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-76.png",
|
||||
"filename" : "wheel2-76.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "1x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-152.png",
|
||||
"filename" : "wheel2-152.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "76x76"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-167.png",
|
||||
"filename" : "wheel2-167.png",
|
||||
"idiom" : "ipad",
|
||||
"scale" : "2x",
|
||||
"size" : "83.5x83.5"
|
||||
},
|
||||
{
|
||||
"filename" : "wheel-1024.png",
|
||||
"filename" : "wheel2-1024.png",
|
||||
"idiom" : "ios-marketing",
|
||||
"scale" : "1x",
|
||||
"size" : "1024x1024"
|
||||
|
||||
|
Before Width: | Height: | Size: 109 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 9.1 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 878 B |
|
Before Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 4.5 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-1024.png
Normal file
|
After Width: | Height: | Size: 103 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-120.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-121.png
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-152.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-167.png
Normal file
|
After Width: | Height: | Size: 9.9 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-180.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-20.png
Normal file
|
After Width: | Height: | Size: 886 B |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-29.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-40.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-41.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-42.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-58.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-59.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-60.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-76.png
Normal file
|
After Width: | Height: | Size: 4.0 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-80.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-81.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
AutoCat/Assets.xcassets/AppIcon.appiconset/wheel2-87.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
@ -4,6 +4,7 @@ import RxSwift
|
||||
import Realm
|
||||
import RealmSwift
|
||||
import PKHUD
|
||||
import MobileCoreServices
|
||||
|
||||
class EventPin: NSObject, MKAnnotation {
|
||||
var coordinate: CLLocationCoordinate2D
|
||||
@ -46,6 +47,7 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
let bag = DisposeBag()
|
||||
var modeButton: UIBarButtonItem!
|
||||
var addButton: UIBarButtonItem!
|
||||
var pasteButton: UIBarButtonItem!
|
||||
var mode: EventsMode = .map
|
||||
|
||||
public var vehicle: Vehicle? {
|
||||
@ -69,12 +71,18 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
|
||||
self.modeButton = UIBarButtonItem(image: UIImage(systemName: "list.bullet"), style: .plain, target: self, action: #selector(switchMode(_:)))
|
||||
self.addButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(addEvent(_:)))
|
||||
self.navigationItem.rightBarButtonItems = [self.modeButton, self.addButton]
|
||||
self.pasteButton = UIBarButtonItem(image: UIImage(systemName: "doc.on.clipboard"), style: .plain, target: self, action: #selector(pasteEvent(_:)))
|
||||
self.setupBarButtonItems()
|
||||
self.map.delegate = self
|
||||
|
||||
self.updateInterface()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
self.setupBarButtonItems()
|
||||
}
|
||||
|
||||
func updateInterface() {
|
||||
if let vehicle = self.vehicle {
|
||||
self.pins = vehicle.events.map(EventPin.init(event:))
|
||||
@ -129,6 +137,14 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
|
||||
func tableView(_ tableView: UITableView, contextMenuConfigurationForRowAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? {
|
||||
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { _ in
|
||||
let copy = UIAction(title: NSLocalizedString("Copy", comment: ""), image: UIImage(systemName: "doc.on.doc")) { action in
|
||||
self.copyEvent(index: indexPath.row)
|
||||
}
|
||||
|
||||
let share = UIAction(title: NSLocalizedString("Share", comment: ""), image: UIImage(systemName: "square.and.arrow.up")) { action in
|
||||
self.shareEvent(index: indexPath.row)
|
||||
}
|
||||
|
||||
let edit = UIAction(title: NSLocalizedString("Edit", comment: ""), image: UIImage(systemName: "pencil")) { action in
|
||||
self.editEvent(index: indexPath.row)
|
||||
}
|
||||
@ -137,11 +153,18 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
self.deleteEvent(index: indexPath.row)
|
||||
}
|
||||
|
||||
return UIMenu(title: NSLocalizedString("Actions", comment: ""), children: [edit, delete])
|
||||
return UIMenu(title: NSLocalizedString("Actions", comment: ""), children: [copy, share, edit, delete])
|
||||
}
|
||||
}
|
||||
|
||||
func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
|
||||
let copy = UIContextualAction(style: .normal, title: NSLocalizedString("Copy", comment: "")) { action, view, completion in
|
||||
self.copyEvent(index: indexPath.row)
|
||||
completion(true)
|
||||
}
|
||||
copy.image = UIImage(systemName: "doc.on.doc")
|
||||
copy.backgroundColor = .systemBlue
|
||||
|
||||
let delete = UIContextualAction(style: .destructive, title: NSLocalizedString("Delete", comment: "")) { action, view, completion in
|
||||
self.deleteEvent(index: indexPath.row, completion: completion)
|
||||
}
|
||||
@ -154,7 +177,7 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
edit.image = UIImage(systemName: "pencil")
|
||||
edit.backgroundColor = .systemBlue
|
||||
|
||||
let configuration = UISwipeActionsConfiguration(actions: [delete, edit])
|
||||
let configuration = UISwipeActionsConfiguration(actions: [delete, edit, copy])
|
||||
configuration.performsFirstActionWithFullSwipe = false
|
||||
return configuration
|
||||
}
|
||||
@ -210,6 +233,45 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
self.navigationController?.pushViewController(controller, animated: true)
|
||||
}
|
||||
|
||||
func copyEvent(index: Int) {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
return
|
||||
}
|
||||
|
||||
var items: [String: Any] = [:]
|
||||
let event = vehicle.events[index]
|
||||
|
||||
if let url = event.getMapLink() {
|
||||
items[kUTTypeURL as String] = url
|
||||
//UIPasteboard.general.setValue(url, forPasteboardType: kUTTypeURL as String)
|
||||
}
|
||||
|
||||
if let data = try? JSONEncoder().encode(event) {
|
||||
items["pro.aliencat.vehicle.event"] = data
|
||||
//UIPasteboard.general.setData(data, forPasteboardType: "pro.aliencat.vehicle.event")
|
||||
}
|
||||
|
||||
if !items.isEmpty {
|
||||
UIPasteboard.general.items = [items]
|
||||
}
|
||||
|
||||
self.setupBarButtonItems()
|
||||
}
|
||||
|
||||
func shareEvent(index: Int) {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
return
|
||||
}
|
||||
|
||||
let event = vehicle.events[index]
|
||||
if let url = event.getMapLink() {
|
||||
let controller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
|
||||
self.present(controller, animated: true)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func addEvent(_ sender: UIBarButtonItem) {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
@ -234,6 +296,44 @@ class EventsController: UIViewController, UITableViewDataSource, UITableViewDele
|
||||
self.navigationController?.pushViewController(controller, animated: true)
|
||||
}
|
||||
|
||||
@objc func pasteEvent(_ sender: UIBarButtonItem) {
|
||||
guard let vehicle = self.vehicle else {
|
||||
HUD.flash(.labeledError(title: nil, subtitle: "Unknown vehicle"))
|
||||
return
|
||||
}
|
||||
guard let data = UIPasteboard.general.data(forPasteboardType: "pro.aliencat.vehicle.event") else { return }
|
||||
|
||||
do {
|
||||
let event = try JSONDecoder().decode(VehicleEvent.self, from: data)
|
||||
let formatter = DateFormatter()
|
||||
formatter.dateStyle = .medium
|
||||
formatter.timeStyle = .medium
|
||||
let msg = formatter.string(from: Date(timeIntervalSince1970: event.date)) + "\n" + event.getLocationString()
|
||||
|
||||
let alert = UIAlertController(title: NSLocalizedString("Paste event", comment: "from clipboard"), message: msg, preferredStyle: .alert)
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Paste", comment: "from clipboard"), style: .default, handler: { action in
|
||||
HUD.show(.progress)
|
||||
event.id = UUID().uuidString
|
||||
Api.add(event: event, to: vehicle.getNumber())
|
||||
.observeOn(MainScheduler.instance)
|
||||
.subscribe(onSuccess: { self.update(vehicle: $0) }, onError:
|
||||
{ error in
|
||||
HUD.show(error: error)
|
||||
})
|
||||
.disposed(by: self.bag)
|
||||
}))
|
||||
alert.addAction(UIAlertAction(title: NSLocalizedString("Cancel", comment: ""), style: .cancel, handler: nil))
|
||||
self.present(alert, animated: true)
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
func setupBarButtonItems() {
|
||||
let pasteVisible = UIPasteboard.general.data(forPasteboardType: "pro.aliencat.vehicle.event") != nil
|
||||
self.navigationItem.rightBarButtonItems = pasteVisible ? [self.modeButton, self.addButton, self.pasteButton] : [self.modeButton, self.addButton]
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func update(vehicle: Vehicle) -> Bool {
|
||||
do {
|
||||
|
||||
@ -48,6 +48,23 @@ class VehicleEvent: Object, Codable, Cloneable {
|
||||
return ["plateNumber"]
|
||||
}
|
||||
|
||||
func getMapLink() -> URL? {
|
||||
var urlString = "http://maps.apple.com/?sll=\(self.latitude),\(self.longitude)"
|
||||
if let address = self.address?.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
|
||||
urlString = urlString + "&address=" + address
|
||||
}
|
||||
return URL(string: urlString)
|
||||
}
|
||||
|
||||
func getLocationString() -> String {
|
||||
let coordinates = "Lat: \(self.latitude), Lon: \(self.longitude)"
|
||||
if let addressString = self.address {
|
||||
return "\(addressString) (\(coordinates)"
|
||||
} else {
|
||||
return coordinates
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Cloneable
|
||||
|
||||
required init(copy: VehicleEvent) {
|
||||
|
||||
@ -3,9 +3,9 @@ import Foundation
|
||||
enum Constants {
|
||||
static var baseUrl: String {
|
||||
#if DEBUG
|
||||
return "http://127.0.0.1:3000/"
|
||||
//return "http://127.0.0.1:3000/"
|
||||
//return "http://192.168.1.67:3000/"
|
||||
//return "https://vps.aliencat.pro:8443/"
|
||||
return "https://vps.aliencat.pro:8443/"
|
||||
#else
|
||||
return "https://vps.aliencat.pro:8443/"
|
||||
#endif
|
||||
|
||||
@ -91,6 +91,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Contract series and number" = "Серия и номер договора";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Copy" = "Копировать";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Copy to pasteboard" = "Копировать в буфер обмена";
|
||||
|
||||
@ -238,6 +241,12 @@
|
||||
/* No comment provided by engineer. */
|
||||
"Owners" = "Владельцы";
|
||||
|
||||
/* from clipboard */
|
||||
"Paste" = "Вставить";
|
||||
|
||||
/* from clipboard */
|
||||
"Paste event" = "Вставить событие";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"Photos" = "Фотографии";
|
||||
|
||||
|
||||