@capawesome/capacitor-action-sheet 0.0.1
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/CapawesomeCapacitorActionSheet.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +185 -0
- package/android/build.gradle +60 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/ActionSheet.java +144 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java +71 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/CustomException.java +20 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/CustomExceptions.java +8 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/options/ActionSheetButton.java +45 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/options/ShowActionsOptions.java +62 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/results/ShowActionsResult.java +25 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/interfaces/Callback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/interfaces/NonEmptyResultCallback.java +7 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/interfaces/Result.java +7 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +258 -0
- package/dist/esm/definitions.d.ts +116 -0
- package/dist/esm/definitions.js +29 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +5 -0
- package/dist/esm/web.js +7 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +50 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +53 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/ActionSheet.swift +59 -0
- package/ios/Plugin/ActionSheetPlugin.swift +47 -0
- package/ios/Plugin/Classes/Options/ActionSheetButton.swift +19 -0
- package/ios/Plugin/Classes/Options/ShowActionsOptions.swift +23 -0
- package/ios/Plugin/Classes/Results/ShowActionsResult.swift +19 -0
- package/ios/Plugin/Enums/CustomError.swift +31 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Protocols/Result.swift +5 -0
- package/package.json +94 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapawesomeCapacitorActionSheet'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '15.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.swift_version = '5.1'
|
|
17
|
+
end
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Robin Genz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/Package.swift
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
import PackageDescription
|
|
3
|
+
|
|
4
|
+
let package = Package(
|
|
5
|
+
name: "CapawesomeCapacitorActionSheet",
|
|
6
|
+
platforms: [.iOS(.v15)],
|
|
7
|
+
products: [
|
|
8
|
+
.library(
|
|
9
|
+
name: "CapawesomeCapacitorActionSheet",
|
|
10
|
+
targets: ["ActionSheetPlugin"])
|
|
11
|
+
],
|
|
12
|
+
dependencies: [
|
|
13
|
+
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
|
|
14
|
+
],
|
|
15
|
+
targets: [
|
|
16
|
+
.target(
|
|
17
|
+
name: "ActionSheetPlugin",
|
|
18
|
+
dependencies: [
|
|
19
|
+
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
|
20
|
+
.product(name: "Cordova", package: "capacitor-swift-pm")
|
|
21
|
+
],
|
|
22
|
+
path: "ios/Plugin"),
|
|
23
|
+
.testTarget(
|
|
24
|
+
name: "ActionSheetPluginTests",
|
|
25
|
+
dependencies: ["ActionSheetPlugin"],
|
|
26
|
+
path: "ios/PluginTests")
|
|
27
|
+
]
|
|
28
|
+
)
|
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Capacitor Action Sheet Plugin
|
|
2
|
+
|
|
3
|
+
Capacitor plugin for native action sheets.
|
|
4
|
+
|
|
5
|
+
<div class="capawesome-z29o10a">
|
|
6
|
+
<a href="https://cloud.capawesome.io/" target="_blank">
|
|
7
|
+
<img alt="Deliver Live Updates to your Capacitor app with Capawesome Cloud" src="https://cloud.capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.png?t=1" />
|
|
8
|
+
</a>
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- 📋 **Action Sheet**: Present a native action sheet with a list of buttons.
|
|
14
|
+
- 🎨 **Button Styles**: Highlight destructive actions and pin a cancel button.
|
|
15
|
+
- 📝 **Title & Message**: Show a title and message on both Android and iOS.
|
|
16
|
+
- 📱 **iPad Ready**: Automatically anchored as a popover on iPad.
|
|
17
|
+
- 🔒 **App Store safe**: Uses only official platform APIs.
|
|
18
|
+
- 📦 **CocoaPods & SPM**: Supports CocoaPods and Swift Package Manager for iOS.
|
|
19
|
+
- 🔁 **Up-to-date**: Always supports the latest Capacitor version.
|
|
20
|
+
- 🤝 **Compatibility**: Works alongside the [Dialog](https://capawesome.io/docs/sdks/capacitor/dialog/) plugin.
|
|
21
|
+
|
|
22
|
+
Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
|
|
23
|
+
|
|
24
|
+
## Newsletter
|
|
25
|
+
|
|
26
|
+
Stay up to date with the latest news and updates about the Capawesome, Capacitor, and Ionic ecosystem by subscribing to our [Capawesome Newsletter](https://cloud.capawesome.io/newsletter/).
|
|
27
|
+
|
|
28
|
+
## Compatibility
|
|
29
|
+
|
|
30
|
+
| Plugin Version | Capacitor Version | Status |
|
|
31
|
+
| -------------- | ----------------- | -------------- |
|
|
32
|
+
| 0.x.x | >=8.x.x | Active support |
|
|
33
|
+
|
|
34
|
+
## Installation
|
|
35
|
+
|
|
36
|
+
You can use our **AI-Assisted Setup** to install the plugin.
|
|
37
|
+
Add the [Capawesome Skills](https://github.com/capawesome-team/skills) to your AI tool using the following command:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npx skills add capawesome-team/skills --skill capacitor-plugins
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Then use the following prompt:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-action-sheet` plugin in my project.
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
If you prefer **Manual Setup**, install the plugin by running the following commands and follow the platform-specific instructions below:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install @capawesome/capacitor-action-sheet
|
|
53
|
+
npx cap sync
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Android
|
|
57
|
+
|
|
58
|
+
#### Variables
|
|
59
|
+
|
|
60
|
+
This plugin will use the following project variables (defined in your app's `variables.gradle` file):
|
|
61
|
+
|
|
62
|
+
- `$androidxMaterialVersion` version of `com.google.android.material:material` (default: `1.12.0`)
|
|
63
|
+
|
|
64
|
+
### iOS
|
|
65
|
+
|
|
66
|
+
No additional configuration is required for this plugin.
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
No configuration required for this plugin.
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
import { ActionSheet, ActionSheetButtonStyle } from '@capawesome/capacitor-action-sheet';
|
|
76
|
+
|
|
77
|
+
const showActions = async () => {
|
|
78
|
+
const { index, canceled } = await ActionSheet.showActions({
|
|
79
|
+
title: 'Photo Options',
|
|
80
|
+
message: 'Select an option to perform.',
|
|
81
|
+
options: [
|
|
82
|
+
{ title: 'Upload' },
|
|
83
|
+
{ title: 'Share' },
|
|
84
|
+
{ title: 'Delete', style: ActionSheetButtonStyle.Destructive },
|
|
85
|
+
{ title: 'Cancel', style: ActionSheetButtonStyle.Cancel },
|
|
86
|
+
],
|
|
87
|
+
});
|
|
88
|
+
console.log('Index:', index, 'Canceled:', canceled);
|
|
89
|
+
};
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## API
|
|
93
|
+
|
|
94
|
+
<docgen-index>
|
|
95
|
+
|
|
96
|
+
* [`showActions(...)`](#showactions)
|
|
97
|
+
* [Interfaces](#interfaces)
|
|
98
|
+
* [Enums](#enums)
|
|
99
|
+
|
|
100
|
+
</docgen-index>
|
|
101
|
+
|
|
102
|
+
<docgen-api>
|
|
103
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
104
|
+
|
|
105
|
+
### showActions(...)
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
showActions(options: ShowActionsOptions) => Promise<ShowActionsResult>
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Show an action sheet with a list of buttons.
|
|
112
|
+
|
|
113
|
+
Only available on Android and iOS.
|
|
114
|
+
|
|
115
|
+
| Param | Type |
|
|
116
|
+
| ------------- | ----------------------------------------------------------------- |
|
|
117
|
+
| **`options`** | <code><a href="#showactionsoptions">ShowActionsOptions</a></code> |
|
|
118
|
+
|
|
119
|
+
**Returns:** <code>Promise<<a href="#showactionsresult">ShowActionsResult</a>></code>
|
|
120
|
+
|
|
121
|
+
**Since:** 0.1.0
|
|
122
|
+
|
|
123
|
+
--------------------
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
### Interfaces
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
#### ShowActionsResult
|
|
130
|
+
|
|
131
|
+
| Prop | Type | Description | Since |
|
|
132
|
+
| -------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ----- |
|
|
133
|
+
| **`canceled`** | <code>boolean</code> | Whether the action sheet was canceled by selecting a cancel button or by dismissing the action sheet. | 0.1.0 |
|
|
134
|
+
| **`index`** | <code>number</code> | The index of the selected button in the `options` array (zero-based). If the action sheet was canceled without a cancel button, the index is `-1`. | 0.1.0 |
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
#### ShowActionsOptions
|
|
138
|
+
|
|
139
|
+
| Prop | Type | Description | Default | Since |
|
|
140
|
+
| ---------------- | -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- | ----- |
|
|
141
|
+
| **`cancelable`** | <code>boolean</code> | Whether the action sheet can be dismissed by tapping outside of it or pressing the back button (Android). On iOS, the action sheet can always be dismissed by tapping outside of it (a system behavior). | <code>true</code> | 0.1.0 |
|
|
142
|
+
| **`message`** | <code>string</code> | The message to display below the title. | | 0.1.0 |
|
|
143
|
+
| **`options`** | <code>ActionSheetButton[]</code> | The buttons to display in the action sheet. | | 0.1.0 |
|
|
144
|
+
| **`title`** | <code>string</code> | The title of the action sheet. | | 0.1.0 |
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
#### ActionSheetButton
|
|
148
|
+
|
|
149
|
+
| Prop | Type | Description | Default | Since |
|
|
150
|
+
| ----------- | ------------------------------------------------------------------------- | ------------------------ | ------------------------------------------- | ----- |
|
|
151
|
+
| **`style`** | <code><a href="#actionsheetbuttonstyle">ActionSheetButtonStyle</a></code> | The style of the button. | <code>ActionSheetButtonStyle.Default</code> | 0.1.0 |
|
|
152
|
+
| **`title`** | <code>string</code> | The title of the button. | | 0.1.0 |
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
### Enums
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
#### ActionSheetButtonStyle
|
|
159
|
+
|
|
160
|
+
| Members | Value | Description | Since |
|
|
161
|
+
| ----------------- | -------------------------- | -------------------------------------------------------------------------------------------- | ----- |
|
|
162
|
+
| **`Cancel`** | <code>'CANCEL'</code> | A button that cancels the action sheet. It should be the last button in the `options` array. | 0.1.0 |
|
|
163
|
+
| **`Default`** | <code>'DEFAULT'</code> | A button with the default style. | 0.1.0 |
|
|
164
|
+
| **`Destructive`** | <code>'DESTRUCTIVE'</code> | A button that indicates a destructive action. | 0.1.0 |
|
|
165
|
+
|
|
166
|
+
</docgen-api>
|
|
167
|
+
|
|
168
|
+
## Migrating from `@capacitor/action-sheet`
|
|
169
|
+
|
|
170
|
+
This plugin is API-compatible with the official [`@capacitor/action-sheet`](https://github.com/ionic-team/capacitor-plugins/tree/main/action-sheet) plugin. The `ActionSheetButtonStyle` enum uses the same values (`DEFAULT`, `DESTRUCTIVE`, `CANCEL`), so no enum changes are required. The following differences apply:
|
|
171
|
+
|
|
172
|
+
| `@capacitor/action-sheet` | `@capawesome/capacitor-action-sheet` |
|
|
173
|
+
| ----------------------------------------------- | ------------------------------------------------------ |
|
|
174
|
+
| `showActions({ title, message, options })` | `showActions({ title, message, options, cancelable })` |
|
|
175
|
+
| `showActions(...) → { index }` | `showActions(...) → { index, canceled }` |
|
|
176
|
+
| `message` and button styles ignored on Android | `message` and button styles rendered on Android |
|
|
177
|
+
| `cancelable` not available | `cancelable` (default `true`) |
|
|
178
|
+
|
|
179
|
+
## Changelog
|
|
180
|
+
|
|
181
|
+
See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/action-sheet/CHANGELOG.md).
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
See [LICENSE](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/action-sheet/LICENSE).
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
|
|
4
|
+
androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.12.0'
|
|
5
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
|
|
6
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
buildscript {
|
|
10
|
+
repositories {
|
|
11
|
+
google()
|
|
12
|
+
mavenCentral()
|
|
13
|
+
}
|
|
14
|
+
dependencies {
|
|
15
|
+
classpath 'com.android.tools.build:gradle:8.13.0'
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
apply plugin: 'com.android.library'
|
|
20
|
+
|
|
21
|
+
android {
|
|
22
|
+
namespace = "io.capawesome.capacitorjs.plugins.actionsheet"
|
|
23
|
+
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
|
|
24
|
+
defaultConfig {
|
|
25
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
|
|
26
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
|
|
27
|
+
versionCode 1
|
|
28
|
+
versionName "1.0"
|
|
29
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
30
|
+
}
|
|
31
|
+
buildTypes {
|
|
32
|
+
release {
|
|
33
|
+
minifyEnabled false
|
|
34
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
lintOptions {
|
|
38
|
+
abortOnError = false
|
|
39
|
+
}
|
|
40
|
+
compileOptions {
|
|
41
|
+
sourceCompatibility JavaVersion.VERSION_21
|
|
42
|
+
targetCompatibility JavaVersion.VERSION_21
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
repositories {
|
|
47
|
+
google()
|
|
48
|
+
mavenCentral()
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
dependencies {
|
|
53
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
54
|
+
implementation project(':capacitor-android')
|
|
55
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
56
|
+
implementation "com.google.android.material:material:$androidxMaterialVersion"
|
|
57
|
+
testImplementation "junit:junit:$junitVersion"
|
|
58
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
59
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
60
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.actionsheet;
|
|
2
|
+
|
|
3
|
+
import android.app.Activity;
|
|
4
|
+
import android.content.Context;
|
|
5
|
+
import android.graphics.Color;
|
|
6
|
+
import android.graphics.Typeface;
|
|
7
|
+
import android.util.TypedValue;
|
|
8
|
+
import android.view.Gravity;
|
|
9
|
+
import android.view.View;
|
|
10
|
+
import android.widget.LinearLayout;
|
|
11
|
+
import android.widget.TextView;
|
|
12
|
+
import androidx.annotation.NonNull;
|
|
13
|
+
import androidx.core.widget.NestedScrollView;
|
|
14
|
+
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
|
15
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.options.ActionSheetButton;
|
|
16
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.options.ShowActionsOptions;
|
|
17
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.results.ShowActionsResult;
|
|
18
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.interfaces.NonEmptyResultCallback;
|
|
19
|
+
import java.util.List;
|
|
20
|
+
|
|
21
|
+
public class ActionSheet {
|
|
22
|
+
|
|
23
|
+
private static final int COLOR_DESTRUCTIVE = Color.parseColor("#B3261E");
|
|
24
|
+
private static final int COLOR_MESSAGE = Color.parseColor("#757575");
|
|
25
|
+
|
|
26
|
+
@NonNull
|
|
27
|
+
private final ActionSheetPlugin plugin;
|
|
28
|
+
|
|
29
|
+
public ActionSheet(@NonNull ActionSheetPlugin plugin) {
|
|
30
|
+
this.plugin = plugin;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public void showActions(@NonNull ShowActionsOptions options, @NonNull NonEmptyResultCallback<ShowActionsResult> callback) {
|
|
34
|
+
Activity activity = plugin.getActivity();
|
|
35
|
+
activity.runOnUiThread(() -> {
|
|
36
|
+
BottomSheetDialog dialog = new BottomSheetDialog(
|
|
37
|
+
activity,
|
|
38
|
+
com.google.android.material.R.style.Theme_MaterialComponents_DayNight_BottomSheetDialog
|
|
39
|
+
);
|
|
40
|
+
LinearLayout container = new LinearLayout(activity);
|
|
41
|
+
container.setOrientation(LinearLayout.VERTICAL);
|
|
42
|
+
int verticalPadding = dpToPx(activity, 8);
|
|
43
|
+
container.setPadding(0, verticalPadding, 0, verticalPadding);
|
|
44
|
+
|
|
45
|
+
if (options.getTitle() != null) {
|
|
46
|
+
container.addView(createHeaderView(activity, options.getTitle(), true));
|
|
47
|
+
}
|
|
48
|
+
if (options.getMessage() != null) {
|
|
49
|
+
container.addView(createHeaderView(activity, options.getMessage(), false));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
List<ActionSheetButton> buttons = options.getButtons();
|
|
53
|
+
int cancelIndex = -1;
|
|
54
|
+
for (int i = 0; i < buttons.size(); i++) {
|
|
55
|
+
ActionSheetButton button = buttons.get(i);
|
|
56
|
+
if (button.isCancel()) {
|
|
57
|
+
if (cancelIndex == -1) {
|
|
58
|
+
cancelIndex = i;
|
|
59
|
+
}
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
final int index = i;
|
|
63
|
+
TextView buttonView = createButtonView(activity, button.getTitle(), button.isDestructive());
|
|
64
|
+
buttonView.setOnClickListener(view -> {
|
|
65
|
+
callback.success(new ShowActionsResult(index, false));
|
|
66
|
+
dialog.dismiss();
|
|
67
|
+
});
|
|
68
|
+
container.addView(buttonView);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
final int resolvedCancelIndex = cancelIndex;
|
|
72
|
+
if (cancelIndex != -1) {
|
|
73
|
+
container.addView(createDividerView(activity));
|
|
74
|
+
TextView cancelButtonView = createButtonView(activity, buttons.get(cancelIndex).getTitle(), false);
|
|
75
|
+
cancelButtonView.setOnClickListener(view -> {
|
|
76
|
+
callback.success(new ShowActionsResult(resolvedCancelIndex, true));
|
|
77
|
+
dialog.dismiss();
|
|
78
|
+
});
|
|
79
|
+
container.addView(cancelButtonView);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
dialog.setCancelable(options.isCancelable());
|
|
83
|
+
dialog.setOnCancelListener(dialogInterface -> callback.success(new ShowActionsResult(resolvedCancelIndex, true)));
|
|
84
|
+
|
|
85
|
+
NestedScrollView scrollView = new NestedScrollView(activity);
|
|
86
|
+
scrollView.addView(container);
|
|
87
|
+
dialog.setContentView(scrollView);
|
|
88
|
+
dialog.show();
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@NonNull
|
|
93
|
+
private TextView createButtonView(@NonNull Context context, @NonNull String title, boolean destructive) {
|
|
94
|
+
TextView textView = new TextView(context);
|
|
95
|
+
textView.setText(title);
|
|
96
|
+
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
|
|
97
|
+
textView.setGravity(Gravity.CENTER_VERTICAL);
|
|
98
|
+
int horizontalPadding = dpToPx(context, 24);
|
|
99
|
+
int verticalPadding = dpToPx(context, 16);
|
|
100
|
+
textView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
|
101
|
+
if (destructive) {
|
|
102
|
+
textView.setTextColor(COLOR_DESTRUCTIVE);
|
|
103
|
+
}
|
|
104
|
+
TypedValue outValue = new TypedValue();
|
|
105
|
+
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
|
|
106
|
+
textView.setBackgroundResource(outValue.resourceId);
|
|
107
|
+
textView.setClickable(true);
|
|
108
|
+
textView.setFocusable(true);
|
|
109
|
+
return textView;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
@NonNull
|
|
113
|
+
private View createDividerView(@NonNull Context context) {
|
|
114
|
+
View divider = new View(context);
|
|
115
|
+
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, dpToPx(context, 1));
|
|
116
|
+
int margin = dpToPx(context, 8);
|
|
117
|
+
params.setMargins(0, margin, 0, margin);
|
|
118
|
+
divider.setLayoutParams(params);
|
|
119
|
+
divider.setBackgroundColor(Color.parseColor("#1F000000"));
|
|
120
|
+
return divider;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@NonNull
|
|
124
|
+
private TextView createHeaderView(@NonNull Context context, @NonNull String text, boolean isTitle) {
|
|
125
|
+
TextView textView = new TextView(context);
|
|
126
|
+
textView.setText(text);
|
|
127
|
+
int horizontalPadding = dpToPx(context, 24);
|
|
128
|
+
int verticalPadding = dpToPx(context, 8);
|
|
129
|
+
textView.setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding);
|
|
130
|
+
if (isTitle) {
|
|
131
|
+
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);
|
|
132
|
+
textView.setTypeface(Typeface.DEFAULT_BOLD);
|
|
133
|
+
} else {
|
|
134
|
+
textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 14);
|
|
135
|
+
textView.setTextColor(COLOR_MESSAGE);
|
|
136
|
+
}
|
|
137
|
+
return textView;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private int dpToPx(@NonNull Context context, int dp) {
|
|
141
|
+
float density = context.getResources().getDisplayMetrics().density;
|
|
142
|
+
return Math.round(dp * density);
|
|
143
|
+
}
|
|
144
|
+
}
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.actionsheet;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
import com.getcapacitor.Logger;
|
|
6
|
+
import com.getcapacitor.Plugin;
|
|
7
|
+
import com.getcapacitor.PluginCall;
|
|
8
|
+
import com.getcapacitor.PluginMethod;
|
|
9
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
10
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.CustomException;
|
|
11
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.options.ShowActionsOptions;
|
|
12
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.results.ShowActionsResult;
|
|
13
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.interfaces.NonEmptyResultCallback;
|
|
14
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.interfaces.Result;
|
|
15
|
+
|
|
16
|
+
@CapacitorPlugin(name = "ActionSheet")
|
|
17
|
+
public class ActionSheetPlugin extends Plugin {
|
|
18
|
+
|
|
19
|
+
public static final String ERROR_UNKNOWN_ERROR = "An unknown error has occurred.";
|
|
20
|
+
public static final String TAG = "ActionSheetPlugin";
|
|
21
|
+
|
|
22
|
+
private ActionSheet implementation;
|
|
23
|
+
|
|
24
|
+
@Override
|
|
25
|
+
public void load() {
|
|
26
|
+
super.load();
|
|
27
|
+
this.implementation = new ActionSheet(this);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@PluginMethod
|
|
31
|
+
public void showActions(PluginCall call) {
|
|
32
|
+
try {
|
|
33
|
+
ShowActionsOptions options = new ShowActionsOptions(call);
|
|
34
|
+
NonEmptyResultCallback<ShowActionsResult> callback = new NonEmptyResultCallback<>() {
|
|
35
|
+
@Override
|
|
36
|
+
public void success(@NonNull ShowActionsResult result) {
|
|
37
|
+
resolveCall(call, result);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
@Override
|
|
41
|
+
public void error(Exception exception) {
|
|
42
|
+
rejectCall(call, exception);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
implementation.showActions(options, callback);
|
|
46
|
+
} catch (Exception exception) {
|
|
47
|
+
rejectCall(call, exception);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private void rejectCall(@NonNull PluginCall call, @NonNull Exception exception) {
|
|
52
|
+
String message = exception.getMessage();
|
|
53
|
+
if (message == null) {
|
|
54
|
+
message = ERROR_UNKNOWN_ERROR;
|
|
55
|
+
}
|
|
56
|
+
String code = null;
|
|
57
|
+
if (exception instanceof CustomException) {
|
|
58
|
+
code = ((CustomException) exception).getCode();
|
|
59
|
+
}
|
|
60
|
+
Logger.error(TAG, message, exception);
|
|
61
|
+
call.reject(message, code);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private void resolveCall(@NonNull PluginCall call, @Nullable Result result) {
|
|
65
|
+
if (result == null) {
|
|
66
|
+
call.resolve();
|
|
67
|
+
} else {
|
|
68
|
+
call.resolve(result.toJSObject());
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.actionsheet.classes;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
|
|
6
|
+
public class CustomException extends Exception {
|
|
7
|
+
|
|
8
|
+
@Nullable
|
|
9
|
+
private final String code;
|
|
10
|
+
|
|
11
|
+
public CustomException(@Nullable String code, @NonNull String message) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.code = code;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@Nullable
|
|
17
|
+
public String getCode() {
|
|
18
|
+
return code;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.actionsheet.classes;
|
|
2
|
+
|
|
3
|
+
public class CustomExceptions {
|
|
4
|
+
|
|
5
|
+
public static final CustomException BUTTON_TITLE_MISSING = new CustomException(null, "each button must provide a title.");
|
|
6
|
+
public static final CustomException OPTIONS_EMPTY = new CustomException(null, "options must not be empty.");
|
|
7
|
+
public static final CustomException OPTIONS_MISSING = new CustomException(null, "options must be provided.");
|
|
8
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.actionsheet.classes.options;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.CustomExceptions;
|
|
5
|
+
import org.json.JSONObject;
|
|
6
|
+
|
|
7
|
+
public class ActionSheetButton {
|
|
8
|
+
|
|
9
|
+
public static final String STYLE_CANCEL = "CANCEL";
|
|
10
|
+
public static final String STYLE_DEFAULT = "DEFAULT";
|
|
11
|
+
public static final String STYLE_DESTRUCTIVE = "DESTRUCTIVE";
|
|
12
|
+
|
|
13
|
+
@NonNull
|
|
14
|
+
private final String style;
|
|
15
|
+
|
|
16
|
+
@NonNull
|
|
17
|
+
private final String title;
|
|
18
|
+
|
|
19
|
+
public ActionSheetButton(@NonNull JSONObject object) throws Exception {
|
|
20
|
+
String title = object.isNull("title") ? null : object.optString("title", null);
|
|
21
|
+
if (title == null) {
|
|
22
|
+
throw CustomExceptions.BUTTON_TITLE_MISSING;
|
|
23
|
+
}
|
|
24
|
+
this.title = title;
|
|
25
|
+
this.style = object.optString("style", STYLE_DEFAULT);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@NonNull
|
|
29
|
+
public String getStyle() {
|
|
30
|
+
return style;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@NonNull
|
|
34
|
+
public String getTitle() {
|
|
35
|
+
return title;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
public boolean isCancel() {
|
|
39
|
+
return style.equals(STYLE_CANCEL);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
public boolean isDestructive() {
|
|
43
|
+
return style.equals(STYLE_DESTRUCTIVE);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
package io.capawesome.capacitorjs.plugins.actionsheet.classes.options;
|
|
2
|
+
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
import androidx.annotation.Nullable;
|
|
5
|
+
import com.getcapacitor.JSArray;
|
|
6
|
+
import com.getcapacitor.PluginCall;
|
|
7
|
+
import io.capawesome.capacitorjs.plugins.actionsheet.classes.CustomExceptions;
|
|
8
|
+
import java.util.ArrayList;
|
|
9
|
+
import java.util.List;
|
|
10
|
+
import org.json.JSONObject;
|
|
11
|
+
|
|
12
|
+
public class ShowActionsOptions {
|
|
13
|
+
|
|
14
|
+
@NonNull
|
|
15
|
+
private final List<ActionSheetButton> buttons;
|
|
16
|
+
|
|
17
|
+
private final boolean cancelable;
|
|
18
|
+
|
|
19
|
+
@Nullable
|
|
20
|
+
private final String message;
|
|
21
|
+
|
|
22
|
+
@Nullable
|
|
23
|
+
private final String title;
|
|
24
|
+
|
|
25
|
+
public ShowActionsOptions(@NonNull PluginCall call) throws Exception {
|
|
26
|
+
JSArray optionsArray = call.getArray("options");
|
|
27
|
+
if (optionsArray == null) {
|
|
28
|
+
throw CustomExceptions.OPTIONS_MISSING;
|
|
29
|
+
}
|
|
30
|
+
List<ActionSheetButton> buttons = new ArrayList<>();
|
|
31
|
+
for (int i = 0; i < optionsArray.length(); i++) {
|
|
32
|
+
JSONObject object = optionsArray.getJSONObject(i);
|
|
33
|
+
buttons.add(new ActionSheetButton(object));
|
|
34
|
+
}
|
|
35
|
+
if (buttons.isEmpty()) {
|
|
36
|
+
throw CustomExceptions.OPTIONS_EMPTY;
|
|
37
|
+
}
|
|
38
|
+
this.buttons = buttons;
|
|
39
|
+
this.cancelable = call.getBoolean("cancelable", true);
|
|
40
|
+
this.message = call.getString("message");
|
|
41
|
+
this.title = call.getString("title");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
@NonNull
|
|
45
|
+
public List<ActionSheetButton> getButtons() {
|
|
46
|
+
return buttons;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@Nullable
|
|
50
|
+
public String getMessage() {
|
|
51
|
+
return message;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
@Nullable
|
|
55
|
+
public String getTitle() {
|
|
56
|
+
return title;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public boolean isCancelable() {
|
|
60
|
+
return cancelable;
|
|
61
|
+
}
|
|
62
|
+
}
|