@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.
- package/CapawesomeCapacitorShake.podspec +17 -0
- package/LICENSE +21 -0
- package/Package.swift +28 -0
- package/README.md +204 -0
- package/android/build.gradle +58 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/Shake.java +80 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/ShakePlugin.java +97 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/CustomException.java +20 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/CustomExceptions.java +9 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/interfaces/Callback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/interfaces/EmptyCallback.java +5 -0
- package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/options/StartWatchingOptions.java +40 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +174 -0
- package/dist/esm/definitions.d.ts +57 -0
- package/dist/esm/definitions.js +2 -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 +6 -0
- package/dist/esm/web.js +10 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +24 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +27 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/Classes/Options/StartWatchingOptions.swift +32 -0
- package/ios/Plugin/Enums/CustomError.swift +21 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/Shake.swift +60 -0
- package/ios/Plugin/ShakePlugin.swift +67 -0
- 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>() => void</code> |
|
|
109
|
+
|
|
110
|
+
**Returns:** <code>Promise<<a href="#pluginlistenerhandle">PluginListenerHandle</a>></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>() => Promise<void></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,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
|
+
}
|
package/android/src/main/java/io/capawesome/capacitorjs/plugins/shake/classes/CustomException.java
ADDED
|
@@ -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,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 @@
|
|
|
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 @@
|
|
|
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"]}
|
package/dist/esm/web.js
ADDED
|
@@ -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
|
+
}
|