diff --git a/App.tsx b/App.tsx index 74ae71f..da18de2 100644 --- a/App.tsx +++ b/App.tsx @@ -223,6 +223,8 @@ export default function App() { const [openParamKey, setOpenParamKey] = useState(null); // FRAME → WATERMARK sub-panel is open (the rail's WATERMARK tab is gone). const [wmPanelOpen, setWmPanelOpen] = useState(false); + // FRAME -> ROTATE strip is open: gates the bubble-level line on the image. + const [rotatePanelOpen, setRotatePanelOpen] = useState(false); const [libraryImageUri, setLibraryImageUri] = useState(null); // Session photo history (camera captures + library exports). The camera @@ -1303,7 +1305,11 @@ export default function App() { availableHeight={deckTop} photoRotation={photoRotation} photoStraighten={effectiveStraighten} - autoRoll={autoHorizon && mode === 'library' ? horizonRoll : null} + autoRoll={ + autoHorizon && mode === 'library' && openTab === 'frame' && rotatePanelOpen + ? horizonRoll + : null + } cameraPermissionGranted={cameraPermissionGranted} onRequestCameraPermission={requestCameraPermission} photoOutput={photoOutput} @@ -1414,6 +1420,7 @@ export default function App() { wmRotation={wmRotation} onRotateWm={() => setWmRotation((r) => (r + 90) % 360)} onWmPanelChange={setWmPanelOpen} + onRotatePanelChange={setRotatePanelOpen} /> )} diff --git a/src/components/AdjustmentPanel.tsx b/src/components/AdjustmentPanel.tsx index 7c82278..56f662e 100644 --- a/src/components/AdjustmentPanel.tsx +++ b/src/components/AdjustmentPanel.tsx @@ -122,6 +122,9 @@ interface AdjustmentPanelProps { // FRAME → WATERMARK sub-panel is open: App needs this to arm the mark's // drag/pinch layer on the image (the old `activeTab === 'watermark'`). onWmPanelChange: (open: boolean) => void; + // The ROTATE strip (or its STRAIGHTEN row) is open: App needs this to keep + // the image's bubble-level line on screen only while that strip is up. + onRotatePanelChange: (open: boolean) => void; } interface ChipDef { @@ -238,6 +241,7 @@ export default function AdjustmentPanel({ wmRotation, onRotateWm, onWmPanelChange, + onRotatePanelChange, }: AdjustmentPanelProps) { // Double-tap on the mark in the viewfinder bumps wmEditNonce -> focus the // input again so the text can be retyped after the keyboard was dismissed. @@ -273,6 +277,12 @@ export default function AdjustmentPanel({ useEffect(() => { onWmPanelChange(openGroup === 'wm'); }, [openGroup]); + // The bubble-level line on the image belongs to the ROTATE strip: it shows + // while that strip (or its STRAIGHTEN row) is open and leaves with the next + // chip, so it never lingers over the photo after the user moved on. + useEffect(() => { + onRotatePanelChange(openGroup === 'rotate' || openParam === 'straighten'); + }, [openGroup, openParam]); // CROP is a plain-frame tool: the moment the selected frame drops it the chip // unmounts, so the ratio strip must close with it (no orphan CROP row). useEffect(() => { @@ -862,8 +872,10 @@ export default function AdjustmentPanel({ selectedFrame, (val) => { // Picking another frame is another parameter: the open slider - // row (STRAIGHTEN) goes with the previous one. + // row (STRAIGHTEN) and the ROTATE strip go with the previous + // one — so the bubble-level line leaves the image too. if (openParam) onOpenParamChange(null); + setOpenGroup(null); onUpdateFrame(val as FrameId); } )}