Skip to content

Conversation

@Und3rf10w
Copy link
Collaborator

@Und3rf10w Und3rf10w commented Jan 5, 2026

Summary

Complete MVP implementation of the OpenPrintTag Writer Android app - a tool for reading, writing, and generating standardized NFC data tags for 3D printing materials.

Changes in this PR

Core Features

  • feat: MVP preparation - Fix compilation, add tests, improve UX
  • feat: add system theme-aware light/dark mode support - Material Design 3 theming with automatic dark mode
  • feat: display decoded tag data instead of raw hex bytes - Human-readable tag display
  • feat: complete OpenPrintTag spec field coverage with tests - All 54 MainRegion + 4 AuxRegion fields
  • feat: comprehensive UI revamp with Material Design 3 - Modern, clean interface overhaul

Bug Fixes

  • fix: correct error toast in read operation and init mode indicator
  • fix: resolve compilation errors in Serializer and GeneratorActivity
  • fix: resolve remaining compilation errors and fix test imports
  • fix: improve CBOR deserialization for external .bin files - Handle integer arrays, mixed types

Refactoring

  • refactor: rename fields to match OpenPrintTag spec verbatim - snake_case field names for easy spec cross-reference

CI/CD

  • ci: improve caching with official Gradle action
  • ci: add concurrency control and artifact uploads

Key Features

Full OpenPrintTag Spec Coverage

  • All 54 MainRegion fields (UUIDs, weights, temperatures, colors, SLA properties, container dimensions)
  • All 4 AuxRegion fields (consumed_weight, workgroup, general_purpose_range_user, last_stir_time)
  • Proper CBOR key mapping via @SerialName annotations
  • No deprecated keys (12, 25, 26) used

Robust CBOR Serialization

  • Custom serializers for mixed CBOR types (IntOrStringSerializer, IntListAsStringListSerializer)
  • Handles integer arrays for tags/certifications
  • LocalDate serialization as epoch seconds
  • Graceful handling of malformed data

Material Design 3 UI

  • Modern card-based layout with sections
  • Material-aware field display (FFF vs SLA)
  • Color swatches with hex preview
  • Temperature range displays
  • Usage progress tracking
  • Tag/certification chips
  • Light/dark theme support

NFC Operations

  • Read tags via NfcA and NfcV protocols
  • Write generated data to tags
  • Import/export .bin files
  • Mode indicator (READ/WRITE)

Generator Activity

  • Comprehensive form for all material properties
  • Smart tag selection with implies/hints system
  • Color pickers for primary + 5 secondary colors
  • Date pickers for manufactured/expiration dates
  • Material class-aware field visibility

Files Changed

Core Model

  • OpenPrintTagModel.kt - Data classes with full spec field coverage
  • Serializer.kt - CBOR encode/decode with NDEF formatting

Activities

  • MainActivity.kt - NFC read/write, file import/export
  • GeneratorActivity.kt - Material data editor form

UI Components

  • TagDisplaySection.kt - Display item builders
  • TagDataAdapter.kt - RecyclerView adapter
  • Theme resources (colors, styles, dimens)

Tests

  • FieldCoverageTest.kt - Spec compliance verification
  • OpenPrintTagModelTest.kt - Model unit tests
  • SerializerTest.kt / SerializerUnitTest.kt - Serialization tests

Test Plan

  • Unit tests pass (./gradlew test - 71 tests)
  • Debug APK builds successfully (./gradlew assembleDebug)
  • Read existing OpenPrintTag .bin files
  • Write data to NFC tags
  • Field coverage tests verify spec compliance
  • Light/dark theme switching works
  • Material class toggle shows/hides relevant fields

UI Screenshots

image Screenshot 2026-01-05 at 2 10 51 PM Screenshot 2026-01-05 at 2 10 26 PM Screenshot 2026-01-05 at 2 10 05 PM Screenshot 2026-01-05 at 2 09 46 PM

This commit brings the OpenPrintTag Writer to MVP-ready state with
critical bug fixes, comprehensive testing, and UX improvements.

