diff --git a/app/src/screens/LocalModelsScreen/PermissionMessage.tsx b/app/src/screens/LocalModelsScreen/PermissionMessage.tsx
index a7f4b94..d28f927 100644
--- a/app/src/screens/LocalModelsScreen/PermissionMessage.tsx
+++ b/app/src/screens/LocalModelsScreen/PermissionMessage.tsx
@@ -1,6 +1,5 @@
import React from 'react';
-import { View, Text, TouchableOpacity } from 'react-native';
-import { createStyles } from './styles';
+import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useTheme } from '../../theme/ThemeProvider';
interface PermissionMessageProps {
@@ -11,24 +10,62 @@ export default function PermissionMessage({
onRequestPermission,
}: PermissionMessageProps) {
const { colors } = useTheme();
- const styles = createStyles(colors);
return (
-
-
- 📁 Permission requise
+
+ 📁
+
+ Permission requise
-
- L'application a besoin d'accéder aux fichiers pour lire vos modèles GGUF
+
+ L'application a besoin d'accéder aux fichiers pour lire vos modèles GGUF.
-
+
Autoriser l'accès aux fichiers
);
}
+
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: 'center',
+ alignItems: 'center',
+ paddingHorizontal: 40,
+ gap: 16,
+ },
+ icon: {
+ fontSize: 56,
+ marginBottom: 8,
+ },
+ title: {
+ fontSize: 22,
+ fontWeight: '700',
+ textAlign: 'center',
+ },
+ subtitle: {
+ fontSize: 15,
+ textAlign: 'center',
+ opacity: 0.65,
+ lineHeight: 22,
+ marginBottom: 8,
+ },
+ button: {
+ paddingHorizontal: 28,
+ paddingVertical: 14,
+ borderRadius: 12,
+ marginTop: 8,
+ },
+ buttonText: {
+ fontSize: 16,
+ fontWeight: '600',
+ textAlign: 'center',
+ },
+});
diff --git a/app/src/screens/LocalModelsScreen/index.tsx b/app/src/screens/LocalModelsScreen/index.tsx
index d2bda6b..242f8c9 100644
--- a/app/src/screens/LocalModelsScreen/index.tsx
+++ b/app/src/screens/LocalModelsScreen/index.tsx
@@ -28,7 +28,6 @@ import type { ModelConfig } from '../../store/types';
import ModelItem from './ModelItem';
import DirectoryPicker from './DirectoryPicker';
import DirectoryEditor from './DirectoryEditor';
-import PermissionMessage from './PermissionMessage';
import ModelsList from './ModelsList';
import { createStyles } from './styles';
import { useTheme } from '../../theme/ThemeProvider';
@@ -381,9 +380,6 @@ export default function LocalModelsScreen() {
)}
)}
- {!hasPermission && (
-
- )}
{/* Models List */}
diff --git a/app/src/screens/ModelsScreen.tsx b/app/src/screens/ModelsScreen.tsx
index fb34825..0b683fe 100644
--- a/app/src/screens/ModelsScreen.tsx
+++ b/app/src/screens/ModelsScreen.tsx
@@ -1,8 +1,15 @@
-import React from 'react';
+import React, { useEffect, useState, useCallback } from 'react';
+import { AppState } from 'react-native';
import { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
+import { useFocusEffect } from '@react-navigation/native';
import { useTheme } from '../theme/ThemeProvider';
import LocalModelsScreen from './LocalModelsScreen';
import HuggingFaceModelsScreen from './HuggingFaceModelsScreen';
+import PermissionMessage from './LocalModelsScreen/PermissionMessage';
+import {
+ checkStoragePermission,
+ requestStoragePermission,
+} from '../utils/permissions';
export type ModelsTabParamList = {
LocalModels: undefined;
@@ -14,6 +21,31 @@ const Tab = createMaterialTopTabNavigator();
export default function ModelsScreen() {
const { colors, scheme } = useTheme();
const isDark = scheme === 'dark';
+ const [hasPermission, setHasPermission] = useState(false);
+
+ const checkPerm = useCallback(async () => {
+ const granted = await checkStoragePermission();
+ setHasPermission(granted);
+ }, []);
+
+ useEffect(() => {
+ checkPerm();
+ const sub = AppState.addEventListener('change', (state) => {
+ if (state === 'active') checkPerm();
+ });
+ return () => sub.remove();
+ }, [checkPerm]);
+
+ useFocusEffect(useCallback(() => { checkPerm(); }, [checkPerm]));
+
+ const handleRequestPermission = async () => {
+ await requestStoragePermission();
+ setTimeout(checkPerm, 1000);
+ };
+
+ if (!hasPermission) {
+ return ;
+ }
return (