Skip to content

Fix onboarding: slim to 4 slides, ImageOrientation enum, asset cleanup#53

Merged
dadachi merged 2 commits into
substrate-v2from
substrate-v2--fix-onboarding
Apr 29, 2026
Merged

Fix onboarding: slim to 4 slides, ImageOrientation enum, asset cleanup#53
dadachi merged 2 commits into
substrate-v2from
substrate-v2--fix-onboarding

Conversation

@dadachi
Copy link
Copy Markdown
Contributor

@dadachi dadachi commented Apr 29, 2026

Mirror of upstream nativeapptemplate/NativeAppTemplate-iOS#63, adapted to this fork.

Summary

  • Reorganize onboarding asset catalog into an Onboarding/ group, rename overview*~universal images to onboarding{1-4}, add a dedicated hero imageset for SignUpOrSignInView, and slim slides 8 → 4 with neutral placeholder descriptions.
  • Replace Onboarding.isPortraitImage: Bool with an ImageOrientation enum (.portrait / .landscape) so call sites read intent instead of decoding a Bool.
  • Drop onboardingsDictionary from OnboardingRepositoryProtocol (it carried two different meanings across impls and nothing accessed it via the protocol). Production OnboardingRepository now exposes a 4-item static array; demo/test doubles updated accordingly.

Test plan

  • make lint passes
  • xcodebuild ... build-for-testing succeeds (iPhone 17, iOS 26.4.1)
  • Run tests in Xcode (Cmd+U)
  • Launch app and confirm onboarding renders 4 slides with correct images and portrait/landscape padding
  • Confirm SignUpOrSignInView renders the new hero image

🤖 Generated with Claude Code

dadachi and others added 2 commits April 29, 2026 12:18
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@dadachi dadachi changed the base branch from main to substrate-v2 April 29, 2026 06:00
@dadachi dadachi merged commit 0260ff7 into substrate-v2 Apr 29, 2026
2 checks passed
@dadachi dadachi deleted the substrate-v2--fix-onboarding branch April 29, 2026 06:10
dadachi added a commit that referenced this pull request May 2, 2026
* Phase 2A-1: Port ItemTag schema update from paid iOS

Ports nativeapptemplate/NativeAppTemplate-iOS#49
- ItemTag model: queueNumber → name; add description/position;
  remove scanState/customerReadAt/alreadyCompleted
- ItemTagAdapter: parse name/description/position; drop legacy attrs
- PermissionsRequest: maximum_queue_number_length meta now optional
  with default 256 (full removal deferred to 2A-3)
- SessionController / App.swift null stub: maximumQueueNumberLength
  default 0 → 256
- ViewModels: queueNumber → name; validateQueueNumberLength →
  validateNameLength; hasInvalidDataQueueNumber → hasInvalidDataName
- Drop 5 production call sites of the deleted fields
  (ShowTagInfoScanResultView, ScanViewModel, ShopDetailViewModel,
  ShopDetailCardView, MainViewModel) — each flagged
  // TODO: removed in Phase 2A-2
- Shop model: drop displayShopServerPath / displayShopServerUrl; drop
  "Open Server Number Tags Webpage" link from ShopDetailView; delete
  NumberTagsWebpageListView/ViewModel and the Shop Settings section
  that linked to it
- Tests: update helpers and adapter fixtures for the new schema;
  delete ScanViewModelTest (queue/NFC-specific, goes away in 2A-2),
  completeTagWhenAlreadyCompleted test (asserted the removed branch),
  and NumberTagsWebpageListViewModelTest

Main target and test target both compile. Some tests may fail at
runtime (deferred to Phase 2A-4 per plan).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Phase 2A-2: Remove NFC / QR / Scan

Ports nativeapptemplate/NativeAppTemplate-iOS#50
to the Free iOS app. Drops all NFC, QR-code, and Scan-tab functionality;
ItemTagDetailView becomes a placeholder until Phase 2A-3 lands the full
generic CRUD UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* remove NativeAppTemplate.xcsheme

