mobile download

This commit is contained in:
Macbook
2026-05-28 14:44:19 +09:00
parent e2816b037f
commit 3503ef33f5
152 changed files with 11021 additions and 687 deletions
+23 -22
View File
@@ -39,7 +39,7 @@ import {
import { normalizeSmaConfig, createDefaultSmaPlotVisibility } from './utils/smaConfig';
import { normalizeIchimokuConfig } from './utils/ichimokuConfig';
import { isUpbitMarket, UPBIT_MARKETS } from './utils/upbitApi';
import { getFavorites, saveFavorites, FAVORITES_CHANGED_EVENT } from './utils/marketStorage';
import { getFavorites, saveFavorites, initFavoritesFromDb, initHoldingsFromDb, FAVORITES_CHANGED_EVENT } from './utils/marketStorage';
import { useChartRealtimeData, type WsStatus } from './hooks/useChartRealtimeData';
import type { OHLCVBar, ChartType, Theme, Timeframe, IndicatorConfig, LegendData, Drawing, ChartMode, MainChartStyle, TradeOrderFillRequest } from './types';
import type { ChartManager } from './utils/ChartManager';
@@ -105,6 +105,7 @@ import { notifyPaperTradesChanged } from './utils/paperTradeEvents';
import { useIsMobile } from './hooks/useMediaQuery';
import MobileChartDock from './components/MobileChartDock';
import LoginModal from './components/LoginModal';
import AppDownloadModal from './components/AppDownloadModal';
import SplashScreen from './components/SplashScreen';
import { getAuthSession, setAuthSession, clearAuthSession, type AuthSession } from './utils/auth';
import { isAppEntered, setAppEntered, clearAppEntered } from './utils/appEntry';
@@ -161,6 +162,7 @@ function App() {
isAppEntered() && !getAuthSession(),
);
const [loginOpen, setLoginOpen] = useState(false);
const [appDownloadOpen, setAppDownloadOpen] = useState(false);
// 전역 지표 파라미터 + 시각 설정 DB 동기화
const {
@@ -217,16 +219,8 @@ function App() {
const { tickers: marketTickers, loading: marketLoading, usdRate } = useMarketTicker();
// ── 레이아웃 상태 ─────────────────────────────────────────────────────
const [layoutDef, setLayoutDef] = useState<LayoutDef>(() => {
const saved = localStorage.getItem('chartLayout');
return LAYOUTS.find(l => l.id === saved) ?? LAYOUTS[0];
});
const [syncOptions, setSyncOptions] = useState<SyncOptions>(() => {
try {
const s = localStorage.getItem('chartLayoutSync');
return s ? JSON.parse(s) : DEFAULT_SYNC;
} catch { return DEFAULT_SYNC; }
});
const [layoutDef, setLayoutDef] = useState<LayoutDef>(() => LAYOUTS[0]);
const [syncOptions, setSyncOptions] = useState<SyncOptions>(DEFAULT_SYNC);
const [activeSlot, setActiveSlot] = useState(0);
// 멀티 레이아웃에서 현재 활성 슬롯의 지표 목록 (IndicatorModal 표시용)
const [activeSlotIndicators, setActiveSlotIndicators] = useState<IndicatorConfig[]>([]);
@@ -387,13 +381,18 @@ function App() {
saveAppDef({ defaultLayoutId: def.id });
}, [layoutDef.count, activeSlot, symbol, timeframe, indicators, saveAppDef]);
// 레이아웃/싱크 변경 시 localStorage 저장
const appLayoutHydratedRef = useRef(false);
useEffect(() => {
localStorage.setItem('chartLayout', layoutDef.id);
}, [layoutDef]);
useEffect(() => {
localStorage.setItem('chartLayoutSync', JSON.stringify(syncOptions));
}, [syncOptions]);
if (!appSettingsLoaded || appLayoutHydratedRef.current) return;
appLayoutHydratedRef.current = true;
if (appDefaults.layoutId) {
const def = LAYOUTS.find(l => l.id === appDefaults.layoutId);
if (def) setLayoutDef(def);
}
if (appDefaults.syncOptions) {
setSyncOptions(appDefaults.syncOptions);
}
}, [appSettingsLoaded, appDefaults.layoutId, appDefaults.syncOptions]);
// 다중 → 싱글 전환 시 activeSlotIndicators 초기화
useEffect(() => {
@@ -1118,10 +1117,6 @@ function App() {
return map;
}, [watchlist]);
// ── 상태 저장 (localStorage) ───────────────────────────────────────────
useEffect(() => {
saveState({ symbol, timeframe, chartType, theme, indicators, watchlist, alertPrices: alerts.map(a => a.price) });
}, [symbol, timeframe, chartType, theme, indicators, watchlist, alerts]);
// body 포털(알림 팝업 등) 테마 CSS 변수 동기화
useEffect(() => {
@@ -1201,10 +1196,10 @@ function App() {
},
onWatchlistLoad: (items: WatchlistItem[]) => {
const syms = items.map(i => i.symbol);
initFavoritesFromDb(syms);
if (syms.length > 0) {
setWatchlist(syms);
setFavoritesList(syms);
saveFavorites(syms, false);
}
},
noAutoSave: !dbLoaded,
@@ -1672,6 +1667,7 @@ function App() {
theme={theme}
onPage={guardedSetMenuPage}
onTheme={handleThemeToggle}
onOpenAppDownload={() => setAppDownloadOpen(true)}
authUser={authUser}
guestMode={guestMode}
menuPermissions={menuPermissions}
@@ -1691,6 +1687,10 @@ function App() {
onSuccess={handleLoginSuccess}
/>
{appDownloadOpen && (
<AppDownloadModal onClose={() => setAppDownloadOpen(false)} />
)}
{/* ── 투자전략 화면 ──────────────────────────────────────────────── */}
{menuPage === 'dashboard' && (
<DashboardPage theme={theme} onGoChart={m => { goToMarketChart(m); setMenuPage('chart'); }} />
@@ -1900,6 +1900,7 @@ function App() {
<ChartToolbarNotify
onOpenNotifyList={openNotificationsPage}
onOpenAppDownload={() => setAppDownloadOpen(true)}
symbol={symbol} timeframe={layoutDef.count > 1 ? activeSlotTf : timeframe} chartType={chartType}
theme={theme} mode={mode} logScale={logScale} showGrid={showGrid}
activeIndicators={toolbarActiveIndicators}