Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
ba4268c
upgrade expo 54 + reanimated + posthog
keeandev Feb 9, 2026
ad1f4f4
expo doctor git ignore change
keeandev Feb 9, 2026
a7ae6fb
remove deprecated code (reanimated, edge to edge flag, safe area view)
keeandev Feb 9, 2026
c113c1e
remove legacy expo file system
keeandev Feb 9, 2026
bfd2d46
replace expo-av with expo-audio
keeandev Feb 9, 2026
f44c047
expo 55
keeandev Feb 10, 2026
90e2bfc
upgrade remaining dependencies
keeandev Feb 10, 2026
2559c1b
update tsconfig based on default expo template
keeandev Feb 10, 2026
7708675
fix: update tsconfig.json to fix @/ imports
keeandev Feb 10, 2026
0bdd124
add package json override for expo 55 compatiblity with package
keeandev Feb 10, 2026
cc5c00e
fix: package lock
keeandev Feb 10, 2026
c66f14b
fix syntax in package.json
keeandev Feb 10, 2026
370ae53
add missing dependency
keeandev Feb 10, 2026
5691a06
update packages again?
keeandev Feb 10, 2026
3e2ce05
migrate dependencies to expo doctor suggestions
keeandev Feb 10, 2026
f377d09
remove unused expo plugin
keeandev Feb 10, 2026
06e5d19
Created assetAudio.ts with documentation, reworked AudioContext and p…
Lomacar Feb 11, 2026
505a32d
Merge branch 'dev' into AssetAudio
Lomacar Feb 11, 2026
6d28c5c
fix color scheme crash on android
keeandev Feb 12, 2026
5fc097f
Imported code for generating waveforms
Lomacar Feb 11, 2026
84ec949
Converted RecordingViewSimplified.tsx to use AssetAudio
Lomacar Feb 12, 2026
9b41f16
convert RecordingView to use AssetAudio
Lomacar Feb 12, 2026
db7a7e8
revamped play all
Lomacar Feb 12, 2026
8a82c37
enhanced audio progress bar
Lomacar Feb 12, 2026
3333c9f
removed test asset from recordingview
Lomacar Feb 12, 2026
f6555c5
refactor: rename supabase scripts to sb and knip to knip:check
keeandev Feb 12, 2026
84e92fa
Integrated AssetAudio into BibleAssetsView, fixed Play All bugs
Lomacar Feb 12, 2026
cc90b1a
update package lock
keeandev Feb 13, 2026
78e22cc
junk that probably shouldn't be in this branch
Lomacar Feb 13, 2026
c3d4a77
chore: style changes
keeandev Feb 13, 2026
cbaa7a6
chore: style changes
keeandev Feb 13, 2026
1cf82cf
chore: update app version to 2.1.0 and fix typo in android release sc…
keeandev Feb 13, 2026
f13eda4
Add isPreferred: true to react-native-alert primary action buttons
keeandev Feb 13, 2026
0b29b0d
fussed with animation of audio progress bar for merged clips
Lomacar Feb 13, 2026
340da6d
Jesus/animate button (#653)
keeandev Feb 13, 2026
7be63b1
Enhance localization support by adding Hindi, Burmese, Thai, and Mand…
keeandev Feb 13, 2026
42127af
Merge branch 'dev' into jesus/expo-54-2026
keeandev Feb 13, 2026
ac1b6b8
fix: package-lock
keeandev Feb 13, 2026
953a631
format + typefix
keeandev Feb 13, 2026
92e8154
fix(ci): use env vars for fingerprint-diff to avoid argument length l…
keeandev Feb 13, 2026
6ef8974
fix(ci): use file-based approach for large fingerprint diffs to avoid…
keeandev Feb 13, 2026
448c88c
change terms page
keeandev Feb 13, 2026
c9350bb
fix padding on download indicator
keeandev Feb 13, 2026
9bcd239
remove @expo/vector-icons and migrate all icons to lucide
keeandev Feb 13, 2026
60bc356
make sure to use the icon component
keeandev Feb 13, 2026
bae374c
remove withoutCredentials
keeandev Feb 13, 2026
e436316
refactor(ci): reorganize iOS and Android build jobs in preview workflow
keeandev Feb 13, 2026
1778440
format fix + check native build workflow attempt fix
keeandev Feb 13, 2026
c78bbcf
disable eas caching temporarily
keeandev Feb 13, 2026
9d20caa
invalidate preview cache
keeandev Feb 13, 2026
b8eb500
fix worker type for ios builds from linux to mac
keeandev Feb 13, 2026
4c64c1b
update ios repack step to use macos-medium for iOS builds
keeandev Feb 13, 2026
88c26aa
fix i agree button not being shown
keeandev Feb 13, 2026
77789cc
record ios screen in maestro tests
keeandev Feb 13, 2026
c0bceb2
try and fix terms page on small screens android
keeandev Feb 14, 2026
7a37508
use consistent testing devices Pixel 6 and iPhone 16e
keeandev Feb 14, 2026
0158249
improved progress bar accuracy for merged segments
Lomacar Feb 14, 2026
ab9bc75
Merge branch 'dev' into AssetAudio
Lomacar Feb 14, 2026
1e7c55f
prettier
Lomacar Feb 14, 2026
9849252
refactor(maestro): update flow paths and add new flows for user manag…
keeandev Feb 17, 2026
9e4c277
fix sign in button press in maestro flow
keeandev Feb 17, 2026
abb1315
add ios autofill fix
keeandev Feb 17, 2026
737544e
fix maestro flow to only apply on IOS - password autofill + run befor…
keeandev Feb 17, 2026
8ddda84
fix agree to terms localization
keeandev Feb 17, 2026
6d09441
add package.json scripts for clean rebuilds + fix swift warnings in m…
keeandev Feb 17, 2026
165165e
dont create apps on maestro test file changes
keeandev Feb 17, 2026
6bffda4
Merge branch 'dev' into jesus/expo-54-2026
keeandev Feb 17, 2026
8b1d480
chore: format fix
keeandev Feb 17, 2026
58a38af
Merge branch 'dev' into jesus/expo-54-2026
keeandev Feb 17, 2026
8c45e99
refactor: standardize item card components with cn() and Button compo…
keeandev Feb 17, 2026
ce784e5
fix text color on play button for audio player
keeandev Feb 17, 2026
8510c6e
add languoid aliases for new localizations + seed local
keeandev Feb 17, 2026
8356243
bump package.json version to 2.1.0 to match app.config.ts
cursoragent Feb 17, 2026
776a959
Merge branch 'dev' into jesus/expo-54-2026
keeandev Feb 17, 2026
2fe692e
add missing localization languages to mustBeOnlineToAcceptInvite and …
cursoragent Feb 17, 2026
61518b1
fix: remove duplicate mustBeOnlineToAcceptInvite entry and format
cursoragent Feb 18, 2026
d95bdb0
Add line-ending policy for consistent working tree state.
Lomacar Feb 18, 2026
7f155a2
Merge expo-54 and align AssetAudio etc.
Lomacar Feb 19, 2026
8a7d05b
fixed Play All with expo-audio
Lomacar Feb 19, 2026
1282560
prettier and lint
Lomacar Feb 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 37 additions & 38 deletions .cursor/rules/animation-guidelines.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -61,23 +61,28 @@ The goal is to make complex products accessible to newcomers without sacrificing
A system of components housed within trays that expand, contract, and adapt in response to user actions:

**Tray Initiation Rules:**

- Trays are initiated by the user (tapping buttons, icons, or opening notifications)
- They can appear standalone on top of any content, or emerge from within other components like buttons

**Height Variation Rule:**

- Each subsequent tray varies in height to make progression unmistakably clear
- This constraint may require rewriting content or tweaking designs to make transitions apparent

**Single Focus Rule:**

- Each tray is dedicated to a singular piece of content (like educational text) or a primary action (like completing a checklist)
- Every tray has a title capturing its function and an icon for dismissal/navigation

**Context Preservation:**

- Unlike full screen transitions that displace users, trays overlay content directly onto the current interface
- Users aren't veering off course—they're diving deeper into their current context
- Contextual continuity keeps flows feeling integrated rather than disjointed

**When to Use Trays vs Full Screens:**

- Use trays for transient actions that don't need permanent display
- Especially helpful for confirmation steps and warnings that appear at the right time
- Trays can serve as starting points for elaborate flows that transition to full screen
Expand Down Expand Up @@ -118,13 +123,15 @@ While speed is important, applying motion thoughtfully can enhance clarity and f
**If a component is visible and will persist in the next phase, it should remain consistent.** Components should "travel" between screens rather than disappear and reappear.

Examples:

- Wallet cards move seamlessly between screens
- Empty states keep unchanged text constant when only a portion needs updating
- The same element animates into its new position rather than fading out/in

### Connected State Transitions

Create interactions where:

- Trays morph into full screen views
- Buttons glide across trays
- Buttons morph into trays and back again
Expand All @@ -142,6 +149,7 @@ For actions where understanding is crucial (like sending money):
### The Cost of Removing Fluidity

Without fluid animations:

- The sense of connection is lost
- Contextual continuity disappears
- Actions feel like "digital whiplash"
Expand All @@ -162,6 +170,7 @@ Delight is about creating moments that resonate on a personal level—making sof
### The Foundation of Delight

Before adding delightful moments:

- Achieve consistent polish everywhere first
- Users notice when parts of an app are less polished
- Every part of the app deserves the same holistic design approach
Expand All @@ -173,11 +182,11 @@ Before adding delightful moments:

The potential for delight increases as feature usage frequency decreases:

| Feature Frequency | Delight Strategy |
|------------------|------------------|
| Feature Frequency | Delight Strategy |
| -------------------------- | ------------------------------------------------------------ |
| Daily use (sending tokens) | Focus on small, efficient touches that don't become tiresome |
| Occasional use (settings) | Add satisfying interactions that reward exploration |
| Rare use (wallet setup) | Create memorable, celebration-worthy moments |
| Occasional use (settings) | Add satisfying interactions that reward exploration |
| Rare use (wallet setup) | Create memorable, celebration-worthy moments |

**Why this works:** The "specialness of a moment" generally decreases with repeated encounters. Rare features benefit most from delightful surprises.

Expand All @@ -188,6 +197,7 @@ The potential for delight increases as feature usage frequency decreases:
- The discovery process itself creates delight

**Examples:**

- QR code screen: Tapping triggers a gentle ripple effect
- Swiping across QR code reveals a sequin-like transformation
- Entering an amount exceeding balance triggers a playful easter egg
Expand All @@ -197,31 +207,35 @@ The potential for delight increases as feature usage frequency decreases:
Match delight intensity to feature frequency:

**High-frequency features (daily use):**

- Commas visually shift place-to-place when inputting numbers
- Small, efficient touches that don't become annoying

**Medium-frequency features:**

- Drag-and-drop with attractive stacking animations
- Satisfying rather than tedious interactions

**Low-frequency features (rare use):**

- Wallet setup: Interactive animation marking the significant occasion
- Backup completion: Confetti fills the screen as reward
- Trash items: Visually tumble into a skeuomorphic trash can with sound effects

### Specific Delight Patterns

| Feature | Delightful Touch |
|---------|------------------|
| First-time browser | Animated arrow guides toward creating a new tab |
| Reordering items | Smooth drag-and-drop with stacking animations |
| Stealth mode | Gentle shimmer effect signals hidden-but-updating values |
| Price charts | Arrow flips direction alongside changing numbers |
| Security tasks | Confetti rewards completion of essential tasks |
| Feature | Delightful Touch |
| ------------------ | -------------------------------------------------------- |
| First-time browser | Animated arrow guides toward creating a new tab |
| Reordering items | Smooth drag-and-drop with stacking animations |
| Stealth mode | Gentle shimmer effect signals hidden-but-updating values |
| Price charts | Arrow flips direction alongside changing numbers |
| Security tasks | Confetti rewards completion of essential tasks |

### The Purpose of Delight

Delightful moments are not just entertainment—they:

- Value and reward the user's time and emotional investment
- Transform mundane interactions into memorable ones
- Create a familiar, friendly companion rather than just a tool
Expand All @@ -245,21 +259,7 @@ Delightful moments are not just entertainment—they:
- **Consider Ease-In-Out:** Appropriate for elements that move and scale but stay on the screen.
- **Avoid Linear:** Linear animations feel unnatural and lack energy; avoid them in 99% of cases.

Use the following custom easing curves for a polished feel:

```css
/* Standard ease-out - good default for most animations */
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);

/* Smooth ease-in-out for symmetrical animations */
--ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

/* Snappy ease for quick feedback */
--ease-snappy: cubic-bezier(0.2, 0, 0, 1);

/* Spring-like bounce */
--ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
```
Use these Custom easing curves for a polished feel exported from `@constants/animations.ts` - import `easeOut`, `easeInOut`, `easeSnappy`, or `easeSpring` for use with React Native Reanimated animations.

### Button Press Feedback

Expand Down Expand Up @@ -426,19 +426,16 @@ For interactive elements, spring physics feel more natural than duration-based a

### Accessibility

- **Respect User Preferences:** Use media queries like `prefers-reduced-motion` to disable or reduce animations for users who prefer it.
- **Respect User Preferences:** Use React Native Reanimated's reduced motion functionality to respect system accessibility settings. All animations should respect the user's reduced motion preferences by default.

```css
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
```
React Native Reanimated provides:

- `ReduceMotion` enum (`System`, `Always`, `Never`) for configuring animation behavior
- `reduceMotion` option in animation functions (`withTiming`, `withSpring`, `withDelay`, etc.)
- `.reduceMotion()` method on layout animations (entering/exiting animations)
- `useReducedMotion()` hook for conditional animation logic

**Reference:** See the [React Native Reanimated Accessibility Guide](https://docs.swmansion.com/react-native-reanimated/docs/guides/accessibility/) for complete documentation, examples, and implementation details.

---

Expand All @@ -463,6 +460,7 @@ For interactive elements, spring physics feel more natural than duration-based a
### Delight Audit

When implementing a feature, ask:

1. How frequently will users encounter this?
2. What's the appropriate intensity of delight?
3. Is there an opportunity for surprise/discovery?
Expand Down Expand Up @@ -499,6 +497,7 @@ When implementing a feature, ask:
## Trade-offs and Commitment

Creating this level of experience requires:

- Conscious trade-offs in development speed
- Obsessive attention to detail
- Deep understanding of app navigation architecture
Expand Down
19 changes: 19 additions & 0 deletions .cursor/rules/creating-components.mdc
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,25 @@ While React Compiler can automatically memoize components, it has limitations an

- **ESLint Disable Comments**: Never use `// eslint-disable-next-line` or similar ESLint disable comments in your code. These comments prevent React Compiler from properly analyzing and optimizing your code. If ESLint flags an issue, fix the underlying problem rather than suppressing the warning. For legitimate cases where a dependency should be excluded (like stable functions or refs), refactor the code to make the stability explicit rather than disabling the exhaustive-deps rule.

- **React Native Reanimated Shared Values**: When working with React Native Reanimated's `useSharedValue`, use the `.get()` and `.set()` methods instead of accessing `.value` directly. This is the React Compiler-compliant API that avoids the need for refs or workarounds. Example:

```tsx
function App() {
const sv = useSharedValue(100);

const animatedStyle = useAnimatedStyle(() => {
'worklet';
return { width: sv.get() * 100 };
});

const handlePress = () => {
sv.set(withTiming(200, { duration: 300 }));
};
}
```

This eliminates the need for refs (`useRef`) and `useEffect` when modifying shared values in inline handlers, as React Compiler treats direct `.value` access as immutable mutations.

### Types and Props API

- **TypeScript**: Ship with comprehensive types for maximum safety and autocomplete
Expand Down
1 change: 1 addition & 0 deletions .eas/workflows/deploy-to-preview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ on:
- '!deno.json'
- '!.cursor/**'
- '!.vscode/**'
- '!.maestro/**'

jobs:
fingerprint:
Expand Down
1 change: 1 addition & 0 deletions .eas/workflows/deploy-to-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ on:
- '!deno.json'
- '!.cursor/**'
- '!.vscode/**'
- '!.maestro/**'

jobs:
fingerprint:
Expand Down
84 changes: 45 additions & 39 deletions .eas/workflows/run-preview-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ jobs:
profile: preview
platform: android

ios_get_build:
name: Check for existing ios build
needs: [fingerprint]
type: get-build
environment: preview
params:
fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
profile: preview-simulator
platform: ios

android_repack:
name: Repack Android
needs: [android_get_build]
Expand All @@ -61,6 +71,27 @@ jobs:
platform: android
profile: preview

ios_repack:
name: Repack iOS
needs: [ios_get_build]
if: ${{ needs.ios_get_build.outputs.build_id }}
type: repack
environment: preview
runs_on: macos-medium
params:
build_id: ${{ needs.ios_get_build.outputs.build_id }}

ios_build:
name: Build iOS
needs: [ios_get_build]
if: ${{ !needs.ios_get_build.outputs.build_id }}
type: build
environment: preview
runs_on: macos-medium
params:
platform: ios
profile: preview-simulator

android_maestro:
name: Run Android Maestro Tests
after: [android_repack, android_build]
Expand All @@ -71,44 +102,19 @@ jobs:
params:
build_id: ${{ needs.android_repack.outputs.build_id || needs.android_build.outputs.build_id }}
record_screen: true
device_identifier: 'pixel_6'
android_system_image_package: 'system-images;android-31;default;x86_64'
flow_path: ['maestro/register.yaml', 'maestro/sign-in.yaml']

# ios_get_build:
# name: Check for existing ios build
# needs: [fingerprint]
# type: get-build
# environment: preview
# params:
# fingerprint_hash: ${{ needs.fingerprint.outputs.ios_fingerprint_hash }}
# profile: preview-simulator

# ios_repack:
# name: Repack iOS
# needs: [ios_get_build]
# if: ${{ needs.ios_get_build.outputs.build_id }}
# type: repack
# environment: preview
# params:
# build_id: ${{ needs.ios_get_build.outputs.build_id }}

# ios_build:
# name: Build iOS
# needs: [ios_get_build]
# if: ${{ !needs.ios_get_build.outputs.build_id }}
# type: build
# environment: preview
# params:
# platform: ios
# profile: preview-simulator
flow_path: ['.maestro/flows/register.yaml', '.maestro/flows/sign-in.yaml']

# ios_maestro:
# name: Run iOS Maestro Tests
# after: [ios_repack, ios_build]
# type: maestro
# environment: preview
# image: latest
# params:
# build_id: ${{ needs.ios_repack.outputs.build_id || needs.ios_build.outputs.build_id }}
# flow_path: ['maestro.yaml']
# flow_path: ['maestro.yaml']
ios_maestro:
name: Run iOS Maestro Tests
after: [ios_repack, ios_build]
type: maestro
environment: preview
image: latest
runs_on: macos-medium
params:
record_screen: true
device_identifier: 'iPhone 16e'
build_id: ${{ needs.ios_repack.outputs.build_id || needs.ios_build.outputs.build_id }}
flow_path: ['.maestro/flows/register.yaml', '.maestro/flows/sign-in.yaml']
Loading