@capawesome/capacitor-shake 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 (34) hide show
  1. package/CapawesomeCapacitorShake.podspec +17 -0
  2. package/LICENSE +21 -0
  3. package/Package.swift +28 -0
  4. package/README.md +204 -0
  5. package/android/build.gradle +58 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/Shake.java +80 -0
  8. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/ShakePlugin.java +97 -0
  9. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/CustomException.java +20 -0
  10. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/CustomExceptions.java +9 -0
  11. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/interfaces/Callback.java +5 -0
  12. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/interfaces/EmptyCallback.java +5 -0
  13. package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/options/StartWatchingOptions.java +40 -0
  14. package/android/src/main/res/.gitkeep +0 -0
  15. package/dist/docs.json +174 -0
  16. package/dist/esm/definitions.d.ts +57 -0
  17. package/dist/esm/definitions.js +2 -0
  18. package/dist/esm/definitions.js.map +1 -0
  19. package/dist/esm/index.d.ts +4 -0
  20. package/dist/esm/index.js +7 -0
  21. package/dist/esm/index.js.map +1 -0
  22. package/dist/esm/web.d.ts +6 -0
  23. package/dist/esm/web.js +10 -0
  24. package/dist/esm/web.js.map +1 -0
  25. package/dist/plugin.cjs.js +24 -0
  26. package/dist/plugin.cjs.js.map +1 -0
  27. package/dist/plugin.js +27 -0
  28. package/dist/plugin.js.map +1 -0
  29. package/ios/Plugin/Classes/Options/StartWatchingOptions.swift +32 -0
  30. package/ios/Plugin/Enums/CustomError.swift +21 -0
  31. package/ios/Plugin/Info.plist +24 -0
  32. package/ios/Plugin/Shake.swift +60 -0
  33. package/ios/Plugin/ShakePlugin.swift +67 -0
  34. package/package.json +91 -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 = 'CapawesomeCapacitorShake'
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: "CapawesomeCapacitorShake",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "CapawesomeCapacitorShake",
10
+ targets: ["ShakePlugin"])
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: "ShakePlugin",
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: "ShakePluginTests",
25
+ dependencies: ["ShakePlugin"],
26
+ path: "ios/PluginTests")
27
+ ]
28
+ )
package/README.md ADDED
@@ -0,0 +1,204 @@
1
+ # @capawesome/capacitor-shake
2
+
3
+ Capacitor plugin to detect shake gestures.
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
+ - 📳 **Shake detection**: Detect physical shake gestures on the device.
14
+ - 🎚️ **Sensitivity**: Configure how strong a shake must be to trigger an event.
15
+ - 🔋 **Battery-friendly**: The sensor is only active while you are watching for shakes.
16
+ - 📱 **Cross-platform**: One consistent API for Android and iOS.
17
+ - 🔁 **Up-to-date**: Always supports the latest Capacitor version.
18
+
19
+ Missing a feature? Just [open an issue](https://github.com/capawesome-team/capacitor-plugins/issues) and we'll take a look!
20
+
21
+ ## Newsletter
22
+
23
+ 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/).
24
+
25
+ ## Compatibility
26
+
27
+ | Plugin Version | Capacitor Version | Status |
28
+ | -------------- | ----------------- | -------------- |
29
+ | 0.x.x | >=8.x.x | Active support |
30
+
31
+ ## Installation
32
+
33
+ You can use our **AI-Assisted Setup** to install the plugin.
34
+ Add the [Capawesome Skills](https://github.com/capawesome-team/skills) to your AI tool using the following command:
35
+
36
+ ```bash
37
+ npx skills add capawesome-team/skills --skill capacitor-plugins
38
+ ```
39
+
40
+ Then use the following prompt:
41
+
42
+ ```
43
+ Use the `capacitor-plugins` skill from `capawesome-team/skills` to install the `@capawesome/capacitor-shake` plugin in my project.
44
+ ```
45
+
46
+ If you prefer **Manual Setup**, install the plugin by running the following command:
47
+
48
+ ```bash
49
+ npm install @capawesome/capacitor-shake
50
+ npx cap sync
51
+ ```
52
+
53
+ This plugin is available on **Android** and **iOS**. On Web, all methods reject as unimplemented.
54
+
55
+ No additional permissions or privacy descriptions are required.
56
+
57
+ ## Configuration
58
+
59
+ No configuration required for this plugin.
60
+
61
+ ## Usage
62
+
63
+ ```typescript
64
+ import { Shake } from '@capawesome/capacitor-shake';
65
+
66
+ const startWatching = async () => {
67
+ await Shake.addListener('shake', () => {
68
+ console.log('Shake detected!');
69
+ });
70
+ await Shake.startWatching({ sensitivity: 'medium' });
71
+ };
72
+
73
+ const stopWatching = async () => {
74
+ await Shake.stopWatching();
75
+ await Shake.removeAllListeners();
76
+ };
77
+ ```
78
+
79
+ ## API
80
+
81
+ <docgen-index>
82
+
83
+ * [`addListener('shake', ...)`](#addlistenershake-)
84
+ * [`removeAllListeners()`](#removealllisteners)
85
+ * [`startWatching(...)`](#startwatching)
86
+ * [`stopWatching()`](#stopwatching)
87
+ * [Interfaces](#interfaces)
88
+ * [Type Aliases](#type-aliases)
89
+
90
+ </docgen-index>
91
+
92
+ <docgen-api>
93
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
94
+
95
+ ### addListener('shake', ...)
96
+
97
+ ```typescript
98
+ addListener(eventName: 'shake', listenerFunc: () => void) => Promise<PluginListenerHandle>
99
+ ```
100
+
101
+ Called when a shake gesture is detected.
102
+
103
+ Only available on Android and iOS.
104
+
105
+ | Param | Type |
106
+ | ------------------ | -------------------------- |
107
+ | **`eventName`** | <code>'shake'</code> |
108
+ | **`listenerFunc`** | <code>() =&gt; void</code> |
109
+
110
+ **Returns:** <code>Promise&lt;<a href="#pluginlistenerhandle">PluginListenerHandle</a>&gt;</code>
111
+
112
+ **Since:** 0.1.0
113
+
114
+ --------------------
115
+
116
+
117
+ ### removeAllListeners()
118
+
119
+ ```typescript
120
+ removeAllListeners() => Promise<void>
121
+ ```
122
+
123
+ Remove all listeners for this plugin.
124
+
125
+ **Since:** 0.1.0
126
+
127
+ --------------------
128
+
129
+
130
+ ### startWatching(...)
131
+
132
+ ```typescript
133
+ startWatching(options?: StartWatchingOptions | undefined) => Promise<void>
134
+ ```
135
+
136
+ Start watching for shake gestures.
137
+
138
+ Only available on Android and iOS.
139
+
140
+ | Param | Type |
141
+ | ------------- | --------------------------------------------------------------------- |
142
+ | **`options`** | <code><a href="#startwatchingoptions">StartWatchingOptions</a></code> |
143
+
144
+ **Since:** 0.1.0
145
+
146
+ --------------------
147
+
148
+
149
+ ### stopWatching()
150
+
151
+ ```typescript
152
+ stopWatching() => Promise<void>
153
+ ```
154
+
155
+ Stop watching for shake gestures.
156
+
157
+ Only available on Android and iOS.
158
+
159
+ **Since:** 0.1.0
160
+
161
+ --------------------
162
+
163
+
164
+ ### Interfaces
165
+
166
+
167
+ #### PluginListenerHandle
168
+
169
+ | Prop | Type |
170
+ | ------------ | ----------------------------------------- |
171
+ | **`remove`** | <code>() =&gt; Promise&lt;void&gt;</code> |
172
+
173
+
174
+ #### StartWatchingOptions
175
+
176
+ | Prop | Type | Description | Default | Since |
177
+ | ----------------- | --------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------- | ----- |
178
+ | **`sensitivity`** | <code><a href="#sensitivity">Sensitivity</a></code> | The sensitivity of the shake detection. Use `'light'` to detect gentle shakes and `'hard'` to only detect strong shakes. Only available on Android and iOS. | <code>'medium'</code> | 0.1.0 |
179
+
180
+
181
+ ### Type Aliases
182
+
183
+
184
+ #### Sensitivity
185
+
186
+ <code>'hard' | 'light' | 'medium'</code>
187
+
188
+ </docgen-api>
189
+
190
+ ## Sensitivity Levels
191
+
192
+ The `sensitivity` option controls how strong a shake must be to emit a `shake` event:
193
+
194
+ - `light`: A gentle shake is enough to trigger an event.
195
+ - `medium`: A moderate shake is required to trigger an event (default).
196
+ - `hard`: Only a strong shake triggers an event.
197
+
198
+ ## Changelog
199
+
200
+ See [CHANGELOG.md](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/shake/CHANGELOG.md).
201
+
202
+ ## License
203
+
204
+ See [LICENSE](https://github.com/capawesome-team/capacitor-plugins/blob/main/packages/shake/LICENSE).
@@ -0,0 +1,58 @@
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
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
6
+ }
7
+
8
+ buildscript {
9
+ repositories {
10
+ google()
11
+ mavenCentral()
12
+ }
13
+ dependencies {
14
+ classpath 'com.android.tools.build:gradle:8.13.0'
15
+ }
16
+ }
17
+
18
+ apply plugin: 'com.android.library'
19
+
20
+ android {
21
+ namespace = "io.capawesome.capacitorjs.plugins.shake"
22
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
23
+ defaultConfig {
24
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
25
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
26
+ versionCode 1
27
+ versionName "1.0"
28
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
29
+ }
30
+ buildTypes {
31
+ release {
32
+ minifyEnabled false
33
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
34
+ }
35
+ }
36
+ lintOptions {
37
+ abortOnError = false
38
+ }
39
+ compileOptions {
40
+ sourceCompatibility JavaVersion.VERSION_21
41
+ targetCompatibility JavaVersion.VERSION_21
42
+ }
43
+ }
44
+
45
+ repositories {
46
+ google()
47
+ mavenCentral()
48
+ }
49
+
50
+
51
+ dependencies {
52
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
53
+ implementation project(':capacitor-android')
54
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
55
+ testImplementation "junit:junit:$junitVersion"
56
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
57
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
58
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,80 @@
1
+ package io.capawesome.capacitorjs.plugins.shake;
2
+
3
+ import android.content.Context;
4
+ import android.hardware.Sensor;
5
+ import android.hardware.SensorEvent;
6
+ import android.hardware.SensorEventListener;
7
+ import android.hardware.SensorManager;
8
+ import androidx.annotation.NonNull;
9
+ import androidx.annotation.Nullable;
10
+ import io.capawesome.capacitorjs.plugins.shake.classes.interfaces.EmptyCallback;
11
+ import io.capawesome.capacitorjs.plugins.shake.classes.options.StartWatchingOptions;
12
+
13
+ public class Shake implements SensorEventListener {
14
+
15
+ @NonNull
16
+ private final ShakePlugin plugin;
17
+
18
+ @Nullable
19
+ private final Sensor accelerometerSensor;
20
+
21
+ private long lastShakeTimestamp = 0;
22
+
23
+ @NonNull
24
+ private final SensorManager sensorManager;
25
+
26
+ private static final long SHAKE_DEBOUNCE_IN_MILLISECONDS = 500;
27
+
28
+ private float shakeThreshold = 0;
29
+
30
+ private boolean watching = false;
31
+
32
+ public Shake(@NonNull ShakePlugin plugin) {
33
+ this.plugin = plugin;
34
+ this.sensorManager = (SensorManager) plugin.getContext().getSystemService(Context.SENSOR_SERVICE);
35
+ this.accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
36
+ }
37
+
38
+ public boolean isAvailable() {
39
+ return accelerometerSensor != null;
40
+ }
41
+
42
+ @Override
43
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {}
44
+
45
+ @Override
46
+ public void onSensorChanged(SensorEvent event) {
47
+ double gX = event.values[0] / SensorManager.GRAVITY_EARTH;
48
+ double gY = event.values[1] / SensorManager.GRAVITY_EARTH;
49
+ double gZ = event.values[2] / SensorManager.GRAVITY_EARTH;
50
+ double gForce = Math.sqrt(gX * gX + gY * gY + gZ * gZ);
51
+ if (gForce < shakeThreshold) {
52
+ return;
53
+ }
54
+ long now = System.currentTimeMillis();
55
+ if (now - lastShakeTimestamp < SHAKE_DEBOUNCE_IN_MILLISECONDS) {
56
+ return;
57
+ }
58
+ lastShakeTimestamp = now;
59
+ plugin.notifyShakeListeners();
60
+ }
61
+
62
+ public void startWatching(@NonNull StartWatchingOptions options, @NonNull EmptyCallback callback) {
63
+ shakeThreshold = options.getShakeThreshold();
64
+ if (!watching) {
65
+ sensorManager.registerListener(this, accelerometerSensor, SensorManager.SENSOR_DELAY_GAME);
66
+ watching = true;
67
+ }
68
+ callback.success();
69
+ }
70
+
71
+ public void stopWatching(@Nullable EmptyCallback callback) {
72
+ if (watching) {
73
+ sensorManager.unregisterListener(this);
74
+ watching = false;
75
+ }
76
+ if (callback != null) {
77
+ callback.success();
78
+ }
79
+ }
80
+ }
@@ -0,0 +1,97 @@
1
+ package io.capawesome.capacitorjs.plugins.shake;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import com.getcapacitor.JSObject;
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.shake.classes.interfaces.EmptyCallback;
11
+ import io.capawesome.capacitorjs.plugins.shake.classes.options.StartWatchingOptions;
12
+
13
+ @CapacitorPlugin(name = "Shake")
14
+ public class ShakePlugin extends Plugin {
15
+
16
+ public static final String ERROR_UNKNOWN_ERROR = "An unknown error occurred.";
17
+ public static final String EVENT_SHAKE = "shake";
18
+ public static final String TAG = "ShakePlugin";
19
+
20
+ private Shake implementation;
21
+
22
+ @Override
23
+ public void load() {
24
+ implementation = new Shake(this);
25
+ }
26
+
27
+ public void notifyShakeListeners() {
28
+ notifyListeners(EVENT_SHAKE, new JSObject());
29
+ }
30
+
31
+ @PluginMethod
32
+ public void startWatching(PluginCall call) {
33
+ try {
34
+ StartWatchingOptions options = new StartWatchingOptions(call);
35
+ if (!implementation.isAvailable()) {
36
+ rejectCallAsUnavailable(call);
37
+ return;
38
+ }
39
+ EmptyCallback callback = new EmptyCallback() {
40
+ @Override
41
+ public void success() {
42
+ resolveCall(call);
43
+ }
44
+
45
+ @Override
46
+ public void error(@NonNull Exception exception) {
47
+ rejectCall(call, exception);
48
+ }
49
+ };
50
+ implementation.startWatching(options, callback);
51
+ } catch (Exception exception) {
52
+ rejectCall(call, exception);
53
+ }
54
+ }
55
+
56
+ @PluginMethod
57
+ public void stopWatching(PluginCall call) {
58
+ try {
59
+ EmptyCallback callback = new EmptyCallback() {
60
+ @Override
61
+ public void success() {
62
+ resolveCall(call);
63
+ }
64
+
65
+ @Override
66
+ public void error(@NonNull Exception exception) {
67
+ rejectCall(call, exception);
68
+ }
69
+ };
70
+ implementation.stopWatching(callback);
71
+ } catch (Exception exception) {
72
+ rejectCall(call, exception);
73
+ }
74
+ }
75
+
76
+ @Override
77
+ protected void handleOnDestroy() {
78
+ implementation.stopWatching(null);
79
+ }
80
+
81
+ private void rejectCall(@NonNull PluginCall call, @NonNull Exception exception) {
82
+ String message = exception.getMessage();
83
+ if (message == null) {
84
+ message = ERROR_UNKNOWN_ERROR;
85
+ }
86
+ Logger.error(TAG, message, exception);
87
+ call.reject(message);
88
+ }
89
+
90
+ private void rejectCallAsUnavailable(@NonNull PluginCall call) {
91
+ call.unavailable("This method is not available on this platform.");
92
+ }
93
+
94
+ private void resolveCall(@NonNull PluginCall call) {
95
+ call.resolve();
96
+ }
97
+ }
@@ -0,0 +1,20 @@
1
+ package io.capawesome.capacitorjs.plugins.shake.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,9 @@
1
+ package io.capawesome.capacitorjs.plugins.shake.classes;
2
+
3
+ public class CustomExceptions {
4
+
5
+ public static final CustomException INVALID_SENSITIVITY = new CustomException(
6
+ null,
7
+ "sensitivity must be one of 'light', 'medium' or 'hard'."
8
+ );
9
+ }
@@ -0,0 +1,5 @@
1
+ package io.capawesome.capacitorjs.plugins.shake.classes.interfaces;
2
+
3
+ public interface Callback {
4
+ void error(Exception exception);
5
+ }
@@ -0,0 +1,5 @@
1
+ package io.capawesome.capacitorjs.plugins.shake.classes.interfaces;
2
+
3
+ public interface EmptyCallback extends Callback {
4
+ void success();
5
+ }
@@ -0,0 +1,40 @@
1
+ package io.capawesome.capacitorjs.plugins.shake.classes.options;
2
+
3
+ import androidx.annotation.NonNull;
4
+ import com.getcapacitor.PluginCall;
5
+ import io.capawesome.capacitorjs.plugins.shake.classes.CustomExceptions;
6
+
7
+ public class StartWatchingOptions {
8
+
9
+ public static final String SENSITIVITY_HARD = "hard";
10
+ public static final String SENSITIVITY_LIGHT = "light";
11
+ public static final String SENSITIVITY_MEDIUM = "medium";
12
+
13
+ private static final float SHAKE_THRESHOLD_HARD = 3.4f;
14
+ private static final float SHAKE_THRESHOLD_LIGHT = 2.3f;
15
+ private static final float SHAKE_THRESHOLD_MEDIUM = 2.7f;
16
+
17
+ private final float shakeThreshold;
18
+
19
+ public StartWatchingOptions(@NonNull PluginCall call) throws Exception {
20
+ String sensitivity = call.getString("sensitivity", SENSITIVITY_MEDIUM);
21
+ this.shakeThreshold = StartWatchingOptions.getShakeThresholdForSensitivity(sensitivity);
22
+ }
23
+
24
+ public float getShakeThreshold() {
25
+ return shakeThreshold;
26
+ }
27
+
28
+ private static float getShakeThresholdForSensitivity(@NonNull String sensitivity) throws Exception {
29
+ switch (sensitivity) {
30
+ case SENSITIVITY_HARD:
31
+ return SHAKE_THRESHOLD_HARD;
32
+ case SENSITIVITY_LIGHT:
33
+ return SHAKE_THRESHOLD_LIGHT;
34
+ case SENSITIVITY_MEDIUM:
35
+ return SHAKE_THRESHOLD_MEDIUM;
36
+ default:
37
+ throw CustomExceptions.INVALID_SENSITIVITY;
38
+ }
39
+ }
40
+ }
File without changes
package/dist/docs.json ADDED
@@ -0,0 +1,174 @@
1
+ {
2
+ "api": {
3
+ "name": "ShakePlugin",
4
+ "slug": "shakeplugin",
5
+ "docs": "",
6
+ "tags": [
7
+ {
8
+ "text": "0.1.0",
9
+ "name": "since"
10
+ }
11
+ ],
12
+ "methods": [
13
+ {
14
+ "name": "addListener",
15
+ "signature": "(eventName: 'shake', listenerFunc: () => void) => Promise<PluginListenerHandle>",
16
+ "parameters": [
17
+ {
18
+ "name": "eventName",
19
+ "docs": "",
20
+ "type": "'shake'"
21
+ },
22
+ {
23
+ "name": "listenerFunc",
24
+ "docs": "",
25
+ "type": "() => void"
26
+ }
27
+ ],
28
+ "returns": "Promise<PluginListenerHandle>",
29
+ "tags": [
30
+ {
31
+ "name": "since",
32
+ "text": "0.1.0"
33
+ }
34
+ ],
35
+ "docs": "Called when a shake gesture is detected.\n\nOnly available on Android and iOS.",
36
+ "complexTypes": [
37
+ "PluginListenerHandle"
38
+ ],
39
+ "slug": "addlistenershake-"
40
+ },
41
+ {
42
+ "name": "removeAllListeners",
43
+ "signature": "() => Promise<void>",
44
+ "parameters": [],
45
+ "returns": "Promise<void>",
46
+ "tags": [
47
+ {
48
+ "name": "since",
49
+ "text": "0.1.0"
50
+ }
51
+ ],
52
+ "docs": "Remove all listeners for this plugin.",
53
+ "complexTypes": [],
54
+ "slug": "removealllisteners"
55
+ },
56
+ {
57
+ "name": "startWatching",
58
+ "signature": "(options?: StartWatchingOptions | undefined) => Promise<void>",
59
+ "parameters": [
60
+ {
61
+ "name": "options",
62
+ "docs": "",
63
+ "type": "StartWatchingOptions | undefined"
64
+ }
65
+ ],
66
+ "returns": "Promise<void>",
67
+ "tags": [
68
+ {
69
+ "name": "since",
70
+ "text": "0.1.0"
71
+ }
72
+ ],
73
+ "docs": "Start watching for shake gestures.\n\nOnly available on Android and iOS.",
74
+ "complexTypes": [
75
+ "StartWatchingOptions"
76
+ ],
77
+ "slug": "startwatching"
78
+ },
79
+ {
80
+ "name": "stopWatching",
81
+ "signature": "() => Promise<void>",
82
+ "parameters": [],
83
+ "returns": "Promise<void>",
84
+ "tags": [
85
+ {
86
+ "name": "since",
87
+ "text": "0.1.0"
88
+ }
89
+ ],
90
+ "docs": "Stop watching for shake gestures.\n\nOnly available on Android and iOS.",
91
+ "complexTypes": [],
92
+ "slug": "stopwatching"
93
+ }
94
+ ],
95
+ "properties": []
96
+ },
97
+ "interfaces": [
98
+ {
99
+ "name": "PluginListenerHandle",
100
+ "slug": "pluginlistenerhandle",
101
+ "docs": "",
102
+ "tags": [],
103
+ "methods": [],
104
+ "properties": [
105
+ {
106
+ "name": "remove",
107
+ "tags": [],
108
+ "docs": "",
109
+ "complexTypes": [],
110
+ "type": "() => Promise<void>"
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ "name": "StartWatchingOptions",
116
+ "slug": "startwatchingoptions",
117
+ "docs": "",
118
+ "tags": [
119
+ {
120
+ "text": "0.1.0",
121
+ "name": "since"
122
+ }
123
+ ],
124
+ "methods": [],
125
+ "properties": [
126
+ {
127
+ "name": "sensitivity",
128
+ "tags": [
129
+ {
130
+ "text": "0.1.0",
131
+ "name": "since"
132
+ },
133
+ {
134
+ "text": "'medium'",
135
+ "name": "default"
136
+ },
137
+ {
138
+ "text": "'medium'",
139
+ "name": "example"
140
+ }
141
+ ],
142
+ "docs": "The sensitivity of the shake detection.\n\nUse `'light'` to detect gentle shakes and `'hard'` to only detect strong shakes.\n\nOnly available on Android and iOS.",
143
+ "complexTypes": [
144
+ "Sensitivity"
145
+ ],
146
+ "type": "Sensitivity"
147
+ }
148
+ ]
149
+ }
150
+ ],
151
+ "enums": [],
152
+ "typeAliases": [
153
+ {
154
+ "name": "Sensitivity",
155
+ "slug": "sensitivity",
156
+ "docs": "",
157
+ "types": [
158
+ {
159
+ "text": "'hard'",
160
+ "complexTypes": []
161
+ },
162
+ {
163
+ "text": "'light'",
164
+ "complexTypes": []
165
+ },
166
+ {
167
+ "text": "'medium'",
168
+ "complexTypes": []
169
+ }
170
+ ]
171
+ }
172
+ ],
173
+ "pluginConfigs": []
174
+ }
@@ -0,0 +1,57 @@
1
+ import type { PluginListenerHandle } from '@capacitor/core';
2
+ /**
3
+ * @since 0.1.0
4
+ */
5
+ export interface ShakePlugin {
6
+ /**
7
+ * Called when a shake gesture is detected.
8
+ *
9
+ * Only available on Android and iOS.
10
+ *
11
+ * @since 0.1.0
12
+ */
13
+ addListener(eventName: 'shake', listenerFunc: () => void): Promise<PluginListenerHandle>;
14
+ /**
15
+ * Remove all listeners for this plugin.
16
+ *
17
+ * @since 0.1.0
18
+ */
19
+ removeAllListeners(): Promise<void>;
20
+ /**
21
+ * Start watching for shake gestures.
22
+ *
23
+ * Only available on Android and iOS.
24
+ *
25
+ * @since 0.1.0
26
+ */
27
+ startWatching(options?: StartWatchingOptions): Promise<void>;
28
+ /**
29
+ * Stop watching for shake gestures.
30
+ *
31
+ * Only available on Android and iOS.
32
+ *
33
+ * @since 0.1.0
34
+ */
35
+ stopWatching(): Promise<void>;
36
+ }
37
+ /**
38
+ * @since 0.1.0
39
+ */
40
+ export interface StartWatchingOptions {
41
+ /**
42
+ * The sensitivity of the shake detection.
43
+ *
44
+ * Use `'light'` to detect gentle shakes and `'hard'` to only detect strong shakes.
45
+ *
46
+ * Only available on Android and iOS.
47
+ *
48
+ * @since 0.1.0
49
+ * @default 'medium'
50
+ * @example 'medium'
51
+ */
52
+ sensitivity?: Sensitivity;
53
+ }
54
+ /**
55
+ * @since 0.1.0
56
+ */
57
+ export type Sensitivity = 'hard' | 'light' | 'medium';
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * @since 0.1.0\n */\nexport interface ShakePlugin {\n /**\n * Called when a shake gesture is detected.\n *\n * Only available on Android and iOS.\n *\n * @since 0.1.0\n */\n addListener(\n eventName: 'shake',\n listenerFunc: () => void,\n ): Promise<PluginListenerHandle>;\n /**\n * Remove all listeners for this plugin.\n *\n * @since 0.1.0\n */\n removeAllListeners(): Promise<void>;\n /**\n * Start watching for shake gestures.\n *\n * Only available on Android and iOS.\n *\n * @since 0.1.0\n */\n startWatching(options?: StartWatchingOptions): Promise<void>;\n /**\n * Stop watching for shake gestures.\n *\n * Only available on Android and iOS.\n *\n * @since 0.1.0\n */\n stopWatching(): Promise<void>;\n}\n\n/**\n * @since 0.1.0\n */\nexport interface StartWatchingOptions {\n /**\n * The sensitivity of the shake detection.\n *\n * Use `'light'` to detect gentle shakes and `'hard'` to only detect strong shakes.\n *\n * Only available on Android and iOS.\n *\n * @since 0.1.0\n * @default 'medium'\n * @example 'medium'\n */\n sensitivity?: Sensitivity;\n}\n\n/**\n * @since 0.1.0\n */\nexport type Sensitivity = 'hard' | 'light' | 'medium';\n"]}
@@ -0,0 +1,4 @@
1
+ import type { ShakePlugin } from './definitions';
2
+ declare const Shake: ShakePlugin;
3
+ export * from './definitions';
4
+ export { Shake };
@@ -0,0 +1,7 @@
1
+ import { registerPlugin } from '@capacitor/core';
2
+ const Shake = registerPlugin('Shake', {
3
+ web: () => import('./web').then(m => new m.ShakeWeb()),
4
+ });
5
+ export * from './definitions';
6
+ export { Shake };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,KAAK,GAAG,cAAc,CAAc,OAAO,EAAE;IACjD,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;CACvD,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { ShakePlugin } from './definitions';\n\nconst Shake = registerPlugin<ShakePlugin>('Shake', {\n web: () => import('./web').then(m => new m.ShakeWeb()),\n});\n\nexport * from './definitions';\nexport { Shake };\n"]}
@@ -0,0 +1,6 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ import type { ShakePlugin } from './definitions';
3
+ export declare class ShakeWeb extends WebPlugin implements ShakePlugin {
4
+ startWatching(): Promise<void>;
5
+ stopWatching(): Promise<void>;
6
+ }
@@ -0,0 +1,10 @@
1
+ import { WebPlugin } from '@capacitor/core';
2
+ export class ShakeWeb extends WebPlugin {
3
+ async startWatching() {
4
+ throw this.unimplemented('Not implemented on web.');
5
+ }
6
+ async stopWatching() {
7
+ throw this.unimplemented('Not implemented on web.');
8
+ }
9
+ }
10
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,QAAS,SAAQ,SAAS;IACrC,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;IACtD,CAAC;IAED,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC,CAAC;IACtD,CAAC;CACF","sourcesContent":["import { WebPlugin } from '@capacitor/core';\n\nimport type { ShakePlugin } from './definitions';\n\nexport class ShakeWeb extends WebPlugin implements ShakePlugin {\n async startWatching(): Promise<void> {\n throw this.unimplemented('Not implemented on web.');\n }\n\n async stopWatching(): Promise<void> {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n"]}
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ var core = require('@capacitor/core');
4
+
5
+ const Shake = core.registerPlugin('Shake', {
6
+ web: () => Promise.resolve().then(function () { return web; }).then(m => new m.ShakeWeb()),
7
+ });
8
+
9
+ class ShakeWeb extends core.WebPlugin {
10
+ async startWatching() {
11
+ throw this.unimplemented('Not implemented on web.');
12
+ }
13
+ async stopWatching() {
14
+ throw this.unimplemented('Not implemented on web.');
15
+ }
16
+ }
17
+
18
+ var web = /*#__PURE__*/Object.freeze({
19
+ __proto__: null,
20
+ ShakeWeb: ShakeWeb
21
+ });
22
+
23
+ exports.Shake = Shake;
24
+ //# sourceMappingURL=plugin.cjs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Shake = registerPlugin('Shake', {\n web: () => import('./web').then(m => new m.ShakeWeb()),\n});\nexport * from './definitions';\nexport { Shake };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ShakeWeb extends WebPlugin {\n async startWatching() {\n throw this.unimplemented('Not implemented on web.');\n }\n async stopWatching() {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;AACK,MAAC,KAAK,GAAGA,mBAAc,CAAC,OAAO,EAAE;AACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC1D,CAAC;;ACFM,MAAM,QAAQ,SAASC,cAAS,CAAC;AACxC,IAAI,MAAM,aAAa,GAAG;AAC1B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;AAC3D,IAAI;AACJ,IAAI,MAAM,YAAY,GAAG;AACzB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;AAC3D,IAAI;AACJ;;;;;;;;;"}
package/dist/plugin.js ADDED
@@ -0,0 +1,27 @@
1
+ var capacitorShake = (function (exports, core) {
2
+ 'use strict';
3
+
4
+ const Shake = core.registerPlugin('Shake', {
5
+ web: () => Promise.resolve().then(function () { return web; }).then(m => new m.ShakeWeb()),
6
+ });
7
+
8
+ class ShakeWeb extends core.WebPlugin {
9
+ async startWatching() {
10
+ throw this.unimplemented('Not implemented on web.');
11
+ }
12
+ async stopWatching() {
13
+ throw this.unimplemented('Not implemented on web.');
14
+ }
15
+ }
16
+
17
+ var web = /*#__PURE__*/Object.freeze({
18
+ __proto__: null,
19
+ ShakeWeb: ShakeWeb
20
+ });
21
+
22
+ exports.Shake = Shake;
23
+
24
+ return exports;
25
+
26
+ })({}, capacitorExports);
27
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst Shake = registerPlugin('Shake', {\n web: () => import('./web').then(m => new m.ShakeWeb()),\n});\nexport * from './definitions';\nexport { Shake };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ShakeWeb extends WebPlugin {\n async startWatching() {\n throw this.unimplemented('Not implemented on web.');\n }\n async stopWatching() {\n throw this.unimplemented('Not implemented on web.');\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,KAAK,GAAGA,mBAAc,CAAC,OAAO,EAAE;IACtC,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC1D,CAAC;;ICFM,MAAM,QAAQ,SAASC,cAAS,CAAC;IACxC,IAAI,MAAM,aAAa,GAAG;IAC1B,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ,IAAI,MAAM,YAAY,GAAG;IACzB,QAAQ,MAAM,IAAI,CAAC,aAAa,CAAC,yBAAyB,CAAC;IAC3D,IAAI;IACJ;;;;;;;;;;;;;;;"}
@@ -0,0 +1,32 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc public class StartWatchingOptions: NSObject {
5
+ private static let sensitivityHard = "hard"
6
+ private static let sensitivityLight = "light"
7
+ private static let sensitivityMedium = "medium"
8
+
9
+ private static let shakeThresholdHard = 3.4
10
+ private static let shakeThresholdLight = 2.3
11
+ private static let shakeThresholdMedium = 2.7
12
+
13
+ let shakeThreshold: Double
14
+
15
+ init(_ call: CAPPluginCall) throws {
16
+ let sensitivity = call.getString("sensitivity", StartWatchingOptions.sensitivityMedium)
17
+ self.shakeThreshold = try StartWatchingOptions.shakeThreshold(for: sensitivity)
18
+ }
19
+
20
+ private static func shakeThreshold(for sensitivity: String) throws -> Double {
21
+ switch sensitivity {
22
+ case sensitivityHard:
23
+ return shakeThresholdHard
24
+ case sensitivityLight:
25
+ return shakeThresholdLight
26
+ case sensitivityMedium:
27
+ return shakeThresholdMedium
28
+ default:
29
+ throw CustomError.invalidSensitivity
30
+ }
31
+ }
32
+ }
@@ -0,0 +1,21 @@
1
+ import Foundation
2
+
3
+ enum CustomError: Error {
4
+ case invalidSensitivity
5
+
6
+ var code: String? {
7
+ switch self {
8
+ case .invalidSensitivity:
9
+ return nil
10
+ }
11
+ }
12
+ }
13
+
14
+ extension CustomError: LocalizedError {
15
+ public var errorDescription: String? {
16
+ switch self {
17
+ case .invalidSensitivity:
18
+ return NSLocalizedString("sensitivity must be one of 'light', 'medium' or 'hard'.", comment: "invalidSensitivity")
19
+ }
20
+ }
21
+ }
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>CFBundleDevelopmentRegion</key>
6
+ <string>$(DEVELOPMENT_LANGUAGE)</string>
7
+ <key>CFBundleExecutable</key>
8
+ <string>$(EXECUTABLE_NAME)</string>
9
+ <key>CFBundleIdentifier</key>
10
+ <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11
+ <key>CFBundleInfoDictionaryVersion</key>
12
+ <string>6.0</string>
13
+ <key>CFBundleName</key>
14
+ <string>$(PRODUCT_NAME)</string>
15
+ <key>CFBundlePackageType</key>
16
+ <string>FMWK</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.0</string>
19
+ <key>CFBundleVersion</key>
20
+ <string>$(CURRENT_PROJECT_VERSION)</string>
21
+ <key>NSPrincipalClass</key>
22
+ <string></string>
23
+ </dict>
24
+ </plist>
@@ -0,0 +1,60 @@
1
+ import Foundation
2
+ import CoreMotion
3
+
4
+ @objc public class Shake: NSObject {
5
+ private let plugin: ShakePlugin
6
+ private var lastShakeTimestamp: TimeInterval = 0
7
+ private lazy var motionManager = CMMotionManager()
8
+ private let queue = OperationQueue()
9
+ private let shakeDebounceInterval: TimeInterval = 0.5
10
+ private var shakeThreshold: Double = 0
11
+ private let updateInterval: TimeInterval = 0.1
12
+ private var watching = false
13
+
14
+ init(plugin: ShakePlugin) {
15
+ self.plugin = plugin
16
+ }
17
+
18
+ @objc public func isAvailable() -> Bool {
19
+ return motionManager.isAccelerometerAvailable
20
+ }
21
+
22
+ @objc public func startWatching(_ options: StartWatchingOptions, completion: @escaping (_ error: Error?) -> Void) {
23
+ shakeThreshold = options.shakeThreshold
24
+ if watching {
25
+ completion(nil)
26
+ return
27
+ }
28
+ motionManager.accelerometerUpdateInterval = updateInterval
29
+ motionManager.startAccelerometerUpdates(to: queue) { [weak self] data, _ in
30
+ guard let self = self, let data = data else {
31
+ return
32
+ }
33
+ self.handleAccelerometerData(data)
34
+ }
35
+ watching = true
36
+ completion(nil)
37
+ }
38
+
39
+ @objc public func stopWatching(completion: ((_ error: Error?) -> Void)? = nil) {
40
+ if watching {
41
+ motionManager.stopAccelerometerUpdates()
42
+ watching = false
43
+ }
44
+ completion?(nil)
45
+ }
46
+
47
+ private func handleAccelerometerData(_ data: CMAccelerometerData) {
48
+ let acceleration = data.acceleration
49
+ let gForce = (acceleration.x * acceleration.x + acceleration.y * acceleration.y + acceleration.z * acceleration.z).squareRoot()
50
+ if gForce < shakeThreshold {
51
+ return
52
+ }
53
+ let now = Date().timeIntervalSince1970
54
+ if now - lastShakeTimestamp < shakeDebounceInterval {
55
+ return
56
+ }
57
+ lastShakeTimestamp = now
58
+ plugin.notifyShakeListeners()
59
+ }
60
+ }
@@ -0,0 +1,67 @@
1
+ import Foundation
2
+ import Capacitor
3
+
4
+ @objc(ShakePlugin)
5
+ public class ShakePlugin: CAPPlugin, CAPBridgedPlugin {
6
+ public let identifier = "ShakePlugin"
7
+ public let jsName = "Shake"
8
+ public let pluginMethods: [CAPPluginMethod] = [
9
+ CAPPluginMethod(name: "startWatching", returnType: CAPPluginReturnPromise),
10
+ CAPPluginMethod(name: "stopWatching", returnType: CAPPluginReturnPromise)
11
+ ]
12
+
13
+ public static let shakeEvent = "shake"
14
+ public static let tag = "ShakePlugin"
15
+
16
+ private var implementation: Shake?
17
+
18
+ override public func load() {
19
+ self.implementation = Shake(plugin: self)
20
+ }
21
+
22
+ @objc public func notifyShakeListeners() {
23
+ notifyListeners(Self.shakeEvent, data: nil)
24
+ }
25
+
26
+ @objc func startWatching(_ call: CAPPluginCall) {
27
+ do {
28
+ let options = try StartWatchingOptions(call)
29
+ guard implementation?.isAvailable() == true else {
30
+ rejectCallAsUnavailable(call)
31
+ return
32
+ }
33
+ implementation?.startWatching(options) { error in
34
+ if let error = error {
35
+ self.rejectCall(call, error)
36
+ return
37
+ }
38
+ self.resolveCall(call)
39
+ }
40
+ } catch {
41
+ rejectCall(call, error)
42
+ }
43
+ }
44
+
45
+ @objc func stopWatching(_ call: CAPPluginCall) {
46
+ implementation?.stopWatching { error in
47
+ if let error = error {
48
+ self.rejectCall(call, error)
49
+ return
50
+ }
51
+ self.resolveCall(call)
52
+ }
53
+ }
54
+
55
+ private func rejectCall(_ call: CAPPluginCall, _ error: Error) {
56
+ CAPLog.print("[", ShakePlugin.tag, "] ", error)
57
+ call.reject(error.localizedDescription)
58
+ }
59
+
60
+ private func rejectCallAsUnavailable(_ call: CAPPluginCall) {
61
+ call.unavailable("This method is not available on this platform.")
62
+ }
63
+
64
+ private func resolveCall(_ call: CAPPluginCall) {
65
+ call.resolve()
66
+ }
67
+ }
package/package.json ADDED
@@ -0,0 +1,91 @@
1
+ {
2
+ "name": "@capawesome/capacitor-shake",
3
+ "version": "0.0.1",
4
+ "description": "Capacitor plugin to detect shake gestures.",
5
+ "main": "dist/plugin.cjs.js",
6
+ "module": "dist/esm/index.js",
7
+ "types": "dist/esm/index.d.ts",
8
+ "unpkg": "dist/plugin.js",
9
+ "files": [
10
+ "android/src/main/",
11
+ "android/build.gradle",
12
+ "dist/",
13
+ "ios/Plugin/",
14
+ "CapawesomeCapacitorShake.podspec",
15
+ "Package.swift"
16
+ ],
17
+ "author": "Robin Genz <mail@robingenz.dev>",
18
+ "license": "MIT",
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/capawesome-team/capacitor-plugins.git"
22
+ },
23
+ "bugs": {
24
+ "url": "https://github.com/capawesome-team/capacitor-plugins/issues"
25
+ },
26
+ "funding": [
27
+ {
28
+ "type": "github",
29
+ "url": "https://github.com/sponsors/capawesome-team/"
30
+ },
31
+ {
32
+ "type": "opencollective",
33
+ "url": "https://opencollective.com/capawesome"
34
+ }
35
+ ],
36
+ "homepage": "https://capawesome.io/docs/plugins/shake/",
37
+ "keywords": [
38
+ "capacitor",
39
+ "plugin",
40
+ "native"
41
+ ],
42
+ "scripts": {
43
+ "verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
44
+ "verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS && cd ..",
45
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
46
+ "verify:web": "npm run build",
47
+ "lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
48
+ "fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
49
+ "eslint": "eslint . --ext ts",
50
+ "prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
51
+ "swiftlint": "node-swiftlint",
52
+ "docgen": "docgen --api ShakePlugin --output-readme README.md --output-json dist/docs.json",
53
+ "build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
54
+ "clean": "rimraf ./dist",
55
+ "watch": "tsc --watch",
56
+ "ios:pod:install": "cd ios && pod install --repo-update && cd ..",
57
+ "ios:spm:install": "cd ios && swift package resolve && cd ..",
58
+ "prepublishOnly": "npm run build"
59
+ },
60
+ "devDependencies": {
61
+ "@capacitor/android": "8.0.0",
62
+ "@capacitor/cli": "8.0.0",
63
+ "@capacitor/core": "8.0.0",
64
+ "@capacitor/docgen": "0.3.1",
65
+ "@capacitor/ios": "8.0.0",
66
+ "@ionic/eslint-config": "0.4.0",
67
+ "eslint": "8.57.0",
68
+ "prettier-plugin-java": "2.6.7",
69
+ "rimraf": "6.1.2",
70
+ "rollup": "4.53.3",
71
+ "swiftlint": "2.0.0",
72
+ "typescript": "5.9.3"
73
+ },
74
+ "peerDependencies": {
75
+ "@capacitor/core": ">=8.0.0"
76
+ },
77
+ "eslintConfig": {
78
+ "extends": "@ionic/eslint-config/recommended"
79
+ },
80
+ "capacitor": {
81
+ "ios": {
82
+ "src": "ios"
83
+ },
84
+ "android": {
85
+ "src": "android"
86
+ }
87
+ },
88
+ "publishConfig": {
89
+ "access": "public"
90
+ }
91
+ }