Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,13 @@ flow-typed
# CocoaPods
/ios/Pods/
GoogleService-Info.plist
.pnpm-store/*
.worktrees/

# React Native Android generated resources (release bundling side effects)
/android/app/src/main/res/**/node_modules_*
/android/app/src/main/res/raw/src_common_constants_strings_*.json
/android/app/src/main/res/**/src_images_logo.png

# Local device verification screenshots
/tmp-device-screen*.png
71 changes: 71 additions & 0 deletions .planning/PROJECT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# PxView Reader Fixes

## What This Is

This repo is an old brownfield React Native Pixiv client that the user is treating as a personal NSFW txt/equb reading app. The current project is not a broad rewrite; it is focused maintenance work to make the existing novel reader faithfully render author content, starting with inline novel images.

## Core Value

When opening a Pixiv novel, the reader must preserve the author's intended reading flow, including inline images in their original position.

## Requirements

### Validated

- ✓ User can authenticate into Pixiv and persist session state across app restarts — existing
- ✓ User can browse Pixiv content across recommendation, ranking, search, and detail flows — existing
- ✓ User can open Pixiv novels inside the app and read them with paging, reading direction, and typography settings — existing

### Active

- [ ] Inline novel image markers render as images inside the body text at the original author-defined position
- [ ] Inline image failures degrade gracefully without breaking the rest of the novel page
- [ ] Existing novel reader behavior remains intact for chapter headers, jump links, reading direction, font size, and line height

### Out of Scope

- Local APK build, install, or startup crash fixes — separate environment/runtime problem and not part of this phase
- React Native or dependency modernization — too broad for the current maintenance goal
- Fullscreen image viewing, zooming, or gallery features for novel images — not required for the user's current need
- Generalized media-system refactor across the whole app — unnecessary for the narrow inline-image goal

## Context

The codebase is materially old: React Native `0.63.5`, React `16.13.1`, Redux Saga, React Navigation 5, and `react-native-htmlview` still drive the app. A codebase map already exists under `.planning/codebase/` and confirms a shared mobile monolith with novel fetching via `pixiv.novelWebview`, parsing in `src/common/helpers/novelTextParser.js`, and rendering in `src/components/NovelViewer.js`.

The user previously got the project to produce an APK only through ad hoc fixes and does not currently trust the local runtime, dependency graph, or build flow. Because validation is weak, current work needs to minimize surface area, stay close to the established reader pipeline, and prefer parser/viewer changes that can be covered by focused tests.

## Constraints

- **Tech stack**: Keep the existing React Native `0.63.5` + `react-native-htmlview` reader pipeline — broad rewrites would create too much risk in an old codebase
- **Scope**: First phase is inline novel images only — the user explicitly wants one concrete behavior fixed before any build/runtime cleanup
- **Validation**: Automated and code-level verification matter more than emulator confidence right now — local install/runtime behavior is currently unreliable
- **Compatibility**: Preserve existing novel reader UX such as page order, jump links, and reading settings — this is already working and should not regress

## Key Decisions

| Decision | Rationale | Outcome |
|----------|-----------|---------|
| Keep the existing `novelWebview -> parser -> HtmlView` pipeline | Smallest-risk change in a brittle brownfield app | — Pending |
| Treat inline novel images as the first and only active feature goal | User only cares about this one reading behavior right now | — Pending |
| Exclude build/crash troubleshooting from the first phase | Avoid mixing environment problems with product behavior changes | — Pending |

## Evolution

This document evolves at phase transitions and milestone boundaries.

**After each phase transition** (via `$gsd-transition`):
1. Requirements invalidated? -> Move to Out of Scope with reason
2. Requirements validated? -> Move to Validated with phase reference
3. New requirements emerged? -> Add to Active
4. Decisions to log? -> Add to Key Decisions
5. "What This Is" still accurate? -> Update if drifted

**After each milestone** (via `$gsd-complete-milestone`):
1. Full review of all sections
2. Core Value check - still the right priority?
3. Audit Out of Scope - reasons still valid?
4. Update Context with current state

---
*Last updated: 2026-04-01 after initialization*
54 changes: 54 additions & 0 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Requirements: PxView Reader Fixes

**Defined:** 2026-04-01
**Core Value:** When opening a Pixiv novel, the reader must preserve the author's intended reading flow, including inline images in their original position.

## v1 Requirements

### Novel Reader

