Log list of available printers and their URLs - swift

I am attempting to set up a UIPrinter instance so that my iPad app can print directly to that printer without having to present the print controller dialogue. The problem I'm having is that I can't seem to find the URL of this printer. It is connected via AirPrint.
Visiting http://localhost:631/printers/ does show the printer, but it shows the USB version of the printer's URL (i.e. usb://Brother/QL-710W?serial=12345).
What I am wondering is, how can I print (to the debug output) a list of my available printers, and their URLs? I figure by doing this I can then locate my printer's AirPrint URL and go from there.
Thanks!

Here's a simplified version in Swift 3 for anyone stumbling upon this same question in 2017:
let pickerController = UIPrinterPickerController(initiallySelectedPrinter: nil)
pickerController.present(animated: true) { (controller, completed, error) in
if completed == true {
print(controller.selectedPrinter!.url)
}
}

This might not be the best way to do it, but I ended up displaying the Printer Picker Controller, then printing (to the debug area) the URL of the selected UIPrinter:
let pickerController = UIPrinterPickerController(initiallySelectedPrinter: nil)
pickerController.presentFromRect(CGRectMake(0, 0, 300, 500), inView: self, animated: true) { (controller:UIPrinterPickerController!, completed:Bool, error:NSError!) -> Void in
println(controller.selectedPrinter?.URL)
}
Open to suggestions if there is a better way!

Here is what I did.
Global Var
var ReceiptPrinterHolder = NSURL()
var currentPrinter: UIPrinter?
var ReceiptPrinter: UIPrinter?
func Works(){
let printerPicker = UIPrinterPickerController(initiallySelectedPrinter: currentPrinter2)
printerPicker.presentFromRect(CGRectMake(0, 0, 300, 500), inView: view, animated: true, completionHandler: {
(printerPicker, userDidSelect, error) in
if userDidSelect {
var selectedPrinter: UIPrinter? { return printerPicker.selectedPrinter }
currentPrinter = selectedPrinter
self.DisplaySelectedAction()
}else{
print("Did not work")
}
})
// return currentPrinter2!
}
#IBAction func ReceiptPrinterAction() {
Works()
if currentPrinter != nil {
Label2.text = "Receipt Printer \(ReceiptPrinter!.displayName)"
ReceiptPrinter = currentPrinter
ReceiptPrinterHolder = ReceiptPrinter!.URL
}
}

Related

Progress Bar doesnt animate in UIKIt, Swift

I am using PHPicker for the first time, using loadFileRepresentation method, which asynchronously writes a copy of a selected file and returns a progress object. I am attaching this progress object to a parent progress where I track progress of copying of all files selected by user, so that I can drive one single progress bar view.
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
var tasks = [Progress]()
let parentTask = Progress()
DispatchQueue.global(qos: .unspecified).async {
for itemProvider in results.map({ $0.itemProvider }) {
if itemProvider.canLoadObject(ofClass: UIImage.self) {
guard let identifier = itemProvider.registeredTypeIdentifiers.first else { return }
guard let filenameExtension = URL(string: identifier)?.pathExtension else { return }
let newTask = itemProvider.loadFileRepresentation(forTypeIdentifier: UTType.image.identifier) { tempPathForFileCopying, error in
if (error != nil) {
print("Error while copying files \(String(describing: error))")
}
let targetPath = self.viewModel.galleryManager.selectedGalleryPath.appendingPathComponent(UUID().uuidString).appendingPathExtension(filenameExtension)
if let tempPathForFileCopying {
do {
try FileManager.default.copyItem(at: tempPathForFileCopying, to: targetPath)
} catch {
print("Error \(error)")
}
self.viewModel.galleryManager.buildThumb(forImage: AlbumImage(fileName: targetPath.lastPathComponent, date: Date()))
self.imagesToBeAdded.append(AlbumImage(fileName: targetPath.lastPathComponent, date: Date()))
}
}
tasks.append(newTask)
parentTask.addChild(newTask, withPendingUnitCount: newTask.totalUnitCount - newTask.completedUnitCount)
}
}
}
for task in tasks {
parentTask.totalUnitCount += task.totalUnitCount
}
self.screenView.progressView.observedProgress = parentTask
self.showLoading(task: parentTask)
}
I than invoke showLoading function, which should end up in while loop, until task.isFinished is true. Strangely, printing progress into the console works fine, and I can see that progress there, but no matter what, I cannot update UI progress bar view from here. Entire UI is stuck, until all the copies of the files are created. Even though that happens on background thread and I am trying to call progressView.setProgress on main thread. Again, printing current progress into the console works fine, but no matter what, UI doesnt update until all that copying is done, which just by that time is useless
func showLoading(task: Progress) {
DispatchQueue.main.async {
while !task.isFinished {
var oldFraction = task.fractionCompleted
usleep(300)
if task.fractionCompleted != oldFraction {
let progress = Float(task.fractionCompleted)
self.screenView.progressView.setProgress(progress, animated: false)
print(progress)
}
}
self.viewModel.addPhotos(images: self.imagesToBeAdded)
}
}

