tauri_plugin_haptics/mobile.rs
1// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
2// SPDX-License-Identifier: Apache-2.0
3// SPDX-License-Identifier: MIT
4
5use serde::{Serialize, de::DeserializeOwned};
6use tauri::{
7 AppHandle, Runtime,
8 plugin::{PluginApi, PluginHandle},
9};
10
11use crate::models::*;
12
13#[cfg(target_os = "android")]
14const PLUGIN_IDENTIFIER: &str = "app.tauri.haptics";
15
16#[cfg(target_os = "ios")]
17tauri::ios_plugin_binding!(init_plugin_haptics);
18
19// initializes the Kotlin or Swift plugin classes
20pub fn init<R: Runtime, C: DeserializeOwned>(
21 _app: &AppHandle<R>,
22 api: PluginApi<R, C>,
23) -> crate::Result<Haptics<R>> {
24 #[cfg(target_os = "android")]
25 let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "HapticsPlugin")?;
26 #[cfg(target_os = "ios")]
27 let handle = api.register_ios_plugin(init_plugin_haptics)?;
28 Ok(Haptics(handle))
29}
30
31/// Access to the haptics APIs.
32pub struct Haptics<R: Runtime>(PluginHandle<R>);
33
34impl<R: Runtime> Haptics<R> {
35 /// Triggers a vibration for `duration` milliseconds.
36 ///
37 /// On iOS this plays a continuous [Core Haptics](https://developer.apple.com/documentation/corehaptics)
38 /// pattern when the device supports it, falling back to the system alert vibration
39 /// otherwise. On Android it uses [`Vibrator`](https://developer.android.com/reference/android/os/Vibrator).
40 ///
41 /// # Errors
42 ///
43 /// Returns [`Error::PluginInvoke`](crate::Error::PluginInvoke) if the underlying Android or
44 /// iOS plugin invocation fails.
45 pub fn vibrate(&self, duration: u32) -> crate::Result<()> {
46 self.0
47 .run_mobile_plugin("vibrate", VibratePayload { duration })
48 .map_err(Into::into)
49 }
50
51 /// Triggers an impact-feedback haptic with the given [`ImpactFeedbackStyle`].
52 ///
53 /// # Errors
54 ///
55 /// Returns [`Error::PluginInvoke`](crate::Error::PluginInvoke) if the underlying Android or
56 /// iOS plugin invocation fails.
57 pub fn impact_feedback(&self, style: ImpactFeedbackStyle) -> crate::Result<()> {
58 self.0
59 .run_mobile_plugin("impactFeedback", ImpactFeedbackPayload { style })
60 .map_err(Into::into)
61 }
62
63 /// Triggers a notification-feedback haptic for the given [`NotificationFeedbackType`].
64 ///
65 /// # Errors
66 ///
67 /// Returns [`Error::PluginInvoke`](crate::Error::PluginInvoke) if the underlying Android or
68 /// iOS plugin invocation fails.
69 pub fn notification_feedback(&self, r#type: NotificationFeedbackType) -> crate::Result<()> {
70 self.0
71 .run_mobile_plugin(
72 "notificationFeedback",
73 NotificationFeedbackPayload { r#type },
74 )
75 .map_err(Into::into)
76 }
77
78 /// Triggers a haptic indicating that a selection changed, e.g. when the value of a picker
79 /// control changes.
80 ///
81 /// # Errors
82 ///
83 /// Returns [`Error::PluginInvoke`](crate::Error::PluginInvoke) if the underlying Android or
84 /// iOS plugin invocation fails.
85 pub fn selection_feedback(&self) -> crate::Result<()> {
86 self.0
87 .run_mobile_plugin("selectionFeedback", ())
88 .map_err(Into::into)
89 }
90}
91
92#[derive(Serialize)]
93struct VibratePayload {
94 duration: u32,
95}
96
97#[derive(Serialize)]
98struct ImpactFeedbackPayload {
99 style: ImpactFeedbackStyle,
100}
101
102#[derive(Serialize)]
103struct NotificationFeedbackPayload {
104 r#type: NotificationFeedbackType,
105}