- [ ] **READ-01**: User can open a Pixiv novel containing inline image markers without seeing raw placeholder text such as `[loadedimage:24095674]`
- [ ] **READ-02**: User sees each inline novel image at the same position relative to surrounding text where the author inserted it
- [ ] **READ-03**: Inline novel images render inside the existing page flow instead of being moved to a separate media-only page
- [ ] **READ-04**: If an inline image cannot be resolved or loaded, the user can still read the rest of the page and sees an inline fallback at that position
- [ ] **READ-05**: Existing novel-reader behaviors for chapter headers, jump links, reading direction, font size, and line height continue to work after inline-image support is added

## v2 Requirements

### Novel Media

- **MED-01**: User can tap an inline novel image to open a fullscreen viewer
- **MED-02**: User benefits from image prefetching or caching for novels with many inline illustrations

### Runtime Reliability

- **RUN-01**: User can install and launch a locally built APK without startup crashes
- **RUN-02**: User can verify inline-image behavior in a repeatable local test workflow

## Out of Scope

| Feature | Reason |
|---------|--------|
| React Native dependency upgrades | Too broad for the current maintenance phase |
| Fullscreen novel-image UX | Nice-to-have, not required for the user's immediate need |
| Cross-app media refactor | Would expand far beyond the novel reader path |
| Build-system stabilization | Separate problem that should be handled after the reader behavior is fixed |

## Traceability

| Requirement | Phase | Status |
|-------------|-------|--------|
| READ-01 | Phase 1 | Pending |
| READ-02 | Phase 2 | Pending |
| READ-03 | Phase 2 | Pending |
| READ-04 | Phase 2 | Pending |
| READ-05 | Phase 3 | Pending |

**Coverage:**
- v1 requirements: 5 total
- Mapped to phases: 5
- Unmapped: 0 ✓

---
*Requirements defined: 2026-04-01*
*Last updated: 2026-04-01 after initial definition*
69 changes: 69 additions & 0 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Roadmap: PxView Reader Fixes

**Created:** 2026-04-01
**Project:** `PxView Reader Fixes`
**Planning Profile:** YOLO, coarse granularity, sequential execution, balanced agents

## Summary

This roadmap is intentionally narrow. It exists to make inline Pixiv novel image markers render correctly inside the existing reader flow without mixing in build stabilization, dependency upgrades, or general reader rewrites.

**3 phases** | **5 v1 requirements** | **All mapped ✓**

| # | Phase | Goal | Requirements | UI hint |
|---|-------|------|--------------|---------|
| 1 | Inline Image Parsing And Resolution | Recognize inline image markers and convert them into renderable reader data without surfacing raw placeholders | READ-01 | no |
| 2 | Inline Reader Rendering And Fallbacks | Render inline images in the body flow at the correct position and fail gracefully when image resolution breaks | READ-02, READ-03, READ-04 | yes |
| 3 | Reader Regression Coverage And Finish Pass | Prove existing novel-reader behavior still works after inline-image support is added | READ-05 | no |

## Phase Details

### Phase 1: Inline Image Parsing And Resolution

**Goal:** Extend the novel text pipeline so loaded-image markup becomes a renderable inline node instead of leaking raw placeholder text into the UI.

**Requirements:** READ-01

**Success criteria:**
1. The parser no longer emits raw `[loadedimage:*]` text into the novel body output.
2. Inline image markers are transformed into a stable intermediate representation that the existing reader can detect.
3. The image-resolution path is isolated to the novel reader flow and does not require a cross-app media refactor.

### Phase 2: Inline Reader Rendering And Fallbacks

**Goal:** Render inline images in-place inside the current reader flow while keeping the rest of the page readable if an image cannot load.

**Requirements:** READ-02, READ-03, READ-04

**Success criteria:**
1. Inline images appear where the author placed them relative to surrounding text.
2. Inline images remain inside the current page flow and are not broken out into separate media pages.
3. Failed image resolution or loading shows an inline fallback state rather than crashing the reader.
4. Reader remains usable for the rest of the current page even when one image fails.

### Phase 3: Reader Regression Coverage And Finish Pass

**Goal:** Protect the existing novel-reader experience against regressions introduced by inline-image support.

**Requirements:** READ-05

**Success criteria:**
1. Automated tests cover the new parser behavior and the custom image-node rendering path.
2. Existing chapter-header and jump-link behavior remains intact after the change.
3. Reading direction, font size, and line-height behavior still work for novels after inline-image support is introduced.

## Coverage Check

| Requirement | Phase |
|-------------|-------|
| READ-01 | Phase 1 |
| READ-02 | Phase 2 |
| READ-03 | Phase 2 |
| READ-04 | Phase 2 |
| READ-05 | Phase 3 |

Coverage result: **5 / 5 requirements mapped**

## Next Step

Use `$gsd-discuss-phase 1` to clarify the implementation shape for inline image parsing and resolution before detailed planning or execution.
32 changes: 32 additions & 0 deletions .planning/STATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# State

## Project Reference

See: `.planning/PROJECT.md` (updated 2026-04-01)

**Core value:** When opening a Pixiv novel, the reader must preserve the author's intended reading flow, including inline images in their original position.
**Current focus:** Phase 1 - Inline Image Parsing And Resolution

## Initialization Status

- Codebase map: complete
- Project context: complete
- Workflow config: complete
- Requirements: complete
- Roadmap: complete

## Active Roadmap

- Phase 1: Inline Image Parsing And Resolution
- Phase 2: Inline Reader Rendering And Fallbacks
- Phase 3: Reader Regression Coverage And Finish Pass

## Immediate Next Command

`$gsd-discuss-phase 1`

## Notes

- This is a brownfield React Native maintenance track, not a greenfield product build.
- Local build/runtime instability is explicitly out of scope for the current roadmap.
- The first milestone is successful only when inline novel images render in-place without regressing the current reader behavior.
66 changes: 66 additions & 0 deletions .planning/codebase/ARCHITECTURE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Architecture

## High-Level Shape
- This is a classic React Native monolith: one mobile app, one shared JS codebase, thin native shells in `android/` and `ios/`.
- App bootstrap is `index.js` -> `src/screens/App/Root.js` -> `src/screens/App/App.js`.
- The app chooses between authenticated and unauthenticated navigation trees based on Redux auth state in `src/screens/App/App.js`.

## Runtime Boot Sequence
- `src/screens/App/Root.js` creates the Redux store/persistor via `src/common/store/configureStore.js`.
- Providers are layered in this order: Redux `Provider`, localization provider, safe-area provider, then Redux Persist gate.
- `src/screens/App/App.js` waits for both persistence rehydration and navigation initial state before rendering the main tree.
- Splash-screen dismissal is coupled to rehydration in `src/screens/App/App.js`.

## Navigation Model
- Logged-out flow uses `src/navigations/AuthNavigator.js`.
- Logged-in flow uses `src/navigations/AppNavigator.js`.
- `src/navigations/AppNavigator.js` is a native stack whose root screen is `SCREENS.Main`.
- `SCREENS.Main` renders `src/navigations/AppTabNavigator.js`, which defines the bottom-tab shell.
- Tab roots are Recommended, RankingPreview, Trending, NewWorks, and MyPage in `src/navigations/AppTabNavigator.js`.
- Shared detail, reader, comments, search result, and settings screens are pushed above the tab shell in `src/navigations/AppNavigator.js`.

## State And Data Flow
- Data flow is action-driven Redux with saga side effects.
- Action constants are centrally declared in `src/common/constants/actionTypes.js`.
- Action creators live in `src/common/actions/`.
- Side effects live in `src/common/sagas/`.
- Persistent and request-state reducers live in `src/common/reducers/`.
- Screens and containers consume denormalized selector output from `src/common/selectors/index.js`.

## Entity Pipeline
- Pixiv responses are normalized with Normalizr in sagas such as `src/common/sagas/recommendedIllusts.js`.
- Shared entity stores live in `src/common/reducers/entities.js`.
- Per-screen/per-query reducers keep ordered IDs, loading flags, timestamps, and pagination cursors.
- Selectors denormalize entities back into render-friendly shapes and apply user-specific filters such as mute/highlight in `src/common/selectors/index.js`.

## Authentication And Session Lifecycle
- Auth is PKCE-based web login initiated from `src/screens/Auth/Auth.js`.
- The login web view returns an auth code handled by `src/screens/Auth/Login.js`.
- Token exchange, refresh, and logout orchestration live in `src/common/sagas/auth.js`.
- Rehydration kicks off token refresh before the rest of the app proceeds in `src/common/sagas/auth.js`.
- Auth state is persisted as part of the Redux root persist config in `src/common/store/configureStore.js`.

## Persistence And Rehydration
- The store persists selected slices to filesystem storage, not just AsyncStorage, in `src/common/store/configureStore.js`.
- There is an explicit migration path from older AsyncStorage-based persists in `src/common/store/getStoredStateMigrateToFileSystemStorage.js`.
- Rehydration is coordinated with auth refresh and language reset in `src/common/sagas/auth.js`.
- Additional manual backup/restore for user settings is separate from redux-persist and lives in `src/screens/MyPage/Backup.js`.

## UI Layering
- `src/screens/` holds route-level screens.
- `src/containers/` contains connected or semi-connected feature wrappers reused by screens.
- `src/components/` contains reusable presentational and low-level widgets, including the `PX*` component family.
- Theming and global styles are centralized in `src/styles/`.
- Localization is provided through context wrappers in `src/components/Localization/`.

## Native Boundaries
- Native Android app host code is in `android/app/src/main/java/com/utopia/pxviewr/`.
- The main custom bridge is the Android ugoira image player under `android/app/src/main/java/com/utopia/pxviewr/UgoiraView/`.
- JS talks to that bridge via `src/components/UgoiraView.android.js`.
- iOS currently relies on stock React Native host wiring plus project-specific app delegate files under `ios/PxViewR/`.

## Notable Architectural Traits
- The architecture is highly slice-oriented: many near-identical action/reducer/saga modules for each Pixiv resource family.
- Business logic is still close to the UI in several places, especially screens such as `src/screens/MyPage/Feedback.js` and `src/screens/MyPage/Backup.js`.
- There is no explicit service layer beyond helper modules like `src/common/helpers/apiClient.js`.
- The app favors pragmatic shared-state reuse over strict feature isolation.
50 changes: 50 additions & 0 deletions .planning/codebase/CONCERNS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Concerns

## Platform And Dependency Age
- The stack is materially old: React Native `0.63.5`, React `16.13.1`, Jest `25`, ESLint `6`, and many pre-2022 ecosystem packages in `package.json`.
- Upgrading this repo will likely require coordinated navigation, Android Gradle, iOS CocoaPods, and native-module work rather than a small incremental bump.
- Android still disables Hermes in `android/app/build.gradle`, which is another signal that runtime/tooling assumptions are dated.

## Checked-In Build Artifacts And Secrets Hygiene
- Generated JS bundle artifacts are committed in `android/app/src/main/assets/index.android.bundle` and `android/app/src/main/assets/index.android.bundle.meta`, which can drift from source and create review noise.
- Debug signing material is present in `android/app/debug.keystore` and `android/keystores/debug.keystore.properties`.
- Release signing expects env/project properties in `android/app/build.gradle`; good that secrets are not hardcoded, but the repo should stay disciplined about not checking in release keystores.

## Auth Flow Fragility
- `src/common/actions/auth.js` still exposes a username/password `login(email, password, isProvisionalAccount)` action shape, but the active login saga in `src/common/sagas/auth.js` only consumes `code` and `codeVerifier`.
- Signup currently dispatches `login(signUpResponse.user_account, signUpResponse.password, true)` from `src/common/sagas/auth.js`, which does not match the code-path the watcher actually expects.
- That mismatch is a likely maintenance trap even if some paths still work via provisional-account behavior.

## Large Central Modules
- `src/common/selectors/index.js` is extremely large and mixes many unrelated feature selectors in one file.
- `src/common/reducers/index.js` and `src/common/sagas/index.js` are also very wide central registries.
- These files are workable today, but they make targeted refactors and code search noisier as the app grows.

## Repetition And Drift Risk
- Many slices are copy-paste variants across actions, reducers, and sagas.
- Repetition lowers the learning curve but increases the odds of inconsistent fixes or missing one slice during changes.
- Navigation also shows legacy residue: active stack/tab navigators coexist with older route config files in `src/navigations/routeConfigs/`.

## Error Handling Quality
- Several flows swallow errors silently, especially `src/screens/MyPage/Backup.js`.
- Saga error handling is inconsistent: some paths dispatch `addError(err)` with raw error objects, others extract messages.
- Production console suppression in `src/screens/App/Root.js` can make field debugging harder if telemetry is incomplete.

## Persistence And Data Safety
- Auth and user settings are persisted locally in `src/common/store/configureStore.js`, including access/refresh token material inside the auth slice.
- Backup/export in `src/screens/MyPage/Backup.js` writes readable JSON files to device storage, which is convenient but increases privacy risk if the exported file is shared or left behind.
- This matters more because the app handles NSFW reading habits, mute lists, and search history.

## Android Storage And OS Compatibility
- Backup uses `WRITE_EXTERNAL_STORAGE` from `src/screens/MyPage/Backup.js`, which is brittle on newer Android versions with scoped storage changes.
- The app likely needs a compatibility pass before modern Android target SDK upgrades.

## Native Maintenance Burden
- Custom native ugoira playback code under `android/app/src/main/java/com/utopia/pxviewr/UgoiraView/` adds value, but it is also a long-term upgrade burden.
- Any React Native major-version move will need that bridge verified early.
- iOS still uses older Objective-C app host patterns under `ios/PxViewR/`, which is normal for the repo age but increases upgrade surface area.

## Testing And Delivery Risk
- Automated coverage is very thin: only `__tests__/sagas/auth.spec.js` is visible.
- There is no visible CI workflow in the repo snapshot.
- The highest-value user journeys for this app, including login, reader behavior, image detail navigation, and save/share flows, are effectively protected by manual testing only.
Loading