feat: implement permission handling in ModelsScreen and update PermissionMessage component

This commit is contained in:
Jonathan Atta
2026-03-04 11:08:40 +01:00
parent a213b1593a
commit 21b669f96c
3 changed files with 80 additions and 15 deletions

View File

@@ -1,6 +1,5 @@
import React from 'react'; import React from 'react';
import { View, Text, TouchableOpacity } from 'react-native'; import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { createStyles } from './styles';
import { useTheme } from '../../theme/ThemeProvider'; import { useTheme } from '../../theme/ThemeProvider';
interface PermissionMessageProps { interface PermissionMessageProps {
@@ -11,24 +10,62 @@ export default function PermissionMessage({
onRequestPermission, onRequestPermission,
}: PermissionMessageProps) { }: PermissionMessageProps) {
const { colors } = useTheme(); const { colors } = useTheme();
const styles = createStyles(colors);
return ( return (
<View style={styles.permissionContainer}> <View style={[styles.container, { backgroundColor: colors.background }]}>
<Text style={styles.permissionText}> <Text style={styles.icon}>📁</Text>
📁 Permission requise <Text style={[styles.title, { color: colors.text }]}>
Permission requise
</Text> </Text>
<Text style={styles.permissionSubtext}> <Text style={[styles.subtitle, { color: colors.text }]}>
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.
</Text> </Text>
<TouchableOpacity <TouchableOpacity
style={styles.permissionButton} style={[styles.button, { backgroundColor: colors.primary }]}
onPress={onRequestPermission} onPress={onRequestPermission}
activeOpacity={0.8}
> >
<Text style={styles.permissionButtonText}> <Text style={[styles.buttonText, { color: colors.onPrimary }]}>
Autoriser l'accès aux fichiers Autoriser l'accès aux fichiers
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
</View> </View>
); );
} }
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',
},
});

View File

@@ -28,7 +28,6 @@ import type { ModelConfig } from '../../store/types';
import ModelItem from './ModelItem'; import ModelItem from './ModelItem';
import DirectoryPicker from './DirectoryPicker'; import DirectoryPicker from './DirectoryPicker';
import DirectoryEditor from './DirectoryEditor'; import DirectoryEditor from './DirectoryEditor';
import PermissionMessage from './PermissionMessage';
import ModelsList from './ModelsList'; import ModelsList from './ModelsList';
import { createStyles } from './styles'; import { createStyles } from './styles';
import { useTheme } from '../../theme/ThemeProvider'; import { useTheme } from '../../theme/ThemeProvider';
@@ -381,9 +380,6 @@ export default function LocalModelsScreen() {
)} )}
</View> </View>
)} )}
{!hasPermission && (
<PermissionMessage onRequestPermission={handleRequestPermission} />
)}
</View> </View>
{/* Models List */} {/* Models List */}

View File

@@ -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 { createMaterialTopTabNavigator } from '@react-navigation/material-top-tabs';
import { useFocusEffect } from '@react-navigation/native';
import { useTheme } from '../theme/ThemeProvider'; import { useTheme } from '../theme/ThemeProvider';
import LocalModelsScreen from './LocalModelsScreen'; import LocalModelsScreen from './LocalModelsScreen';
import HuggingFaceModelsScreen from './HuggingFaceModelsScreen'; import HuggingFaceModelsScreen from './HuggingFaceModelsScreen';
import PermissionMessage from './LocalModelsScreen/PermissionMessage';
import {
checkStoragePermission,
requestStoragePermission,
} from '../utils/permissions';
export type ModelsTabParamList = { export type ModelsTabParamList = {
LocalModels: undefined; LocalModels: undefined;
@@ -14,6 +21,31 @@ const Tab = createMaterialTopTabNavigator<ModelsTabParamList>();
export default function ModelsScreen() { export default function ModelsScreen() {
const { colors, scheme } = useTheme(); const { colors, scheme } = useTheme();
const isDark = scheme === 'dark'; 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 <PermissionMessage onRequestPermission={handleRequestPermission} />;
}
return ( return (
<Tab.Navigator <Tab.Navigator