* Restore item-tag swipe actions on ShopDetailView; rename reset → idle

Reverts the upstream PR's removal of the complete/idle swipe actions on
ShopDetailView so users can still mark items completed or send them back
to idled without going through Settings.

Renames the user-facing "reset" terminology to "idle" since the action
just transitions a completed tag back to the idled state:

- ItemTag UI/ViewModel/strings: resetTag → idleTag, isResetting → isIdling,
  itemTagReset[Error] → itemTagIdled[Error], button label "Reset" → "Idle".
- ItemTag repository layer: ItemTagRepositoryProtocol.reset → idle,
  ItemTagRepository / DemoItemTagRepository / TestItemTagRepository updated.
- ItemTag network layer: ResetItemTagRequest → IdleItemTagRequest,
  ItemTagsService.resetItemTag → idleItemTag, HTTP path
  /shopkeeper/item_tags/:id/reset → /shopkeeper/item_tags/:id/idle.

Backend must expose PATCH /shopkeeper/item_tags/:id/idle.

Shop repository / network layer left as `reset` (no UI surfaces it).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Silence success toasts on item-tag complete/idle in ShopDetailView

Ports nativeapptemplate/NativeAppTemplate-iOS#52.
The swipe action already reflects the state change via ShopDetailCardView's
re-render after reload(); the extra success toast was redundant noise.
Errors still post to the message bus so users still see feedback when
something actually fails.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Phase 2A-3: Generic CRUD UI for ItemTag

Ports nativeapptemplate/NativeAppTemplate-iOS#53
to the Free iOS app. Replaces the Phase 2A-2 ItemTagDetailView placeholder
with a full generic CRUD UI; relaxes Create/Edit validation; adds a
description field; makes ItemTag.position non-optional.

Schema:
- ItemTag.position: Int? -> Int = 0; toJson() excludes position (server
  auto-assigns).
- ItemTagAdapter strict-guards position; throws invalidOrMissingAttributes
  when missing.
- Mock ItemTag(position: nil) -> position: 1 across tests.

Rename:
- maximumQueueNumberLength -> maximumNameLength across SessionController,
  protocol, App.swift NullSessionController, TestSessionController,
  PermissionsRequest. Default fallback 256 -> 100.
- PermissionsRequest reads meta["maximum_name_length"].

Create + Edit:
- Validation: name 1-100 chars (any string), description 0-1000 chars.
  Drops alphanumeric and count >= 2 checks; standard keyboard.
- New description field with multi-line TextEditor.
- Edit's hasInvalidData also requires name OR description changed.

Detail view full rewrite:
- State badge (IdlingTag / CompletedTag), description display,
  completedAt timestamp.
- Toggle button (Mark as completed / Mark as idled) calling
  ItemTagRepository.complete(id:) / idle(id:).
