1675 Commits

Author SHA1 Message Date
harukin-expo-dev-env
c425c0917b Merge commit '7b7ac73169255ae569ab38756f14a139dd255b9c' into develop 2026-05-02 09:15:31 +00:00
harukin-expo-dev-env
7b7ac73169 feat: add detailed changelog for version update to 7.0.3, highlighting new features and improvements 2026-05-02 08:59:55 +00:00
harukin-expo-dev-env
8594e79c25 Merge commit '6ce2cad4e5428dd30c066053176c59784cbe6fc0' into develop 2026-05-02 03:01:15 +00:00
harukin-expo-dev-env
6ce2cad4e5 fix: update version code to 7.0.3 2026-05-02 02:59:29 +00:00
harukin-expo-dev-env
75795f31e9 Merge commit '35542339943b4da6c181d5b6cc586d720752ab13' into patch/6.x 2026-05-02 02:53:10 +00:00
harukin-expo-dev-env
3554233994 fix: update header colors in injected JavaScript for better visibility 2026-05-02 02:52:22 +00:00
harukin-expo-dev-env
d71cc373c9 fix: sync WebView train display when playback frame changes
The XHR interceptor baked _MOCK_TRAIN at page load time, so seeking or
advancing a playback frame only changed React state but had no effect
on the already-loaded WebView page.

- webviewXhrInterceptor.ts:
  - Expose window.__jrsMockUpdateTrain(newData) from inside the IIFE so
    the _MOCK_TRAIN variable can be updated after page load
  - Add generateMockUpdateScript(trainPositions) helper: calls
    __jrsMockUpdateTrain with fresh data + GetDateTime, then calls
    window.setReload() to trigger the page's own redraw cycle

- WebView.tsx:
  - Import generateMockUpdateScript
  - Add useEffect watching mockTrainPositions (skips first mount since
    beforeContentLoaded already has correct data)
  - When mockApiFeatureEnabled && mockTrainPositions changes, inject the
    update script via webview.current.injectJavaScript()

Result: seeking, prev/next frame, and auto-advance during playback now
immediately update the train position display in the WebView.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-02 01:06:34 +00:00
harukin-expo-dev-env
3587f72434 feat: add RecordingStatusBar with elapsed timer and keep-awake
- RecordingStatusBar.tsx: shown during recorderState === 'recording'
  - absolute positioned red bar at top of map screen (zIndex 2000)
  - blinking REC dot (700ms interval) + REC label + MM:SS elapsed timer
  - snapshot count display (right side)
  - pointerEvents="none" so it doesn't block map interaction
  - activateKeepAwakeAsync while recording, deactivated on stop/unmount
    (same pattern as FixedPositionBox, tag = 'recording-status-bar')
- Apps.tsx: render <RecordingStatusBar /> alongside PlaybackTimeline

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-02 00:59:03 +00:00
harukin-expo-dev-env
4f4d3cad0a fix: crash on playback start + support multiple recordings
Crash fix (React Hooks violation):
- PlaybackTimeline.tsx: move ALL hooks (useRef for PanResponder, useCallback)
  to before the early return; use seekRef/totalRef to share values into
  PanResponder handlers without stale closure issues

Multiple recordings support:
- trainRecorder.ts: redesign to id-based multi-recording system
  - RecordingMeta type for lightweight list (no snapshots)
  - TrainRecording now includes id field
  - saveRecording/loadRecordingById/deleteRecordingById/loadRecordingList
  - migrateOldRecording() migrates old single MOCK_RECORDING key on first launch
- constants/storage.ts: add MOCK_RECORDINGS_INDEX + MOCK_RECORDING_DATA_PREFIX keys
- useTrainMenu: savedRecording → recordingList (RecordingMeta[]) + activeRecording (TrainRecording|null)
  - startPlayback(id) loads full recording on demand
  - deleteRecording(id) deletes by id and refreshes list
  - stopPlayback clears activeRecording
- DataSourceSettings: recording list UI
  - shows all recordings with date/time, snapshot count, duration
  - ▶ play and 削除 buttons per row
  - recording/playing status indicator

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-02 00:52:30 +00:00
harukin-expo-dev-env
8144e8a48a feat: add playback timeline UI with pause/resume/seek controls
- useTrainMenu: add playbackPaused state, pausePlayback/resumePlayback/seekToSnapshot
  - playback loop now respects playbackPaused (no timer when paused)
  - seekToSnapshot pauses playback and immediately applies snapshot data
  - expose playbackIndex, playbackPaused + new functions in context value
