expo-orb 0.1.0 → 0.2.0
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/README.md +1 -1
- package/android/src/main/java/expo/modules/breathing/BreathingConfiguration.kt +20 -0
- package/android/src/main/java/expo/modules/breathing/BreathingExerciseView.kt +247 -0
- package/android/src/main/java/expo/modules/breathing/BreathingSharedState.kt +104 -0
- package/android/src/main/java/expo/modules/breathing/BreathingTextCue.kt +41 -0
- package/android/src/main/java/expo/modules/breathing/ExpoBreathingExerciseModule.kt +156 -0
- package/android/src/main/java/expo/modules/breathing/ExpoBreathingExerciseView.kt +123 -0
- package/android/src/main/java/expo/modules/breathing/MorphingBlobView.kt +128 -0
- package/android/src/main/java/expo/modules/breathing/ProgressRingView.kt +50 -0
- package/build/ExpoBreathingExercise.types.d.ts +48 -0
- package/build/ExpoBreathingExercise.types.d.ts.map +1 -0
- package/build/ExpoBreathingExercise.types.js +2 -0
- package/build/ExpoBreathingExercise.types.js.map +1 -0
- package/build/ExpoBreathingExerciseModule.d.ts +16 -0
- package/build/ExpoBreathingExerciseModule.d.ts.map +1 -0
- package/build/ExpoBreathingExerciseModule.js +52 -0
- package/build/ExpoBreathingExerciseModule.js.map +1 -0
- package/build/ExpoBreathingExerciseView.d.ts +4 -0
- package/build/ExpoBreathingExerciseView.d.ts.map +1 -0
- package/build/ExpoBreathingExerciseView.js +7 -0
- package/build/ExpoBreathingExerciseView.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -0
- package/build/index.js.map +1 -1
- package/expo-module.config.json +2 -2
- package/ios/Breathing/BreathingConfiguration.swift +57 -0
- package/ios/Breathing/BreathingExerciseView.swift +451 -0
- package/ios/Breathing/BreathingSharedState.swift +84 -0
- package/ios/Breathing/BreathingTextCue.swift +14 -0
- package/ios/Breathing/MorphingBlobView.swift +242 -0
- package/ios/Breathing/ProgressRingView.swift +27 -0
- package/ios/ExpoBreathingExerciseModule.swift +182 -0
- package/ios/ExpoBreathingExerciseView.swift +124 -0
- package/package.json +8 -5
- package/src/ExpoBreathingExercise.types.ts +50 -0
- package/src/ExpoBreathingExerciseModule.ts +67 -0
- package/src/ExpoBreathingExerciseView.tsx +11 -0
- package/src/index.ts +11 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
package expo.modules.breathing
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.Canvas
|
|
4
|
+
import androidx.compose.runtime.Composable
|
|
5
|
+
import androidx.compose.ui.Modifier
|
|
6
|
+
import androidx.compose.ui.geometry.Offset
|
|
7
|
+
import androidx.compose.ui.graphics.Brush
|
|
8
|
+
import androidx.compose.ui.graphics.Color
|
|
9
|
+
import androidx.compose.ui.graphics.Path
|
|
10
|
+
import androidx.compose.ui.graphics.drawscope.DrawScope
|
|
11
|
+
import kotlin.math.PI
|
|
12
|
+
import kotlin.math.cos
|
|
13
|
+
import kotlin.math.min
|
|
14
|
+
import kotlin.math.sin
|
|
15
|
+
import kotlin.math.tan
|
|
16
|
+
|
|
17
|
+
@Composable
|
|
18
|
+
fun MorphingBlobView(
|
|
19
|
+
baseRadius: Float,
|
|
20
|
+
pointCount: Int,
|
|
21
|
+
offsets: List<Double>,
|
|
22
|
+
colors: List<Color>,
|
|
23
|
+
innerColor: Color,
|
|
24
|
+
showInnerBlob: Boolean,
|
|
25
|
+
modifier: Modifier = Modifier
|
|
26
|
+
) {
|
|
27
|
+
Canvas(modifier = modifier) {
|
|
28
|
+
val size = min(this.size.width, this.size.height)
|
|
29
|
+
val center = Offset(this.size.width / 2f, this.size.height / 2f)
|
|
30
|
+
val effectiveRadius = baseRadius * size / 2f
|
|
31
|
+
|
|
32
|
+
// Draw main blob
|
|
33
|
+
val mainPath = createBlobPath(center, effectiveRadius, pointCount, offsets)
|
|
34
|
+
drawPath(
|
|
35
|
+
path = mainPath,
|
|
36
|
+
brush = Brush.radialGradient(
|
|
37
|
+
colors = colors,
|
|
38
|
+
center = center,
|
|
39
|
+
radius = effectiveRadius
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
// Draw inner blob for depth
|
|
44
|
+
if (showInnerBlob) {
|
|
45
|
+
val innerPath = createBlobPath(
|
|
46
|
+
center = center,
|
|
47
|
+
baseRadius = effectiveRadius * 0.6f,
|
|
48
|
+
pointCount = pointCount,
|
|
49
|
+
offsets = offsets.map { it * 0.7 }
|
|
50
|
+
)
|
|
51
|
+
drawPath(
|
|
52
|
+
path = innerPath,
|
|
53
|
+
color = innerColor
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private fun DrawScope.createBlobPath(
|
|
60
|
+
center: Offset,
|
|
61
|
+
baseRadius: Float,
|
|
62
|
+
pointCount: Int,
|
|
63
|
+
offsets: List<Double>
|
|
64
|
+
): Path {
|
|
65
|
+
val path = Path()
|
|
66
|
+
if (pointCount < 3) return path
|
|
67
|
+
|
|
68
|
+
// Generate points around the circle with offsets
|
|
69
|
+
val points = mutableListOf<Offset>()
|
|
70
|
+
for (i in 0 until pointCount) {
|
|
71
|
+
val angle = (i.toDouble() / pointCount) * 2 * PI - PI / 2
|
|
72
|
+
val offset = if (i < offsets.size) offsets[i] else 0.0
|
|
73
|
+
val radius = baseRadius * (1.0 + offset).toFloat()
|
|
74
|
+
|
|
75
|
+
points.add(
|
|
76
|
+
Offset(
|
|
77
|
+
x = center.x + (cos(angle) * radius).toFloat(),
|
|
78
|
+
y = center.y + (sin(angle) * radius).toFloat()
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Tangent coefficient for smooth cubic bezier curves
|
|
84
|
+
val tangentCoeff = ((4.0 / 3.0) * tan(PI / (2.0 * pointCount))).toFloat()
|
|
85
|
+
|
|
86
|
+
// Start at first point
|
|
87
|
+
path.moveTo(points[0].x, points[0].y)
|
|
88
|
+
|
|
89
|
+
// Draw cubic bezier curves between each pair of points
|
|
90
|
+
for (i in 0 until pointCount) {
|
|
91
|
+
val current = points[i]
|
|
92
|
+
val next = points[(i + 1) % pointCount]
|
|
93
|
+
|
|
94
|
+
// Calculate angles for tangent directions
|
|
95
|
+
val currentAngle = (i.toDouble() / pointCount) * 2 * PI - PI / 2
|
|
96
|
+
val nextAngle = (((i + 1) % pointCount).toDouble() / pointCount) * 2 * PI - PI / 2
|
|
97
|
+
|
|
98
|
+
// Current point's radius and tangent
|
|
99
|
+
val currentOffset = if (i < offsets.size) offsets[i] else 0.0
|
|
100
|
+
val currentRadius = baseRadius * (1.0 + currentOffset).toFloat()
|
|
101
|
+
val currentTangentLength = currentRadius * tangentCoeff
|
|
102
|
+
|
|
103
|
+
// Next point's radius and tangent
|
|
104
|
+
val nextOffset = if ((i + 1) % pointCount < offsets.size) offsets[(i + 1) % pointCount] else 0.0
|
|
105
|
+
val nextRadius = baseRadius * (1.0 + nextOffset).toFloat()
|
|
106
|
+
val nextTangentLength = nextRadius * tangentCoeff
|
|
107
|
+
|
|
108
|
+
// Control points are perpendicular to radial direction
|
|
109
|
+
val control1 = Offset(
|
|
110
|
+
x = current.x + (cos(currentAngle + PI / 2) * currentTangentLength).toFloat(),
|
|
111
|
+
y = current.y + (sin(currentAngle + PI / 2) * currentTangentLength).toFloat()
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
val control2 = Offset(
|
|
115
|
+
x = next.x + (cos(nextAngle - PI / 2) * nextTangentLength).toFloat(),
|
|
116
|
+
y = next.y + (sin(nextAngle - PI / 2) * nextTangentLength).toFloat()
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
path.cubicTo(
|
|
120
|
+
control1.x, control1.y,
|
|
121
|
+
control2.x, control2.y,
|
|
122
|
+
next.x, next.y
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
path.close()
|
|
127
|
+
return path
|
|
128
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package expo.modules.breathing
|
|
2
|
+
|
|
3
|
+
import androidx.compose.foundation.Canvas
|
|
4
|
+
import androidx.compose.runtime.Composable
|
|
5
|
+
import androidx.compose.ui.Modifier
|
|
6
|
+
import androidx.compose.ui.geometry.Offset
|
|
7
|
+
import androidx.compose.ui.geometry.Size
|
|
8
|
+
import androidx.compose.ui.graphics.Color
|
|
9
|
+
import androidx.compose.ui.graphics.StrokeCap
|
|
10
|
+
import androidx.compose.ui.graphics.drawscope.Stroke
|
|
11
|
+
import kotlin.math.min
|
|
12
|
+
|
|
13
|
+
@Composable
|
|
14
|
+
fun ProgressRingView(
|
|
15
|
+
progress: Double,
|
|
16
|
+
color: Color,
|
|
17
|
+
lineWidth: Float,
|
|
18
|
+
modifier: Modifier = Modifier
|
|
19
|
+
) {
|
|
20
|
+
Canvas(modifier = modifier) {
|
|
21
|
+
val size = min(this.size.width, this.size.height)
|
|
22
|
+
val radius = (size - lineWidth) / 2f
|
|
23
|
+
val center = Offset(this.size.width / 2f, this.size.height / 2f)
|
|
24
|
+
val topLeft = Offset(center.x - radius, center.y - radius)
|
|
25
|
+
val arcSize = Size(radius * 2, radius * 2)
|
|
26
|
+
|
|
27
|
+
// Background ring
|
|
28
|
+
drawArc(
|
|
29
|
+
color = color.copy(alpha = 0.2f),
|
|
30
|
+
startAngle = 0f,
|
|
31
|
+
sweepAngle = 360f,
|
|
32
|
+
useCenter = false,
|
|
33
|
+
topLeft = topLeft,
|
|
34
|
+
size = arcSize,
|
|
35
|
+
style = Stroke(width = lineWidth)
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
// Progress arc
|
|
39
|
+
val clampedProgress = progress.coerceIn(0.0, 1.0).toFloat()
|
|
40
|
+
drawArc(
|
|
41
|
+
color = color,
|
|
42
|
+
startAngle = -90f, // Start from top
|
|
43
|
+
sweepAngle = 360f * clampedProgress,
|
|
44
|
+
useCenter = false,
|
|
45
|
+
topLeft = topLeft,
|
|
46
|
+
size = arcSize,
|
|
47
|
+
style = Stroke(width = lineWidth, cap = StrokeCap.Round)
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { ColorValue, StyleProp, ViewStyle } from 'react-native';
|
|
2
|
+
export type BreathPhase = 'inhale' | 'holdIn' | 'exhale' | 'holdOut';
|
|
3
|
+
export interface BreathPhaseConfig {
|
|
4
|
+
phase: BreathPhase;
|
|
5
|
+
duration: number;
|
|
6
|
+
targetScale: number;
|
|
7
|
+
label: string;
|
|
8
|
+
}
|
|
9
|
+
export interface BreathingPattern {
|
|
10
|
+
phases: BreathPhaseConfig[];
|
|
11
|
+
cycles?: number;
|
|
12
|
+
}
|
|
13
|
+
export type BreathingPreset = 'relaxing' | 'box' | 'energizing' | 'calming';
|
|
14
|
+
export interface PhaseChangeEvent {
|
|
15
|
+
phase: BreathPhase;
|
|
16
|
+
label: string;
|
|
17
|
+
phaseIndex: number;
|
|
18
|
+
cycle: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ExerciseCompleteEvent {
|
|
21
|
+
totalCycles: number;
|
|
22
|
+
totalDuration: number;
|
|
23
|
+
}
|
|
24
|
+
export interface ExpoBreathingExerciseViewProps {
|
|
25
|
+
blobColors?: ColorValue[];
|
|
26
|
+
innerBlobColor?: ColorValue;
|
|
27
|
+
glowColor?: ColorValue;
|
|
28
|
+
particleColor?: ColorValue;
|
|
29
|
+
progressRingColor?: ColorValue;
|
|
30
|
+
textColor?: ColorValue;
|
|
31
|
+
showProgressRing?: boolean;
|
|
32
|
+
showTextCue?: boolean;
|
|
33
|
+
showInnerBlob?: boolean;
|
|
34
|
+
showShadow?: boolean;
|
|
35
|
+
showParticles?: boolean;
|
|
36
|
+
showWavyBlobs?: boolean;
|
|
37
|
+
showGlowEffects?: boolean;
|
|
38
|
+
pointCount?: number;
|
|
39
|
+
wobbleIntensity?: number;
|
|
40
|
+
onPhaseChange?: (event: {
|
|
41
|
+
nativeEvent: PhaseChangeEvent;
|
|
42
|
+
}) => void;
|
|
43
|
+
onExerciseComplete?: (event: {
|
|
44
|
+
nativeEvent: ExerciseCompleteEvent;
|
|
45
|
+
}) => void;
|
|
46
|
+
style?: StyleProp<ViewStyle>;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=ExpoBreathingExercise.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoBreathingExercise.types.d.ts","sourceRoot":"","sources":["../src/ExpoBreathingExercise.types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,WAAW,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,SAAS,CAAC;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,WAAW,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,8BAA8B;IAC7C,UAAU,CAAC,EAAE,UAAU,EAAE,CAAC;IAC1B,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,iBAAiB,CAAC,EAAE,UAAU,CAAC;IAC/B,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,gBAAgB,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,WAAW,EAAE,qBAAqB,CAAA;KAAE,KAAK,IAAI,CAAC;IAC7E,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;CAC9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoBreathingExercise.types.js","sourceRoot":"","sources":["../src/ExpoBreathingExercise.types.ts"],"names":[],"mappings":"","sourcesContent":["import type { ColorValue, StyleProp, ViewStyle } from 'react-native';\n\nexport type BreathPhase = 'inhale' | 'holdIn' | 'exhale' | 'holdOut';\n\nexport interface BreathPhaseConfig {\n phase: BreathPhase;\n duration: number; // milliseconds\n targetScale: number; // e.g., 1.0 to 1.3\n label: string; // \"Breathe In\"\n}\n\nexport interface BreathingPattern {\n phases: BreathPhaseConfig[];\n cycles?: number; // undefined = infinite\n}\n\nexport type BreathingPreset = 'relaxing' | 'box' | 'energizing' | 'calming';\n\nexport interface PhaseChangeEvent {\n phase: BreathPhase;\n label: string;\n phaseIndex: number;\n cycle: number;\n}\n\nexport interface ExerciseCompleteEvent {\n totalCycles: number;\n totalDuration: number;\n}\n\nexport interface ExpoBreathingExerciseViewProps {\n blobColors?: ColorValue[];\n innerBlobColor?: ColorValue;\n glowColor?: ColorValue;\n particleColor?: ColorValue;\n progressRingColor?: ColorValue;\n textColor?: ColorValue;\n showProgressRing?: boolean;\n showTextCue?: boolean;\n showInnerBlob?: boolean;\n showShadow?: boolean;\n showParticles?: boolean;\n showWavyBlobs?: boolean;\n showGlowEffects?: boolean;\n pointCount?: number; // Morphing points (default: 8)\n wobbleIntensity?: number; // 0-1\n onPhaseChange?: (event: { nativeEvent: PhaseChangeEvent }) => void;\n onExerciseComplete?: (event: { nativeEvent: ExerciseCompleteEvent }) => void;\n style?: StyleProp<ViewStyle>;\n}\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { NativeModule } from 'expo';
|
|
2
|
+
import type { BreathingPattern, BreathingPreset } from './ExpoBreathingExercise.types';
|
|
3
|
+
declare class ExpoBreathingExerciseModuleType extends NativeModule {
|
|
4
|
+
startBreathingExercise(pattern: BreathingPattern): void;
|
|
5
|
+
stopBreathingExercise(): void;
|
|
6
|
+
pauseBreathingExercise(): void;
|
|
7
|
+
resumeBreathingExercise(): void;
|
|
8
|
+
}
|
|
9
|
+
declare const module: ExpoBreathingExerciseModuleType;
|
|
10
|
+
export default module;
|
|
11
|
+
export declare function startBreathingExercise(pattern: BreathingPattern): void;
|
|
12
|
+
export declare function stopBreathingExercise(): void;
|
|
13
|
+
export declare function pauseBreathingExercise(): void;
|
|
14
|
+
export declare function resumeBreathingExercise(): void;
|
|
15
|
+
export declare function getBreathingPreset(preset: BreathingPreset): BreathingPattern;
|
|
16
|
+
//# sourceMappingURL=ExpoBreathingExerciseModule.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoBreathingExerciseModule.d.ts","sourceRoot":"","sources":["../src/ExpoBreathingExerciseModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AACzD,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAEvF,OAAO,OAAO,+BAAgC,SAAQ,YAAY;IAChE,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI;IACvD,qBAAqB,IAAI,IAAI;IAC7B,sBAAsB,IAAI,IAAI;IAC9B,uBAAuB,IAAI,IAAI;CAChC;AAED,QAAA,MAAM,MAAM,iCAAgF,CAAC;AAE7F,eAAe,MAAM,CAAC;AAEtB,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAEtE;AAED,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAED,wBAAgB,uBAAuB,IAAI,IAAI,CAE9C;AAoCD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,GAAG,gBAAgB,CAE5E"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { requireNativeModule } from 'expo';
|
|
2
|
+
const module = requireNativeModule('ExpoBreathingExercise');
|
|
3
|
+
export default module;
|
|
4
|
+
export function startBreathingExercise(pattern) {
|
|
5
|
+
module.startBreathingExercise(pattern);
|
|
6
|
+
}
|
|
7
|
+
export function stopBreathingExercise() {
|
|
8
|
+
module.stopBreathingExercise();
|
|
9
|
+
}
|
|
10
|
+
export function pauseBreathingExercise() {
|
|
11
|
+
module.pauseBreathingExercise();
|
|
12
|
+
}
|
|
13
|
+
export function resumeBreathingExercise() {
|
|
14
|
+
module.resumeBreathingExercise();
|
|
15
|
+
}
|
|
16
|
+
const BREATHING_PRESETS = {
|
|
17
|
+
relaxing: {
|
|
18
|
+
phases: [
|
|
19
|
+
{ phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },
|
|
20
|
+
{ phase: 'holdIn', duration: 7000, targetScale: 1.35, label: 'Hold' },
|
|
21
|
+
{ phase: 'exhale', duration: 8000, targetScale: 0.75, label: 'Breathe Out' },
|
|
22
|
+
],
|
|
23
|
+
cycles: 4,
|
|
24
|
+
},
|
|
25
|
+
box: {
|
|
26
|
+
phases: [
|
|
27
|
+
{ phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },
|
|
28
|
+
{ phase: 'holdIn', duration: 4000, targetScale: 1.35, label: 'Hold' },
|
|
29
|
+
{ phase: 'exhale', duration: 4000, targetScale: 0.75, label: 'Breathe Out' },
|
|
30
|
+
{ phase: 'holdOut', duration: 4000, targetScale: 0.75, label: 'Hold' },
|
|
31
|
+
],
|
|
32
|
+
cycles: 4,
|
|
33
|
+
},
|
|
34
|
+
energizing: {
|
|
35
|
+
phases: [
|
|
36
|
+
{ phase: 'inhale', duration: 2000, targetScale: 1.35, label: 'Breathe In' },
|
|
37
|
+
{ phase: 'exhale', duration: 2000, targetScale: 0.75, label: 'Breathe Out' },
|
|
38
|
+
],
|
|
39
|
+
cycles: 10,
|
|
40
|
+
},
|
|
41
|
+
calming: {
|
|
42
|
+
phases: [
|
|
43
|
+
{ phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },
|
|
44
|
+
{ phase: 'exhale', duration: 6000, targetScale: 0.75, label: 'Breathe Out' },
|
|
45
|
+
],
|
|
46
|
+
cycles: 6,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
export function getBreathingPreset(preset) {
|
|
50
|
+
return BREATHING_PRESETS[preset];
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=ExpoBreathingExerciseModule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoBreathingExerciseModule.js","sourceRoot":"","sources":["../src/ExpoBreathingExerciseModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAUzD,MAAM,MAAM,GAAG,mBAAmB,CAAkC,uBAAuB,CAAC,CAAC;AAE7F,eAAe,MAAM,CAAC;AAEtB,MAAM,UAAU,sBAAsB,CAAC,OAAyB;IAC9D,MAAM,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;AACzC,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,MAAM,CAAC,qBAAqB,EAAE,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,sBAAsB;IACpC,MAAM,CAAC,sBAAsB,EAAE,CAAC;AAClC,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,MAAM,CAAC,uBAAuB,EAAE,CAAC;AACnC,CAAC;AAED,MAAM,iBAAiB,GAA8C;IACnE,QAAQ,EAAE;QACR,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;YACrE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;SAC7E;QACD,MAAM,EAAE,CAAC;KACV;IACD,GAAG,EAAE;QACH,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;YACrE,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;YAC5E,EAAE,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE;SACvE;QACD,MAAM,EAAE,CAAC;KACV;IACD,UAAU,EAAE;QACV,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;SAC7E;QACD,MAAM,EAAE,EAAE;KACX;IACD,OAAO,EAAE;QACP,MAAM,EAAE;YACN,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,YAAY,EAAE;YAC3E,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;SAC7E;QACD,MAAM,EAAE,CAAC;KACV;CACF,CAAC;AAEF,MAAM,UAAU,kBAAkB,CAAC,MAAuB;IACxD,OAAO,iBAAiB,CAAC,MAAM,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from 'expo';\nimport type { BreathingPattern, BreathingPreset } from './ExpoBreathingExercise.types';\n\ndeclare class ExpoBreathingExerciseModuleType extends NativeModule {\n startBreathingExercise(pattern: BreathingPattern): void;\n stopBreathingExercise(): void;\n pauseBreathingExercise(): void;\n resumeBreathingExercise(): void;\n}\n\nconst module = requireNativeModule<ExpoBreathingExerciseModuleType>('ExpoBreathingExercise');\n\nexport default module;\n\nexport function startBreathingExercise(pattern: BreathingPattern): void {\n module.startBreathingExercise(pattern);\n}\n\nexport function stopBreathingExercise(): void {\n module.stopBreathingExercise();\n}\n\nexport function pauseBreathingExercise(): void {\n module.pauseBreathingExercise();\n}\n\nexport function resumeBreathingExercise(): void {\n module.resumeBreathingExercise();\n}\n\nconst BREATHING_PRESETS: Record<BreathingPreset, BreathingPattern> = {\n relaxing: {\n phases: [\n { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'holdIn', duration: 7000, targetScale: 1.35, label: 'Hold' },\n { phase: 'exhale', duration: 8000, targetScale: 0.75, label: 'Breathe Out' },\n ],\n cycles: 4,\n },\n box: {\n phases: [\n { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'holdIn', duration: 4000, targetScale: 1.35, label: 'Hold' },\n { phase: 'exhale', duration: 4000, targetScale: 0.75, label: 'Breathe Out' },\n { phase: 'holdOut', duration: 4000, targetScale: 0.75, label: 'Hold' },\n ],\n cycles: 4,\n },\n energizing: {\n phases: [\n { phase: 'inhale', duration: 2000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'exhale', duration: 2000, targetScale: 0.75, label: 'Breathe Out' },\n ],\n cycles: 10,\n },\n calming: {\n phases: [\n { phase: 'inhale', duration: 4000, targetScale: 1.35, label: 'Breathe In' },\n { phase: 'exhale', duration: 6000, targetScale: 0.75, label: 'Breathe Out' },\n ],\n cycles: 6,\n },\n};\n\nexport function getBreathingPreset(preset: BreathingPreset): BreathingPattern {\n return BREATHING_PRESETS[preset];\n}\n"]}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ExpoBreathingExerciseViewProps } from './ExpoBreathingExercise.types';
|
|
3
|
+
export default function ExpoBreathingExerciseView(props: ExpoBreathingExerciseViewProps): React.JSX.Element;
|
|
4
|
+
//# sourceMappingURL=ExpoBreathingExerciseView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoBreathingExerciseView.d.ts","sourceRoot":"","sources":["../src/ExpoBreathingExerciseView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,8BAA8B,EAAE,MAAM,+BAA+B,CAAC;AAK/E,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,8BAA8B,qBAEtF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { requireNativeView } from 'expo';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
const NativeView = requireNativeView('ExpoBreathingExercise');
|
|
4
|
+
export default function ExpoBreathingExerciseView(props) {
|
|
5
|
+
return <NativeView {...props}/>;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=ExpoBreathingExerciseView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExpoBreathingExerciseView.js","sourceRoot":"","sources":["../src/ExpoBreathingExerciseView.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACzC,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,MAAM,UAAU,GACd,iBAAiB,CAAC,uBAAuB,CAAC,CAAC;AAE7C,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAqC;IACrF,OAAO,CAAC,UAAU,CAAC,IAAI,KAAK,CAAC,EAAG,CAAC;AACnC,CAAC","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { ExpoBreathingExerciseViewProps } from './ExpoBreathingExercise.types';\n\nconst NativeView: React.ComponentType<ExpoBreathingExerciseViewProps> =\n requireNativeView('ExpoBreathingExercise');\n\nexport default function ExpoBreathingExerciseView(props: ExpoBreathingExerciseViewProps) {\n return <NativeView {...props} />;\n}\n"]}
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { default, setOrbActivity } from './ExpoOrbModule';
|
|
2
2
|
export { default as ExpoOrbView } from './ExpoOrbView';
|
|
3
3
|
export * from './ExpoOrb.types';
|
|
4
|
+
export { default as ExpoBreathingExerciseModule, startBreathingExercise, stopBreathingExercise, pauseBreathingExercise, resumeBreathingExercise, getBreathingPreset, } from './ExpoBreathingExerciseModule';
|
|
5
|
+
export { default as ExpoBreathingExerciseView } from './ExpoBreathingExerciseView';
|
|
6
|
+
export * from './ExpoBreathingExercise.types';
|
|
4
7
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC;AAEjC,OAAO,EACL,OAAO,IAAI,2BAA2B,EACtC,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,cAAc,+BAA+B,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
export { default, setOrbActivity } from './ExpoOrbModule';
|
|
2
2
|
export { default as ExpoOrbView } from './ExpoOrbView';
|
|
3
3
|
export * from './ExpoOrb.types';
|
|
4
|
+
export { default as ExpoBreathingExerciseModule, startBreathingExercise, stopBreathingExercise, pauseBreathingExercise, resumeBreathingExercise, getBreathingPreset, } from './ExpoBreathingExerciseModule';
|
|
5
|
+
export { default as ExpoBreathingExerciseView } from './ExpoBreathingExerciseView';
|
|
6
|
+
export * from './ExpoBreathingExercise.types';
|
|
4
7
|
//# sourceMappingURL=index.js.map
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC","sourcesContent":["export { default, setOrbActivity } from './ExpoOrbModule';\nexport { default as ExpoOrbView } from './ExpoOrbView';\nexport * from './ExpoOrb.types';\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,eAAe,CAAC;AACvD,cAAe,iBAAiB,CAAC;AAEjC,OAAO,EACL,OAAO,IAAI,2BAA2B,EACtC,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,cAAc,+BAA+B,CAAC","sourcesContent":["export { default, setOrbActivity } from './ExpoOrbModule';\nexport { default as ExpoOrbView } from './ExpoOrbView';\nexport * from './ExpoOrb.types';\n\nexport {\n default as ExpoBreathingExerciseModule,\n startBreathingExercise,\n stopBreathingExercise,\n pauseBreathingExercise,\n resumeBreathingExercise,\n getBreathingPreset,\n} from './ExpoBreathingExerciseModule';\nexport { default as ExpoBreathingExerciseView } from './ExpoBreathingExerciseView';\nexport * from './ExpoBreathingExercise.types';\n"]}
|
package/expo-module.config.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"platforms": ["apple", "android", "web"],
|
|
3
3
|
"apple": {
|
|
4
|
-
"modules": ["ExpoOrbModule"]
|
|
4
|
+
"modules": ["ExpoOrbModule", "ExpoBreathingExerciseModule"]
|
|
5
5
|
},
|
|
6
6
|
"android": {
|
|
7
|
-
"modules": ["expo.modules.orb.ExpoOrbModule"]
|
|
7
|
+
"modules": ["expo.modules.orb.ExpoOrbModule", "expo.modules.breathing.ExpoBreathingExerciseModule"]
|
|
8
8
|
}
|
|
9
9
|
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import SwiftUI
|
|
2
|
+
|
|
3
|
+
public struct BreathingConfiguration {
|
|
4
|
+
var blobColors: [Color]
|
|
5
|
+
var innerBlobColor: Color
|
|
6
|
+
var glowColor: Color
|
|
7
|
+
var particleColor: Color
|
|
8
|
+
var progressRingColor: Color
|
|
9
|
+
var textColor: Color
|
|
10
|
+
var showProgressRing: Bool
|
|
11
|
+
var showTextCue: Bool
|
|
12
|
+
var showInnerBlob: Bool
|
|
13
|
+
var showShadow: Bool
|
|
14
|
+
var showParticles: Bool
|
|
15
|
+
var showWavyBlobs: Bool
|
|
16
|
+
var showGlowEffects: Bool
|
|
17
|
+
var pointCount: Int
|
|
18
|
+
var wobbleIntensity: Double
|
|
19
|
+
|
|
20
|
+
public init(
|
|
21
|
+
blobColors: [Color] = [
|
|
22
|
+
Color(red: 0.4, green: 0.7, blue: 0.9),
|
|
23
|
+
Color(red: 0.3, green: 0.5, blue: 0.8),
|
|
24
|
+
Color(red: 0.5, green: 0.3, blue: 0.7)
|
|
25
|
+
],
|
|
26
|
+
innerBlobColor: Color = Color.white.opacity(0.3),
|
|
27
|
+
glowColor: Color = .white,
|
|
28
|
+
particleColor: Color = .white,
|
|
29
|
+
progressRingColor: Color = Color.white.opacity(0.5),
|
|
30
|
+
textColor: Color = .white,
|
|
31
|
+
showProgressRing: Bool = true,
|
|
32
|
+
showTextCue: Bool = true,
|
|
33
|
+
showInnerBlob: Bool = true,
|
|
34
|
+
showShadow: Bool = true,
|
|
35
|
+
showParticles: Bool = true,
|
|
36
|
+
showWavyBlobs: Bool = true,
|
|
37
|
+
showGlowEffects: Bool = true,
|
|
38
|
+
pointCount: Int = 8,
|
|
39
|
+
wobbleIntensity: Double = 1.0
|
|
40
|
+
) {
|
|
41
|
+
self.blobColors = blobColors
|
|
42
|
+
self.innerBlobColor = innerBlobColor
|
|
43
|
+
self.glowColor = glowColor
|
|
44
|
+
self.particleColor = particleColor
|
|
45
|
+
self.progressRingColor = progressRingColor
|
|
46
|
+
self.textColor = textColor
|
|
47
|
+
self.showProgressRing = showProgressRing
|
|
48
|
+
self.showTextCue = showTextCue
|
|
49
|
+
self.showInnerBlob = showInnerBlob
|
|
50
|
+
self.showShadow = showShadow
|
|
51
|
+
self.showParticles = showParticles
|
|
52
|
+
self.showWavyBlobs = showWavyBlobs
|
|
53
|
+
self.showGlowEffects = showGlowEffects
|
|
54
|
+
self.pointCount = pointCount
|
|
55
|
+
self.wobbleIntensity = wobbleIntensity
|
|
56
|
+
}
|
|
57
|
+
}
|