@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.
Files changed (40) hide show
  1. package/CapawesomeCapacitorActionSheet.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +185 -0
  5. package/android/build.gradle +60 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/ActionSheet.java +144 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/ActionSheetPlugin.java +71 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/CustomException.java +20 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/CustomExceptions.java +8 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/options/ActionSheetButton.java +45 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/options/ShowActionsOptions.java +62 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/classes/results/ShowActionsResult.java +25 -0
  14. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/interfaces/Callback.java +5 -0
  15. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/interfaces/NonEmptyResultCallback.java +7 -0
  16. package/android/src/main/java/io/capawesome/capacitorjs/plugins/actionsheet/interfaces/Result.java +7 -0
  17. package/android/src/main/res/.gitkeep +0 -0
  18. package/dist/docs.json +258 -0
  19. package/dist/esm/definitions.d.ts +116 -0
  20. package/dist/esm/definitions.js +29 -0
  21. package/dist/esm/definitions.js.map +1 -0
  22. package/dist/esm/index.d.ts +4 -0
  23. package/dist/esm/index.js +7 -0
  24. package/dist/esm/index.js.map +1 -0
  25. package/dist/esm/web.d.ts +5 -0
  26. package/dist/esm/web.js +7 -0
  27. package/dist/esm/web.js.map +1 -0
  28. package/dist/plugin.cjs.js +50 -0
  29. package/dist/plugin.cjs.js.map +1 -0
  30. package/dist/plugin.js +53 -0
  31. package/dist/plugin.js.map +1 -0
  32. package/ios/Plugin/ActionSheet.swift +59 -0
  33. package/ios/Plugin/ActionSheetPlugin.swift +47 -0
  34. package/ios/Plugin/Classes/Options/ActionSheetButton.swift +19 -0
  35. package/ios/Plugin/Classes/Options/ShowActionsOptions.swift +23 -0
  36. package/ios/Plugin/Classes/Results/ShowActionsResult.swift +19 -0
  37. package/ios/Plugin/Enums/CustomError.swift +31 -0
  38. package/ios/Plugin/Info.plist +24 -0
  39. package/ios/Plugin/Protocols/Result.swift +5 -0
  40. 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&lt;<a href="#showactionsresult">ShowActionsResult</a>&gt;</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,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -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
+ }
@@ -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
+ }