fix: respect safe area insets and improve drag visual feedback

This commit is contained in:
Mohamed Boudra
2026-01-31 22:57:47 +07:00
parent c57c86286a
commit 7c50b2a66b
6 changed files with 40 additions and 20 deletions

View File

@@ -1,6 +1,7 @@
import { useCallback, useEffect, useRef, useState } from "react";
import { Alert, Platform, Pressable, Text, View } from "react-native";
import { useRouter } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { CameraView, useCameraPermissions } from "expo-camera";
import type { BarcodeScanningResult } from "expo-camera";
@@ -13,7 +14,6 @@ const styles = StyleSheet.create((theme) => ({
},
header: {
paddingHorizontal: theme.spacing[6],
paddingTop: theme.spacing[6],
paddingBottom: theme.spacing[4],
flexDirection: "row",
justifyContent: "space-between",
@@ -32,7 +32,6 @@ const styles = StyleSheet.create((theme) => ({
body: {
flex: 1,
paddingHorizontal: theme.spacing[6],
paddingBottom: theme.spacing[6],
},
cameraWrap: {
flex: 1,
@@ -132,6 +131,7 @@ function extractOfferUrlFromScan(result: BarcodeScanningResult): string | null {
export default function PairScanScreen() {
const { theme } = useUnistyles();
const insets = useSafeAreaInsets();
const router = useRouter();
const { upsertDaemonFromOfferUrl } = useDaemonRegistry();
@@ -172,17 +172,17 @@ export default function PairScanScreen() {
if (Platform.OS === "web") {
return (
<View style={styles.container}>
<View style={styles.header}>
<View style={[styles.header, { paddingTop: insets.top + theme.spacing[2] }]}>
<Text style={styles.headerTitle}>Scan QR</Text>
<Pressable onPress={() => router.back()}>
<Text style={styles.headerButtonText}>Close</Text>
</Pressable>
</View>
<View style={styles.body}>
<View style={[styles.body, { paddingBottom: insets.bottom + theme.spacing[6] }]}>
<View style={styles.permissionCard}>
<Text style={styles.permissionTitle}>Not available on web</Text>
<Text style={styles.permissionBody}>
QR scanning isnt supported in the web build. Use Paste link instead.
QR scanning isn't supported in the web build. Use "Paste link" instead.
</Text>
<Pressable style={styles.permissionButton} onPress={() => router.replace("/settings")}>
<Text style={styles.permissionButtonText}>Back to Settings</Text>
@@ -197,14 +197,14 @@ export default function PairScanScreen() {
return (
<View style={styles.container}>
<View style={styles.header}>
<View style={[styles.header, { paddingTop: insets.top + theme.spacing[2] }]}>
<Text style={styles.headerTitle}>Scan QR</Text>
<Pressable onPress={() => router.back()}>
<Text style={styles.headerButtonText}>Close</Text>
</Pressable>
</View>
<View style={styles.body}>
<View style={[styles.body, { paddingBottom: insets.bottom + theme.spacing[6] }]}>
{!granted ? (
<View style={styles.permissionCard}>
<Text style={styles.permissionTitle}>Camera permission</Text>

View File

@@ -12,6 +12,7 @@ import {
Platform,
} from "react-native";
import { router } from "expo-router";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { StyleSheet, UnistylesRuntime, useUnistyles } from "react-native-unistyles";
import { Sun, Moon, Monitor } from "lucide-react-native";
import { Fonts } from "@/constants/theme";
@@ -378,6 +379,8 @@ const styles = StyleSheet.create((theme) => ({
export default function SettingsScreen() {
const { theme } = useUnistyles();
const insets = useSafeAreaInsets();
const { settings, isLoading: settingsLoading, updateSettings, resetSettings } = useAppSettings();
const {
daemons,
@@ -561,7 +564,7 @@ export default function SettingsScreen() {
<View style={styles.container}>
<MenuHeader title="Settings" />
<ScrollView style={styles.scrollView}>
<ScrollView style={styles.scrollView} contentContainerStyle={{ paddingBottom: insets.bottom }}>
<View style={styles.content}>
{/* Host Management */}
<View style={styles.section}>

View File

@@ -1,5 +1,6 @@
import { useEffect, useRef } from "react";
import { ActivityIndicator, Pressable, Text, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";
import { StyleSheet, useUnistyles } from "react-native-unistyles";
import { Check, X, XCircle } from "lucide-react-native";
import { useDownloadStore, formatSpeed, formatEta } from "@/stores/download-store";
@@ -8,6 +9,7 @@ const AUTO_DISMISS_DELAY = 3000;
export function DownloadToast() {
const { theme } = useUnistyles();
const insets = useSafeAreaInsets();
const downloads = useDownloadStore((state) => state.downloads);
const activeDownloadId = useDownloadStore((state) => state.activeDownloadId);
const dismissDownload = useDownloadStore((state) => state.dismissDownload);
@@ -39,7 +41,7 @@ export function DownloadToast() {
}
return (
<View style={styles.container} pointerEvents="box-none">
<View style={[styles.container, { bottom: theme.spacing[4] + insets.bottom }]} pointerEvents="box-none">
<View style={styles.toast}>
{activeDownload.status === "downloading" ? (
<ActivityIndicator size="small" color={theme.colors.foreground} />
@@ -89,7 +91,6 @@ export function DownloadToast() {
const styles = StyleSheet.create((theme) => ({
container: {
position: "absolute",
bottom: theme.spacing[4],
left: theme.spacing[4],
right: theme.spacing[4],
zIndex: 1000,

View File

@@ -61,10 +61,14 @@ function SortableItem<T>({
// Trigger drag - handled by dnd-kit's listeners
};
const baseTransform = CSS.Transform.toString(transform);
const scaleTransform = isDragging ? "scale(1.02)" : "";
const combinedTransform = [baseTransform, scaleTransform].filter(Boolean).join(" ");
const style = {
transform: CSS.Transform.toString(transform),
transform: combinedTransform || undefined,
transition,
opacity: isDragging ? 0.5 : 1,
opacity: isDragging ? 0.9 : 1,
zIndex: isDragging ? 1000 : 1,
};

View File

@@ -649,6 +649,7 @@ const styles = StyleSheet.create((theme) => ({
},
sectionDragging: {
opacity: 0.9,
transform: [{ scale: 1.02 }],
},
chevron: {
opacity: 0.5,

View File

@@ -617,14 +617,25 @@ function AgentScreenContent({
<View style={styles.headerRightContent}>
<Pressable onPress={toggleFileExplorer} style={styles.menuButton}>
{isMobile ? (
<Folder
size={20}
color={
isExplorerOpen
? theme.colors.foreground
: theme.colors.foregroundMuted
}
/>
checkout?.isGit ? (
<GitBranch
size={20}
color={
isExplorerOpen
? theme.colors.foreground
: theme.colors.foregroundMuted
}
/>
) : (
<Folder
size={20}
color={
isExplorerOpen
? theme.colors.foreground
: theme.colors.foregroundMuted
}
/>
)
) : (
<PanelRight
size={16}