Skip to content

Commit 375900b

Browse files
committed
RU-T46 PR#199 fixes
1 parent d586596 commit 375900b

File tree

5 files changed

+79
-59
lines changed

5 files changed

+79
-59
lines changed

env.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,6 @@ const client = z.object({
8888
LOGGING_KEY: z.string(),
8989
APP_KEY: z.string(),
9090
UNIT_MAPBOX_PUBKEY: z.string(),
91-
UNIT_MAPBOX_DLKEY: z.string(),
9291
IS_MOBILE_APP: z.boolean(),
9392
SENTRY_DSN: z.string(),
9493
COUNTLY_APP_KEY: z.string(),
@@ -123,7 +122,6 @@ const _clientEnv = {
123122
APP_KEY: process.env.UNIT_APP_KEY || '',
124123
IS_MOBILE_APP: true, // or whatever default you want
125124
UNIT_MAPBOX_PUBKEY: process.env.UNIT_MAPBOX_PUBKEY || '',
126-
UNIT_MAPBOX_DLKEY: process.env.UNIT_MAPBOX_DLKEY || '',
127125
SENTRY_DSN: process.env.UNIT_SENTRY_DSN || '',
128126
COUNTLY_APP_KEY: process.env.UNIT_COUNTLY_APP_KEY || '',
129127
COUNTLY_SERVER_URL: process.env.UNIT_COUNTLY_SERVER_URL || '',

plugins/withMediaButtonModule.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,17 @@ import android.content.IntentFilter
155155
import android.media.session.MediaSession
156156
import android.media.session.PlaybackState
157157
import android.os.Build
158+
import android.util.Log
158159
import android.view.KeyEvent
159160
import com.facebook.react.bridge.*
160161
import com.facebook.react.modules.core.DeviceEventManagerModule
161162
162163
class MediaButtonModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext), LifecycleEventListener {
163164
165+
companion object {
166+
private const val TAG = "MediaButtonModule"
167+
}
168+
164169
private var mediaSession: MediaSession? = null
165170
private var isListening = false
166171
private var mediaButtonReceiver: BroadcastReceiver? = null
@@ -300,7 +305,7 @@ class MediaButtonModule(reactContext: ReactApplicationContext) : ReactContextBas
300305
try {
301306
reactApplicationContext.unregisterReceiver(it)
302307
} catch (e: Exception) {
303-
// Receiver may not be registered
308+
Log.d(TAG, "Failed to unregister media button receiver: \${e.message}")
304309
}
305310
}
306311
mediaButtonReceiver = null
@@ -482,13 +487,8 @@ const withMediaButtonModule = (config) => {
482487
const packagesMatch = mainApplication.contents.match(packagesPattern);
483488

484489
if (packagesMatch) {
485-
if (packagesMatch[1]) {
486-
// Already has toMutableList()
487-
mainApplication.contents = mainApplication.contents.replace(packagesPattern, `val packages = PackageList(this).packages.toMutableList()\n packages.add(MediaButtonPackage())`);
488-
} else {
489-
// Need to add toMutableList()
490-
mainApplication.contents = mainApplication.contents.replace(packagesPattern, `val packages = PackageList(this).packages.toMutableList()\n packages.add(MediaButtonPackage())`);
491-
}
490+
// Replace the packages declaration, ensuring toMutableList() is present so we can add our package
491+
mainApplication.contents = mainApplication.contents.replace(packagesPattern, `val packages = PackageList(this).packages.toMutableList()\n packages.add(MediaButtonPackage())`);
492492
console.log('[withMediaButtonModule] Registered MediaButtonPackage in MainApplication.kt');
493493
}
494494
}

src/services/media-button.service.ts

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@ import { DeviceEventEmitter, NativeEventEmitter, NativeModules, Platform } from
33
import { logger } from '@/lib/logging';
44
import { audioService } from '@/services/audio.service';
55
import { type AudioButtonEvent, useBluetoothAudioStore } from '@/stores/app/bluetooth-audio-store';
6+
import {
7+
createDefaultPTTSettings,
8+
type MediaButtonPTTSettings,
9+
type PTTMode,
10+
} from '@/types/ptt';
11+
12+
// Re-export PTT types for backwards compatibility
13+
export { type MediaButtonPTTSettings, type PTTMode };
614

715
// Lazy import to break dependency cycle with livekit-store
816
const getLiveKitStore = () => require('@/stores/app/livekit-store').useLiveKitStore;
@@ -16,37 +24,14 @@ export interface MediaButtonEvent {
1624
source?: 'airpods' | 'bluetooth_earbuds' | 'wired_headset' | 'unknown';
1725
}
1826

19-
// PTT mode configuration
20-
export type PTTMode = 'toggle' | 'push_to_talk';
21-
22-
// Settings for media button PTT functionality
23-
export interface MediaButtonPTTSettings {
24-
enabled: boolean;
25-
pttMode: PTTMode;
26-
// For toggle mode: single press toggles mute state
27-
// For push_to_talk mode: press to unmute, release to mute (requires double-tap for this)
28-
usePlayPauseForPTT: boolean;
29-
// Double tap behavior
30-
doubleTapAction: 'none' | 'toggle_mute';
31-
doubleTapTimeoutMs: number;
32-
}
33-
34-
const DEFAULT_PTT_SETTINGS: MediaButtonPTTSettings = {
35-
enabled: true,
36-
pttMode: 'toggle',
37-
usePlayPauseForPTT: true,
38-
doubleTapAction: 'toggle_mute',
39-
doubleTapTimeoutMs: 400,
40-
};
41-
4227
// Try to get the native module (will be null if not installed)
4328
const { MediaButtonModule } = NativeModules;
4429

4530
class MediaButtonService {
4631
private static instance: MediaButtonService;
4732
private isInitialized = false;
4833
private eventListeners: { remove: () => void }[] = [];
49-
private settings: MediaButtonPTTSettings = DEFAULT_PTT_SETTINGS;
34+
private settings: MediaButtonPTTSettings = createDefaultPTTSettings();
5035
private lastPressTimestamp: number = 0;
5136
private doubleTapTimer: ReturnType<typeof setTimeout> | null = null;
5237
private pendingSingleTap: boolean = false;

src/stores/app/bluetooth-audio-store.ts

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,19 @@
11
import { type Peripheral } from 'react-native-ble-manager';
22
import { create } from 'zustand';
33

4+
import {
5+
createDefaultPTTSettings,
6+
DEFAULT_MEDIA_BUTTON_PTT_SETTINGS,
7+
type MediaButtonPTTSettings,
8+
type PTTMode,
9+
} from '@/types/ptt';
10+
11+
// Re-export PTT types for backwards compatibility
12+
export { DEFAULT_MEDIA_BUTTON_PTT_SETTINGS, type MediaButtonPTTSettings, type PTTMode };
13+
414
// Re-export Peripheral as Device for compatibility
515
export type Device = Peripheral;
616

7-
// PTT mode configuration for media buttons (AirPods/earbuds)
8-
export type PTTMode = 'toggle' | 'push_to_talk';
9-
10-
// Settings for media button PTT functionality
11-
export interface MediaButtonPTTSettings {
12-
enabled: boolean;
13-
pttMode: PTTMode;
14-
// For toggle mode: single press toggles mute state
15-
// For push_to_talk mode: press to unmute, release to mute
16-
usePlayPauseForPTT: boolean;
17-
// Double tap behavior
18-
doubleTapAction: 'none' | 'toggle_mute';
19-
doubleTapTimeoutMs: number;
20-
}
21-
2217
// Bluetooth state enum to match react-native-ble-plx API
2318
export enum State {
2419
Unknown = 'unknown',
@@ -62,15 +57,6 @@ export interface AudioDeviceSelection {
6257
speaker: AudioDeviceInfo | null;
6358
}
6459

65-
// Default media button PTT settings
66-
export const DEFAULT_MEDIA_BUTTON_PTT_SETTINGS: MediaButtonPTTSettings = {
67-
enabled: true,
68-
pttMode: 'toggle',
69-
usePlayPauseForPTT: true,
70-
doubleTapAction: 'toggle_mute',
71-
doubleTapTimeoutMs: 400,
72-
};
73-
7460
interface BluetoothAudioState {
7561
// Bluetooth state
7662
bluetoothState: State;
@@ -153,7 +139,7 @@ export const useBluetoothAudioStore = create<BluetoothAudioState>((set, get) =>
153139
isAudioRoutingActive: false,
154140
buttonEvents: [],
155141
lastButtonAction: null,
156-
mediaButtonPTTSettings: DEFAULT_MEDIA_BUTTON_PTT_SETTINGS,
142+
mediaButtonPTTSettings: createDefaultPTTSettings(),
157143

158144
// Bluetooth state actions
159145
setBluetoothState: (state) => set({ bluetoothState: state }),

src/types/ptt.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* PTT (Push-to-Talk) types and settings for media button functionality.
3+
* Used by bluetooth-audio-store and media-button.service.
4+
*/
5+
6+
/**
7+
* PTT mode configuration for media buttons (AirPods/earbuds)
8+
* - 'toggle': Single press toggles mute state on/off
9+
* - 'push_to_talk': Press and hold to unmute, release to mute
10+
*/
11+
export type PTTMode = 'toggle' | 'push_to_talk';
12+
13+
/**
14+
* Settings for media button PTT functionality
15+
*/
16+
export interface MediaButtonPTTSettings {
17+
/** Whether media button PTT functionality is enabled */
18+
enabled: boolean;
19+
/** The PTT mode to use */
20+
pttMode: PTTMode;
21+
/**
22+
* Whether to use play/pause button for PTT
23+
* - For toggle mode: single press toggles mute state
24+
* - For push_to_talk mode: press to unmute, release to mute
25+
*/
26+
usePlayPauseForPTT: boolean;
27+
/** Double tap action behavior */
28+
doubleTapAction: 'none' | 'toggle_mute';
29+
/** Timeout in milliseconds to detect double tap */
30+
doubleTapTimeoutMs: number;
31+
}
32+
33+
/**
34+
* Default media button PTT settings.
35+
* This object is frozen to prevent accidental mutations.
36+
*/
37+
export const DEFAULT_MEDIA_BUTTON_PTT_SETTINGS: Readonly<MediaButtonPTTSettings> = Object.freeze({
38+
enabled: true,
39+
pttMode: 'toggle',
40+
usePlayPauseForPTT: true,
41+
doubleTapAction: 'toggle_mute',
42+
doubleTapTimeoutMs: 400,
43+
});
44+
45+
/**
46+
* Creates a mutable copy of the default PTT settings.
47+
* Use this when initializing state that needs to be modified.
48+
*/
49+
export const createDefaultPTTSettings = (): MediaButtonPTTSettings => ({
50+
...DEFAULT_MEDIA_BUTTON_PTT_SETTINGS,
51+
});

0 commit comments

Comments
 (0)