- Fix type errors: lowercase `int?` → `Int?` in OpenPrintTagModel.kt
  (totalWeight, ActTotalWeight, consumedWeight fields)
- Add missing `JsonNode` import in Serializer.kt

- Remove duplicate nested onNewIntent() inside onCreate() that
  shadowed the class-level override in MainActivity
- Wire materialClass dropdown to model in GeneratorActivity
  (was being ignored during serialization)
- Add NFC intent filters to AndroidManifest for proper tag discovery:
  - NDEF_DISCOVERED for application/vnd.openprinttag MIME type
  - TECH_DISCOVERED with nfc_tech_filter.xml (NfcA, NfcV, Ndef)

- Set versionCode=1, versionName="0.1.0"
- Add test dependencies (JUnit 4.13.2, AndroidX Test, Espresso)
- Create proguard-rules.pro with rules for:
  - Kotlinx.serialization (keep serializers and companions)
  - Jackson CBOR (keep ObjectMapper methods)
  - SnakeYAML and model classes
- Update CI workflow to use JDK 21 and add explicit build step

- Create adaptive app icons (vector drawables):
  - ic_launcher_background.xml (teal gradient)
  - ic_launcher_foreground.xml (3D printer/tag design)
  - ic_launcher.xml and ic_launcher_round.xml (adaptive configs)
- Create comprehensive strings.xml with 40+ externalized strings
  for all UI text, error messages, toasts, and status indicators