- PlaybackTimeline.tsx: new component shown when recorderState === 'playing'
  - absolute positioned bar at top of map screen (zIndex 2000)
  - prev/play-pause/next frame buttons + skip-to-start/end
  - time display (HH:mm:ss) + snapshot counter (n/total) + total duration
  - PanResponder-based scrubber track with filled progress bar and draggable thumb
- Apps.tsx: render <PlaybackTimeline /> alongside FixedPositionBox
- Remove MockApiToggle.tsx (no longer used since settings-only toggle)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-02 00:42:56 +00:00
harukin-expo-dev-env
37c08ad257 feat: add train position record & playback feature
Implements snapshot-based recording and playback of live train
position data for mock API debugging (admin-only).

Recording:
- startRecording() disables mock mode and begins capturing live
  train snapshots every ~15s (via getCurrentTrain polling)
- Each snapshot stores { t: elapsed_ms, trains: TrainEntry[] }
- stopRecording() saves completed recording to AsyncStorage

Playback:
- startPlayback() enables mock mode and loops through snapshots
  at their original recorded timing using useEffect+setTimeout
- stopPlayback() returns to idle

Storage:
- Single slot in AsyncStorage (MOCK_RECORDING key)
- Loaded on app start in useTrainMenu
- deleteRecording() removes it

New files:
- lib/mockApi/trainRecorder.ts — TrainRecording/TrainSnapshot types
  + save/load/delete AsyncStorage helpers

Modified files:
- constants/storage.ts — add MOCK_RECORDING key
- stateBox/useTrainMenu.tsx — recorder state + all controls
- stateBox/useCurrentTrain.tsx — call addTrainSnapshot after live fetch
- components/Settings/DataSourceSettings.tsx — record/play UI with
  status dot, snapshot count, and action buttons

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-02 00:31:55 +00:00
harukin-expo-dev-env
b5eb830734 fix: update useWebViewRemount to include backgroundThresholdMs option for better app state handling 2026-05-01 23:25:50 +00:00
harukin-expo-dev-env
92f4b37861 feat: apply mock data to currentTrain (app-side train positions)
When MOCK_API_FEATURE_ENABLED is on, getCurrentTrain() now returns
mock data instead of fetching from the n8n webhook or fallback API.

- App.tsx: move TrainMenuProvider before CurrentTrainProvider so
  useTrainMenu() is available inside CurrentTrainProvider
- useCurrentTrain: import useTrainMenu + MOCK_TRAIN_POSITIONS;
  getCurrentTrain() short-circuits to mock data when mockApiFeatureEnabled;
  added useEffect on mockApiFeatureEnabled to reload immediately on toggle

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 12:40:30 +00:00
harukin-expo-dev-env
a35956848a refactor: remove map-screen MOCK switch; settings toggle controls mock directly
The separate runtime MOCK switch on the map screen is removed.
Now the admin-only settings toggle (MOCK_API_FEATURE_ENABLED) is the
single control point — turning it on activates mock mode immediately,
turning it off deactivates it.

- useTrainMenu: remove mockApiEnabled/setMockApiEnabled state;
  mockApiConfig now derives from mockApiFeatureEnabled alone
- WebView: use mockApiFeatureEnabled for key prop (triggers reload)
- Apps.tsx: remove MockApiToggle import and JSX usage

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 12:35:36 +00:00
harukin-expo-dev-env
a809d287a2 fix: eliminate UX flash by calling setStrings() immediately in observer
The 100ms pure-debounce approach caused a visible layout flash on every
render (normal mode too) because Tokyo UX was not applied for 100ms.

Fix: call setStrings() immediately in the MutationObserver callback to
prevent any flash, AND keep a 250ms delayed follow-up call to catch
async train re-renders from mock XHR setTimeout(0) responses.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 11:59:52 +00:00
harukin-expo-dev-env
7566910821 fix: re-apply Tokyo UX after async train re-renders
Root cause: setStrings() was called synchronously in setReload(),
but the mock XHR interceptor responds via setTimeout(0), so the
site re-rendered train elements AFTER setStrings() ran, stripping
Tokyo UX styling.

Two-pronged fix:
1. setReload() now calls setStrings() again after 200ms to
   re-apply Tokyo UX once the async re-render completes.
