Compare commits

...

7 Commits

Author SHA1 Message Date
Mekan1206
47420f9941 Update app.json to enforce dark mode and enhance Android navigation bar styling
- Changed userInterfaceStyle from 'automatic' to 'dark' for consistent theming.
- Added androidNavigationBar configuration with background color and bar style for improved UI on Android devices.
2025-09-20 11:42:59 +05:00
Mekan1206
68affb3d4b Update app configuration and scripts for improved build process
- Added package name to app.json for better identification.
- Updated start scripts in package.json to use 'expo run' commands for Android and iOS.
2025-09-20 11:24:49 +05:00
Mekan1206
9e0e285172 Remove temporary swap file for localization, cleaning up project structure. 2025-09-17 19:36:17 +05:00
Mekan1206
c2cd61c679 Refactor localization and simplify HomeScreen functionality
- Removed English and Russian localization files, focusing solely on Turkmen.
- Simplified language initialization in i18n.ts to default to Turkmen.
- Cleaned up HomeScreen by removing modal for language selection and related state management.
2025-09-17 19:25:49 +05:00
Mekan1206
acddbf48f0 Refactor TabIndex to use fixed dark mode and comment out hotel service in ServicesScreen
- Set color scheme in TabIndex to a fixed 'dark' value for consistent theming.
- Commented out the hotel service option in ServicesScreen for potential future redesign.
2025-09-17 19:20:03 +05:00
Mekan1206
4a92077786 hide homescreen activity 2025-09-17 19:15:48 +05:00
Mekan1206
e542371268 Add expo-asset dependency and update layout for safe area insets
- Included expo-asset in app.json and package.json for asset management.
- Refactored layout components in HomeScreen, TabIndex, Programs, and ServicesScreen to utilize safe area insets for better UI on different devices.
- Updated StatusBar style in RootLayoutNav for improved visibility.
2025-09-17 19:14:09 +05:00
11 changed files with 1624 additions and 770 deletions

View File