How to upload multiple image on firebase using Swift's PHPickerController [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
so in Swift, you have the ability to upload an image/video with ease using UIImageViewController. I did research and came across PHPickerController and I am trying to incorporate that into my code - for the reasoning being that I want multiple images/videos selected and once user presses "button" it pushes that batch to firebase cloud. I have been struggling with this for sometime now. Any sample swift file of doing just this would be much appreciated.
This worked for me.
Note: Make sure that the images you are selecting from the photoLibrary are not the default ones that come with xCode. Some of the default images do not work because they don't have a file location.
SwiftUI Solution
Here is how you call the PHPickerViewController:
struct PHPicker: UIViewControllerRepresentable {
func makeUIViewController(context: Context) -> PHPickerViewController {
var config = PHPickerConfiguration()
config.selectionLimit = 5
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = context.coordinator
return pickerViewController
}
func updateUIViewController(_ uiViewController: PHPickerViewController, context: Context) {
}
class something: NSObject, PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
var fileName: Int = 5
for result in results {
// Get all the images that you selected from the PHPickerViewController
result.itemProvider.loadObject(ofClass: UIImage.self) { object, error in
// Check for errors
if let error = error {
print("Sick error dawg \(error.localizedDescription)")
} else {
// Convert the image into Data so we can upload to firebase
if let image = object as? UIImage {
let imageData = image.jpegData(compressionQuality: 1.0)
// You NEED to make sure you somehow change the name of each picture that you upload which is why I am using the variable "count".
// If you do not change the filename for each picture you upload, it will try to upload the file to the same file and it will give you an error.
Storage.storage().reference().child("fileName").child("\(fileName)").putData(imageData!)
fileName += 1
print("Uploaded to firebase")
} else {
print("There was an error.")
}
}
}
}
}
}
func makeCoordinator() -> something {
return something()
}
}
Here is how I present the sheet:
struct PresentMyPicker: View {
#State var presentSheet: Bool = false
var body: some View {
VStack {
Button {
presentSheet.toggle()
} label: {
Text("Click me")
}
}
.sheet(isPresented: $presentSheet) {
PHPicker()
}
}
}
UIKit solution
This is how I present the PHPickerViewController when they tap the button:
func setupView() {
var config = PHPickerConfiguration()
config.selectionLimit = 5
config.filter = PHPickerFilter.images
let pickerViewController = PHPickerViewController(configuration: config)
pickerViewController.delegate = self
view.addSubview(button)
button.addAction(UIAction() { _ in
self.present(pickerViewController, animated: true)
}, for: .touchUpInside)
}
Here is my delegate function that runs after you click "Add" with the selected images you want to upload.
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true)
var fileName: Int = 1
for result in results {
// Get all the images that you selected from the PHPickerViewController
result.itemProvider.loadObject(ofClass: UIImage.self) { object, error in
// Check for errors
if let error = error {
print("Sick error dawg \(error.localizedDescription)")
} else {
// Convert the image into Data so we can upload to firebase
if let image = object as? UIImage {
let imageData = image.jpegData(compressionQuality: 1.0)
// You NEED to make sure you somehow change the name of each picture that you upload which is why I am using the variable "fileName".
// If you do not change the filename for each picture you upload, it will try to upload all the selected images to the same file location and give you an error.
Storage.storage().reference().child("CollectionName").child("\(fileName)").putData(imageData!)
fileName += 1
} else {
print("There was an error.")
}
}
}
}
}
Also if you are wanting to upload videos to firebase and having trouble take a look at this example it took me forever to figure this out. Uploading Videos to firebase correctly.

