437 lines
13 KiB
TypeScript
437 lines
13 KiB
TypeScript
import { useTheme } from '@/components/ThemeContext';
|
||
import { router } from 'expo-router';
|
||
import { VideoView, useVideoPlayer } from 'expo-video';
|
||
import { ArrowLeft, Play, X } from 'lucide-react-native';
|
||
import React, { useEffect, useMemo, useState } from 'react';
|
||
import { useTranslation } from 'react-i18next';
|
||
import {
|
||
FlatList,
|
||
Image,
|
||
Pressable,
|
||
ScrollView,
|
||
StyleSheet,
|
||
Text,
|
||
TouchableOpacity,
|
||
View,
|
||
} from 'react-native';
|
||
import ImageViewer from 'react-native-image-zoom-viewer';
|
||
import Modal from 'react-native-modal';
|
||
|
||
type ManualStep = {
|
||
image: any;
|
||
description?: string;
|
||
};
|
||
|
||
type Language = {
|
||
code: 'uz' | 'ru' | 'en';
|
||
label: string;
|
||
flag: string;
|
||
};
|
||
|
||
const languages: Language[] = [
|
||
{ code: 'uz', label: "O'zbekcha", flag: '🇺🇿' },
|
||
{ code: 'ru', label: 'Русский', flag: '🇷🇺' },
|
||
{ code: 'en', label: 'English', flag: '🇬🇧' },
|
||
];
|
||
|
||
export function ManualTab() {
|
||
const { isDark } = useTheme();
|
||
const { t, i18n } = useTranslation();
|
||
const [isPlaying, setIsPlaying] = useState(false);
|
||
|
||
/** 🔹 Modal states */
|
||
const [imageVisible, setImageVisible] = useState(false);
|
||
const [imageIndex, setImageIndex] = useState(0);
|
||
const [langPickerVisible, setLangPickerVisible] = useState(false);
|
||
|
||
/** 🔹 Video tili (SELECT uchun) */
|
||
const userLang = i18n.language.startsWith('ru')
|
||
? 'ru'
|
||
: i18n.language.startsWith('en')
|
||
? 'en'
|
||
: 'uz';
|
||
|
||
const [selectedLang, setSelectedLang] = useState<'uz' | 'ru' | 'en'>(userLang);
|
||
|
||
/** 🔹 RASM tili (faqat app tili bo‘yicha) */
|
||
const imageLang: 'uz' | 'ru' | 'en' = userLang;
|
||
|
||
/** 🔹 Theme */
|
||
const theme = {
|
||
background: isDark ? '#0f172a' : '#f8fafc',
|
||
cardBg: isDark ? '#1e293b' : '#ffffff',
|
||
text: isDark ? '#ffffff' : '#0f172a',
|
||
primary: '#3b82f6',
|
||
textMuted: isDark ? '#94a3b8' : '#64748b',
|
||
border: isDark ? '#334155' : '#e2e8f0',
|
||
};
|
||
|
||
/** 🔹 Video manbalari (SELECT ga bog‘liq) */
|
||
const videos = {
|
||
uz: require('@/assets/manual/manual_video_uz.mp4'),
|
||
ru: require('@/assets/manual/manual_video_ru.mp4'),
|
||
en: require('@/assets/manual/manual_video_en.mp4'),
|
||
};
|
||
|
||
const player = useVideoPlayer(videos[selectedLang], (player) => {
|
||
player.loop = false;
|
||
});
|
||
/** 🔹 Rasmlar (FAqat imageLang) */
|
||
const steps: ManualStep[] = [
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step1.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step1.jpg')
|
||
: require('@/assets/manual/image_en/step1.jpg'),
|
||
description: t("Ilovani oching va ro'yxatdan o'ting"),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step2.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step2.jpg')
|
||
: require('@/assets/manual/image_en/step2.jpg'),
|
||
description: t("Profilni to'ldiring"),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step3.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step3.jpg')
|
||
: require('@/assets/manual/image_en/step3.jpg'),
|
||
description: t("To'lov usulini qo'shing"),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step4.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step4.jpg')
|
||
: require('@/assets/manual/image_en/step4.jpg'),
|
||
description: t('Xaridni tanlang'),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step5.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step5.jpg')
|
||
: require('@/assets/manual/image_en/step5.jpg'),
|
||
description: t("To'lovni amalga oshiring"),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step6.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step6.jpg')
|
||
: require('@/assets/manual/image_en/step6.jpg'),
|
||
description: t("Natijani ko'ring"),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step7.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step7.jpg')
|
||
: require('@/assets/manual/image_en/step7.jpg'),
|
||
description: t("Natijani ko'ring"),
|
||
},
|
||
{
|
||
image:
|
||
imageLang === 'uz'
|
||
? require('@/assets/manual/image_uz/step8.jpg')
|
||
: imageLang === 'ru'
|
||
? require('@/assets/manual/image_ru/step8.jpg')
|
||
: require('@/assets/manual/image_en/step8.jpg'),
|
||
description: t("Natijani ko'ring"),
|
||
},
|
||
];
|
||
|
||
/** 🔹 Image viewer */
|
||
const images = useMemo(
|
||
() => steps.map((step) => ({ url: '', props: { source: step.image } })),
|
||
[imageLang]
|
||
);
|
||
|
||
useEffect(() => {
|
||
// listener qo'shish
|
||
const subscription = player.addListener('playingChange', (state) => {
|
||
setIsPlaying(state.isPlaying);
|
||
});
|
||
|
||
return () => {
|
||
subscription.remove();
|
||
};
|
||
}, [player]);
|
||
|
||
const renderStep = ({ item, index }: { item: ManualStep; index: number }) => (
|
||
<Pressable
|
||
onPress={() => {
|
||
setImageIndex(index);
|
||
setImageVisible(true);
|
||
}}
|
||
>
|
||
<View style={[styles.stepCard, { backgroundColor: theme.cardBg }]}>
|
||
<Image source={item.image} style={styles.stepImage} />
|
||
</View>
|
||
</Pressable>
|
||
);
|
||
|
||
return (
|
||
<ScrollView style={[styles.container, { backgroundColor: theme.background }]}>
|
||
{/* HEADER */}
|
||
<View style={styles.hero}>
|
||
<View style={styles.topHeader}>
|
||
<Pressable onPress={() => router.back()}>
|
||
<ArrowLeft color={theme.text} size={24} />
|
||
</Pressable>
|
||
<Text style={[styles.headerTitle, { color: theme.text }]}>
|
||
{t("Foydalanish qo'llanmasi")}
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
|
||
{/* VIDEO */}
|
||
<View style={styles.section}>
|
||
<Text style={[styles.sectionTitle, { color: theme.text }]}>
|
||
{t("Foydalanish qo'llanmasi")}
|
||
</Text>
|
||
<Text style={[styles.subtitle, { color: theme.textMuted }]}>
|
||
{t("Quyidagi qisqa video yoki rasmlarni ko'rib chiqing")}
|
||
</Text>
|
||
{/* <View style={{ alignContent: 'flex-end', alignItems: 'flex-end', paddingHorizontal: 16 }}>
|
||
<Pressable
|
||
style={[
|
||
styles.langSelector,
|
||
{ backgroundColor: theme.cardBg, borderColor: theme.border },
|
||
]}
|
||
onPress={() => setLangPickerVisible(true)}
|
||
>
|
||
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
||
<Text style={{ fontSize: 20 }}>{selectedLanguage?.flag}</Text>
|
||
</View>
|
||
<ChevronDown color={theme.textMuted} />
|
||
</Pressable>
|
||
</View> */}
|
||
|
||
<View style={[styles.videoCard, { backgroundColor: theme.cardBg }]}>
|
||
<VideoView
|
||
player={player}
|
||
style={styles.video}
|
||
allowsFullscreen
|
||
allowsPictureInPicture
|
||
nativeControls={true}
|
||
contentFit="cover"
|
||
/>
|
||
|
||
{!isPlaying && (
|
||
<View
|
||
style={{
|
||
position: 'absolute',
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
bottom: 0,
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
}}
|
||
>
|
||
<TouchableOpacity
|
||
style={{
|
||
backgroundColor: 'white',
|
||
borderRadius: 50,
|
||
width: 40,
|
||
height: 40,
|
||
justifyContent: 'center',
|
||
alignContent: 'center',
|
||
alignItems: 'center',
|
||
}}
|
||
onPress={() => {
|
||
player.play();
|
||
setIsPlaying(true);
|
||
}}
|
||
>
|
||
<Play color={'white'} size={26} fill={'black'} />
|
||
</TouchableOpacity>
|
||
</View>
|
||
)}
|
||
</View>
|
||
</View>
|
||
|
||
{/* RASMLAR */}
|
||
<View style={styles.section}>
|
||
{/* <Text style={[styles.sectionTitle, { color: theme.text }]}>
|
||
{t('Foydalanish rasm qo‘llanma')}
|
||
</Text> */}
|
||
|
||
<FlatList
|
||
horizontal
|
||
data={steps}
|
||
renderItem={renderStep}
|
||
showsHorizontalScrollIndicator={false}
|
||
contentContainerStyle={{ paddingHorizontal: 16, gap: 20 }}
|
||
/>
|
||
</View>
|
||
|
||
{/* IMAGE MODAL */}
|
||
<Modal isVisible={imageVisible} style={{ margin: 0 }}>
|
||
<ImageViewer
|
||
imageUrls={images}
|
||
index={imageIndex}
|
||
enableSwipeDown
|
||
onSwipeDown={() => setImageVisible(false)}
|
||
renderHeader={() => (
|
||
<Pressable style={styles.closeButton} onPress={() => setImageVisible(false)}>
|
||
<X size={32} color="#fff" />
|
||
</Pressable>
|
||
)}
|
||
/>
|
||
</Modal>
|
||
|
||
{/* LANGUAGE MODAL */}
|
||
{/* <Modal isVisible={langPickerVisible} onBackdropPress={() => setLangPickerVisible(false)}>
|
||
<View style={[styles.langModalContent, { backgroundColor: theme.cardBg }]}>
|
||
<Text style={{ color: 'white', marginBottom: 10, fontSize: 18 }}>
|
||
{t('Video tilini tanlang')}
|
||
</Text>
|
||
{languages.map((lang) => {
|
||
const isSelected = selectedLang === lang.code;
|
||
|
||
return (
|
||
<Pressable
|
||
key={lang.code}
|
||
onPress={() => {
|
||
setSelectedLang(lang.code);
|
||
setLangPickerVisible(false);
|
||
}}
|
||
style={[
|
||
styles.langOption,
|
||
{
|
||
borderColor: isSelected ? theme.primary : theme.border,
|
||
backgroundColor: isSelected ? theme.primary + '15' : 'transparent',
|
||
},
|
||
]}
|
||
>
|
||
<View style={styles.langOptionLeft}>
|
||
<Text style={{ fontSize: 26 }}>{lang.flag}</Text>
|
||
<Text
|
||
style={{
|
||
color: isSelected ? theme.primary : theme.text,
|
||
fontWeight: isSelected ? '700' : '500',
|
||
fontSize: 16,
|
||
}}
|
||
>
|
||
{lang.label}
|
||
</Text>
|
||
</View>
|
||
|
||
{isSelected && (
|
||
<View style={[styles.checkmark, { backgroundColor: theme.primary }]}>
|
||
<Check size={20} color={'white'} />
|
||
</View>
|
||
)}
|
||
</Pressable>
|
||
);
|
||
})}
|
||
</View>
|
||
</Modal> */}
|
||
</ScrollView>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
container: { flex: 1 },
|
||
hero: { padding: 20 },
|
||
topHeader: { flexDirection: 'row', alignItems: 'center', gap: 12 },
|
||
headerTitle: { fontSize: 18, fontWeight: '700', marginHorizontal: 16 },
|
||
subtitle: { fontSize: 16, marginTop: 5, fontWeight: '500', marginHorizontal: 16 },
|
||
|
||
section: { marginBottom: 28 },
|
||
sectionTitle: { fontSize: 20, fontWeight: '700', marginLeft: 16 },
|
||
|
||
langSelector: {
|
||
margin: 5,
|
||
width: 80,
|
||
gap: 5,
|
||
paddingVertical: 5,
|
||
borderRadius: 14,
|
||
borderWidth: 1.5,
|
||
alignContent: 'center',
|
||
alignItems: 'center',
|
||
flexDirection: 'row',
|
||
justifyContent: 'center',
|
||
},
|
||
|
||
videoCard: {
|
||
marginHorizontal: 16,
|
||
marginTop: 10,
|
||
borderRadius: 20,
|
||
overflow: 'hidden',
|
||
position: 'relative',
|
||
},
|
||
video: { width: '100%', aspectRatio: 9 / 13 },
|
||
|
||
stepCard: { borderRadius: 16, overflow: 'hidden' },
|
||
stepImage: { width: 300, height: 300 },
|
||
|
||
closeButton: {
|
||
position: 'absolute',
|
||
top: 50,
|
||
right: 20,
|
||
padding: 8,
|
||
zIndex: 50,
|
||
backgroundColor: 'rgba(0,0,0,0.5)',
|
||
borderRadius: 20,
|
||
},
|
||
|
||
langModalContent: {
|
||
padding: 20,
|
||
borderRadius: 20,
|
||
},
|
||
langOption: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
paddingVertical: 14,
|
||
paddingHorizontal: 16,
|
||
borderRadius: 14,
|
||
borderWidth: 1.5,
|
||
marginBottom: 10,
|
||
},
|
||
|
||
langOptionLeft: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
gap: 12,
|
||
},
|
||
|
||
checkmark: {
|
||
width: 24,
|
||
height: 24,
|
||
borderRadius: 12,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
},
|
||
|
||
checkmarkText: {
|
||
color: '#fff',
|
||
fontSize: 14,
|
||
fontWeight: 'bold',
|
||
},
|
||
playOverlay: {
|
||
position: 'absolute',
|
||
top: 0,
|
||
left: 0,
|
||
right: 0,
|
||
bottom: 0,
|
||
alignItems: 'center',
|
||
justifyContent: 'center',
|
||
backgroundColor: 'rgba(0,0,0,0.25)',
|
||
},
|
||
});
|