Wrap String constants in enum Strings namespace#52
Merged
dadachi merged 1 commit intoApr 28, 2026
Conversation
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>
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
extension Stringblock inConstants.swiftto a caselessenum Stringsnamespace, matching the existingNativeAppTemplateConstantsidiom in the same file.cardDateString/cardTimeStringliterals inDateFormatter+Extensions.swiftand drop the small extension they lived in.String.footoStrings.foo, including dot-shorthand uses formessage:,text:,buttonTitle:, and?.message ==parameters.Mirrors upstream nativeapptemplate/NativeAppTemplate-iOS#62, adapted to this Free fork (which does not have the Account/Invitation surface and keeps the existing
image()/isAlphanumeric()Stringhelpers because tests still depend on them).Test plan
make lintpasses (SwiftLint + SwiftFormat, 0 violations)xcodebuild buildsucceeds for iPhone simulator (generic)xcodebuild testsucceeds on iPhone 17 simulator (all tests pass)Back to Start Screenbutton on permission error🤖 Generated with Claude Code