@@ -6,7 +6,7 @@
"orientation": "portrait",
"icon": "./assets/images/icon.png",
"scheme": "umra",
"userInterfaceStyle": "automatic",
"userInterfaceStyle": "dark",
"newArchEnabled": true,
"splash": {
"image": "./assets/images/splash-icon.png",
@@ -21,7 +21,12 @@
"foregroundImage": "./assets/images/adaptive-icon.png",
"backgroundColor": "#ffffff"
},
"edgeToEdgeEnabled": true
"edgeToEdgeEnabled": true,
"package": "com.nurmuhammet.ali.Umra",
"androidNavigationBar": {
"backgroundColor": "#1C1C1E",
"barStyle": "light-content"
}
},
"web": {
"bundler": "metro",
@@ -29,7 +34,8 @@
"favicon": "./assets/images/favicon.png"
},
"plugins": [
"expo-router"
"expo-router",
"expo-asset"
],
"experiments": {
"typedRoutes": true

View File

@@ -1,4 +1,4 @@
import { StyleSheet, SafeAreaView, ScrollView, I18nManager, Modal, Pressable } from 'react-native';
import { StyleSheet, ScrollView } from 'react-native';
import { Text, View } from '@/components/Themed';
import FeatureCard from '@/components/FeatureCard';
import PrayerTimeCard from '@/components/PrayerTimeCard';
@@ -8,18 +8,17 @@ import * as Updates from 'expo-updates';
import AsyncStorage from '@react-native-async-storage/async-storage';
import Colors from '@/constants/Colors';
import { useState } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
export default function HomeScreen() {
const [modalVisible, setModalVisible] = useState(false);
const insets = useSafeAreaInsets();
const changeLanguage = async (lang: 'en' | 'tk' | 'ru') => {
if (!lang) return;
setModalVisible(false);
if (lang === i18n.locale.substring(0, 2)) return;
await AsyncStorage.setItem('user-language', lang);
i18n.locale = lang;
I18nManager.forceRTL(false); // Assuming LTR for all three languages
Updates.reloadAsync();
};
@@ -38,50 +37,27 @@ export default function HomeScreen() {
];
return (
<SafeAreaView style={styles.container}>
<View style={[styles.container, { paddingTop: insets.top }]}>
<View style={styles.header}>
<Text style={styles.title}>{i18n.t('home')}</Text>
<Pressable onPress={() => setModalVisible(true)} style={pickerSelectStyles.inputIOS}>
<Text style={{ color: 'white' }}>{currentLanguage}</Text>
</Pressable>
</View>
<Modal
animationType="slide"
transparent={true}
visible={modalVisible}
onRequestClose={() => {
setModalVisible(!modalVisible);
}}>
<Pressable style={styles.modalOverlay} onPress={() => setModalVisible(false)}>
<View style={styles.modalView}>
{languages.map((lang) => (
<Pressable
key={lang.value}
style={styles.modalButton}
onPress={() => changeLanguage(lang.value as 'en' | 'tk' | 'ru')}>
<Text style={styles.modalButtonText}>{lang.label}</Text>
</Pressable>
))}
</View>
</Pressable>
</Modal>
<ScrollView>
<View style={styles.innerContainer}>
<FeatureCard
{/* <FeatureCard
badgeText="Şu gün, 07:00"
title="Aýşe metjidi"
description="Oteldan ugraýar, 1-njy etazda garaşmaly"
image={require('@/assets/images/aisha.jpg')}
/>
/> */}
<PrayerTimeCard />
{/* <ServicesGrid services={services} /> */}
</View>
</ScrollView>
</SafeAreaView>
</View>
);
}

View File

@@ -1,9 +1,9 @@
import { Pressable, SafeAreaView, ScrollView, StyleSheet, Text, View } from 'react-native';
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { useCallback, useEffect, useState } from 'react';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { getPrayerTimes, cities } from '../../utils/prayerTimeCalculator';
import i18n from '../../i18n';
import { useColorScheme } from 'react-native';
import Colors from '../../constants/Colors';
type Prayer = {
@@ -14,11 +14,12 @@ type Prayer = {
type City = keyof typeof cities;
export default function TabIndex() {
const colorScheme = useColorScheme();
const colorScheme = 'dark';
const theme = Colors[colorScheme ?? 'light'];
const [selectedCity, setSelectedCity] = useState<City>('Makkah');
const [prayerTimes, setPrayerTimes] = useState<Prayer[]>([]);
const [nextPrayerName, setNextPrayerName] = useState<string | null>(null);
const insets = useSafeAreaInsets();
const prayerNameMapping: { [key: string]: string } = {
fajr: i18n.t('fajr'),
@@ -88,7 +89,7 @@ export default function TabIndex() {
};
return (
<SafeAreaView style={[styles.container, { backgroundColor: theme.background }]}>
<View style={[styles.container, { backgroundColor: theme.background, paddingTop: insets.top }]}>
<View style={[styles.citySelector, { backgroundColor: theme.background }]}>
{(Object.keys(cities) as City[]).map((city) => (
<Pressable
@@ -109,7 +110,7 @@ export default function TabIndex() {
<ScrollView contentContainerStyle={styles.listContainer}>
{prayerTimes.map(renderPrayerTime)}
</ScrollView>
</SafeAreaView>
</View>
);
}

View File

@@ -1,7 +1,8 @@
import { useState } from 'react';
import { StyleSheet, SafeAreaView, Text, View, TouchableOpacity, ScrollView } from 'react-native';
import { StyleSheet, Text, View, TouchableOpacity, ScrollView } from 'react-native';
import Colors from '@/constants/Colors';
import { FontAwesome, FontAwesome5 } from '@expo/vector-icons';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
type Activity = {
time: string;
@@ -18,6 +19,7 @@ type Activities = {
export default function Programs() {
const colorScheme = 'dark';
const [activeDay, setActiveDay] = useState('Day 1');
const insets = useSafeAreaInsets();
const activities: Activities = {
'Day 1': [
@@ -54,7 +56,7 @@ export default function Programs() {
};
return (
<SafeAreaView style={[styles.container, { backgroundColor: Colors[colorScheme].background }]}>
<View style={[styles.container, { backgroundColor: Colors[colorScheme].background, paddingTop: insets.top }]}>
<View style={styles.header}>
<Text style={[styles.title, { color: Colors[colorScheme].text }]}>Umrah Pilgrimage</Text>
</View>
@@ -95,7 +97,7 @@ export default function Programs() {
</View>
))}
</ScrollView>
</SafeAreaView>
</View>
);
}

View File

@@ -1,4 +1,4 @@
import { StyleSheet, SafeAreaView, View, TouchableOpacity, Dimensions } from 'react-native';
import { StyleSheet, View, TouchableOpacity, Dimensions } from 'react-native';
import { Text } from '@/components/Themed';
import i18n from '@/i18n';
import { FontAwesome5 } from '@expo/vector-icons';
@@ -8,12 +8,14 @@ import CurrencyConverterModal from '@/components/CurrencyConverterModal';
import HotelBusinessCardModal from '@/components/HotelBusinessCardModal';
import LostKeyModal from '@/components/LostKeyModal';
import PhrasebookModal from '@/components/PhrasebookModal';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
export default function ServicesScreen() {
const [currencyModalVisible, setCurrencyModalVisible] = useState(false);
const [hotelModalVisible, setHotelModalVisible] = useState(false);
const [lostKeyModalVisible, setLostKeyModalVisible] = useState(false);
const [phrasebookModalVisible, setPhrasebookModalVisible] = useState(false);
const insets = useSafeAreaInsets();
const services = [
{
@@ -22,12 +24,12 @@ export default function ServicesScreen() {
icon: <FontAwesome5 name="dollar-sign" size={24} color="#D4AF37" />,
onPress: () => setCurrencyModalVisible(true),
},
{
title: i18n.t('Hotel'),
name: 'hotelCard',
icon: <FontAwesome5 name="hotel" size={24} color="#D4AF37" />,
onPress: () => setHotelModalVisible(true),
},
// {
// title: i18n.t('Hotel'),
// name: 'hotelCard',
// icon: <FontAwesome5 name="hotel" size={24} color="#D4AF37" />,
// onPress: () => setHotelModalVisible(true),
// },
{
title: i18n.t('Lost room key'),
name: 'lostKey',
@@ -43,7 +45,7 @@ export default function ServicesScreen() {
];
return (
<SafeAreaView style={styles.container}>
<View style={[styles.container, { paddingTop: insets.top }]}>
<Text style={styles.title}>{i18n.t('services')}</Text>
<View style={styles.grid}>
@@ -69,7 +71,7 @@ export default function ServicesScreen() {
visible={phrasebookModalVisible}
onClose={() => setPhrasebookModalVisible(false)}
/>
</SafeAreaView>
</View>
);
}

View File

@@ -6,6 +6,7 @@ import * as SplashScreen from 'expo-splash-screen';
import React, { useEffect } from 'react';
import 'react-native-reanimated';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { StatusBar } from 'expo-status-bar';
import { initializeLanguage } from '@/i18n';
import { makeRequest } from '@/utils/makeRequest';
@@ -67,6 +68,7 @@ function RootLayoutNav() {
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="modal" options={{ presentation: 'modal' }} />
</Stack>
<StatusBar style="light" />
</ThemeProvider>
);
}

17
i18n.ts
View File

@@ -1,29 +1,16 @@
import { I18n } from 'i18n-js';
import * as Localization from 'expo-localization';
import AsyncStorage from '@react-native-async-storage/async-storage';
import en from './locales/en.json';
import tk from './locales/tk.json';
import ru from './locales/ru.json';
const i18n = new I18n({
en,
tk,
ru,
});
i18n.locale = 'tk';
i18n.enableFallback = true;
// Function to initialize the language
export const initializeLanguage = async () => {
const savedLanguage = await AsyncStorage.getItem('user-language');
if (savedLanguage) {
i18n.locale = savedLanguage;
} else {
// If no language is saved, detect from device and default to Turkmen
const userLanguageCode = Localization.getLocales()[0]?.languageCode;
i18n.locale = ['en', 'tk', 'ru'].includes(userLanguageCode || '') ? userLanguageCode! : 'tk';
}
i18n.locale = 'tk';
};
export default i18n;

View File

@@ -1,53 +0,0 @@
{
"home": "Home",
"services": "Services",
"supplications": "Supplications",
"yourJourneyToHajj": "Your Journey to Hajj",
"hajjEssentials": "Everything you need for Hajj essentials.",
"umrah": "Umrah",
"bookPermit": "Book Permit",
"nobleRawdah": "Noble Rawdah",
"newExperience": "New Experience",
"prayerTimes": "Prayer Times",
"programs": "Programs",
"Programs": "Schedule",
"leftOnPrayer": "Left on {{prayerName}} prayer",
"servicesToEnrich": "Services to Enrich Your Spiritual Experience",
"quran": "Qur'an",
"hadith": "Hadith",
"dua": "Dua",
"currencyConverter": "Currency Converter",
"hotelCard": "Hotel Card",
"lostKey": "Lost Key?",
"translator": "Translator",
"adhkar": "Adhkar",
"hisnAlMuslim": "Hisn Al-Muslim",
"Makkah": "Makkah",
"Medina": "Medina",
"Jeddah": "Jeddah",
"fajr": "Fajr",
"sunrise": "Sunrise",
"dhuhr": "Dhuhr",
"asr": "Asr",
"maghrib": "Maghrib",
"isha": "Isha",
"morningEveningThikr": "Thikr said in the morning and evening",
"beforeSleepingThikr": "Thikr before sleeping",
"afterSalamThikr": "Thikr after salam",
"breakingFastSupplication": "Upon breaking fast",
"fastingPersonSupplication": "Supplication said by one fasting when presented with food and does not break his fast",
"insultedWhileFasting": "When insulted while fasting",
"seeingFruitSupplication": "Supplication upon seeing the early or premature fruit",
"sneezingSupplication": "Supplication upon sneezing",
"sarToTmt": "SAR to TMT",
"hotelBusinessCard": "Hotel Business Card",
"masterkeyBox": "Masterkey Box",
"Money": "Money",
"Hotel": "Hotel",
"Lost room key": "Lost room key",
"Phrasebook": "Phrasebook",
"Enter text in Turkmen": "Enter text",
"Translate": "Translate",
"Salah": "Salah",
"menuSalah": "Salah"
}

View File

@@ -1,53 +0,0 @@
{
"home": "Главная",
"services": "Сервисы",
"supplications": "Молитвы",
"yourJourneyToHajj": "Ваше путешествие в Хадж",
"hajjEssentials": "Все, что вам нужно для Хаджа.",
"umrah": "Умра",
"bookPermit": "Забронировать разрешение",
"nobleRawdah": "Благородная Равда",
"newExperience": "Новый опыт",
"prayerTimes": "Время молитв",
"programs": "Программы",
"Programs": "Расписание",
"leftOnPrayer": "Осталось до молитвы {{prayerName}}",
"servicesToEnrich": "Услуги для обогащения вашего духовного опыта",
"quran": "Коран",
"hadith": "Хадис",
"dua": "Дуа",
"currencyConverter": "Конвертер валют",
"hotelCard": "Карта отеля",
"lostKey": "Потеряли ключ?",
"translator": "Переводчик",
"adhkar": "Азкар",
"hisnAlMuslim": "Крепость мусульманина",
"Makkah": "Мекка",
"Medina": "Медина",
"Jeddah": "Джидда",
"fajr": "Фаджр",
"sunrise": "Восход",
"dhuhr": "Зухр",
"asr": "Аср",
"maghrib": "Магриб",
"isha": "Иша",
"morningEveningThikr": "Зикр, читаемый утром и вечером",
"beforeSleepingThikr": "Зикр перед сном",
"afterSalamThikr": "Зикр после салама",
"breakingFastSupplication": "При разговении",
"fastingPersonSupplication": "Мольба, произносимая постящимся, когда ему преподносят еду, и он не прерывает свой пост",
"insultedWhileFasting": "Когда оскорбляют во время поста",
"seeingFruitSupplication": "Мольба при виде ранних или незрелых плодов",
"sneezingSupplication": "Мольба при чихании",
"sarToTmt": "SAR в TMT",
"hotelBusinessCard": "Визитная карточка отеля",
"masterkeyBox": "Ящик для мастер-ключей",
"Money": "Деньги",
"Hotel": "Отель",
"Lost room key": "Ключ от номера утерян",
"Phrasebook": "Разговорник",
"Enter text in Turkmen": "Введите текст",
"Translate": "Перевести",
"Salah": "Намаз",
"menuSalah": "Намаз"
}

2175
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,8 +4,8 @@
"version": "1.0.0",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"android": "expo run:android",
"ios": "expo run:ios",
"web": "expo start --web",
"test": "jest --watchAll"
},
@@ -18,6 +18,7 @@
"@react-navigation/native": "^7.1.6",
"adhan": "^4.4.3",
"expo": "~53.0.20",
"expo-asset": "~11.1.7",
"expo-file-system": "~18.1.11",
"expo-font": "~13.3.2",
"expo-linking": "~7.1.7",