Skip to content

Commit ac729dc

Browse files
committed
Feat: Enhancements and Fixes
- added subtitle appearance settings - added subtitle time delay feature - added notification for download - ehancements on download functionality - fixes of paddings on mediaplayer
1 parent 622d97c commit ac729dc

30 files changed

+8956
-141
lines changed

android/app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ android {
8383
minSdkVersion rootProject.ext.minSdkVersion
8484
targetSdkVersion rootProject.ext.targetSdkVersion
8585
versionCode 1
86-
versionName "1.0.2"
86+
versionName "1.1.0"
8787
}
8888
signingConfigs {
8989
debug {

android/app/src/main/AndroidManifest.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
<uses-permission android:name="android.permission.INTERNET" />
44
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
5+
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
6+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
7+
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
58

69
<application
710
android:name=".MainApplication"
@@ -25,5 +28,11 @@
2528
<category android:name="android.intent.category.LAUNCHER" />
2629
</intent-filter>
2730
</activity>
31+
32+
<!-- Notifee Foreground Service for download notifications -->
33+
<service
34+
android:name="app.notifee.core.ForegroundService"
35+
android:foregroundServiceType="dataSync"
36+
android:exported="false" />
2837
</application>
2938
</manifest>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android"
2+
android:width="24dp"
3+
android:height="24dp"
4+
android:viewportWidth="24"
5+
android:viewportHeight="24"
6+
android:tint="#FFFFFF">
7+
<path
8+
android:fillColor="@android:color/white"
9+
android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
10+
</vector>

android/gradle.properties

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ hermesEnabled=true
4646
# Note: Only works with ReactActivity and should not be used with custom Activity.
4747
edgeToEdgeEnabled=false
4848

49+
# Set Java toolchain to 17
50+
org.gradle.java.home=C:\\Program Files\\Microsoft\\jdk-17.0.11.9-hotspot
4951

5052
RNVideo_useExoplayerDash=true
5153
RNVideo_useExoplayerHls=true
79.8 MB
Binary file not shown.

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@
1515
"dependencies": {
1616
"@gorhom/bottom-sheet": "^5.2.6",
1717
"@kesha-antonov/react-native-background-downloader": "^3.2.6",
18+
"@notifee/react-native": "^9.1.8",
1819
"@react-native-async-storage/async-storage": "^2.2.0",
1920
"@react-native-community/netinfo": "^11.4.1",
20-
"@react-native-community/slider": "^5.1.0",
21+
"@react-native-community/slider": "^5.1.2",
2122
"@react-native-vector-icons/evil-icons": "^12.4.0",
2223
"@react-native-vector-icons/fontawesome6": "^12.3.0",
2324
"@react-native/new-app-screen": "0.82.1",
@@ -41,8 +42,8 @@
4142
"react-native-vector-icons": "^10.2.0",
4243
"react-native-video": "^6.18.0",
4344
"react-native-webview": "^13.16.0",
44-
"react-native-worklets": "^0.6.1",
45-
"wyzie-lib": "^2.2.5"
45+
"react-native-worklets": "^0.7.0",
46+
"wyzie-lib": "2.2.5"
4647
},
4748
"devDependencies": {
4849
"@babel/core": "^7.25.2",

src/components/CreditsModal/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ const CreditsModal: React.FC<CreditsModalProps> = ({ isOpen, onClose }) => {
5050
style={styles.logo}
5151
resizeMode="contain"
5252
/>
53-
<Text style={styles.versionText}>1.0.1</Text>
53+
<Text style={styles.versionText}>1.1.0</Text>
5454
<ScrollView>
5555
<Text style={styles.sectionTitle}>
5656
What is Flick?

src/components/MediaPlayer/SubtitleOverlay.tsx

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import React, { useState, useEffect } from 'react';
2-
import { View, Text, StyleSheet } from 'react-native';
1+
import React, { useState, useEffect, useMemo } from 'react';
2+
import { View, Text, StyleSheet, ViewStyle, TextStyle } from 'react-native';
3+
import { SubtitleStyle, DEFAULT_SUBTITLE_STYLE } from '../../types';
34

45
interface SubtitleCue {
56
start: number;
@@ -11,6 +12,8 @@ interface SubtitleOverlayProps {
1112
subtitleContent: string | null;
1213
currentTime: number;
1314
isVideoFullscreen: boolean;
15+
delay?: number; // Delay in seconds (positive = subtitles later, negative = subtitles earlier)
16+
style?: SubtitleStyle; // Custom subtitle style from settings
1417
}
1518

1619
const parseSRT = (srtContent: string): SubtitleCue[] => {
@@ -62,10 +65,63 @@ export const SubtitleOverlay: React.FC<SubtitleOverlayProps> = ({
6265
subtitleContent,
6366
currentTime,
6467
isVideoFullscreen,
68+
delay = 0,
69+
style = DEFAULT_SUBTITLE_STYLE,
6570
}) => {
6671
const [cues, setCues] = useState<SubtitleCue[]>([]);
6772
const [currentCue, setCurrentCue] = useState<string | null>(null);
6873

74+
// Compute font size based on style setting and fullscreen mode
75+
const computedFontSize = useMemo(() => {
76+
const baseSizes = {
77+
small: isVideoFullscreen ? 14 : 10,
78+
medium: isVideoFullscreen ? 18 : 14,
79+
large: isVideoFullscreen ? 22 : 18,
80+
xlarge: isVideoFullscreen ? 26 : 22,
81+
};
82+
return baseSizes[style.fontSize] || baseSizes.medium;
83+
}, [style.fontSize, isVideoFullscreen]);
84+
85+
// Compute background color with opacity
86+
const computedBackgroundColor = useMemo(() => {
87+
if (style.backgroundOpacity === 0) return 'transparent';
88+
const hex = style.backgroundColor.replace('#', '');
89+
const r = parseInt(hex.substring(0, 2), 16);
90+
const g = parseInt(hex.substring(2, 4), 16);
91+
const b = parseInt(hex.substring(4, 6), 16);
92+
return `rgba(${r}, ${g}, ${b}, ${style.backgroundOpacity})`;
93+
}, [style.backgroundColor, style.backgroundOpacity]);
94+
95+
// Dynamic container style based on position
96+
const containerStyle: ViewStyle = useMemo(() => ({
97+
position: 'absolute',
98+
left: 0,
99+
right: 0,
100+
alignItems: 'center',
101+
paddingHorizontal: 20,
102+
...(style.position === 'top' ? { top: 50 } : { bottom: 20 }),
103+
}), [style.position]);
104+
105+
// Dynamic text style
106+
const textStyle: TextStyle = useMemo(() => ({
107+
color: style.fontColor,
108+
textAlign: 'center',
109+
fontSize: computedFontSize,
110+
fontWeight: style.fontWeight === 'bold' ? '700' : '400',
111+
textShadowColor: style.textShadow ? 'rgba(0, 0, 0, 1)' : 'transparent',
112+
textShadowOffset: style.textShadow ? { width: 1, height: 1 } : { width: 0, height: 0 },
113+
textShadowRadius: style.textShadow ? 2 : 0,
114+
}), [style.fontColor, style.fontWeight, style.textShadow, computedFontSize]);
115+
116+
// Dynamic text container style
117+
const textContainerStyle: ViewStyle = useMemo(() => ({
118+
backgroundColor: computedBackgroundColor,
119+
paddingVertical: 8,
120+
paddingHorizontal: 16,
121+
borderRadius: 4,
122+
maxWidth: '100%',
123+
}), [computedBackgroundColor]);
124+
69125
useEffect(() => {
70126
if (subtitleContent) {
71127
try {
@@ -87,50 +143,27 @@ export const SubtitleOverlay: React.FC<SubtitleOverlayProps> = ({
87143
return;
88144
}
89145

90-
const adjustedTime = currentTime + 0.5;
146+
// Apply delay: positive delay means subtitles appear later (subtract from currentTime)
147+
// negative delay means subtitles appear earlier (add to currentTime)
148+
const adjustedTime = currentTime - delay + 0.5;
91149
const activeCue = cues.find(
92150
cue => adjustedTime >= cue.start && adjustedTime <= cue.end
93151
);
94152

95153
setCurrentCue(activeCue ? activeCue.text : null);
96-
}, [currentTime, cues]);
154+
}, [currentTime, cues, delay]);
97155

98156
if (!currentCue) {
99157
return null;
100158
}
101159

102160
return (
103-
<View style={styles.container}>
104-
<View style={styles.textContainer}>
105-
<Text style={[styles.text, isVideoFullscreen && { fontSize: 18 }]}>{currentCue}</Text>
161+
<View style={containerStyle}>
162+
<View style={textContainerStyle}>
163+
<Text style={textStyle}>{currentCue}</Text>
106164
</View>
107165
</View>
108166
);
109167
};
110168

111-
const styles = StyleSheet.create({
112-
container: {
113-
position: 'absolute',
114-
bottom: 20,
115-
left: 0,
116-
right: 0,
117-
alignItems: 'center',
118-
paddingHorizontal: 20,
119-
},
120-
textContainer: {
121-
backgroundColor: 'rgba(0, 0, 0, 0)',
122-
paddingVertical: 8,
123-
paddingHorizontal: 16,
124-
borderRadius: 4,
125-
maxWidth: '100%',
126-
},
127-
text: {
128-
color: '#FFFFFF',
129-
textAlign: 'center',
130-
fontSize: 12,
131-
fontWeight: '600',
132-
textShadowColor: 'rgba(0, 0, 0, 1)',
133-
textShadowOffset: { width: 1, height: 1 },
134-
textShadowRadius: 2,
135-
},
136-
});
169+
export default SubtitleOverlay;

src/components/MediaPlayer/controls/BottomBar.tsx

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useState } from 'react';
22
import { Text, TouchableOpacity, View } from 'react-native';
33
import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons';
44
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
@@ -23,12 +23,27 @@ export const BottomBar: React.FC<BottomBarProps> = ({
2323
onSubtitlePress,
2424
onResize,
2525
onFullscreen,
26+
subtitleDelay = 0,
27+
onSubtitleDelayChange,
28+
onResetSubtitleDelay,
2629
}) => {
30+
const [showDelayControls, setShowDelayControls] = useState(false);
31+
32+
const handleSubtitleLongPress = () => {
33+
if (hasSubtitles && onSubtitleDelayChange) {
34+
setShowDelayControls(!showDelayControls);
35+
}
36+
};
37+
38+
const formatDelay = (delay: number) => {
39+
const sign = delay >= 0 ? '+' : '';
40+
return `${sign}${delay.toFixed(1)}s`;
41+
};
42+
2743
return (
2844
<View
2945
style={[
3046
styles.bottomBar,
31-
fullscreen ? { paddingBottom: sizes.height * 0.01 } : {},
3247
hidden ? styles.bottomBarHidden : styles.bottomBarVisible,
3348
]}
3449
>
@@ -52,10 +67,49 @@ export const BottomBar: React.FC<BottomBarProps> = ({
5267

5368
<Text style={styles.timeText}>{timeLabel}</Text>
5469

70+
{/* Subtitle delay controls - shown when long-pressing subtitle button */}
71+
{showDelayControls && hasSubtitles && onSubtitleDelayChange && (
72+
<View style={styles.delayControlsContainer}>
73+
<TouchableOpacity
74+
onPress={() => onSubtitleDelayChange(-0.5)}
75+
style={styles.delayButton}
76+
>
77+
<MaterialCommunityIcon
78+
name="minus"
79+
size={sizes.width * 0.04}
80+
color={colors.white}
81+
/>
82+
</TouchableOpacity>
83+
84+
<TouchableOpacity
85+
onPress={onResetSubtitleDelay}
86+
style={styles.delayValueButton}
87+
>
88+
<Text style={styles.delayText}>{formatDelay(subtitleDelay)}</Text>
89+
</TouchableOpacity>
90+
91+
<TouchableOpacity
92+
onPress={() => onSubtitleDelayChange(0.5)}
93+
style={styles.delayButton}
94+
>
95+
<MaterialCommunityIcon
96+
name="plus"
97+
size={sizes.width * 0.04}
98+
color={colors.white}
99+
/>
100+
</TouchableOpacity>
101+
</View>
102+
)}
103+
55104
{onSubtitlePress && (
56-
<TouchableOpacity onPress={onSubtitlePress} style={styles.subtitleButton}>
105+
<TouchableOpacity
106+
onPress={onSubtitlePress}
107+
onLongPress={handleSubtitleLongPress}
108+
delayLongPress={500}
109+
style={styles.subtitleButton}
110+
>
57111
<MaterialCommunityIcon
58-
name="closed-caption"
112+
name={showDelayControls ? 'timer-outline' : 'closed-caption'}
59113
size={sizes.width * 0.05}
60114
color={hasSubtitles ? colors.red : colors.white}
61115
/>

0 commit comments

Comments
 (0)