expo-mail-composer 12.1.1 → 12.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@
10
10
 
11
11
  ### 💡 Others
12
12
 
13
+ ## 12.2.0 — 2023-05-08
14
+
15
+ ### 💡 Others
16
+
17
+ - Migrated Android codebase to use the new modules API. ([#21200](https://github.com/expo/expo/pull/21200) by [@alanjhughes](https://github.com/alanjhughes))
18
+
13
19
  ## 12.1.1 — 2023-02-09
14
20
 
15
21
  _This version does not introduce any user-facing changes._
package/README.md CHANGED
@@ -16,7 +16,7 @@ Provides an API to compose mails using OS specific UI
16
16
 
17
17
  # Installation in managed Expo projects
18
18
 
19
- For [managed](https://docs.expo.dev/versions/latest/introduction/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/mail-composer/).
19
+ For [managed](https://docs.expo.dev/archive/managed-vs-bare/) Expo projects, please follow the installation instructions in the [API documentation for the latest stable release](https://docs.expo.dev/versions/latest/sdk/mail-composer/).
20
20
 
21
21
  # Installation in bare React Native projects
22
22
 
@@ -25,7 +25,7 @@ For bare React Native projects, you must ensure that you have [installed and con
25
25
  ### Add the package to your npm dependencies
26
26
 
27
27
  ```
28
- expo install expo-mail-composer
28
+ npx expo install expo-mail-composer
29
29
  ```
30
30
 
31
31
  ### Configure for iOS
@@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
3
3
  apply plugin: 'maven-publish'
4
4
 
5
5
  group = 'host.exp.exponent'
6
- version = '12.1.1'
6
+ version = '12.2.0'
7
7
 
8
8
  buildscript {
9
9
  def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
@@ -74,7 +74,7 @@ android {
74
74
  minSdkVersion safeExtGet("minSdkVersion", 21)
75
75
  targetSdkVersion safeExtGet("targetSdkVersion", 33)
76
76
  versionCode 17
77
- versionName "12.1.1"
77
+ versionName "12.2.0"
78
78
  }
79
79
  lintOptions {
80
80
  abortOnError false
@@ -1,93 +1,75 @@
1
1
  package expo.modules.mailcomposer
2
2
 
3
- import android.app.Activity
4
- import android.content.Context
5
3
  import android.content.Intent
6
4
  import android.content.pm.LabeledIntent
7
5
  import android.net.Uri
8
6
  import android.os.Bundle
9
- import expo.modules.core.ExportedModule
10
- import expo.modules.core.ModuleRegistry
11
- import expo.modules.core.ModuleRegistryDelegate
12
- import expo.modules.core.Promise
13
- import expo.modules.core.arguments.ReadableArguments
14
- import expo.modules.core.interfaces.ActivityProvider
15
- import expo.modules.core.interfaces.ExpoMethod
16
- import expo.modules.core.interfaces.ActivityEventListener
17
- import expo.modules.core.interfaces.services.UIManager
7
+ import expo.modules.kotlin.Promise
8
+ import expo.modules.kotlin.exception.Exceptions
9
+ import expo.modules.kotlin.modules.Module
10
+ import expo.modules.kotlin.modules.ModuleDefinition
18
11
 
19
- class MailComposerModule(
20
- context: Context,
21
- private val moduleRegistryDelegate: ModuleRegistryDelegate = ModuleRegistryDelegate()
22
- ) : ExportedModule(context), ActivityEventListener {
12
+ class MailComposerModule : Module() {
13
+ private val context
14
+ get() = appContext.reactContext ?: throw Exceptions.ReactContextLost()
15
+ private val currentActivity
16
+ get() = appContext.currentActivity ?: throw Exceptions.MissingActivity()
23
17
  private var composerOpened = false
24
- private val uiManager: UIManager by moduleRegistry()
25
18
  private var pendingPromise: Promise? = null
26
- override fun getName() = "ExpoMailComposer"
27
- private val activityProvider: ActivityProvider by moduleRegistry()
28
19
 
29
- private inline fun <reified T> moduleRegistry() = moduleRegistryDelegate.getFromModuleRegistry<T>()
20
+ override fun definition() = ModuleDefinition {
21
+ Name("ExpoMailComposer")
30
22
 
31
- override fun onCreate(moduleRegistry: ModuleRegistry) {
32
- moduleRegistryDelegate.onCreate(moduleRegistry)
33
- uiManager.registerActivityEventListener(this)
34
- }
23
+ AsyncFunction("isAvailableAsync") {
24
+ return@AsyncFunction true
25
+ }
35
26
 
36
- override fun onDestroy() {
37
- uiManager.unregisterActivityEventListener(this)
38
- }
27
+ AsyncFunction("composeAsync") { options: MailComposerOptions, promise: Promise ->
28
+ val intent = Intent(Intent.ACTION_SENDTO).apply { data = Uri.parse("mailto:") }
29
+ val application = currentActivity.application
30
+ val resolveInfo = context.packageManager.queryIntentActivities(intent, 0)
39
31
 
40
- @ExpoMethod
41
- fun isAvailableAsync(promise: Promise) {
42
- promise.resolve(true)
43
- }
32
+ val mailIntents = resolveInfo.map { info ->
33
+ val mailIntentBuilder = MailIntentBuilder(options)
34
+ .setComponentName(info.activityInfo.packageName, info.activityInfo.name)
35
+ .putRecipients(Intent.EXTRA_EMAIL)
36
+ .putCcRecipients(Intent.EXTRA_CC)
37
+ .putBccRecipients(Intent.EXTRA_BCC)
38
+ .putSubject(Intent.EXTRA_SUBJECT)
39
+ .putBody(Intent.EXTRA_TEXT, options.isHtml ?: false)
40
+ .putAttachments(
41
+ Intent.EXTRA_STREAM,
42
+ application
43
+ )
44
44
 
45
- @ExpoMethod
46
- fun composeAsync(options: ReadableArguments, promise: Promise) {
47
- val intent = Intent(Intent.ACTION_SENDTO).apply { data = Uri.parse("mailto:") }
48
- val application = activityProvider.currentActivity.application
49
- val resolveInfo = context.packageManager.queryIntentActivities(intent, 0)
50
- val mailIntents = resolveInfo.map { info ->
51
- val isHtml = options.containsKey("isHtml") && options.getBoolean("isHtml")
52
- val mailIntentBuilder = MailIntentBuilder(options)
53
- .setComponentName(info.activityInfo.packageName, info.activityInfo.name)
54
- .putExtraIfKeyExists("recipients", Intent.EXTRA_EMAIL)
55
- .putExtraIfKeyExists("ccRecipients", Intent.EXTRA_CC)
56
- .putExtraIfKeyExists("bccRecipients", Intent.EXTRA_BCC)
57
- .putExtraIfKeyExists("subject", Intent.EXTRA_SUBJECT)
58
- .putExtraIfKeyExists("body", Intent.EXTRA_TEXT, isHtml)
59
- .putParcelableArrayListExtraIfKeyExists(
60
- "attachments",
61
- Intent.EXTRA_STREAM,
62
- application
45
+ LabeledIntent(
46
+ mailIntentBuilder.build(),
47
+ info.activityInfo.packageName,
48
+ info.loadLabel(context.packageManager),
49
+ info.icon
63
50
  )
64
- LabeledIntent(
65
- mailIntentBuilder.build(),
66
- info.activityInfo.packageName,
67
- info.loadLabel(context.packageManager),
68
- info.icon
69
- )
70
- }.toMutableList()
71
- val chooser = Intent.createChooser(
72
- mailIntents.removeAt(mailIntents.size - 1),
73
- null
74
- ).apply {
75
- putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toTypedArray())
76
- addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
77
- }
78
- pendingPromise = promise
79
- activityProvider.currentActivity.startActivityForResult(chooser, REQUEST_CODE)
80
- composerOpened = true
81
- }
51
+ }.toMutableList()
52
+
53
+ val chooser = Intent.createChooser(
54
+ mailIntents.removeAt(mailIntents.size - 1),
55
+ null
56
+ ).apply {
57
+ putExtra(Intent.EXTRA_INITIAL_INTENTS, mailIntents.toTypedArray())
58
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
59
+ }
82
60
 
83
- override fun onNewIntent(intent: Intent) = Unit
61
+ pendingPromise = promise
62
+ currentActivity.startActivityForResult(chooser, REQUEST_CODE)
63
+ composerOpened = true
64
+ }
84
65
 
85
- override fun onActivityResult(activity: Activity, requestCode: Int, resultCode: Int, data: Intent?) {
86
- if (requestCode == REQUEST_CODE && pendingPromise != null) {
87
- val promise = pendingPromise ?: return
88
- if (composerOpened) {
89
- composerOpened = false
90
- promise.resolve(Bundle().apply { putString("status", "sent") })
66
+ OnActivityResult { _, payload ->
67
+ if (payload.requestCode == REQUEST_CODE && pendingPromise != null) {
68
+ val promise = pendingPromise ?: return@OnActivityResult
69
+ if (composerOpened) {
70
+ composerOpened = false
71
+ promise.resolve(Bundle().apply { putString("status", "sent") })
72
+ }
91
73
  }
92
74
  }
93
75
  }
@@ -7,19 +7,13 @@ import android.net.Uri
7
7
  import android.text.Html
8
8
  import android.util.Log
9
9
  import androidx.core.content.FileProvider
10
- import expo.modules.core.arguments.ReadableArguments
11
10
  import java.io.File
12
11
 
13
12
  class MailIntentBuilder(
14
- private val options: ReadableArguments
13
+ private val options: MailComposerOptions
15
14
  ) {
16
15
  private val mailIntent = Intent(Intent.ACTION_SEND_MULTIPLE)
17
16
 
18
- @Suppress("UNCHECKED_CAST")
19
- private fun getStringArrayFrom(key: String): Array<String?> {
20
- return (options.getList(key) as List<String?>).toTypedArray()
21
- }
22
-
23
17
  private fun contentUriFromFile(file: File, application: Application): Uri = try {
24
18
  FileProvider.getUriForFile(
25
19
  application,
@@ -36,41 +30,55 @@ class MailIntentBuilder(
36
30
  mailIntent.component = ComponentName(pkg, cls)
37
31
  }
38
32
 
39
- fun putExtraIfKeyExists(key: String, intentName: String) = apply {
40
- if (options.containsKey(key)) {
41
- if (options.getList(key) != null) {
42
- mailIntent.putExtra(intentName, getStringArrayFrom(key))
43
- } else {
44
- mailIntent.putExtra(intentName, options.getString(key))
45
- }
33
+ fun putRecipients(intentName: String) = apply {
34
+ options.recipients?.let {
35
+ mailIntent.putExtra(intentName, it.toTypedArray())
46
36
  }
47
37
  }
48
38
 
49
- fun putExtraIfKeyExists(key: String, intentName: String, isBodyHtml: Boolean) = apply {
50
- if (options.containsKey(key)) {
39
+ fun putCcRecipients(intentName: String) = apply {
40
+ options.ccRecipients?.let {
41
+ mailIntent.putExtra(intentName, it.toTypedArray())
42
+ }
43
+ }
44
+
45
+ fun putBccRecipients(intentName: String) = apply {
46
+ options.bccRecipients?.let {
47
+ mailIntent.putExtra(intentName, it.toTypedArray())
48
+ }
49
+ }
50
+
51
+ fun putSubject(intentName: String) = apply {
52
+ options.subject?.let {
53
+ mailIntent.putExtra(intentName, it)
54
+ }
55
+ }
56
+
57
+ fun putBody(intentName: String, isBodyHtml: Boolean) = apply {
58
+ options.body?.let {
51
59
  val body = if (isBodyHtml) {
52
- Html.fromHtml(options.getString(key))
60
+ Html.fromHtml(options.body)
53
61
  } else {
54
- options.getString(key)
62
+ options.body
55
63
  }
56
64
  mailIntent.putExtra(intentName, body)
57
65
  }
58
66
  }
59
67
 
60
- fun putParcelableArrayListExtraIfKeyExists(
61
- key: String,
68
+ fun putAttachments(
62
69
  intentName: String,
63
70
  application: Application,
64
71
  ) = apply {
65
72
  try {
66
- if (options.containsKey(key)) {
67
- val requestedAttachments = getStringArrayFrom(key)
68
- val attachments = requestedAttachments.map { requestedAttachment ->
73
+ options.attachments?.let { requestedAttachments ->
74
+ val attachments = requestedAttachments.toTypedArray().map { requestedAttachment ->
69
75
  val path = Uri.parse(requestedAttachment).path
70
- requireNotNull(path, { "Path to attachment can not be null" })
76
+ requireNotNull(path) { "Path to attachment can not be null" }
77
+
71
78
  val attachmentFile = File(path)
72
79
  contentUriFromFile(attachmentFile, application)
73
80
  }.toCollection(ArrayList())
81
+
74
82
  mailIntent.putParcelableArrayListExtra(intentName, attachments)
75
83
  }
76
84
  } catch (error: IllegalArgumentException) {
@@ -0,0 +1,21 @@
1
+ package expo.modules.mailcomposer
2
+
3
+ import expo.modules.kotlin.records.Field
4
+ import expo.modules.kotlin.records.Record
5
+
6
+ data class MailComposerOptions(
7
+ @Field
8
+ val recipients: List<String>?,
9
+ @Field
10
+ val ccRecipients: List<String>?,
11
+ @Field
12
+ val bccRecipients: List<String>?,
13
+ @Field
14
+ val subject: String?,
15
+ @Field
16
+ val body: String?,
17
+ @Field
18
+ val isHtml: Boolean?,
19
+ @Field
20
+ val attachments: List<String>?,
21
+ ) : Record
@@ -3,5 +3,8 @@
3
3
  "platforms": ["ios", "android"],
4
4
  "ios": {
5
5
  "modules": ["MailComposerModule"]
6
+ },
7
+ "android": {
8
+ "modules": ["expo.modules.mailcomposer.MailComposerModule"]
6
9
  }
7
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-mail-composer",
3
- "version": "12.1.1",
3
+ "version": "12.2.0",
4
4
  "description": "Provides an API to compose mails using OS specific UI",
5
5
  "main": "build/MailComposer.js",
6
6
  "types": "build/MailComposer.d.ts",
@@ -43,5 +43,5 @@
43
43
  "peerDependencies": {
44
44
  "expo": "*"
45
45
  },
46
- "gitHead": "1f8a6a09570fd451378565ca34933018ce48454e"
46
+ "gitHead": "4ba50c428c8369bb6b3a51a860d4898ad4ccbe78"
47
47
  }
@@ -1,9 +0,0 @@
1
- package expo.modules.mailcomposer
2
-
3
- import android.content.Context
4
- import expo.modules.core.BasePackage
5
-
6
- class MailComposerPackage : BasePackage() {
7
- override fun createExportedModules(context: Context) =
8
- listOf(MailComposerModule(context))
9
- }