2. textInsert MutationObserver now watches with subtree:true
   (childList only, not attributes - no infinite loop risk)
   with 100ms debouncing, so ANY train element re-render
   (including those triggered by mock XHR data) will trigger
   a re-application of Tokyo UX.
   - currentLines postMessage now only fires when direct
     children of #disp change (line selection changes only)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 11:51:13 +00:00
harukin-expo-dev-env
2cf6b679c5 fix: Tokyo UX stripped when mock is active
Two bugs caused the Tokyo UX to be stripped/broken when mock mode was ON:

1. **Double callback firing**: the interceptor's `setTimeout` called both
   `onreadystatechange.call(self)` AND `dispatchEvent(new Event('readystatechange'))`.
   Since `dispatchEvent` already fires `onXxx` property handlers via the DOM event
   model, the page's callback fired twice, causing a second DOM re-render that could
   overwrite Tokyo UX modifications. Fixed by relying on `dispatchEvent` only (with
   `ProgressEvent` for load events), with a direct-call fallback only for environments
   that lack `dispatchEvent`.

2. **No double-injection guard**: if `injectedJavaScriptBeforeContentLoaded` caused
   the interceptor to run more than once (e.g., `onPageStarted` fires multiple times
   on Android), `_origOpen` would capture the already-patched version, leading to
   unexpected behaviour. Fixed by adding `if (window.__jrsMockActive) return;` at the
   top of the interceptor IIFE.

3. **Belt-and-suspenders injection**: the interceptor is now also prepended to
   `injectedJavaScript` (Tokyo UX script) via the restored `mockApiConfig` parameter
   on `injectJavascriptData`. The `__jrsMockActive` guard ensures it's a no-op when
   `injectedJavaScriptBeforeContentLoaded` already ran it, but guarantees the
   interceptor is active on platforms where IJBCL is unreliable — before
   `MoveDisplayStation` triggers the first train-data poll via `onLoadEnd`.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 11:40:11 +00:00
harukin-expo-dev-env
1dcc25dec0 chore: update train.json with live disrupted data (2026-05-01 19:42)
94列車、62列車遅延の運行乱れデータをキャプチャ。
モックAPIのテストデータとして有用な状態。

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-05-01 10:43:19 +00:00
harukin-expo-dev-env
24f0c82b54 fix: call _origOpen even when intercepting to allow setRequestHeader
インターセプト対象のXHRでも_origOpen()を呼ぶよう修正。
これによりXHRがOPENED状態に入り、ページ側のsetRequestHeader()呼び出しが
エラーなく実行される。実際のリクエストはsend()でブロックすることで
モックデータのみ返す動作は維持される。

Playwright実機テスト結果:
- arg1=train&arg2=train: 2回インターセプト成功、実ネットワーク0件
- setRequestHeaderエラー: 解消
- 路線選択後のstation dataロード: 正常動作

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 22:49:22 +00:00
harukin-expo-dev-env
8321a47cbb fix: move XHR interceptor to injectedJavaScriptBeforeContentLoaded
インターセプターをページスクリプトより前に実行されるよう修正。
injectedJavaScript(ページ読込後)からinjectedJavaScriptBeforeContentLoaded
(ページスクリプト実行前)へ移動することで、モックON時のページフリーズを解消。

- lib/webViewInjectjavascript.ts: injectJavascriptDataからインターセプターを分離、
  generateBeforeContentLoadedScript()を新規エクスポート
- stateBox/useTrainMenu.tsx: injectJavascriptBeforeContentLoadedを別途計算しコンテキストに追加
- components/Apps/WebView.tsx: injectedJavaScriptBeforeContentLoadedプロップを追加

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 16:50:55 +00:00
harukin-expo-dev-env
59821a40d2 fix: rewrite XHR interceptor using prototype patching
Replaces the MockXHR wrapper class with direct prototype patching.

Root cause of broken page:
1. CRITICAL: callbacks called without .call(self) → 'this' inside
   onload/onreadystatechange was the global object, so this.responseText
   returned undefined and the page's JSON.parse crashed silently
2. responseType='json' not handled → page received string instead of
   parsed object when using xhr.response
3. instanceof XMLHttpRequest returned false, potentially breaking page
   validation logic

New approach (prototype-patch):
- Save original XMLHttpRequest.prototype.open and .send
- Patch open() to detect mock URL and store mock body on the instance
- Patch send() to define instance-level property getters (status,
  responseText, response, readyState) and fire callbacks with correct
  'this' context via .call(self)