- Add mode indicator colors to colors.xml:
  - mode_read_background (#4CAF50 green)
  - mode_write_background (#F44336 red)

- SerializerTest.kt: 17 tests covering CBOR encoding, NDEF formatting,
  dual-record generation, and deserialization
- OpenPrintTagModelTest.kt: 17 tests for model defaults, field
  assignments, nested regions, and date serialization
- SelectionManagerTest.kt: 15 tests for tag selection logic including
  implies chains, hints, circular dependencies, and edge cases

- Add ProgressBar for visual feedback during NFC operations
- Add mode indicator TextView showing current read/write mode
  with color-coded background (green=read, red=write)
- Add try-catch error handling around all NFC operations with
  user-friendly error messages via Toast and status TextView
- Update activity_main.xml layout with new UI components
- Fix bug where read failure showed "Write Failed" toast instead of
  "Read Failed" in readAndDisplayTag() error handler
- Add toast_read_failed string resource for read operation errors
- Call updateModeIndicator() in onCreate() to ensure mode indicator
  is properly initialized on app startup
- Replace manual Gradle cache with gradle/actions/setup-gradle@v4
  which handles caching automatically and more efficiently
- Add Android SDK caching for faster subsequent builds
- Remove --no-daemon flag (Gradle action manages daemon lifecycle)

This should reduce CI build times from ~5-10 min to ~1-2 min on cache hits.
- Remove redundant Android SDK cache (pre-installed on runners)
- Add concurrency group to cancel in-progress runs on new pushes
- Upload test results as artifact (even on failure) for debugging
- Upload debug APK as downloadable artifact
## Serializer.kt fixes:
- Change `OpenPrintTagModel.MainRegion` to `MainRegion` (top-level class)
- Change `OpenPrintTagModel.AuxRegion` to `AuxRegion` (top-level class)
- Add missing `decodeCbor()` function called by parseNextNdefRecord
- Add `deserialize()` method for GeneratorActivity to use
- Add `findCborPayloadStart()` helper for payload extraction
- Add JsonNode overloads for `decodeMainRegion()` and `decodeAuxRegion()`
  to fix type mismatch errors (functions expected ByteArray, got JsonNode)

## AndroidManifest.xml:
- Remove deprecated `package` attribute (namespace is in build.gradle)

These changes fix 40+ compilation errors that were causing CI build failure.
Serializer.kt:
- Add explicit type annotations for JsonNode variables
- Use path() instead of get() for null-safe int access
- Rename JsonNode overloads to decodeMainRegionFromNode/decodeAuxRegionFromNode
  to avoid overload resolution ambiguity
- Add null fallback for decodeMainRegion assignment

Test files:
- Fix imports: MainRegion, AuxRegion, UrlRegion are top-level classes,
  not nested in OpenPrintTagModel
- Update all test references from OpenPrintTagModel.* to direct class refs

Build now compiles successfully and all tests pass.
Replace hardcoded colors with theme attributes in layouts:
- tag_category_header.xml: use colorSurfaceVariant/colorOnSurface
- tag_selectable_option.xml: use colorOnSurface/colorOnSurfaceVariant

Use explicit Light/Dark themes for reliable switching:
- values/styles.xml: Theme.Material3.Light.NoActionBar
- values-night/styles.xml: Theme.Material3.Dark.NoActionBar
- Add deserialize() call in readAndDisplayTag() and loadBytesFromFile()
- Add formatModelForDisplay() to show human-readable material properties
- Load enum maps (classMap, typeMap, tagsMap, certsMap) for deserialization
- Add testOptions.returnDefaultValues for Android unit tests
- Add serialization tests for various model configurations
@Und3rf10w Und3rf10w requested a review from DBNinja January 5, 2026 17:10
- Fix findCborPayloadStart() to properly parse NDEF record headers
  and calculate correct CBOR payload offset
- Add version marker detection to skip {2: version} wrapper objects
- Add custom serializers for int-to-string conversion:
  - IntOrStringSerializer for non-null String fields
  - NullableIntOrStringSerializer for nullable String fields
  - IntListAsStringListSerializer for List<String> from int arrays
- Replace kotlinx.serialization with direct JsonNode mapping in
  decodeMainRegionFromNode() for more lenient type handling
- Handle bytes-to-hex conversion for color fields stored as raw bytes

This enables loading .bin files that use different CBOR encoding
formats, such as files from other OpenPrintTag implementations.
This commit implements full coverage of all OpenPrintTag specification
fields and adds comprehensive test coverage for spec compliance.

Model Changes (OpenPrintTagModel.kt):
- Add 22 new MainRegion fields: UUIDs (keys 0-3), brand IDs (5-7),
  writeProtection (13), expirationDate (15), emptyContainerWeight (18),
  shoreHardness A/D (31-32), minNozzleDiameter (33), container
  dimensions (42-45), SLA viscosity fields (46-49), containerVolumetricCapacity
  (50), cureWavelength (51), filament lengths (53-54)
- Add 2 new AuxRegion fields: generalPurposeRangeUser (2), lastStirTime (3)
- Fix critical key mapping: filamentDiameter now uses key 30 (key 12 is deprecated)
- Fix type mismatches: weight fields changed from Int to Float per spec
- Rename fields per spec: brand→brandName, totalWeight→nominalNettoFullWeight,
  ActTotalWeight→actualNettoFullWeight, idealChamberTemp→chamberTemperature,
  secondary_color_X→secondaryColorX, transmission_distance→transmissionDistance
- Add NullableLocalDateSerializer for optional date fields

Serializer Changes:
- Update encoder (encodeMain) to support all 50+ fields
- Update decoder (decodeMainRegionFromNode) with all field mappings
- Update decodeAuxRegionFromNode to decode directly from JsonNode
- Update encodeAux to support new aux fields

UI Changes:
- MainActivity: Enhanced display showing hardness, certifications,
  expiration date, spool dimensions, country of origin
- GeneratorActivity: Updated field references

Test Coverage:
- New FieldCoverageTest.kt: Spec compliance tests verifying all 56
  CBOR keys present, deprecated keys not used, correct types
- Updated OpenPrintTagModelTest.kt: Tests for all new fields
- Updated SerializerTest.kt and SerializerUnitTest.kt: Fixed field refs
- Added test resource: openprinttag_PETG_Kandy_Blast.bin
- Added kotlin-reflect dependency for reflection-based tests

Breaking Changes:
- Field renames require code updates (brand→brandName, etc.)
- Weight fields now Float instead of Int
- Key 12 removed, key 30 used for filamentDiameter
This commit introduces a complete UI overhaul following Material Design 3
principles with a Modern Minimal aesthetic (teal accent #14B8A6).

## Design System Foundation
- Add dimens.xml with consistent spacing system (xs/sm/md/lg/xl)
- Add type.xml with typography scale (headlines, body, labels, section headers)
- Add themes.xml with component theme overlays (cards, buttons, chips, progress)
- Expand colors.xml with teal-based palette for light mode
- Add values-night/colors.xml for proper dark mode support

## Tag Data Display System (MainActivity)
- Create TagDisplaySection.kt with sealed class hierarchy for 8 display types:
  MaterialHeader, SectionHeader, PropertyRow, TemperatureRow, UsageProgress,
  ColorSwatches, ChipGroup, EmptyState
- Create TagDataAdapter.kt with ViewHolders for rich card-based display
- Add 8 item layouts for RecyclerView-based tag data presentation
- Replace plain text display with visual cards, color swatches, progress bars
- Add material-class-aware display logic (shows FFF vs SLA fields appropriately)
- Display usage tracking from AuxRegion (consumed weight with progress bar)

## MainActivity Improvements
- Redesign layout with CoordinatorLayout, AppBarLayout, BottomAppBar
- Add toolbar menu for quick access to Generator, Load, and Save actions
- Implement proper view binding throughout (remove all findViewById)
- Add mode indicator as Material Chip with teal/amber colors
- Keep Read/Write toggle buttons in bottom bar for primary actions

## GeneratorActivity Expansion
- Expand form from ~8 fields to 50+ fields covering full OpenPrintTag spec:
  - UUIDs (instance, package, material, brand)
  - Brand-specific IDs (instance, package, material)
  - Write protection setting
  - Dates with Material DatePicker (manufactured, expiration)
  - Weights (nominal, actual, empty container)
  - 6 colors with color pickers (primary + 5 secondary)
  - Physical properties (diameter, density, nozzle, shore hardness, length)
  - All temperatures (print, bed, chamber min/max, preheat)
  - Container dimensions (width, outer/inner/hole diameter)
  - SLA properties (viscosity at 4 temps, cure wavelength, volume)
  - Certifications with multi-select dialog
- Implement material-class-aware field filtering:
  - FFF: shows filament, temperature, and spool dimension fields
  - SLA: shows viscosity, cure wavelength, container volume fields
  - SLS: shows temperature fields only
- Auto-populate all fields when loading cached tag data
- Organize fields into logical collapsible sections

## New Resources
- Drawables: ic_arrow_back, ic_calendar, ic_edit, ic_folder_open, ic_save,
  progress_usage, progress_usage_track
- Menu: menu_main.xml for toolbar actions
- Layouts: 8 item_*.xml layouts for RecyclerView display
- Strings: 60+ new strings for section headers, hints, labels

## Technical Improvements
- Full view binding usage in both activities
- Extracted reusable methods (launchGenerator, loadBinFile, saveBinFile)
- Proper coroutine usage for async operations
- Clean separation of UI logic with TagDisplayBuilder
@Und3rf10w Und3rf10w changed the title feat: MVP preparation - Vibecoded with Opus 4.5 feat: MVP - Vibecoded with Opus 4.5 Jan 5, 2026
Use snake_case field names to match the official OpenPrintTag
specification exactly, making it easier to cross-reference code
with spec documentation. No functional changes - purely cosmetic
renames across 8 files (~200 field references).

Key changes:
- brandName → brand_name
- materialType → material_type
- nominalNettoFullWeight → nominal_netto_full_weight
- minPrintTemp → min_print_temperature
- All UUID fields (instanceUuid → instance_uuid, etc.)
- All secondary color fields (secondaryColor0 → secondary_color_0)
- All SLA fields (viscosity25c → viscosity_25c)
- All container dimension fields
@DBNinja
Copy link
Owner

DBNinja commented Jan 6, 2026

It's okay.

@DBNinja DBNinja closed this Jan 6, 2026
@DBNinja DBNinja reopened this Jan 6, 2026
@DBNinja DBNinja merged commit 6f7a155 into main Jan 6, 2026
2 checks passed
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.

3 participants