[ios] Add default email client support to about menu #7862

Merged
v-lozko merged 5 commits from aboutemail into master 2024-04-24 23:12:57 +00:00

View file

@ -481,6 +481,20 @@ private extension AboutController {
}
return false
}
func openDefaultMailApp(subject: String, body: String, recipients: [String]) -> Bool {
var components = URLComponents(string: "mailto:\(recipients.joined(separator: ";"))")
components?.queryItems = [
URLQueryItem(name: "subject", value: subject),
URLQueryItem(name: "body", value: body.replacingOccurrences(of: "\n", with: "\r\n")),
]
Review

This code doesn't work for me... I'm using Spark (to field):
image

The Problem is in the toRecipients - it is an array of Strings. And to work as a subject it should be joined using ;.
Please take a look at the code used before for opening other apps:

    func openGmail(subject: String, body: String, recipients: [String]) -> Bool {
      var components = URLComponents(string: "googlegmail://co")!
      components.queryItems = [
        URLQueryItem(name: "to", value: recipients.joined(separator: ";")),
        URLQueryItem(name: "subject", value: subject),
        URLQueryItem(name: "body", value: body),
      ]

      if let url = components.url, UIApplication.shared.canOpenURL(url) {
        UIApplication.shared.open(url)
        return true
      }
      return false
    }

So you can create the same method and handle the default app using URLComponents.
Here is the hardcoded one that I've made just as a reference (needs to be refactored):

func openDefaultApp(subject: String, body: String, recipients: [String]) -> Bool {
    var components = URLComponents(string: "mailto:\(recipients.joined(separator: ";").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")")!
    components.queryItems = [
      URLQueryItem(name: "subject", value: subject),
      URLQueryItem(name: "body", value: body),
    ]

    if let url = components.url, UIApplication.shared.canOpenURL(url) {
      UIApplication.shared.open(url)
      return true
    }
    return false
  }

As a result:
image

This code doesn't work for me... I'm using Spark (`to` field): <img width="300" alt="image" src="https://github.com/organicmaps/organicmaps/assets/79797627/8db4a210-3838-45fd-bc4b-95178a8c836e"> The Problem is in the `toRecipients` - it is an array of Strings. And to work as a subject it should be joined using `;`. Please take a look at the code used before for opening other apps: ```swift func openGmail(subject: String, body: String, recipients: [String]) -> Bool { var components = URLComponents(string: "googlegmail://co")! components.queryItems = [ URLQueryItem(name: "to", value: recipients.joined(separator: ";")), URLQueryItem(name: "subject", value: subject), URLQueryItem(name: "body", value: body), ] if let url = components.url, UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url) return true } return false } ``` So you can create the same method and handle the default app using URLComponents. Here is the hardcoded one that I've made just as a reference (needs to be refactored): ```swift func openDefaultApp(subject: String, body: String, recipients: [String]) -> Bool { var components = URLComponents(string: "mailto:\(recipients.joined(separator: ";").addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")")! components.queryItems = [ URLQueryItem(name: "subject", value: subject), URLQueryItem(name: "body", value: body), ] if let url = components.url, UIApplication.shared.canOpenURL(url) { UIApplication.shared.open(url) return true } return false } ``` As a result: <img width="300" alt="image" src="https://github.com/organicmaps/organicmaps/assets/79797627/0fe68515-41c0-422d-aac6-0ea2289ab71b">
if let url = components?.url, UIApplication.shared.canOpenURL(url) {
biodranik commented 2024-04-09 19:08:23 +00:00 (Migrated from github.com)
Review

When does it return false?

When does it return false?
v-lozko commented 2024-04-09 19:14:13 +00:00 (Migrated from github.com)
Review

when UIApplication.shared.canOpenURL(url) returns false or components?.url doesnt construct properly

when UIApplication.shared.canOpenURL(url) returns false or components?.url doesnt construct properly
v-lozko commented 2024-04-16 12:17:44 +00:00 (Migrated from github.com)
Review

@biodranik is there anything else needed for this?

@biodranik is there anything else needed for this?
UIApplication.shared.open(url)
return true
}
return false
}
let subject = emailSubject(subject: header)
let body = emailBody()
@ -491,15 +505,10 @@ private extension AboutController {
openOutlook(subject: subject, body: body, recipients: toRecipients))) {
return
}
// From iOS 14, it is possible to change the default mail app, and mailto should open a default mail app.
if MWMMailViewController.canSendMail() {
let vc = MWMMailViewController()
vc.mailComposeDelegate = self
vc.setSubject(subject)
vc.setMessageBody(body, isHTML:false)
vc.setToRecipients(toRecipients)
vc.navigationBar.tintColor = UIColor.whitePrimaryText()
self.present(vc, animated: true, completion:nil)
if openDefaultMailApp(subject: subject, body: body, recipients: toRecipients) {
return
} else {
let text = String(format:L("email_error_body"), toRecipients.joined(separator: ";"))
let alert = UIAlertController(title: L("email_error_title"), message: text, preferredStyle: .alert)
@ -510,13 +519,6 @@ private extension AboutController {
}
}
// MARK: - MFMailComposeViewControllerDelegate
extension AboutController: MFMailComposeViewControllerDelegate {
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
self.dismiss(animated: true, completion: nil)
}
}
// MARK: - UIStackView + AddArrangedSubviewWithSeparator
private extension UIStackView {
func addArrangedSubviewWithSeparator(_ view: UIView) {