- New isToggling, completeItemTag(), idleItemTag(); failure posts error
  toast, success silently re-renders (matching PR #52).

ItemTagListCardView: name + description preview (2 lines) + state badge +
completedAt.

Constants: removed tagNumber/tagNumberIsInvalid; added nameLabel,
descriptionLabel, itemTagNamePlaceholder, itemTagNameIsInvalid,
itemTagDescriptionIsInvalid, completedAtLabel, markAsCompleted,
markAsIdled, itemTagNameHelp/itemTagDescriptionHelp helpers, and
NativeAppTemplateConstants.maximumItemTagDescriptionLength = 1_000.

Deviations from upstream PR #53:
- Skipped permission gates (canUpdateShops/canDeleteShops/canCreateShops)
  - Free repo has no Permission system. Edit/delete/toggle/create are
  unconditionally available. Skipped the upstream permissionChecking
  parameterized tests for the same reason.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Bump TestSessionController.maximumNameLength default 4 → 100

The new hasInvalidDataChangeDetection test in ItemTagEditViewModelTest
sets name = "Updated" (7 chars), which tripped the old default of 4
(carried over from the queue-number-length era). Match upstream Paid PR's
default of 100.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* remove scan folder

* Display completedAt as yyyy/MM/dd HH:mm regardless of locale

Ports nativeapptemplate/NativeAppTemplate-iOS#54.
ItemTagDetailView's completed-timestamp row was using
Text(completedAt.formatted()), which is locale-dependent — same instant
rendered as 4/26/2026, 10:30 AM (en_US), 26/04/2026, 10:30 (en_GB), or
2026/04/26 10:30 (ja_JP). Non-Gregorian calendars (Buddhist, Japanese
imperial) could shift the year value entirely.

Introduces Date.cardDateTimeString that stitches existing cardDateString
+ cardTimeString format constants, and pins Locale(identifier:
"en_US_POSIX") on the shared DateFormatter.formatter(for:) factory so
every fixed-format formatter is calendar/locale-stable.

- DateFormatter+Extensions.swift:
  - cardDateString: "MMM dd yyyy" → "yyyy/MM/dd" (the MMM token was
    locale-aware; the constant had zero callers).
  - formatter(for:) factory: pins Locale(identifier: "en_US_POSIX").
- Date+Extensions.swift: new cardDateTimeString computed property.
- ItemTagDetailView, ShopDetailCardView, ItemTagListCardView: switched
  to cardDateTimeString.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove "How To Use" link from Support section in SettingsView

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove NativeAppTemplate.entitlements

The associated-domains entitlement is no longer needed; the entitlements
file is now empty and dropped. CODE_SIGN_ENTITLEMENTS unset for both
Debug and Release configs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop maximum_name_length from permissions; move to Constants

Ports nativeapptemplate/NativeAppTemplate-iOS#59.

Two-step cleanup of maximumNameLength:

1. Stop reading maximum_name_length from /shopkeeper/permissions. The
   client already tolerated its absence via a "?? 100" fallback, so this
   is dead plumbing. Drops the field from PermissionsResponse, the meta
   read in PermissionsRequest.handle, and the assignment in
   SessionController.fetchPermissions.

2. Move maximumNameLength from SessionController to Constants. Now that
   it's a fixed value, it's just a constant — like
   maximumItemTagDescriptionLength. Adds
   NativeAppTemplateConstants.maximumItemTagNameLength = 100, drops
   maximumNameLength from SessionControllerProtocol / SessionController /
   NullSessionController / TestSessionController. ItemTagCreateViewModel
   and ItemTagEditViewModel now read the constant directly and no longer
   take sessionController. Updates the call sites in ItemTagListView /
   ItemTagDetailView. Tests rewritten to drop sessionController field
   and update truncation tests to use 100+ char strings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add client-side length caps + truncation for Shop name/description

Ports nativeapptemplate/NativeAppTemplate-iOS#60.
Mirror the ItemTag pattern from PR #49 for Shop. Server has no caps on
Shop name/description; this is a client-only UX guard.

- Constants: maximumShopNameLength = 100, maximumShopDescriptionLength
  = 1_000. New strings: shopNameIsInvalid, shopDescriptionIsInvalid,
  plus shopNameHelp(maximumLength:) / shopDescriptionHelp(maximumLength:)
  parametric helpers.
- ShopCreateViewModel + ShopBasicSettingsViewModel: split hasInvalidData
  into hasInvalidDataName + hasInvalidDataDescription, expose
  maximumNameLength / maximumDescriptionLength, add validateNameLength()
  / validateDescriptionLength().
- ShopCreateView + ShopBasicSettingsView: wire .onChange truncation on
  Name and Description; switch to two-line footer (always-visible help
  + conditional red "is invalid" text), matching ItemTagCreateView.
- Tests: added maximumNameLength, maximumDescriptionLength, parametric
  nameValidation / descriptionValidation, and the two truncation tests
  on both viewmodel test suites; replaced the old simple
  hasInvalidData(name:) parametric test in ShopCreateViewModelTest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop unused tags-scanned count and howToUse; tighten ItemTag labels

- Drop scannedItemTagsCount from Shop model, adapter, demo repo, and tests; remove the "tags scanned by customers" stat from ShopListCardView.
- Replace ShopDetailView "Learn More" link with a left-aligned shopDetailInstruction ("Swipe an item tag to change its status.").
- Swap the OnboardingView "How to use" link for the Support Website link; trim onboarding from 13 to 8 descriptions and drop unused String(localized:) wrap.
- Normalize ItemTag string keys: editTag/addTag/deleteTag/etc. -> editItemTag/addItemTag/deleteItemTag/etc.
- Drop unused constants: howToUseUrl, learnMore, createShops, createTags.

* Wrap String constants in enum Strings namespace

Convert the large `extension String` block in `Constants.swift` to a
caseless `enum Strings` namespace, matching the existing
`NativeAppTemplateConstants` idiom in the same file. Inline the
two `cardDateString`/`cardTimeString` literals in
`DateFormatter+Extensions.swift` and remove the small extension
they lived in. Update call sites across the app and tests from
`String.foo` to `Strings.foo`, including dot-shorthand uses for
`message:`, `text:`, `buttonTitle:`, and `?.message ==` parameters.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Replace onboarding image assets with new set; add hero asset

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Slim onboarding to 4 slides; ImageOrientation enum; hero asset

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Drop onboarding reload ceremony

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add unit tests for untested Models and Date extension

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Ignore .claude/scheduled_tasks.lock

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove vestigial code from NFC/Scan removal

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* README: drop stale NFC/QR feature lines

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove dead code: ImageSaver, composited(), unused colors and fonts

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Cleanup: dead Date helper, swiftier String predicates, README env vars

- Drop unused cardTimeAgoInWordsDateString and its timeAgoInWordsDateFormatter
- Move isBlank and validateEmail from Utility static helpers to String
  computed-property extensions (isBlank, isValidEmail) and update all call
  sites in production and tests
- Fold UtilityTest cases into StringExtensionsTest and delete UtilityTest
- README: clarify that Xcode is in practice the only NATEMPLATE_API_* env
  var injector, so the hardcoded fallbacks are what keep Debug builds
  working when launched from SpringBoard or after Xcode disconnects

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove Beta build configuration

The Beta config has no shared scheme and isn't referenced by CI, README, or
any xcconfig — drop it from the pbxproj so the project only ships Debug and
Release.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Remove unused String helpers: image(withAttributes:size:), isAlphanumeric

The String.image(...) renderer and both isAlphanumeric() overloads have no
production callers — only their own tests reference them. Drop the helpers
and their tests; UIKit/Foundation imports collapse to Foundation since the
remaining isBlank / isValidEmail need only that.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* add docs-private to gitignore

* phase2-prestep-number-tag-rename.md removed

* Normalize substrate naming: drop NATI-/NATEMPLATE_API_ abbreviations

- Env vars: NATEMPLATE_API_{SCHEME,DOMAIN,PORT} -> NATIVEAPPTEMPLATE_API_*
  in Constants.swift and README.md
- Error codes: NATI-XXXX -> NATIVEAPPTEMPLATE-XXXX across production and
  test Swift files, plus CHANGELOG.md
- CLAUDE.md: error-code section reframed as a shared iOS+Android prefix;
  dropped the stale NFCError.swift / NATIVEAPPTEMPLATE-3xxx row (file no
  longer present in this fork)

Mirrors upstream PR nativeapptemplate/NativeAppTemplate-iOS#71.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Add CHANGELOG entry for substrate naming normalization

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Update CHANGELOG for 3.2.0 release

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* Bump version to 3.2.0 (build 10)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant