Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
614 commits
Select commit Hold shift + click to select a range
41f2a13
Split AppFeatureTests into ParserFeatureTests + DownloadsFeatureTests
chihchy Jun 28, 2026
29b01d9
Make cancelled-cleanup scheduling test deterministic
chihchy Jun 29, 2026
fce7f02
Add OSLogExt module and app identifier
chihchy Jun 29, 2026
181018b
Use OSLog in BackgroundProcessingClient
chihchy Jun 29, 2026
1210a51
Use OSLog in AppModels
chihchy Jun 29, 2026
0a780e2
Use OSLog in ParserFeature
chihchy Jun 29, 2026
5b91459
Use OSLog in DatabaseClient
chihchy Jun 29, 2026
dd9ed76
Use OSLog in SettingFeature WebView
chihchy Jun 29, 2026
f78011f
Use OSLog in NetworkingFeature
chihchy Jun 29, 2026
3b5db5b
Use OSLog in ReadingFeature, drop UI noise
chihchy Jun 29, 2026
fc56bec
Use OSLog in DownloadClient
chihchy Jun 29, 2026
34234a6
Use OSLog in AppTools
chihchy Jun 29, 2026
1579a15
Remove SwiftyBeaver logging plumbing
chihchy Jun 29, 2026
8a4e1e9
Add AppActivityLog model and LogsClient module
chihchy Jun 29, 2026
8656f78
Rebuild log viewer with live pump and picker
chihchy Jun 29, 2026
ecacb52
Delete SwiftyBeaver module and dead log file APIs
chihchy Jun 29, 2026
7af25e0
Rename General log entry to App Activity Logs
chihchy Jun 29, 2026
eab6663
Add SettingFeatureTests for log viewer pump
chihchy Jun 29, 2026
7cc93c5
Move logger instances to files that use them
chihchy Jun 29, 2026
20b3e80
Fix activity log title and empty-page baseline
chihchy Jun 29, 2026
ab5a653
Reset activity log launch count per day
chihchy Jun 29, 2026
b59003e
Build log file names with joined separators
chihchy Jun 29, 2026
fe57aff
Add Run picker with Current section and sheet
chihchy Jun 29, 2026
656e406
Rename launch log names to run, drop launchDate
chihchy Jun 29, 2026
addc605
Show run time HHmm, cap picker at 5 incl current
chihchy Jul 1, 2026
346b62f
Log app activity events at notice level
chihchy Jul 1, 2026
ae39ed9
Use file URL as RunLogFile identity
chihchy Jul 1, 2026
8a8b931
Add Open in Files button to activity logs
chihchy Jul 1, 2026
93528aa
Use sentence case for App activity logs label
chihchy Jul 1, 2026
6985542
Resync localizations to match en, add logs keys
chihchy Jul 1, 2026
b5afaa9
Drop Copied from attribution comments
chihchy Jul 1, 2026
5da21f9
Drop Localizable.strings file headers
chihchy Jul 1, 2026
c5b11f3
Adopt TCA AlertState/ConfirmationDialogState
chihchy Jul 1, 2026
1bc4818
Adopt `@Presents` for Search modal sheets
chihchy Jul 1, 2026
477e636
Adopt `@Presents` for Setting web-view sheets
chihchy Jul 1, 2026
2d65b2c
Adopt `@Presents` for list-feature modal sheets
chihchy Jul 1, 2026
896593d
Adopt `@Presents` for Reading/Downloads modals
chihchy Jul 1, 2026
516d867
Adopt `@Presents` for Detail sub-view modals
chihchy Jul 1, 2026
a0d4b44
Adopt `@Presents` for AppRoute setting/newDawn
chihchy Jul 1, 2026
e5d2f61
Adopt `@Presents` for DateSeek picker sheet
chihchy Jul 1, 2026
943e284
Adopt `@Presents` for DetailSearch modal sheets
chihchy Jul 1, 2026
2547e78
Adopt `@Presents` for Detail modal sheets
chihchy Jul 1, 2026
ac96e48
Remove unused sheet(unwrapping:case:) helper
chihchy Jul 1, 2026
b011ff0
Extract activity-logs pump behind shared state
chihchy Jul 1, 2026
9080a6b
Convert Setting navigation to StackState
chihchy Jul 1, 2026
40e95b1
Convert gallery drill-down to StackState
chihchy Jul 1, 2026
7793073
Replace NavigationView with NavigationStack
chihchy Jul 1, 2026
f9a2578
Modernize QuickSearch word editor navigation
chihchy Jul 1, 2026
2d30967
Remove RecurseReducer and deprecated nav helpers
chihchy Jul 1, 2026
5b204ba
Present gallery detail modally on iPad
chihchy Jul 1, 2026
96d4ea7
Drive progress HUDs from optional state
chihchy Jul 1, 2026
88620c0
Delete SwiftUINavigationExt and direct dep
chihchy Jul 1, 2026
c8417a7
Replace AlertState with custom AppAlertState
chihchy Jul 1, 2026
8da2826
Render AppAlertState alerts with native alert
chihchy Jul 2, 2026
4c5095d
Fold progress HUD state into AppAlertState
chihchy Jul 2, 2026
3bb38a7
Replace AlertKit page-jump with native alert
chihchy Jul 2, 2026
06700b0
Enrich page jump alert message
chihchy Jul 2, 2026
5ed262f
Present page jump via AppAlertState, autofocus
chihchy Jul 2, 2026
40af5b7
Anchor confirm dialogs to trigger controls
chihchy Jul 2, 2026
4bf4201
Reset compose state when presenting comment sheet
chihchy Jul 2, 2026
b39bf62
Share gallery push helper, guard duplicates
chihchy Jul 2, 2026
400f893
Delete dead teardown action cases
chihchy Jul 2, 2026
3b33ad2
Add Setting stack navigation tests
chihchy Jul 2, 2026
19b9cbb
Drop stale AlertKit pin from Package.resolved
chihchy Jul 2, 2026
6d63f65
Remove orphaned detail delete-download string
chihchy Jul 2, 2026
171ce50
Guard duplicate pushes on non-gallery routes
chihchy Jul 2, 2026
a73e043
Delete dead setCommentContent action
chihchy Jul 2, 2026
a7b1463
Replace FilePicker with native fileImporter
chihchy Jul 2, 2026
c51614f
Remove FilePicker acknowledgement entry
chihchy Jul 2, 2026
9d55284
Coordinate fileImporter read for iCloud files
chihchy Jul 2, 2026
3535446
Cover parent tag-translation import intercept
chihchy Jul 2, 2026
9f45036
Add SystemNotificationExt glass toast module
chihchy Jul 2, 2026
140ab25
Rename HUD style and L10n keys to toast
chihchy Jul 2, 2026
75fedcf
Adopt .toast presentation, remove TTProgressHUD
chihchy Jul 2, 2026
423ef2f
Swap acknowledgement to SystemNotification
chihchy Jul 2, 2026
9777d2a
Fix toast dismiss identity and animation scope
chihchy Jul 2, 2026
3fb7270
Drop stale TTProgressHUD pin from Package.resolved
chihchy Jul 2, 2026
9055c5a
Tidy SystemNotificationExt header comments
chihchy Jul 2, 2026
2c411de
Restore swipe axis guard, fix dismiss race
chihchy Jul 3, 2026
3dd9877
Drop SwiftUINavigation acknowledgement entry
chihchy Jul 3, 2026
f0e2f7f
Update copyright statement
chihchy Jul 3, 2026
05bd3c8
Update contributors list
chihchy Jul 3, 2026
e3452af
Remove translations wanted section from READMEs
chihchy Jul 3, 2026
389a874
Update L10n keys
chihchy Jul 3, 2026
b3a0236
Remove InfoPlist.strings header comments
chihchy Jul 3, 2026
2d14cd9
Localize strings with placeholder values
chihchy Jul 3, 2026
b7a693e
Realign locales, drop straggler unused key
chihchy Jul 3, 2026
bdb4d60
Move CookieClient strings to catalog
chihchy Jul 3, 2026
17f9239
Move GalleryListComponents strings to catalog
chihchy Jul 3, 2026
4269e6b
Move SearchFeature strings to catalog
chihchy Jul 3, 2026
a253029
Move AppFeature strings to catalog
chihchy Jul 3, 2026
10d18e8
Move MigrationFeature strings to catalog
chihchy Jul 3, 2026
e75b5c1
Move DateSeekFeature strings to catalog
chihchy Jul 3, 2026
b9c106c
Move DownloadClient strings to catalog
chihchy Jul 3, 2026
98d8e57
Move QuickSearchFeature strings to catalog
chihchy Jul 3, 2026
c8b5677
Move ReadingSettingFeature strings to catalog
chihchy Jul 3, 2026
feec309
Move ReadingFeature strings to catalog
chihchy Jul 3, 2026
c1e7c59
Move HomeFeature strings to catalog
chihchy Jul 3, 2026
df4080a
Move AppComponents strings to catalog
chihchy Jul 3, 2026
9da7588
Move FiltersFeature strings to catalog
chihchy Jul 3, 2026
79185b1
Move DownloadsFeature strings to catalog
chihchy Jul 3, 2026
628fe21
Move DetailFeature strings to catalog
chihchy Jul 3, 2026
af29851
Move SettingFeature strings to catalog
chihchy Jul 3, 2026
d52660b
Move AppModels strings to catalog
chihchy Jul 3, 2026
05c404a
Move shared strings to Resources, drop SwiftGen
chihchy Jul 3, 2026
7db197a
Add SFSafeSymbolsExt, use Label resource init
chihchy Jul 3, 2026
a91c137
Drop redundant String(localized:) in view APIs
chihchy Jul 3, 2026
91bde55
Drop String(localized:) in labeled view controls
chihchy Jul 3, 2026
5ed0cd3
Bridge TextState to LocalizedStringResource
chihchy Jul 3, 2026
08c6068
Type shared component titles as resources
chihchy Jul 3, 2026
43b186d
Convert App InfoPlist strings to catalog
chihchy Jul 3, 2026
52e8564
Update to Xcode recommended settings
chihchy Jul 4, 2026
bbfa362
Fix double-escaped newlines in catalog values
chihchy Jul 4, 2026
2aedfac
Fix escapes and %% in SettingFeature catalog
chihchy Jul 4, 2026
afe79d2
Add matches_count singular plural variant
chihchy Jul 4, 2026
b714d0d
Default swiftSettings to fix Package file_length
chihchy Jul 4, 2026
c08b790
Use searchable prompt resource overload
chihchy Jul 4, 2026
c53b1ea
Strip toast/new_dawn prefixes, qualify none/optional
chihchy Jul 4, 2026
fc8df4d
Type count placeholders as %lld with Int args
chihchy Jul 4, 2026
89ae159
Add LOCALIZATION_PREFERS_STRING_CATALOGS build setting
chihchy Jul 4, 2026
f9777ff
Resolve bundle via #bundle macro in symbols
chihchy Jul 4, 2026
b6493ec
Convert component title params to resources
chihchy Jul 4, 2026
4e3cacb
Add resource overloads to toast caption
chihchy Jul 4, 2026
60db0bc
Label numeric l10n args via substitutions
chihchy Jul 4, 2026
f99739b
Stop Xcode auto-extracting non-string UI text
chihchy Jul 4, 2026
2e45c6d
Stop remaining UI string auto-extraction
chihchy Jul 4, 2026
e16e8d4
Update label_text_image_shorthand rule
chihchy Jul 4, 2026
28a1e1d
Fill all locales for non-translated xcstrings keys
chihchy Jul 4, 2026
a550014
Type Category.value as LocalizedStringResource
chihchy Jul 4, 2026
2501a86
Type Language.value as LocalizedStringResource
chihchy Jul 4, 2026
0defd6f
Type BrowsingCountry.name as resource
chihchy Jul 4, 2026
03d2d50
Type TagNamespace.value as resource
chihchy Jul 4, 2026
094900e
Type EhSetting option enums as resources
chihchy Jul 4, 2026
94a5d9b
Type remaining AppModels display enums
chihchy Jul 4, 2026
1d66294
Convert EhSetting section labels to resources
chihchy Jul 4, 2026
8bd52be
Convert SettingFeature view labels to resources
chihchy Jul 4, 2026
46f62e5
Convert DetailFeature view labels to resources
chihchy Jul 4, 2026
e26b085
Convert DownloadsFeature view labels to resources
chihchy Jul 4, 2026
ab6b370
Convert misc feature view labels to resources
chihchy Jul 4, 2026
dc50769
Type LinkRow text as LocalizedStringResource
chihchy Jul 4, 2026
ea8beb1
Type form-field component labels as resources
chihchy Jul 4, 2026
574327e
Add AlertView resource message overload
chihchy Jul 4, 2026
027f0b1
Add NewDawnView resource text overload
chihchy Jul 4, 2026
56723ef
Type missingFiles message as resource
chihchy Jul 4, 2026
4cdf85b
Embed count in download summary keys
chihchy Jul 4, 2026
bec40f4
Embed count in torrents label key
chihchy Jul 4, 2026
6328cae
Embed run count in activity log run key
chihchy Jul 4, 2026
03f5ae8
Embed index in favorite category key
chihchy Jul 4, 2026
6f9cf62
Remove empty string literal usage
chihchy Jul 5, 2026
5272e69
Remove SwiftGen acknowledgement entry
chihchy Jul 5, 2026
c6b0835
Add `@Shared` appStorage keys and light models
chihchy Jul 5, 2026
2f6c7ca
Persist user and settings via `@Shared` appStorage
chihchy Jul 5, 2026
198322b
Persist search filters via `@Shared` appStorage
chihchy Jul 5, 2026
b06f122
Persist search history and quick-search words
chihchy Jul 5, 2026
49fcba8
Persist tag translator via `@Shared` fileStorage
chihchy Jul 5, 2026
e63d713
Persist reading progress via gallery history
chihchy Jul 5, 2026
79122dc
Render history from batched gdata metadata
chihchy Jul 5, 2026
352f1d2
Seed gallery detail from navigation, drop DB reads
chihchy Jul 5, 2026
2b381ca
Stop caching gallery data in the database
chihchy Jul 5, 2026
e9c29a8
Remove MigrationFeature launch gating
chihchy Jul 5, 2026
bc0618b
Remove DatabaseClient module and Core Data
chihchy Jul 5, 2026
bfcb220
Add limit notices to history and quick search
chihchy Jul 5, 2026
06a0829
Rebuild tag translator from cached raw JSON
chihchy Jul 5, 2026
f4652b3
Add schemaVersion anchor to persisted models
chihchy Jul 5, 2026
856ded4
Fix cross-domain deletion in cookie test store
chihchy Jul 5, 2026
e12d0f4
Seed pushed reader with gallery, config, language
chihchy Jul 6, 2026
1183fc4
Validate history writes and tolerate gdata errors
chihchy Jul 6, 2026
3975f14
Page History fetch and bound gdata concurrency
chihchy Jul 6, 2026
3eef872
Debounce reading-progress persistence
chihchy Jul 6, 2026
622c496
Sequence tag-translator rebuild before fetch
chihchy Jul 6, 2026
78738c5
Store Setting in `@Shared`, drop write-through
chihchy Jul 6, 2026
d9fe8ea
Prune history off the launch path
chihchy Jul 6, 2026
a208753
Remove dead fields from persisted models
chihchy Jul 6, 2026
48b65f7
Drop Core Data debug args from scheme
chihchy Jul 6, 2026
f237f56
Decode HTML entities in a single pass
chihchy Jul 6, 2026
f2c6c7a
Document cap policies and schemaVersion
chihchy Jul 6, 2026
1b0ad9f
Guard recently-seen suggestions from re-fetching
chihchy Jul 6, 2026
223e1e5
Replace fossil databaseLoadingState with restore flag
chihchy Jul 6, 2026
790a947
Delete custom translations file on removal
chihchy Jul 6, 2026
caf4d19
Share newer-only greeting merge across writers
chihchy Jul 6, 2026
a4c0cd4
Extract shared LimitBanner component
chihchy Jul 6, 2026
030a834
Share one gdata publisher across both requests
chihchy Jul 6, 2026
eaad9d0
Add Filter snapshot accessors for shared reads
chihchy Jul 6, 2026
8d83b6f
Unify tolerant decoders via shared helper
chihchy Jul 6, 2026
16d612e
Flush reading progress on reader dismissal
chihchy Jul 6, 2026
5e207bf
Rename fossil databaseReducer to sessionReducer
chihchy Jul 6, 2026
874940e
Require gallery in PreviewsReducer.State; bail on vanished download
chihchy Jul 6, 2026
e4c7fd8
Eliminate `@Shared` setting setter deprecations
chihchy Jul 6, 2026
7a3eebf
Silence initialState test-target warnings
chihchy Jul 6, 2026
e1b52c6
Fix flaky expiration-assertion release test
chihchy Jul 7, 2026
dd5c59d
Replace banner with ListNoticeView
chihchy Jul 8, 2026
185a4d3
Update "Date to Seek" to "Date seek"
chihchy Jul 8, 2026
9ca5f08
Update outdated comments
chihchy Jul 8, 2026
002bc49
Drop DB-changelog comments and dead error case
chihchy Jul 8, 2026
14dd080
Tighten gdata decode to Parser's required set
chihchy Jul 8, 2026
adf4ce8
Move greeting to in-memory shared slot
chihchy Jul 8, 2026
5854076
Replace tolerant decoders with strict decode
chihchy Jul 8, 2026
f52b119
Replace Filter singletons with SharedReader
chihchy Jul 8, 2026
0d73966
Enforce Detail always holds a real Gallery
chihchy Jul 8, 2026
071428d
Remove vestigial hasRestoredSession gate
chihchy Jul 8, 2026
face288
Route reader flush from AppReducer scene phase
chihchy Jul 8, 2026
5705b53
Read tagTranslator via `@Shared`, drop threading
chihchy Jul 8, 2026
c5bfb70
Read user via `@Shared`, drop param threading
chihchy Jul 8, 2026
0ce0b2d
Read setting via `@Shared`; Reading writes binding
chihchy Jul 8, 2026
10757b1
Drop setting-derived onAppear action payloads
chihchy Jul 8, 2026
6e61f23
Drop now-unused AppModels import in gallery hub
chihchy Jul 8, 2026
2751772
Clamp scale factors in the Setting model
chihchy Jul 9, 2026
4191237
Reader edits setting via view-owned `@Shared`
chihchy Jul 9, 2026
c5c359c
Seed reader pager from saved resume page
chihchy Jul 9, 2026
5265077
Read setting in list leaves via `@SharedReader`
chihchy Jul 9, 2026
bbda677
Read user via `@SharedReader` in view leaves
chihchy Jul 9, 2026
0d138c0
Drop dead empty defaults on pushed states
chihchy Jul 9, 2026
70eb646
Reword scene-phase flush test comment
chihchy Jul 9, 2026
7277a2a
Document no-schema-gate convention on blobs
chihchy Jul 9, 2026
c81ac31
Remove reader pager defaults and dead onChange
chihchy Jul 9, 2026
1850aa4
Retire Gallery.empty in favor of .preview
chihchy Jul 9, 2026
7ff5a83
Move autoLock/blur invariant into Setting model
chihchy Jul 9, 2026
7c3fb1d
Give Laboratory its own reducer for SNI effect
chihchy Jul 9, 2026
8c29f26
Give App Icon its own reducer for icon effect
chihchy Jul 9, 2026
0043fc4
Give Reading its own reducer for landscape
chihchy Jul 9, 2026
352cd76
Move galleryHost effect into Account reducer
chihchy Jul 9, 2026
5de9e5d
Trigger tag rebuild via General delegate
chihchy Jul 9, 2026
4ada8cd
Move color-scheme effect into Appearance reducer
chihchy Jul 9, 2026
2ace7ca
Read setting via `@Shared` in Download screen
chihchy Jul 9, 2026
0cba11e
Delete settingBinding and BindingReducer from Setting
chihchy Jul 9, 2026
99de0a4
Let ReadingSettingView own its `@Shared` setting
chihchy Jul 9, 2026
495e088
Read tagTranslator in GeneralSettingView via `@SharedReader`
chihchy Jul 9, 2026
8d62396
Read bypassesSNIFiltering via `@SharedReader` in leaves
chihchy Jul 9, 2026
624f3a9
Let ReadingSettingView hold its own reducer
chihchy Jul 9, 2026
01237d4
Gate all persisted models with SchemaVersion
chihchy Jul 9, 2026
15eb999
Log rejected schemaVersion via OSLog
chihchy Jul 9, 2026
234cc9a
Add mock-v2 migration tests for all models
chihchy Jul 9, 2026
990a1cd
Cover add/remove/type/derive/merge migrations
chihchy Jul 9, 2026
04b2bdd
Add progressive schema migration engine
chihchy Jul 9, 2026
b04cb72
Rework migration to array-of-schemas design
chihchy Jul 9, 2026
9474661
docs: map existing codebase
chihchy Jul 9, 2026
e82da32
Update AGENTS.md
chihchy Jul 9, 2026
e226a15
docs: initialize project
chihchy Jul 9, 2026
872199f
chore: add project config
chihchy Jul 9, 2026
8285599
docs: define v1 requirements
chihchy Jul 9, 2026
76a5844
docs: create roadmap (11 phases)
chihchy Jul 9, 2026
37d76ac
fix(apptools): set disk size limit for cache
dyphire Aug 12, 2026
cf68120
feat(ui): enhanced visual feedback for gallery details and lists
dyphire Aug 13, 2026
7ddbf3b
feat(ui): implement highlight for watched tags
dyphire Aug 13, 2026
57eebfc
refactor(home): optimize the selection logic of the top card
dyphire Aug 13, 2026
cbe3989
fix(reader): thumbnail preview in reader not working
dyphire Aug 14, 2026
93e7671
feat(reader): add automatic vertical reading support for galleries co…
dyphire Aug 15, 2026
9f787e8
fix(ui): tag suggestion function does not adapt to EH search syntax
dyphire Aug 15, 2026
9dfbca7
feat(search): add search suggestion support for quick search content …
dyphire Aug 15, 2026
c2d4043
fix(config): EhSetting parsed incorrectly
dyphire Aug 18, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
45 changes: 26 additions & 19 deletions .github/workflows/deploy-pre-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,13 @@ name: Deploy Pre-release
on:
workflow_dispatch:
inputs:
versionTag:
description: 'Version tag'
required: true
type: string
releaseTitle:
description: 'Release title'
required: true
type: string
releaseDescription:
description: 'Release description'
required: true
required: false
type: string
env:
DEVELOPER_DIR: /Applications/Xcode_26.5.app
Expand Down Expand Up @@ -47,16 +43,13 @@ jobs:
- name: Run tests
run: xcodebuild clean test
-skipMacroValidation
-skipPackagePluginValidation
-scheme ${{ env.SCHEME_NAME }}
-destination 'platform=iOS Simulator,name=iPhone Air'
- name: Bump version
id: bump-version
uses: yanamura/ios-bump-version@v1
with:
version: ${{ inputs.versionTag }}
- name: Xcode archive
run: xcodebuild archive
-skipMacroValidation
-skipPackagePluginValidation
-scheme ${{ env.SCHEME_NAME }}
-destination 'generic/platform=iOS'
-archivePath ${{ env.ARCHIVE_PATH }}
Expand All @@ -77,15 +70,29 @@ jobs:
- name: Retrieve data
id: retrieve-data
run: |
echo "size=$(stat -f%z $IPA_OUTPUT_PATH)" >> $GITHUB_OUTPUT
echo "version_date=$(date -u +"%Y-%m-%dT%T")" >> $GITHUB_OUTPUT
app_info_plist="$PAYLOAD_PATH/$SCHEME_NAME.app/Info.plist"
version="$(plutil -extract CFBundleShortVersionString raw -o - "$app_info_plist")"
size="$(stat -f%z "$IPA_OUTPUT_PATH")"

[[ ! -z "$version" ]] || exit 1
[[ ! -z "$size" ]] || exit 1

{
echo "size=$size"
echo "version=$version"
echo "version_date=$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
} >> "$GITHUB_OUTPUT"
- name: Validate data
env:
RELEASE_TITLE: ${{ inputs.releaseTitle }}
RELEASE_SIZE: ${{ steps.retrieve-data.outputs.size }}
RELEASE_VERSION: ${{ steps.retrieve-data.outputs.version }}
RELEASE_DATE: ${{ steps.retrieve-data.outputs.version_date }}
run: |
[[ ! -z "${{ inputs.releaseTitle }}" ]] || exit 1
[[ ! -z "${{ inputs.releaseDescription }}" ]] || exit 1
[[ ! -z "${{ steps.retrieve-data.outputs.size }}" ]] || exit 1
[[ ! -z "${{ steps.bump-version.outputs.version }}" ]] || exit 1
[[ ! -z "${{ steps.retrieve-data.outputs.version_date }}" ]] || exit 1
[[ ! -z "$RELEASE_TITLE" ]] || exit 1
[[ ! -z "$RELEASE_SIZE" ]] || exit 1
[[ ! -z "$RELEASE_VERSION" ]] || exit 1
[[ ! -z "$RELEASE_DATE" ]] || exit 1
- name: Release to GitHub
uses: softprops/action-gh-release@v3
with:
Expand All @@ -94,5 +101,5 @@ jobs:
files: ${{ env.IPA_OUTPUT_PATH }}
token: ${{ secrets.GITHUB_TOKEN }}
name: ${{ inputs.releaseTitle }}
body: ${{ inputs.releaseDescription }}
tag_name: 'v${{ steps.bump-version.outputs.version }}'
body: ${{ inputs.releaseDescription || '' }}
tag_name: ${{ steps.retrieve-data.outputs.version }}
25 changes: 11 additions & 14 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ on:
types: [closed]
env:
DEVELOPER_DIR: /Applications/Xcode_26.5.app
APP_VERSION: '2.8.0'
SCHEME_NAME: 'EhPanda'
ALTSTORE_JSON_PATH: './AltStore.json'
BUILDS_PATH: '/tmp/action-builds'
Expand Down Expand Up @@ -43,16 +42,13 @@ jobs:
- name: Run tests
run: xcodebuild clean test
-skipMacroValidation
-skipPackagePluginValidation
-scheme ${{ env.SCHEME_NAME }}
-destination 'platform=iOS Simulator,name=iPhone Air'
- name: Bump version
id: bump-version
uses: yanamura/ios-bump-version@v1
with:
version: ${{ env.APP_VERSION }}
- name: Xcode archive
run: xcodebuild archive
-skipMacroValidation
-skipPackagePluginValidation
-scheme ${{ env.SCHEME_NAME }}
-destination 'generic/platform=iOS'
-archivePath ${{ env.ARCHIVE_PATH }}
Expand Down Expand Up @@ -146,12 +142,7 @@ jobs:
token: ${{ secrets.GITHUB_TOKEN }}
body: ${{ github.event.pull_request.body }}
name: ${{ github.event.pull_request.title }}
tag_name: 'v${{ steps.retrieve-data.outputs.version }}'
- name: Commit bump version
run: |
git add .
git commit -m "Bump version"
git push origin HEAD
tag_name: ${{ steps.retrieve-data.outputs.version }}
- name: Update AltStore.json
env:
RELEASE_SIZE: ${{ steps.retrieve-data.outputs.size }}
Expand Down Expand Up @@ -202,10 +193,16 @@ jobs:
git commit -m "Update AltStore.json"
git push origin HEAD
- name: Post release notes
env:
RELEASE_VERSION: ${{ steps.retrieve-data.outputs.version }}
RELEASE_BODY: ${{ github.event.pull_request.body }}
RELEASE_NOTES: ${{ steps.retrieve-data.outputs.notes }}
run: |
message="$(printf '*%s Release Notes:*\n%s' "$RELEASE_VERSION" "$RELEASE_BODY")"
curl https://api.telegram.org/bot${{ secrets.TELEGRAM_BOT_TOKEN }}/sendMessage \
-d parse_mode=markdown -d chat_id=${{ secrets.TELEGRAM_CHANNEL_ID }} \
-d text='*v${{ steps.retrieve-data.outputs.version }} Release Notes:*%0A${{ github.event.pull_request.body }}'
--data-urlencode "text=$message"

payload="$(jq -n --arg content "**$RELEASE_VERSION Release Notes:**\n$RELEASE_NOTES" '{content: $content}')"
curl ${{ secrets.DISCORD_WEBHOOK }} \
-F 'payload_json={"content": "**v${{ steps.retrieve-data.outputs.version }} Release Notes:**\n${{ steps.retrieve-data.outputs.notes }}"}'
-F "payload_json=$payload"
1 change: 1 addition & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ jobs:
- name: Run tests
run: xcodebuild clean test
-skipMacroValidation
-skipPackagePluginValidation
-scheme ${{ env.SCHEME_NAME }}
-destination 'platform=iOS Simulator,name=iPhone Air'
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
build
.build
.DS_Store
.xcode-home
EhPanda.xcodeproj/xcuserdata
EhPanda.xcodeproj/project.xcworkspace/xcuserdata
EhPanda.xcodeproj/project.xcworkspace/xcuserdata
Config/LocalSigning.xcconfig

# AppPackage (local Swift package)
AppPackage/.build
AppPackage/.swiftpm/xcode/xcuserdata
AppPackage/.swiftpm/xcode/package.xcworkspace/xcuserdata
123 changes: 123 additions & 0 deletions .planning/PROJECT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# EhPanda

## What This Is

EhPanda is an open-source iOS / iPadOS client for E-Hentai / ExHentai — browsing, searching, favorites, gallery detail, reading, and downloading — built in SwiftUI on The Composable Architecture, modularized into a thin app shell (`App/`) plus a local Swift package (`AppPackage/`). This milestone is a **dependency-reduction & modernization** pass ahead of the unreleased **v3.0.0**: shrink the third-party surface to a minimal, justified set; move networking to async/await and TCA toward 2.0; retire legacy UI/architecture patterns (screen-metric math, global helpers, parameter drilling); and ratchet up lint — all with **behavior parity**, no user-facing regressions.

## Core Value

The load-bearing paths must keep working: reliably **fetch, parse, read, and download** galleries from E-Hentai / ExHentai. Every task in this milestone is a foundation change — parity with today's behavior is the bar; a modernization that regresses browsing, reading, or downloading has failed.

## Requirements

### Validated

<!-- Inferred from the existing codebase (see .planning/codebase/). These already ship and are relied upon. -->

- ✓ Browse & search galleries — Home (Frontpage/Popular/Watched/Toplists/History), Search, Favorites — existing
- ✓ Gallery detail — comments, torrents, archives, previews, tag detail — existing
- ✓ Reading — paged & vertical, dual-page, zoom/pan gestures, reading settings — existing
- ✓ Downloads — concurrent page downloads + background processing task — existing
- ✓ Auth — E-Hentai/ExHentai session cookies via `WKWebView` login — existing
- ✓ Tag translation — EhTagTranslation database + OpenCC Simplified/Traditional conversion — existing
- ✓ Persistence — swift-sharing `@Shared` (no Core Data) + progressive schema-migration engine (all models at v1) — existing
- ✓ Modular architecture — App-shell + `AppPackage` local package; deps centralized in `Package.swift` — existing

### Active

<!-- This milestone's scope: 21 locked tasks. Hypotheses until shipped. Grouped by theme; the roadmap phases them. -->

**A · Dependency reduction**
- [ ] 1. Fork **SwiftyOpenCC** — modernize its OpenCC dependency, package requirement & Swift version; rebuild on the latest stack
- [ ] 2. Fork **UIImageColors** — same modernization treatment
- [ ] 3. Migrate **SwiftCommonMark → Apple swift-markdown** (usage is parse-only via `MarkdownUtil`; confirm `DetailView`)
- [ ] 4. Replace **WaterfallGrid** with a custom SwiftUI `Layout` · *feasibility spike first*
- [ ] 5. Replace **SwiftUIPager** with a built-in page-style `TabView` · *feasibility spike first*
- [ ] 6. Investigate inlining **DeprecatedAPI** (`getCFReadStream`) without deprecation warnings; adopt a non-deprecated API if actionable
- [ ] 7. Migrate to the latest **Colorful** (modernization, not reduction)

**B · Concurrency & framework modernization**
- [ ] 8. Migrate **Combine-based requests → async/await** (`NetworkingFeature` request layer + `ApplicationClient`/`AuthorizationClient`/`ImageClient`/`LibraryClient` + consuming reducer effects)
- [ ] 13. Pin **TCA `from: 1.25.3` with traits** (`ComposableArchitecture2Deprecations`, `ComposableArchitecture2DeprecationOverloads`) and resolve all surfaced deprecations

**C · UI architecture**
- [ ] 10. **Modernize adaptive layout** — remove screen-dependent logic (`DeviceUtil` + `DeviceClient`); prefer size classes / `containerRelativeFrame` / `onGeometryChange` / `ViewThatFits`, **avoiding `GeometryReader`**; retire `TouchHandler` via native gestures
- [ ] 11. **Decompose `GenericList`** — let each of its 8 consuming pages build its own list from shared atoms instead of a super-list
- [ ] 12. **Universal device orientation** on every page + remove EhPanda's custom orientation lock (delete `enablesLandscape`), deferring the lock to iOS's built-in feature
- [ ] 15. **Root-level privacy mask** — replace `blurRadius` parameter-drilling (~25 inits, 39 `.autoBlur` sites) with one mask per root surface (app root + ~41 modal roots), driven by shared state
- [ ] 19. **Remove the auto-lock feature** — delete `autoLockPolicy`, the biometric re-auth path, and `AuthorizationClient`; replace the security-section control with a description pointing users to iOS's built-in per-app lock (background blur is kept)

**D · Architecture hygiene**
- [ ] 14. **De-globalize `*Util` → injected clients, kill singletons** — the AppTools Utils (Device/Haptics/UserDefaults/File/Cookie) plus `URLUtil` and `AppUtil`, and the `TouchHandler.shared` / `DataCache.shared` globals; keep pure value types & constants

**E · Correctness, security & tests (folded-in concerns, later timing)**
- [ ] 16. **Move session cookies to Keychain** (during #14's CookieClient work) + audit that no cookie values are ever logged
- [ ] 17. **Client-layer test coverage** — `NetworkingFeature` (during #8), `CookieClient` & `ImageClient` (during #14)
- [ ] 18. **Fix `Category.private.filterValue`** — remove the `fatalError` landmine
- [ ] 20. **Structured error handling + user-facing error surface** (gates the `optional_try` rule) — replace silent `try?` (144 sites) with proper `do/catch` that surfaces user-relevant failures through a structured error surface (Description / Suggested Solution / Context / environment info; non-blocking failure toast → tap for detail), keeping best-effort parsing explicitly optional

**F · UI polish**
- [ ] 21. **Numeric text polish** — apply `.monospacedDigit()` + `.contentTransition(.numericText())` to most number-bearing text (counts, page numbers, sizes, ratings)

**G · Lint hardening (capstone + refactor-gated)**
- [ ] 9. Enable the commented-out custom rules + opt-in `multiline_function_chains` & `sorted_imports` + a new **labeled-tuple-elements** rule, all at **error** level. Mechanical rules (`sorted_imports`, `multiline_function_chains`, `single_line_trailing_closure`, labeled-tuples) land as a capstone sweep; refactor-gated rules sequence **with** their refactors: `optional_try` → #20, plus `binding_initializer`, `lifecycle_modifiers`, `unchecked_subscript_index_access`

### Out of Scope

<!-- Explicit boundaries to prevent re-adding. -->

- **ParserFeature complexity refactor** (extract per-field sub-parsers) — real value but rides on nothing else here; deferred to a future milestone
- **DownloadClient decomposition** (555+ line files) — large standalone refactor; deferred
- **Broad client-layer tests beyond networking/cookie/image** (Reading/Home/Search/Favorites features) — deferred; this milestone covers only the seams already being reworked
- **Post-release v2 schema migrations + migration-mock cleanup** — deferred until v3.0.0 ships; models stay at v1 this milestone
- **Any visual redesign** — the UI-architecture tasks are mechanism swaps, not re-skins; behavior/appearance parity required
- **Re-enabling `function_body_length` / `cyclomatic_complexity` / `type_body_length`** — kept disabled; `ParserFeature` relies on it and it wasn't requested

## Context

- **v3.0.0 in flight, unreleased.** Last release was v2.8.0; ~600+ commits of refactoring since (persistence drop-to-`@Shared`, navigation refactor, migration engine — all landed). This milestone is the next batch: dependency reduction + modernization before v3.0.0 ships.
- **Codebase map** lives at `.planning/codebase/` (STACK, ARCHITECTURE, STRUCTURE, CONVENTIONS, TESTING, INTEGRATIONS, CONCERNS).
- **Reference designs** for the structured error surface (#20) and the refactor-gated lint rules (#9) have been captured name-free; the plan phase needs no external lookup.
- **Two tasks carry parity risk** and are spiked first: SwiftUIPager→`TabView` (core reading UX) and WaterfallGrid→custom `Layout` (masonry column balancing).

## Constraints

- **Tech stack**: Swift 6.3.1, iOS/iPadOS 26 minimum, SwiftUI + TCA 1.25.x + swift-sharing; Xcode-only build/test (bare `swift build` fails); SwiftLint runs as a build-tool plugin.
- **Parity**: No user-facing behavior or appearance regressions — this is a foundation milestone, not a feature or redesign one.
- **Schema**: Persisted `@Shared` models stay at **v1**, edited in place, for the whole pre-release milestone — no `VersionedSchema` v2 / migration until v3.0.0 releases.
- **Lint**: SwiftLint-as-error; never suppress, disable, or add `// swiftlint:disable` without explicit user permission.
- **Reference privacy**: Never record the name of any local project consulted for implementation references in any repository artifact (see AGENTS.md) — absolute and non-waivable.

## Key Decisions

| Decision | Rationale | Outcome |
|----------|-----------|---------|
| Combine→async/await stays in this milestone (not split out) | One coherent modernization milestone; sequence it after the isolated dep removals | — Pending |
| Spike-first for WaterfallGrid→Layout and SwiftUIPager→TabView | "Bet on native parity" items that can genuinely fail; reading is core UX | — Pending |
| Avoid `GeometryReader`; prefer size classes / `containerRelativeFrame` / `onGeometryChange` / `ViewThatFits` | Most cases don't need it; it's greedy and layout-disruptive | — Pending |
| Retire `TouchHandler` via `SpatialTapGesture.location` + `MagnifyGesture.startAnchor` | Native gestures (iOS 17+) cover all three uses; kills a global singleton | — Pending |
| Remove auto-lock (use iOS built-in per-app lock); **keep** background blur | OS app-lock supersedes the custom biometric flow; app-switcher blur stays as standalone privacy | — Pending |
| `@Shared` models edited in place at v1 until v3.0.0 ships | No released data to migrate from pre-release; defers first real v2 to post-release | — Pending |
| De-`Util` package-wide (incl. `URLUtil`, `AppUtil`) | Injected clients over singletons/global helpers; consistent architecture | — Pending |
| Fold in cookies→Keychain, networking/cookie/image tests, `.private.filterValue` fix; defer Parser/Download refactors | Coupled concerns are cheap while their seams are open; standalone refactors are separate scope | — Pending |
| Recommended sequence: small-blast deps → swaps/spikes → migrations (#8/#13) → architecture (#10/#11/#12/#14/#15/#19) → concerns (#16–18,#20) → lint capstone (#9) | Minimize churn; write new code to the new bar; lint ratchets last | — 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-07-09 after initialization*
Loading