- responseType='json' handled: response getter returns parsed object
- instanceof XMLHttpRequest always true (prototype chain untouched)
- dispatchEvent fires load/readystatechange for addEventListener users
- Non-mock requests delegate to original open/send unchanged

All 6 test cases pass: onload, onreadystatechange, addEventListener,
responseType=json, instanceof, and non-mock pass-through

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 16:05:41 +00:00
harukin-expo-dev-env
42473189da fix: reload WebView on mock toggle and fix XHR callback timing bug
- components/Apps/WebView.tsx:
  - import mockApiEnabled from context
  - add mockApiEnabled to WebView key so toggling forces a full reload
    (injectedJavaScript only runs at page load, so reload is required)

- lib/mockApi/webviewXhrInterceptor.ts:
  - Fix callback timing bug: callbacks set before open() were stored on
    _orig (because _mockBody was null), never on self._onload, causing
    mock send() to fire no-op callbacks
  - Always store all callbacks/listeners in _callbacks/_listeners maps
  - Apply _callbacks to _orig at send() time when not mocked
  - Fix addEventListener: always buffer in _listeners, apply to _orig
    at send() time; add removeEventListener support

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 15:50:37 +00:00
harukin-expo-dev-env
71e1ad8d22 feat: add admin mock API toggle in settings and map screen switch
- constants/storage.ts: add MOCK_API_FEATURE_ENABLED key
- stateBox/useTrainMenu.tsx:
  - import MOCK_TRAIN_POSITIONS; auto-populate on mount and on toggle-off
  - add mockApiFeatureEnabled (persistent, admin-only) state + setter
  - mockApiConfig now requires both mockApiFeatureEnabled AND mockApiEnabled
- components/Settings/DataSourceSettings.tsx:
  - add mock API debug section (admin-gated, showDebugSelector)
  - Switch toggles mockApiFeatureEnabled and persists to AsyncStorage
- components/Apps/MockApiToggle.tsx: new component
  - absolute-positioned to the left of ReloadButton
  - visible only when mockApiFeatureEnabled && mapSwitch==="true"
  - MOCK label + Switch toggles mockApiEnabled runtime state
- components/Apps.tsx: render MockApiToggle alongside ReloadButton

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 15:41:24 +00:00
harukin-expo-dev-env
170fbf0a57 feat: add WebView XHR interceptor for mock train position injection
- Scrape & analyse all 19 internal APIs of train.jr-shikoku.co.jp/sp.html
  using puppeteer + Chromium remote debugging
- Save live-captured sample JSON for every API endpoint under
  lib/mockApi/mockData/ (station lists, lang, timetable, train positions, etc.)
- Add lib/mockApi/webviewXhrInterceptor.ts – generates a JS snippet that
  overrides XMLHttpRequest inside the WebView before page scripts run;
  intercepts /g?arg1=train&arg2=train (and optionally all static APIs)
  returning mock data instead of the real server response
- Add lib/mockApi/index.ts – convenience re-exports + MOCK_TRAIN_POSITIONS
  constant pre-populated with captured sample data
