diff --git a/components/UI/MediaViewer.tsx/MediaVideo.android.tsx b/components/UI/MediaViewer.tsx/MediaVideo.android.tsx index 6ce01a7e..6e499089 100644 --- a/components/UI/MediaViewer.tsx/MediaVideo.android.tsx +++ b/components/UI/MediaViewer.tsx/MediaVideo.android.tsx @@ -18,6 +18,7 @@ import { usePanGesture, } from "react-native-gesture-handler"; import { runOnJS } from "react-native-worklets"; +import useVideoAudioControls from "./useVideoAudioControls"; export type VideoItem = { type: "video"; @@ -28,12 +29,14 @@ type MediaVideoProps = { source: Post["videos"][number]; focused: boolean; overlayStyle: AnimatedStyleHandle<{ opacity: number }>; + isMuted: boolean; + setIsMuted: (isMuted: boolean) => void; }; const PLAYBACK_RATES = [0.5, 1, 1.5, 2]; function MediaVideo(props: MediaVideoProps) { - const { source, focused, overlayStyle } = props; + const { source, focused, overlayStyle, isMuted, setIsMuted } = props; const { width, height } = useSafeAreaFrame(); const { top: safeAreaTop, left: safeAreaLeft } = useSafeAreaInsets(); @@ -41,6 +44,7 @@ function MediaVideo(props: MediaVideoProps) { VideoCache.makeCachedVideoSource(source.source), (player) => { player.audioMixingMode = "mixWithOthers"; + player.muted = isMuted; player.loop = true; player.timeUpdateEventInterval = 1 / 15; player.seekTolerance = { @@ -50,6 +54,13 @@ function MediaVideo(props: MediaVideoProps) { }, ); + useVideoAudioControls({ + player, + focused, + isMuted, + setIsMuted, + }); + const videoTimeAtSeekStart = useSharedValue(0); const wasPlayingAtSeekStart = useSharedValue(false); const isSeeking = useSharedValue(false); @@ -142,10 +153,8 @@ function MediaVideo(props: MediaVideoProps) { useEffect(() => { if (focused) { player.play(); - player.volume = 1; } else { player.pause(); - player.volume = 0; } }, [focused]); @@ -258,6 +267,35 @@ function MediaVideo(props: MediaVideoProps) { {playbackRate ?? 1}x + { + e.preventDefault(); + e.stopPropagation(); + }} + > + setIsMuted(!isMuted)} + > + + + ); @@ -338,6 +376,9 @@ const styles = StyleSheet.create({ position: "absolute", left: 10, }, + audioControlContainer: { + position: "absolute", + }, playbackRateButton: { borderRadius: 100, alignItems: "center", diff --git a/components/UI/MediaViewer.tsx/MediaVideo.ios.tsx b/components/UI/MediaViewer.tsx/MediaVideo.ios.tsx index e3c08536..623471fb 100644 --- a/components/UI/MediaViewer.tsx/MediaVideo.ios.tsx +++ b/components/UI/MediaViewer.tsx/MediaVideo.ios.tsx @@ -17,6 +17,7 @@ import { import DismountWhenBackgrounded from "../../Other/DismountWhenBackgrounded"; import VideoCache from "../../../utils/VideoCache"; import { Post } from "../../../api/Posts"; +import useVideoAudioControls from "./useVideoAudioControls"; export type VideoItem = { type: "video"; @@ -28,12 +29,14 @@ type MediaVideoProps = { focused: boolean; overlayOpacity: Animated.Value; setIsScrollLocked: (isScrollLocked: boolean) => void; + isMuted: boolean; + setIsMuted: (isMuted: boolean) => void; }; const PLAYBACK_RATES = [0.5, 1, 1.5, 2]; function MediaVideo(props: MediaVideoProps) { - const { source, focused, overlayOpacity } = props; + const { source, focused, overlayOpacity, isMuted, setIsMuted } = props; const { width, height } = useSafeAreaFrame(); const { top: safeAreaTop, left: safeAreaLeft } = useSafeAreaInsets(); @@ -41,11 +44,19 @@ function MediaVideo(props: MediaVideoProps) { VideoCache.makeCachedVideoSource(source.source), (player) => { player.audioMixingMode = "mixWithOthers"; + player.muted = isMuted; player.loop = true; player.timeUpdateEventInterval = 1 / 15; }, ); + useVideoAudioControls({ + player, + focused, + isMuted, + setIsMuted, + }); + const touchStart = useRef({ x: 0, y: 0, @@ -118,10 +129,8 @@ function MediaVideo(props: MediaVideoProps) { useEffect(() => { if (focused) { player.play(); - player.volume = 1; } else { player.pause(); - player.volume = 0; } }, [focused]); @@ -273,6 +282,35 @@ function MediaVideo(props: MediaVideoProps) { {playbackRate ?? 1}x + { + e.preventDefault(); + e.stopPropagation(); + }} + > + setIsMuted(!isMuted)} + > + + + ); } @@ -348,6 +386,9 @@ const styles = StyleSheet.create({ position: "absolute", left: 10, }, + audioControlContainer: { + position: "absolute", + }, playbackRateButton: { borderRadius: 100, alignItems: "center", diff --git a/components/UI/MediaViewer.tsx/MediaViewer.android.tsx b/components/UI/MediaViewer.tsx/MediaViewer.android.tsx index 02de23aa..db08da03 100644 --- a/components/UI/MediaViewer.tsx/MediaViewer.android.tsx +++ b/components/UI/MediaViewer.tsx/MediaViewer.android.tsx @@ -69,6 +69,8 @@ export default function MediaViewer({ startingColumnIndex, onFocusedItemChange, getCurrentPost, + isMuted, + setIsMuted, onClose, }: MediaViewerProps) { const { width, height } = useSafeAreaFrame(); @@ -475,6 +477,8 @@ export default function MediaViewer({ columns={columns} pagerEnabled={pagerEnabled} overlayStyle={overlayStyle} + isMuted={isMuted} + setIsMuted={setIsMuted} /> ))} @@ -497,6 +501,8 @@ type RowStripProps = { columns: SharedValue>; pagerEnabled: SharedValue; overlayStyle: AnimatedStyleHandle<{ opacity: number }>; + isMuted: boolean; + setIsMuted: (isMuted: boolean) => void; }; function RowStrip({ @@ -511,6 +517,8 @@ function RowStrip({ columns, pagerEnabled, overlayStyle, + isMuted, + setIsMuted, }: RowStripProps) { const horizontalStyle = useAnimatedStyle(() => ({ transform: [ @@ -555,6 +563,8 @@ function RowStrip({ source={item.source} focused={centerColumn === column && isRowFocused} overlayStyle={overlayStyle} + isMuted={isMuted} + setIsMuted={setIsMuted} /> )} diff --git a/components/UI/MediaViewer.tsx/MediaViewer.ios.tsx b/components/UI/MediaViewer.tsx/MediaViewer.ios.tsx index 9375b192..851515c9 100644 --- a/components/UI/MediaViewer.tsx/MediaViewer.ios.tsx +++ b/components/UI/MediaViewer.tsx/MediaViewer.ios.tsx @@ -26,6 +26,8 @@ type MediaViewerProps = { startingColumnIndex: number; onFocusedItemChange?: (index: number) => void; getCurrentPost?: (rowIndex: number) => Post | PostDetail | null; + isMuted: boolean; + setIsMuted: (isMuted: boolean) => void; onClose: () => void; }; @@ -35,6 +37,8 @@ export default function MediaViewer({ startingColumnIndex, onFocusedItemChange, getCurrentPost, + isMuted, + setIsMuted, onClose, }: MediaViewerProps) { const { width, height } = useSafeAreaFrame(); @@ -301,6 +305,8 @@ export default function MediaViewer({ } overlayOpacity={overlayOpacity.current} setIsScrollLocked={setIsScrollLocked} + isMuted={isMuted} + setIsMuted={setIsMuted} /> ) : null} diff --git a/components/UI/MediaViewer.tsx/types.ts b/components/UI/MediaViewer.tsx/types.ts index ce375f7e..74eb0206 100644 --- a/components/UI/MediaViewer.tsx/types.ts +++ b/components/UI/MediaViewer.tsx/types.ts @@ -24,5 +24,7 @@ export type MediaViewerProps = { startingColumnIndex: number; onFocusedItemChange?: (index: number) => void; getCurrentPost?: (rowIndex: number) => Post | PostDetail | null; + isMuted: boolean; + setIsMuted: (isMuted: boolean) => void; onClose: () => void; }; diff --git a/components/UI/MediaViewer.tsx/useVideoAudioControls.ts b/components/UI/MediaViewer.tsx/useVideoAudioControls.ts new file mode 100644 index 00000000..e233192f --- /dev/null +++ b/components/UI/MediaViewer.tsx/useVideoAudioControls.ts @@ -0,0 +1,51 @@ +import { VideoPlayer } from "expo-video"; +import { useEffect } from "react"; +import { VolumeManager } from "react-native-volume-manager"; +import { isMediaVolumeIncrease } from "./videoAudioControls"; + +export default function useVideoAudioControls({ + player, + focused, + isMuted, + setIsMuted, +}: { + player: VideoPlayer; + focused: boolean; + isMuted: boolean; + setIsMuted: (isMuted: boolean) => void; +}) { + useEffect(() => { + player.muted = isMuted; + }, [isMuted, player]); + + useEffect(() => { + if (!focused || !isMuted) return; + + let cancelled = false; + let listener: ReturnType | null = + null; + let previousVolume: number | null = null; + + VolumeManager.getVolume() + .then(({ volume }) => { + if (cancelled) return; + previousVolume = volume; + listener = VolumeManager.addVolumeListener((event) => { + if (isMediaVolumeIncrease(previousVolume, event.volume, event.type)) { + setIsMuted(false); + } + if (event.type === undefined || event.type === "music") { + previousVolume = event.volume; + } + }); + }) + .catch(() => { + // The mute button still works if the native volume API is unavailable. + }); + + return () => { + cancelled = true; + listener?.remove(); + }; + }, [focused, isMuted, setIsMuted]); +} diff --git a/components/UI/MediaViewer.tsx/videoAudioControls.test.ts b/components/UI/MediaViewer.tsx/videoAudioControls.test.ts new file mode 100644 index 00000000..ac050e21 --- /dev/null +++ b/components/UI/MediaViewer.tsx/videoAudioControls.test.ts @@ -0,0 +1,18 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { isMediaVolumeIncrease } from "./videoAudioControls.ts"; + +test("detects iOS and Android media volume increases", () => { + assert.equal(isMediaVolumeIncrease(0.25, 0.5), true); + assert.equal(isMediaVolumeIncrease(0.25, 0.5, "music"), true); +}); + +test("ignores the initial reading, decreases, and unchanged volume", () => { + assert.equal(isMediaVolumeIncrease(null, 0.5), false); + assert.equal(isMediaVolumeIncrease(0.5, 0.25), false); + assert.equal(isMediaVolumeIncrease(0.5, 0.5), false); +}); + +test("ignores unrelated Android volume streams", () => { + assert.equal(isMediaVolumeIncrease(0.25, 0.5, "ring"), false); +}); diff --git a/components/UI/MediaViewer.tsx/videoAudioControls.ts b/components/UI/MediaViewer.tsx/videoAudioControls.ts new file mode 100644 index 00000000..d4600e03 --- /dev/null +++ b/components/UI/MediaViewer.tsx/videoAudioControls.ts @@ -0,0 +1,11 @@ +export function isMediaVolumeIncrease( + previousVolume: number | null, + nextVolume: number, + volumeType?: string, +) { + return ( + previousVolume !== null && + nextVolume > previousVolume && + (volumeType === undefined || volumeType === "music") + ); +} diff --git a/constants/documentation.ts b/constants/documentation.ts index d7e0a1e9..c7253a4d 100644 --- a/constants/documentation.ts +++ b/constants/documentation.ts @@ -267,7 +267,7 @@ AI Summaries is a [Hydra Pro](hydra://settings/guide/?doc=hydra_pro) feature. Ma appearance_settings: { key: "appearance_settings", title: "Appearance Settings", - description: "Post appearance (compact mode, split view, subreddit display, text lengths, flairs, blur options, summaries, auto-play, live text, tap to collapse), comment appearance (vote indicators, AutoModerator, flairs, summaries, tap to collapse), tab appearance (username, hide on scroll)", + description: "Post appearance (compact mode, split view, subreddit display, text lengths, flairs, blur options, summaries, auto-play, default video mute, live text, tap to collapse), comment appearance (vote indicators, AutoModerator, flairs, summaries, tap to collapse), tab appearance (username, hide on scroll)", vector: [-0.022940528, 0.0016233673, 0.003962395, 0.060299315, 0.032066837, -0.03141027, -0.0027034236, -0.020826375, 0.013630376, 0.07658223, -0.02959814, -0.024778921, -0.019683944, 0.03844869, 0.022257695, -0.0008781613, -0.015271799, 0.040943652, 0.031016327, 0.08320045, 0.039893143, -0.040076982, 0.03056986, 0.0715923, -0.020248594, -0.006545995, 0.014011187, 0.050319463, 0.016939485, -0.006299781, 0.010334399, -0.008568228, 0.011273293, -0.027733482, -0.015534427, -0.027864795, 0.02287487, 0.0033091088, 0.024752658, 0.03561231, -0.020524353, -0.019381922, -0.025934482, 0.02523852, -0.0525518, 0.03311735, 0.007727819, 0.0042086085, -0.0008642092, 0.057673037, -0.008587925, 0.006578823, -0.018042522, 0.01338088, 0.0048225005, 0.0047634095, -0.04517196, -0.0036144133, -0.009559647, -0.029046621, -0.014024317, 0.007563677, 0.03359008, -0.0017464741, -0.04469923, -0.003140042, -0.03994567, 0.023846593, -0.02106274, -0.012317237, 0.06465893, -0.07248524, -0.002719838, 0.0061586187, 0.01793747, -0.0069399364, -0.030701175, 0.018095046, -0.011319253, -0.0079641845, 0.005134371, 0.0099404575, -0.02439811, -0.0141425, -0.0038639095, 0.022901133, -0.056517474, 0.00981571, -0.06917613, 0.023991037, 0.021627389, -0.0024457201, -0.050923504, -0.028547628, 0.026682971, -0.0131445145, -0.0006048644, -0.02011728, -0.025199125, 0.096699506, 0.069596335, -0.05725283, -0.06245286, -0.03104259, 0.048165914, 0.0036472417, 0.010419752, 0.011398041, -0.006834885, -0.010899048, -0.07831557, -0.022717293, 0.0043169423, -0.008469743, 0.02059001, -0.008436914, 0.022835476, -0.0010398414, 0.00711721, -0.03159411, -0.017989995, 0.009303586, 0.03122643, -0.007609637, 0.020419301, -0.014943515, -0.021995068, -0.020708192, -0.12417036, -0.01309199, 0.054416455, 0.03466685, 0.052499272, -0.05609727, -0.003857344, -0.0063358927, -0.022034463, 0.023176892, -0.024700133, -0.019040506, 0.031357743, -0.0032582246, 0.029204197, -0.024345586, -0.03742444, -0.02135163, 0.00032336032, 0.0039065867, -0.014838464, 0.02153547, 0.003407594, 0.037083026, -0.021299103, -0.0094677275, -0.01623039, -0.026919337, 0.06744279, 0.019972835, -0.051369973, 0.030044606, -0.015928369, -0.033274926, -0.040418398, -0.012238449, -0.026157716, -0.014667756, -0.03056986, -0.051868964, -0.038947683, 0.00019543192, 0.024056695, -0.017911207, 0.01423442, -0.03718808, 0.0491639, 0.0033714827, -0.04375377, -0.009835406, -0.033143613, 0.020773849, -0.024345586, 0.04622247, -0.07458626, 0.015875842, -0.06113972, -0.03361634, -0.017110193, -0.02533044, 0.00873237, -0.024096088, 0.034325436, -0.034036547, -0.023413258, -0.007347009, -0.012120267, -0.010472278, 0.018397069, -0.031620372, -0.036006253, 0.0023685733, 0.037634544, 0.03852748, 0.010249045, 0.015258668, 0.022152644, -0.016414229, -0.015560689, 0.038159803, -0.0041528, -0.006069982, 0.020642536, -0.014588967, 0.016939485, 0.014982909, -0.02345265, 0.009139443, -0.04603863, 0.002751025, -0.046642676, 0.02781227, -0.010669249, 0.023308206, 0.058093242, 0.016729383, 0.013111686, 0.03159411, 0.020340513, 0.003620979, -0.023045579, 0.05066088, 0.032434516, -0.0067823594, -0.035901204, -0.0015248819, 0.02894157, -0.049820468, -0.0050358856, -0.022625374, 0.011923296, 0.006775794, 0.024936497, 0.045986105, -0.013426839, 0.018659696, 0.053182103, -0.008883381, -0.016493019, -0.06387105, 0.007176301, -0.026735498, 0.055834644, 0.018081915, 0.0106955115, -0.015705135, -0.010281873, -0.042939626, -0.024726395, 0.025067812, -0.029676927, -0.014694018, 0.004172497, -0.014943515, -0.015324324, -0.047194194, -0.011043494, 0.027076913, 0.014562705, 0.019001111, -0.030438548, -0.057357885, 0.042598207, 0.03500827, 0.015403113, 0.037739597, -0.0028495102, -0.048376016, -0.009979852, 0.010859654, 0.009658133, 0.016243521, 0.02238901, -0.008935907, 0.02202133, 0.0048060864, -0.016584938, -0.010176823, -0.0053543216, 0.00581392, 0.054889183, -0.018095046, 0.029466825, 0.012730876, 0.025120337, -0.020471826, -0.023741541, 0.07479636, 0.009973286, 0.033379976, -0.031200167, -0.021929411, -0.009868234, -0.004966946, 0.01528493, -0.016886959, 0.039210312, 0.03624262, 0.012212187, 0.0042742654, 0.015350588, -0.028101161, -0.011463698, 0.0033074673, -0.024989024, -0.02534357, -0.073430695, -0.02354457, 0.03466685, 0.042178005, -0.014195026, -0.019053638, -0.004303811, 0.020471826, -0.0058664456, 0.005160634, 0.050319463, -0.026591051, 0.034719378, 0.00835156, -0.0028921873, -0.04296589, 0.030386021, -0.07080442, -0.010334399, 0.03424665, 0.006601803, -0.06928118, -0.004471236, 0.05588717, -0.06907108, 0.028048635, -0.0039919405, -0.03466685, -0.02875773, -0.014562705, -0.04031335, 0.0034404225, -0.03587494, -0.012271278, -0.037056763, 0.040602237, -0.005413413, 0.036295146, -0.0070843813, -0.04538206, -0.024989024, 0.01432634, -0.023938512, -0.03217189, -0.051790178, 0.028495103, -0.013256132, -0.026078928, 0.004494216, -0.026682971, 0.024529425, -0.024831446, -0.04716793, 0.004943966, 0.0055644237, -0.0019221063, -0.00290696, -0.030333497, 0.03674161, -0.0033091088, -0.012389461, -0.011877337, 0.019079901, -0.029860767, -0.03500827, -0.033248663, 0.014943515, -0.006841451, 0.025304176, -0.00067626627, 0.042860836, -0.022362746, 0.007176301, 0.005413413, 0.0077212537, 0.017622316, -0.0072156955, 0.0026952166, -0.010708643, -0.007649031, 0.024989024, 0.04251942, -0.020051623, -0.000077813704, 0.028442577, 0.020563746, 0.06450135, -0.027287016, -0.054994233, -0.004901289, 0.011883902, -0.0008207115, 0.04622247, 0.019880915, 0.032250676, 0.020038491, 0.050266936, -0.020839505, 0.028678942, -0.0111288475, -0.021561733, 0.002728045, 0.03443049, 0.00545609, 0.05977406, 0.030202182, 0.019290002, -0.048533592, -0.026236504, -0.0045303274, 0.008673279, 0.043858822, -0.00882429, -0.022848608, 0.044252764, -0.05202654, -0.022073856, 0.023833461, 0.07006906, 0.022704162, -0.011023796, -0.020629404, -0.009992983, 0.029466825, -0.014720281, 0.0030563294, -0.015521295, 0.009579345, -0.003831081, -0.030412285, 0.027575906, 0.01366977, 0.026971862, -0.014851595, -0.008522268, -0.02676176, -0.007734385, 0.028626416, -0.04905885, 0.04811339, 0.02107587, -0.00547907, 0.03169916, -0.0033977455, 0.03293351, -0.0134596685, 0.05068714, 0.010104599, 0.027838534, 0.017320296, 0.018252622, -0.010071771, -0.036137566, 0.021325367, 0.011752589, -0.029099146, 0.037450705, -0.0044449735, 0.0592488, -0.030648649, -0.014877858, -0.020104147, 0.03461433, -0.032775935, 0.013958661, -0.0045139133, -0.0113652125, 0.0029381472, -0.011358647, 0.031068854, 0.017727368, 0.034220386, 0.03537595, -0.006276801, -0.005049017, -0.012441986, -0.003831081, 0.0050785625, 0.03190926, -0.0141425, 0.021338498, -0.007662162, -0.025593067, -0.034325436, 0.037056763, -0.029781979, 0.027418328, -0.03274967, 0.003877041, 0.03130522, 0.029046621, -0.013866741, 0.03519211, 0.0058073546, -0.0058664456, 0.024503162, -0.072380185, 0.00081045256, 0.032986037, 0.0016053116, -0.0343517, 0.021811228, -0.02543549, 0.020104147, 0.033196136, -0.016282916, -0.03340624, 0.014510179, 0.03190926, 0.016742514, 0.07437616, -0.00711721, -0.03369513, -0.042178005, -0.08587925, -0.03007087, -0.022047592, -0.0394992, 0.015009171, -0.00031843604, -0.03272341, 0.019972835, -0.013998055, -0.038842633, -0.018856667, -0.013945529, 0.018186966, -0.008312166, 0.03616383, 0.008804592, 0.01784555, 0.004943966, -0.0013574568, 0.001854808, 0.028022373, 0.0009224797, 0.05788314, 0.0012327087, 0.05039825, -0.032198153, 0.019578893, 0.0099404575, 0.0017382669, 0.0064146807, -0.008469743, 0.032014314, 0.0012819513, -0.032250676, 0.010209651, 0.015547558, -0.026801154, 0.014208157, 0.055677067, -0.0068677138, -0.020813243, 0.008069235, -0.004064163, -0.0018531665, -0.001959859, -0.000610199, 0.008798027, -0.032224417, -0.023754673, -0.024319323, 0.02060314, 0.016387967, -0.026512263, -0.018869799, 0.009750052, 0.032907248, -0.040917393, 0.015022303, -0.010281873, 0.04961037, 0.0056300806, -0.014352602, 0.019578893, -0.006834885, -0.01906677, 0.03776586, -0.002693575, -0.0063588726, -0.03122643, 0.0137354275, 0.016637463, 0.01304603, -0.023675885, -0.037266865, -0.026735498, -0.015311194, -0.019828388, 0.014155632, 0.021522338, -0.048691172, 0.020248594, -0.0037687072, -0.0067495313, -0.01546877, -0.024030432, -0.0012138323, 0.018869799, 0.023150628, 0.008843987, -0.027759746, 0.044173975, -0.039893143, -0.007773779, -0.014733412, -0.014365734, 0.018738484, 0.0077869105, 0.009796012, -0.002309482, -0.05066088, 0.014680887, 0.0067035714, 0.035848677, 0.01129299, 0.0294143, 0.008102064, -0.006073265, -0.0130263325, 0.036321405, 0.013551588, 0.004047749, -0.033248663, 0.008903078, 0.026643578, 0.00015839732, 0.017884944, 0.010905614, 0.0045237616, -0.020458696, 0.014772806, -0.004966946, 0.016007157, 0.009690961, -0.008187418, 0.029020358, -0.010229348, 0.018292017, -0.034115333, -0.018843535, -0.0022142795, -0.020813243, 0.017543528, -0.030779963, 0.029020358, -0.023203155, -0.008738936, -0.023373863, -0.0069399364, 0.01461523, -0.027260752, -0.00783287, 0.028416313, -0.00716317, -0.01133895, 0.02875773, -0.0030678194, 0.030990066, -0.006257104, 0.044436604, -0.014602099, -0.02571125, 0.058723547, -0.0039361324, 0.015994025, -0.036268882, -0.0639761, 0.02571125, -0.019710207, -0.012061176, 0.03406281, 0.018909192, 0.0008740577, 0.0012499436, 0.03361634, -0.004917703, 0.0012975448, -0.02723449, 0.014378865, -0.010577329, 0.02449003, 0.03217189, -0.07537414, 0.01048541, 0.014378865, 0.012212187, -0.03482443, -0.0039033038, 0.013433405, -0.017491003, 0.019434448, 0.031935524, -0.012776836, -0.026722366, 0.0131051205, -0.051580075, 0.0541013, 0.013374315, -0.0002995597, -0.01499604, 0.011076322, 0.01871222, 0.00940207, -0.010583895, -0.0077869105, -0.0067035714, 0.0019335962, 0.0014403487, 0.0022881436, 0.013564719, 0.014772806, -0.0008798027, -0.0045139133, -0.010098034, -0.026945598, 0.015114223, 0.016059682, -0.0026295595, 0.05798819, -0.024700133, -0.016309178, -0.01595463, 0.0042775483, -0.0042414367, 0.014365734, 0.051448762, -0.015613215, 0.011017231, -0.002585241, -0.033931494, 0.029571876, -0.02571125, 0.03093754, 0.041101232, 0.0110041, 0.009487425, -0.03760828, -0.0012655371, 0.023478914, 0.009316716, -0.026722366, -0.0033813312, 0.061664976, 0.012612694, 0.03466685, 0.009907629, 0.008272772, -0.030359758, -0.010491976, -0.012330369, -0.02325568, -0.03710929, 0.013472799, -0.013387445, -0.02571125, -0.02686681, -0.003410877, 0.047561873, -0.034771904, 0.018620301, -0.014247552, 0.003535625, -0.018961718, -0.012934413, 0.021312235, 0.007419232, -0.017438477, 0.01537685, -0.024188008, 0.00929702, -0.05588717, -0.010465712, 0.011122282, -0.011988954, -0.011457132, 0.016821302, -0.030885015, -0.005439676, 0.024516294, 0.0016578372, -0.068073094, 0.02316376, 0.011700063, -0.008843987, 0.0034830994, -0.009040957, -0.0077606477, 0.0006175854, 0.051448762, -0.02002536, 0.018383937, -0.018344542, 0.010452582, 0.0044876505, 0.008456611, -0.051947754, -0.00080881116, -0.04089113, 0.019880915, -0.011155111, -0.026170848, -0.0045007817, -0.014300076, 0.04414771, -0.005157351, -0.026367819, 0.0011703345, 0.015521295, 0.026709234, -0.0043103765, -0.0028921873, 0.02325568, -0.016860697, -0.004861895, 0.0064606406, 0.019381922, -0.014129369, 0.018305149, 0.014444522, -0.010124297, 0.0028626416, -0.04301841, 0.008436914, 0.02295366, 0.015009171, -0.04081234, 0.02258598, 0.0066740257, -0.0296244, 0.030228445, 0.0010882635, 0.004431842, 0.021890016, 0.0058697285, -0.013354617, -0.029099146, -0.020209199, -0.01699201, -0.04848107, 0.008850552, 0.032986037, 0.03093754, 0.028705204, 0.021719309, 0.023360731, -0.011023796, -0.0048093693, 0.0047732578, -0.012428855, -0.002603297, 0.021929411, 0.023767805, 0.017018273, -0.021430418, 0.005561141, -0.0047863894, -0.008344994, 0.012730876, 0.01993344, -0.011050059, 0.03957799, 0.0077606477, 0.0072682207, 0.00864045, 0.020642536, -0.018777879, 0.012448552, -0.03056986, 0.03482443, -0.0036341103, 0.010413188, 0.007458626, 0.02686681, -0.01432634, -0.030543597, -0.021115264, 0.003302543, 0.028101161, 0.0563599, -0.00065328635, 0.017412215, 0.0022963507, 0.027024388, -0.01784555, -0.009756618, -0.0035848678, 0.02580317, -0.014195026, -0.012914715, 0.063713476, -0.015521295, -0.0069924616, 0.040549714, 0.016663726, -0.011096019, 0.009671264, -0.0042644166, -0.017149586, 0.0025950896, -0.027628431, 0.023386994, -0.0070581185, -0.014877858, 0.003962395, -0.037818383, -0.014772806, 0.0067068543, -0.03768707, 0.010446016, 0.012967241, -0.023991037, 0.021863753, -0.013682902, 0.004096992, 0.0042578513, -0.027497116, 0.013590982, 0.008450045, 0.044646703, 0.019381922, -0.0068480168, 0.029388037, -0.035769887, 0.011890468, -0.035664838, -0.0008428707, -0.029177934, -0.01963142, 0.014339471, -0.022060724, 0.02875773, 0.0046353783, -0.0058533144, 0.0068480168, 0.030018343, -0.008955603, -0.021758704, -0.045250747, 0.017070798, 0.011043494, 0.028915307, -0.018265754, 0.012120267, -0.05341847, 0.015311194, -0.007714688, -0.014050581, -0.012468249, 0.010052074, -0.005833617, -0.00002928914, 0.014391996, 0.017898075, -0.0069530676, 0.004658358, 0.051475022, -0.000030468913, 0.043990135, -0.013039464, 0.020169806, -0.011686931, 0.019145558, 0.012185924, -0.00707125, 0.044646703, 0.0044679535, 0.029204197, -0.013085424, -0.04632752, -0.013774822, -0.025593067, 0.015731398, 0.007399535, -0.00032664317, -0.043044675, 0.01604655, -0.002747742, -0.03485069, -0.0058434657, 0.050450776, 0.03485069, 0.06654985, -0.020813243, -0.008929341, 0.0024736244, 0.0615074, -0.032775935, 0.03093754, 0.043622456, 0.00992076, -0.006089679, 0.0011785417, 0.0066838744, 0.008456611, 0.011076322, 0.06654985, -0.0027034236, 0.00006391291, -0.01812131, -0.0082399435, -0.004884875, -0.017963734, -0.009500556, -0.023308206, 0.013269263, 0.012940979, -0.008889947, 0.013787953, -0.00036952534, -0.012770271, 0.027943585, 0.044830542, 0.0010505107, 0.019473841, 0.030596124, 0.0064179637, 0.017188981, -0.0037555757, 0.020169806, 0.00016732255, 0.060509417, 0.03453554, -0.035270896, -0.026998125, -0.030832488, 0.01461523, -0.015481901, 0.021364762, 0.007951053, -0.007714688, -0.03217189, 0.0032385276, 0.033537555, 0.0064245295, -0.019408185, 0.016033418, 0.03093754, 0.0064639235, -0.014076843, 0.017543528, 0.025185993, 0.026328424, 0.021968804, -0.024923366, 0.0099010635, 0.014982909, -0.023413258, -0.003131835, 0.012487946, 0.0032237547, 0.009782881, 0.022218302, -0.028521365, 0.033169877, -0.03579615, 0.024188008, -0.054258876, 0.025409227, 0.008128326, -0.013308657, -0.013564719, 0.0064507923, -0.012041478, -0.010446016, 0.025566803, -0.00125733, -0.009986417, -0.054416455, 0.016059682, 0.024647607, -0.020931425, 0.0072550895, 0.01888293, -0.0077212537, -0.0036406762, -0.010623289, -0.0064343777, -0.016401099, -0.024306191, 0.014628361, 0.044751756, 0.011575314, 0.01880414, 0.002165037, 0.009040957, 0.020169806, 0.030254709, 0.0077869105, 0.003143325, 0.003046481, 0.0099010635, -0.024096088, 0.011956125, 0.037634544, 0.015206142, -0.028363789, 0.050004307, -0.010386924, -0.013282395, 0.003597999, -0.01528493, 0.02733954, 0.016545543, 0.016663726, 0.014195026, -0.008285903, 0.012849059, -0.010288439, 0.009572779, -0.01086622, -0.02656479, 0.00538715, -0.0042742654, 0.0022618808, -0.016965747, -0.009776315, -0.05541444, -0.012934413, 0.022283958, 0.0025343571, -0.014352602, 0.015403113, 0.003597999, -0.0094283335, 0.004687904, -0.031016327, -0.019079901, 0.0014444522, -0.020655666, -0.003643959, 0.07968123, -0.027575906, 0.01775363, -0.015074829, 0.053943723, -0.0018531665, 0.027786007, 0.011805113, -0.020681929, 0.021666784, -0.012382895, -0.025881957, -0.0060995277, 0.006329327, 0.008148024, -0.011897033, 0.010071771, 0.00787883, 0.045408323, -0.00056588056, 0.017635448, -0.005150785, 0.025002154, 0.014720281, 0.026696103, 0.0058894255, 0.030543597, 0.011706629, 0.031436533, 0.026459739, -0.019880915, -0.027680956, -0.017517265, 0.05152755, -0.035060793, 0.028022373, 0.02571125, -0.008837421, 0.030517336, 0.0039985063, -0.0041921944, -0.030228445, 0.030307233, -0.01133895, -0.003962395, -0.00010925721, -0.052446745, 0.011470264, 0.016256653, -0.015600083, 0.014930383, 0.008115195, 0.0019516519, -0.0039492636, -0.00005544932, -0.029309249, 0.052709375, 0.035060793, -0.033143613, -0.01147683, -0.035769887, 0.06586702, -0.0141425, -0.0036505247, -0.0023685733, -0.0017546811, 0.03198805, 0.006293216, 0.005475787, 0.0056596263, -0.024923366, -0.017320296, 0.015705135, 0.0343517, 0.0055644237, 0.015087959, -0.02781227, 0.02410922, 0.03519211, -0.021128396, 0.0003643959, -0.00491442, 0.013577851, -0.0024966043, -0.042493157, 0.0096646985, 0.026801154, -0.018935455, -0.0008576435, 0.025133468, 0.0064901863, -0.01124703, 0.044725493, 0.036032517, 0.025737511, 0.013295526, -0.035769887, 0.02875773, 0.027287016, -0.0047666924, 0.019697076, 0.0031695878, 0.022756688, -0.008088932, -0.011056625, 0.014247552, -0.0044613876, -0.0184102, 0.0042545684, 0.0031531735, -0.024411242, -0.008436914, 0.04564469, 0.027891058, 0.0016767136, -0.03330119, -0.021299103, 0.028783992, -0.03742444, -0.056044746, 0.037161816, -0.021995068, 0.013282395, -0.023899117, 0.00021769371, -0.009047523, -0.009047523, -0.007622768, 0.01537685, 0.0026098625, -0.026433475, 0.008561662, 0.018042522, 0.0064934692, -0.046169944, -0.012921281, 0.0014551214, 0.0026295595, -0.035769887, 0.0013615603, 0.01219249, 0.010065205, -0.0066149347, -0.020721324, 0.010098034, -0.005787657, 0.0055644237, 0.029965818, -0.020366777, -0.003962395, -0.02600014, -0.007957619, 0.012369763, 0.03863253, 0.0097040925, -0.027444592, -0.035087056, 0.017766763, 0.009395505, -0.0064639235, -0.012468249, -0.012310673, -0.03293351, -0.015298062, 0.01129299, -0.018265754, -0.037844647, -0.0047601266, 0.036373932, -0.012940979, -0.013814216, -0.022993052, -0.028862782, 0.04414771, 0.00144199, -0.026144585, 0.010662683, 0.00028047815, -0.056990206, 0.016676858, -0.009559647, -0.008929341, -0.012468249, -0.011457132, 0.005209876, 0.003916435, 0.002207714, -0.03272341, 0.006112659, -0.0074717575, 0.00047067803, -0.023373863, 0.003182719, -0.021706177, 0.010354096, 0.031095115, 0.02609206, -0.014864726, 0.017162718, 0.035638575, 0.011391475, -0.0011284783, -0.0067429654, -0.032381993, -0.026643578, 0.02238901, 0.002340669, 0.019079901, -0.021023344, 0.021509206, -0.020340513, -0.008541965, -0.012067742, 0.015810186, 0.037634544, 0.045250747, -0.012041478, 0.004156083, 0.014457653, 0.021364762, 0.011752589, 0.0033977455, 0.019828388, -0.022940528, -0.014877858, -0.0010890841, -0.017530397, 0.0208789, 0.003120345, 0.0033288058, 0.006050285, -0.014339471, -0.0113652125, 0.032565832, -0.019408185, 0.00012403002, 0.001359919, -0.010899048, -0.024332454, 0.016598068, 0.005994477, -0.016781908, -0.04270326, 0.016952617, -0.020209199, 0.036268882, 0.007432363, -0.0046353783, -0.0019467276, -0.0065295803, 0.01633544, 0.010610158, 0.07516404, -0.016532412, 0.013998055, -0.034955744, 0.011746023, -0.0048192176, 0.019119294, -0.027497116, -0.020366777, -0.004730581, 0.0063982666, -0.016781908, 0.0055775554, 0.018659696, 0.017727368, -0.016059682, -0.023767805, 0.039551727, -0.016217258, -0.00877833, -0.018646564, 0.026380949, 0.011575314, -0.02259911, 0.033169877, 0.021929411, -0.0010004473, -0.0059583653, -0.008364691, 0.003643959, -0.012586432, 0.004881592, 0.010354096, -0.0055283126, -0.013170778, -0.015179879, 0.014313208, 0.036478985, 0.037450705, -0.0015421169, -0.013866741, 0.0027099892, 0.027733482, -0.020458696, -0.0025934482, -0.00940207, -0.0028051918, 0.0032959774, 0.02410922, -0.031646635, 0.0041659316, 0.022612242, 0.0009602324, 0.027943585, -0.0045204787, 0.017819287, -0.016348572, -0.010124297, 0.008443479, -0.0024145332, -0.015521295, -0.021837492, 0.001012758, -0.004359619, -0.007944487, 0.022664769, -0.029072883, -0.023505177, 0.026354687, 0.016190996, 0.0003904535, -0.0139717925, 0.009008129, 0.018147573, -0.014300076, 0.025514279, 0.00018312124, -0.01680817, 0.015770791, 0.033169877, 0.04262447, -0.004471236, 0.030228445, -0.0077475165, 0.008535399, 0.011319253, 0.026170848, -0.008653582, -0.005416696, -0.019001111, -0.0011506375, -0.017687974, 0.03737192, 0.026210241, 0.015902106, 0.014956646, 0.010656117, 0.0015971045, 0.019171821, 0.008719238, -0.006601803, -0.000039753213, -0.0032155477, 0.021784965, 0.023938512, -0.03718808, 0.0053444733, -0.011483395, 0.017569792, 0.017123325, -0.015311194, 0.023098104, -0.008653582, 0.026065797, 0.056412425, 0.0066871573, 0.025868826, -0.0051245224, -0.010446016, -0.018265754, 0.046957828, -0.031147642, 0.03881637, -0.0114046065, -0.03474564, 0.019079901, 0.028678942, -0.037713334, 0.013216738, 0.016440492, 0.016493019, 0.019053638, 0.009014695, 0.018370805, -0.028626416, 0.0045007817, -0.020668797], text: `# Appearance Settings @@ -299,6 +299,8 @@ Appearance settings control how posts, comments, and tabs are displayed. Configu **Auto Play Videos**: Automatically plays videos as you scroll. Uses more data and battery. +**Mute Videos by Default**: Starts full-screen videos muted. Changing mute from the video controls applies to other videos until Hydra is restarted. + **Live Text**: Enables text recognition in images using iOS Live Text, allowing you to select and copy text. Learn more in the [Live Text guide](hydra://settings/guide/?doc=live_text). **Tap to Collapse**: When enabled, tapping on a post\'s media or content area in the detail view collapses it. When disabled, tapping the post content does nothing, which can be useful to avoid accidentally collapsing posts while reading. Enabled by default. @@ -1950,6 +1952,8 @@ For multi-image posts, swipe left and right to browse between images. An indicat ## Video Player +Videos show a mute button in the full-screen controls. Enable **Mute Videos by Default** in Appearance settings to begin each app session muted. Hydra remembers your mute choice until the app is restarted. Pressing the device volume-up button also unmutes the current video. + **Tap the playback speed button** (top-left corner in full-screen video) to cycle through 0.5x, 1x, 1.5x, and 2x playback speeds. **Drag horizontally** on a video to scrub through it. Videos also support **Picture-in-Picture** on iOS — use the system PiP gesture to keep watching while you browse. diff --git a/contexts/MediaViewerContext.tsx b/contexts/MediaViewerContext.tsx index 4cfb1fb5..9560d99b 100644 --- a/contexts/MediaViewerContext.tsx +++ b/contexts/MediaViewerContext.tsx @@ -1,6 +1,7 @@ import { createContext, RefObject, + useContext, useEffect, useMemo, useRef, @@ -11,6 +12,7 @@ import MediaViewer, { } from "../components/UI/MediaViewer.tsx/MediaViewer"; import { Post } from "../api/Posts"; import { PostDetail } from "../api/PostDetail"; +import { PostSettingsContext } from "./SettingsContexts/PostSettingsContext"; type DisplayMediaDataRequest = { media: MediaItemCollection; @@ -39,8 +41,14 @@ const initialMediaViewerContext = { export const MediaViewerContext = createContext(initialMediaViewerContext); export function MediaViewerProvider({ children }: React.PropsWithChildren) { + const { muteVideosByDefault } = useContext(PostSettingsContext); const [displayMediaData, setDisplayMediaData] = useState(null); + const [isMuted, setIsMuted] = useState(muteVideosByDefault); + + useEffect(() => { + setIsMuted(muteVideosByDefault); + }, [muteVideosByDefault]); const isShowing = useRef(false); const visibilityListeners = useRef>(new Set()); @@ -121,6 +129,8 @@ export function MediaViewerProvider({ children }: React.PropsWithChildren) { }} startingRowIndex={displayMediaData.startingRowIndex ?? 0} startingColumnIndex={displayMediaData.startingColumnIndex ?? 0} + isMuted={isMuted} + setIsMuted={setIsMuted} onClose={() => setDisplayMediaData(null)} /> )} diff --git a/contexts/SettingsContexts/PostSettingsContext.tsx b/contexts/SettingsContexts/PostSettingsContext.tsx index 5c90daa8..095f226c 100644 --- a/contexts/SettingsContexts/PostSettingsContext.tsx +++ b/contexts/SettingsContexts/PostSettingsContext.tsx @@ -15,6 +15,7 @@ const initialValues = { blurNSFW: true, showPostSummary: true, autoPlayVideos: true, + muteVideosByDefault: false, liveTextInteraction: false, tapToCollapsePost: true, }; @@ -33,6 +34,7 @@ const initialPostSettingsContext = { toggleBlurNSFW: (_newValue?: boolean) => {}, toggleShowPostSummary: (_newValue?: boolean) => {}, toggleAutoPlayVideos: (_newValue?: boolean) => {}, + toggleMuteVideosByDefault: (_newValue?: boolean) => {}, toggleLiveTextInteraction: (_newValue?: boolean) => {}, toggleTapToCollapsePost: (_newValue?: boolean) => {}, }; @@ -93,6 +95,12 @@ export function PostSettingsProvider({ children }: React.PropsWithChildren) { useMMKVBoolean("autoPlayVideos"); const autoPlayVideos = storedAutoPlayVideos ?? initialValues.autoPlayVideos; + const [storedMuteVideosByDefault, setMuteVideosByDefault] = useMMKVBoolean( + "muteVideosByDefault", + ); + const muteVideosByDefault = + storedMuteVideosByDefault ?? initialValues.muteVideosByDefault; + const [storedliveTextInteraction, setliveTextInteraction] = useMMKVBoolean( "liveTextInteraction", ); @@ -156,6 +164,11 @@ export function PostSettingsProvider({ children }: React.PropsWithChildren) { toggleAutoPlayVideos: (newValue = !autoPlayVideos) => setAutoPlayVideos(newValue), + muteVideosByDefault: + muteVideosByDefault ?? initialValues.muteVideosByDefault, + toggleMuteVideosByDefault: (newValue = !muteVideosByDefault) => + setMuteVideosByDefault(newValue), + liveTextInteraction: liveTextInteraction ?? initialValues.liveTextInteraction, toggleLiveTextInteraction: (newValue = !liveTextInteraction) => diff --git a/documentation/appearance_settings.md b/documentation/appearance_settings.md index e18bfd40..c0979daf 100644 --- a/documentation/appearance_settings.md +++ b/documentation/appearance_settings.md @@ -1,6 +1,6 @@ ===METADATA=== title: Appearance Settings -description: Post appearance (compact mode, split view, subreddit display, text lengths, flairs, blur options, summaries, auto-play, live text, tap to collapse), comment appearance (vote indicators, AutoModerator, flairs, summaries, tap to collapse), tab appearance (username, hide on scroll) +description: Post appearance (compact mode, split view, subreddit display, text lengths, flairs, blur options, summaries, auto-play, default video mute, live text, tap to collapse), comment appearance (vote indicators, AutoModerator, flairs, summaries, tap to collapse), tab appearance (username, hide on scroll) ===END METADATA=== # Appearance Settings @@ -33,6 +33,8 @@ Appearance settings control how posts, comments, and tabs are displayed. Configu **Auto Play Videos**: Automatically plays videos as you scroll. Uses more data and battery. +**Mute Videos by Default**: Starts full-screen videos muted. Changing mute from the video controls applies to other videos until Hydra is restarted. + **Live Text**: Enables text recognition in images using iOS Live Text, allowing you to select and copy text. Learn more in the [Live Text guide](hydra://settings/guide/?doc=live_text). **Tap to Collapse**: When enabled, tapping on a post's media or content area in the detail view collapses it. When disabled, tapping the post content does nothing, which can be useful to avoid accidentally collapsing posts while reading. Enabled by default. diff --git a/documentation/tips_and_tricks.md b/documentation/tips_and_tricks.md index b1da1503..1357537a 100644 --- a/documentation/tips_and_tricks.md +++ b/documentation/tips_and_tricks.md @@ -35,6 +35,8 @@ For multi-image posts, swipe left and right to browse between images. An indicat ## Video Player +Videos show a mute button in the full-screen controls. Enable **Mute Videos by Default** in Appearance settings to begin each app session muted. Hydra remembers your mute choice until the app is restarted. Pressing the device volume-up button also unmutes the current video. + **Tap the playback speed button** (top-left corner in full-screen video) to cycle through 0.5x, 1x, 1.5x, and 2x playback speeds. **Drag horizontally** on a video to scrub through it. Videos also support **Picture-in-Picture** on iOS — use the system PiP gesture to keep watching while you browse. diff --git a/package-lock.json b/package-lock.json index 2b6d1c87..882f6920 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,6 +60,7 @@ "react-native-safe-area-context": "~5.6.2", "react-native-screens": "~4.23.0", "react-native-url-polyfill": "^2.0.0", + "react-native-volume-manager": "^2.0.8", "react-native-web": "^0.21.0", "react-native-webview": "13.16.0", "react-native-worklets": "0.9.1", @@ -12637,6 +12638,16 @@ "react-native": "*" } }, + "node_modules/react-native-volume-manager": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/react-native-volume-manager/-/react-native-volume-manager-2.0.8.tgz", + "integrity": "sha512-aZM47/mYkdQ4CbXpKYO6Ajiczv7fxbQXZ9c0H8gRuQUaS3OCz/MZABer6o9aDWq0KMNsQ7q7GVFLRPnSSeeMmw==", + "license": "MIT", + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, "node_modules/react-native-web": { "version": "0.21.0", "resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.21.0.tgz", diff --git a/package.json b/package.json index 76820c92..fe81a6bf 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "react-native-safe-area-context": "~5.6.2", "react-native-screens": "~4.23.0", "react-native-url-polyfill": "^2.0.0", + "react-native-volume-manager": "^2.0.8", "react-native-web": "^0.21.0", "react-native-webview": "13.16.0", "react-native-worklets": "0.9.1", @@ -88,4 +89,4 @@ "wrapper-webpack-plugin": "^2.2.2" }, "private": true -} \ No newline at end of file +} diff --git a/pages/SettingsPage/Appearance.tsx b/pages/SettingsPage/Appearance.tsx index 98e15f8d..12a2bd0e 100644 --- a/pages/SettingsPage/Appearance.tsx +++ b/pages/SettingsPage/Appearance.tsx @@ -54,6 +54,8 @@ export default function Appearance() { toggleShowPostSummary, autoPlayVideos, toggleAutoPlayVideos, + muteVideosByDefault, + toggleMuteVideosByDefault, liveTextInteraction, toggleLiveTextInteraction, tapToCollapsePost, @@ -363,6 +365,24 @@ export default function Appearance() { text: "Auto play videos", onPress: () => toggleAutoPlayVideos(), }, + { + key: "muteVideosByDefault", + icon: ( + + ), + rightIcon: ( + toggleMuteVideosByDefault()} + /> + ), + text: "Mute videos by default", + onPress: () => toggleMuteVideosByDefault(), + }, { key: "liveTextInteraction", icon: ( diff --git a/tsconfig.json b/tsconfig.json index e22f4e15..c0155bbf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "expo/tsconfig.base", "compilerOptions": { - "strict": true + "strict": true, + "allowImportingTsExtensions": true } -} \ No newline at end of file +}