Swift callkit sometimes can't activate loudspeaker after received call (only incoming call)

after follow #Marco comment, i updated code like below, but still not working, the loudspeaker sometimes can not enabled
Before report new call/ user accepted call I called the 2 methods below:
configureAudioSessionToDefaultSpeaker()
func configureAudioSessionToDefaultSpeaker() {
let session = AVAudioSession.sharedInstance()
do {
try session.setCategory(AVAudioSession.Category.playAndRecord, mode: .default)
try session.setActive(true)
try session.setMode(AVAudioSession.Mode.voiceChat)
try session.setPreferredSampleRate(44100.0)
try session.setPreferredIOBufferDuration(0.005)
} catch {
print("Failed to configure `AVAudioSession`: \(error)")
}
}
I updated more code:
func startCallWithPhoneNumber(call : CallInfoModel) {
configureAudioSessionToDefaultSpeaker()
currentCall = call
if let unwrappedCurrentCall = currentCall {
let handle = CXHandle.init(type: .generic, value: unwrappedCurrentCall.CallerDisplay ?? UNKNOWN)
let startCallAction = CXStartCallAction.init(call: unwrappedCurrentCall.uuid, handle: handle)
let transaction = CXTransaction.init()
transaction.addAction(startCallAction)
requestTransaction(transaction: transaction)
self.provider?.reportOutgoingCall(with: startCallAction.callUUID, startedConnectingAt: nil)
}
}
func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) {
configureAudioSessionToDefaultSpeaker()
delegate?.callDidAnswer()
action.fulfill()
currentCall?.isAccepted = true
let sb = UIStoryboard(name: "main", bundle: nil)
let vc = sb.instantiateViewController(withIdentifier: "SingleCallVC") as! SingleCallVC
vc.modalPresentationStyle = .fullScreen
vc.callObj = currentCall
vc.isIncoming = true
let appDelegate = AppDelegate.shared
appDelegate.window?.rootViewController?.present(vc, animated: true, completion: nil)
}
My call almost work normally but sometime loudspeaker can not be enabled. I read many documents but nothing worked for me. Could someone give me some advice? Thanks.
You're configuring the AudioSession two times. The RTCAudioSession it's a proxy of AVAudioSession. You should do only one configuration to avoid unexpected results. RTCAudioSession should expose all the methods of the AVAudioSession, so you should be able to make all the configurations you want inside configureRtcAudioSession() and eliminate configureAudioSessionToDefaultSpeaker() or viceversa. I'm not sure if it will solve your issue but at least it should help to avoid unexpected behaviors.
I've had success with enabling the speaker using the method below.
let audioQueue = DispatchQueue(label: "audio")
func setSpeaker(_ isEnabled: Bool) {
audioQueue.async {
defer {
AVAudioSession.sharedInstance().unlockForConfiguration()
}
AVAudioSession.sharedInstance().lockForConfiguration()
do {
try AVAudioSession.sharedInstance().overrideOutputAudioPort(isEnabled ? .speaker : .none)
} catch {
debugPrint(error.localizedDescription)
}
}
}
// Enables the audio speaker.
setSpeaker(true)
// Disables the audio speaker.
setSpeaker(false)

Is there a way to make MLVision text recognition faster?