- Extend InjectJavascriptOptions with optional mockApiConfig field
- injectJavascriptData() prepends the interceptor JS when mockApiConfig is set
- TrainMenuContext gains mockApiEnabled / setMockApiEnabled and
  mockTrainPositions / setMockTrainPositions state; consumers can enable
  mock mode and inject custom TrainEntry[] without reloading the app

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-30 15:30:06 +00:00
harukin-expo-dev-env
899c655d8c fix: add platformNum property to train data structures for improved display 2026-04-30 15:18:28 +00:00
harukin-expo-dev-env
4c1a315f5d fix: add loading and error handling in GeneralWebView component with reload functionality 2026-04-30 14:27:15 +00:00
harukin-expo-dev-env
a8c785bf7f fix: expose setReload function to the global window object for accessibility 2026-04-30 14:01:55 +00:00
harukin-expo-dev-env
a9668e6d51 fix: trim train numbers in sorting and filtering logic for accurate matching 2026-04-30 09:49:44 +00:00
harukin-expo-dev-env
3a4e083b9d feat: add FormationChips, FadingSubCycler, and ActiveFormationChipsCycler components for enhanced train data visualization 2026-04-30 08:59:46 +00:00
harukin-expo-dev-env
45cc68ae56 fix: normalize train numbers by stripping suffixes in TrainDataSources and useUnyohub
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 15:51:15 +00:00
harukin-expo-dev-env
d2e2f1d05c Merge commit '43f8095912f564ab02c3ddfbc0e218df5778cee6' into develop 2026-04-29 11:15:58 +00:00
harukin-expo-dev-env
43f8095912 feat: add changelog for version update from 064d81d4 to a959cf39, highlighting improvements in elesite integration, navigation stability, keyboard handling, and overall user experience 2026-04-29 11:15:52 +00:00
harukin-expo-dev-env
14e8e3422c Merge commit 'fac89f6f2ab74695e4f52e6a043e43f7f5c7f411' into patch/6.x 2026-04-26 08:49:28 +00:00
harukin-expo-dev-env
fac89f6f2a fix: simplify elesite permission handling and update version code to 7.0.2 2026-04-26 08:43:04 +00:00
harukin-expo-dev-env
331b9d64d2 Merge commit '94eb84b6de6c0ad86f90542c80efe262595e8a57' into develop 2026-04-26 07:56:56 +00:00
harukin-expo-dev-env
94eb84b6de fix: enhance ListViewItem cycling animation and update train pair mapping in BusAndTrainDataProvider 2026-04-25 07:34:10 +00:00
harukin-expo-dev-env
9fb591d6c2 Merge commit '3ecb301e8276ca20ce9af849e5d808850653a0ab' into fix/April-Mid-Patch 2026-04-19 11:09:20 +00:00
harukin-expo-dev-env
3ecb301e82 fix: update WebView navigation and adjust interval timing in CurrentTrainProvider 2026-04-19 11:09:13 +00:00
harukin-expo-dev-env
16e06573a1 Merge commit '5a1430d84960b4e35b562c06c07ed13d3be09c79' into experiment/web-url-experimental 2026-04-14 13:55:43 +00:00
harukin-expo-dev-env
5a1430d849 fix(HeaderText): update todayOperation prop to filter out completed operations 2026-04-14 13:55:37 +00:00
harukin-expo-dev-env
0fa3ba6029 Merge commit 'ff908414116aeb75e5d735ca184c21c1a7d17ad3' into experiment/web-url-experimental 2026-04-13 23:54:29 +00:00
harukin-expo-dev-env
ff90841411 Add new logo image for Elesite to relationLogo assets 2026-04-13 07:47:25 +00:00
harukin-expo-dev-env
2d14758e83 Merge commit 'a09ba456993d9f0854aa48beb8805a6fff4c0f96' into experiment/web-url-experimental 2026-04-12 11:18:09 +00:00
harukin-expo-dev-env
a09ba45699 fix(ExGridView): remove zoom scale properties from Animated.ScrollView 2026-04-12 10:02:00 +00:00
harukin-expo-dev-env
b3cf1c8ca3 Merge commit '76a617cde632ebca36da29a3a0f402541cc77191' into experiment/web-url-experimental 2026-04-12 08:19:06 +00:00
harukin-expo-dev-env
76a617cde6 fix(TrainDataView): update onLongPress condition to check currentTrainData instead of onLine 2026-04-12 08:18:59 +00:00
harukin-expo-dev-env
07399f4b4e fix(HeaderText): update todayOperation to use allTodayOperation for accurate state filtering
fix(TrainIconStatus): add cache option to fetch request for improved data handling
2026-04-12 08:18:33 +00:00
harukin-expo-dev-env
1b2ba087d5 feat: 投稿システム接続先のデバッグ機能を追加し、環境設定を管理できるようにした 2026-04-11 04:13:45 +00:00
harukin-expo-dev-env
374901c9fa fix: タブバーのアニメーションとキーボード非表示設定を削除
fix: JRSTraInfoコンポーネントの初期データ読み込み処理をuseEffectで追加
2026-04-10 09:36:09 +00:00
harukin-expo-dev-env
36be7801f6 fix(SearchUnitBox): use animatedOffset with Animated.View for smooth keyboard avoidance
- Replace measuredOffset (plain number) with animatedOffset (Animated.Value)
  so the search bar smoothly follows the keyboard instead of jumping abruptly
- Wrap position:absolute container in Animated.View to accept Animated.Value as bottom
- Remove LayoutAnimation.configureNext calls that conflicted with Animated.timing
  from useKeyboardAvoid, causing layout animation races on Android
- Drop unused keyboardHeight guard (keyboardHeight > 0 ? measuredBottom : 0);
  animatedOffset starts at 0 and is driven by the hook's timing, so no jump

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 02:30:46 +00:00