I am using MLVision cloud text recognition for my app. I capture/upload a photo and then I start the process. When it recognises the image and extract the text, then I separate it and append every separated block into an array.
The code below is for the whole process.
lazy var vision = Vision.vision()
var textRecognizer: VisionTextRecognizer!
var test = [] as Array<String>
override func viewDidLoad() {
super.viewDidLoad()
let options = VisionCloudTextRecognizerOptions()
options.languageHints = ["en","hi"]
textRecognizer = vision.cloudTextRecognizer(options: options)
}
//where pickedImage is the image that user captures.
let visionImage = VisionImage(image: pickedImage)
textRecognizer.process(visionImage, completion: { (features, error) in
guard error == nil, let features = features else {
self.resultView.text = "Could not recognize any text"
self.dismiss(animated: true, completion: nil)
return
}
for block in features.blocks {
for line in block.lines{
//for element in line.elements{
self.resultView.text = self.resultView.text + "\(line.text)"
}
}
self.separate()
})
func separate(){
let separators = CharacterSet(charactersIn: (":)(,•/·]["))
let ofWordsArray = self.resultView.text.components(separatedBy: separators)
for word in ofWordsArray{
let low = word.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
if low != ""{
test.append(low)
}
}
print(test)
}
Everything works fine and I get the result that I want.The problem is that I think is really slow. It takes about 20sec for the entire process.Is there a way to make it faster?
Thanks in advance.
You are using the VisionCloudTextRecognizer. Speed will depend on your connection, in my case it was only few seconds. Your other option is to use on-device text recognition or use a hybrid approach, where you first detect on-device, then correct with Cloud API later.

NSKeyedUnarchiver.unarchiveObject() unarchives old object

I want to save the user's filter selections on FilterViewController.
When FilterViewController is closed, NSKeyedArchiver.archiveRootObject archives the user's selections. However, NSKeyedUnarchiver.unarchiveObject opens up the initial default selections (NOT the user's selections). How to fix this?
FiltersViewController.swift
override func viewWillAppear(_ animated: Bool) {
if let filterSections = NSKeyedUnarchiver.unarchiveObject(withFile: filterViewModel.filtersFilePath) as? [FilterSection] {
// Retrieves initial default selections, NOT user's selection
filterViewModel.filterSections = filterSections
filtersTableView.reloadData()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
// Saves what user selects
let isSuccessful = NSKeyedArchiver.archiveRootObject(self.filterViewModel.filterSections, toFile: self.filterViewModel.filtersFilePath)
if (isSuccessful) {
print("Saved filters") // This is printed
} else {
print("Didn't Save filters")
}
}
FilterViewModel.swift
class FilterViewModel: NSObject {
// Contains all filtered sections displayed on table view
var filterSections: [FilterSection] = []
// File Path to saved Filter Sections
var filtersFilePath: String {
let manager = FileManager.default
let url = manager.urls(for: .documentDirectory, in: .userDomainMask).first
print("this is the url path in the documentDirectory \(url)")
return (url!.appendingPathComponent("FilterSelectionData").path)
}
override init() {
super.init()
filterSections = self.getFilterSections()
}
}
CompanyViewController.swift
#objc func filterButtonTapped() {
var filterViewModel: FilterViewModel
if (self.filterViewModel != nil) {
filterViewModel = self.filterViewModel! // This runs
}
else {
self.filterViewModel = FilterViewModel()
filterViewModel = self.filterViewModel!
}
let filtersVC = FiltersViewController(filterViewModel: filterViewModel)
self.navigationController?.pushViewController(filtersVC, animated: true)
}
You are using self.getFilterSections to set filterSections in FilterViewModel init. I suppose self.getFilterSections is a method that returns the default values. For me, it should not be the case, rather if you have archived some values, you should get that in this method. Although, this alone should not be the reason for the issue, but may be a reason for inducing bug. Try changing self.getFilterSections to return archived values if possible otherwise default values and check whether the bug is still there.