Skip to content

doc: added changelog

d4744bd
Select commit
Loading
Failed to load commit list.
Sign in for the full log view
Merged

doc: added changelog #139

doc: added changelog
d4744bd
Select commit
Loading
Failed to load commit list.
GitHub Actions / Unit Tests succeeded May 15, 2026 in 0s

411 passed, 0 failed and 0 skipped

Tests passed successfully

✅ test-results.json

411 tests were completed in 76s with 411 passed, 0 failed and 0 skipped.

Test suite Passed Failed Skipped Time
test/alerts_test.dart 3✅ 704ms
test/color_test.dart 32✅ 92ms
test/colorblind_filter_test.dart 38✅ 96ms
test/datetime_extension_test.dart 3✅ 34ms
test/datetime_test.dart 26✅ 85ms
test/duration_test.dart 12✅ 43ms
test/file_utilities_test.dart 25✅ 102ms
test/grid_test.dart 7✅ 37ms
test/helpers_test.dart 14✅ 82ms
test/orm_test.dart 21✅ 64ms
test/password_input_test.dart 7✅ 1s
test/separator_extension_test.dart 24✅ 67ms
test/table_controller_test.dart 9✅ 48ms
test/theme_color_test.dart 26✅ 77ms
test/widgets/alerts_test.dart 3✅ 720ms
test/widgets/avatar_test.dart 18✅ 1s
test/widgets/button_test.dart 7✅ 953ms
test/widgets/chip_test.dart 2✅ 650ms
test/widgets/color_picker_test.dart 12✅ 2s
test/widgets/field_error_test.dart 8✅ 642ms
test/widgets/layo_test.dart 3✅ 709ms
test/widgets/number_input_test.dart 31✅ 2s
test/widgets/responsive_row_test.dart 38✅ 1s
test/widgets/table2_test.dart 21✅ 22s
test/widgets/tabs_test.dart 21✅ 2s

✅ test/alerts_test.dart

ThemedAlert widget
  ✅ renders info alert
  ✅ renders success alert
  ✅ renders custom alert with icon and color

✅ test/color_test.dart

toHex()
  ✅ converts black to #000000
  ✅ converts white to #FFFFFF
  ✅ converts kAccentColor (#FF8200)
  ✅ converts kPrimaryColor (#001e60)
  ✅ outputs uppercase hex
  ✅ ignores alpha channel
  ✅ hex getter is alias for toHex()
toHexWithAlpha()
  ✅ includes full alpha (#FFFFFFFF for white)
  ✅ includes zero alpha (#00000000 for transparent)
  ✅ includes partial alpha (#80FF8200)
  ✅ alpha comes first in AARRGGBB format
  ✅ hexWithAlpha getter is alias for toHexWithAlpha()
toInt()
  ✅ converts to ARGB integer
  ✅ handles alpha channel correctly
  ✅ black is 0xFF000000
  ✅ white is 0xFFFFFFFF
  ✅ transparent is 0x00000000
fromHex()
  ✅ parses black #000000
  ✅ parses white #FFFFFF
  ✅ parses accent color #FF8200
  ✅ parses primary color #001E60
  ✅ parses lowercase hex #ff8200
  ✅ sets alpha to 255 (fully opaque)
fromHexWithAlpha()
  ✅ parses full alpha #FFFFFFFF
  ✅ parses zero alpha #00000000
  ✅ parses partial alpha #80FF8200
  ✅ parses alpha first in AARRGGBB format
Round-trip conversions
  ✅ Color -> toHex() -> fromHex() -> Color preserves RGB
  ✅ Color -> toHexWithAlpha() -> fromHexWithAlpha() -> Color preserves ARGB
  ✅ Color -> toInt() -> Color() preserves exact value
JSON aliases
  ✅ toJson() is equivalent to toHex()
  ✅ fromJson() is equivalent to fromHex()

✅ test/colorblind_filter_test.dart

protanopiaFilter()
  ✅ strength 0.0 returns identity matrix
  ✅ strength 1.0 returns full filter matrix
  ✅ strength 0.5 returns interpolated matrix
  ✅ has exactly 20 elements
  ✅ handles boundary strength values
protanomalyFilter()
  ✅ strength 0.0 returns identity matrix
  ✅ strength 1.0 returns full filter matrix
  ✅ strength 0.5 returns interpolated matrix
  ✅ has exactly 20 elements
deuteranopiaFilter()
  ✅ strength 0.0 returns identity matrix
  ✅ strength 1.0 returns full filter matrix
  ✅ strength 0.5 returns interpolated matrix
  ✅ has exactly 20 elements
deuteranomalyFilter()
  ✅ strength 0.0 returns identity matrix
  ✅ strength 1.0 returns full filter matrix
  ✅ strength 0.5 returns interpolated matrix
  ✅ has exactly 20 elements
tritanopiaFilter()
  ✅ strength 0.0 returns identity matrix
  ✅ strength 1.0 returns full filter matrix
  ✅ strength 0.5 returns interpolated matrix
  ✅ has exactly 20 elements
tritanomalyFilter()
  ✅ strength 0.0 returns identity matrix
  ✅ strength 1.0 returns full filter matrix
  ✅ strength 0.5 returns interpolated matrix
  ✅ has exactly 20 elements
ColorblindFilter extension
  ✅ normal mode returns identity matrix
  ✅ protanopia mode creates ColorFilter from protanopia matrix
  ✅ protanomaly mode creates ColorFilter from protanomaly matrix
  ✅ deuteranopia mode creates ColorFilter from deuteranopia matrix
  ✅ deuteranomaly mode creates ColorFilter from deuteranomaly matrix
  ✅ tritanopia mode creates ColorFilter from tritanopia matrix
  ✅ tritanomaly mode creates ColorFilter from tritanomaly matrix
  ✅ all modes accept strength parameter
Matrix interpolation behavior
  ✅ increasing strength gradually changes matrix values
  ✅ all filters preserve alpha channel (elements 15-19)
Edge cases
  ✅ negative strength handled (treated as 0 or clamped)
  ✅ strength > 1.0 handled (extrapolates or clamped)
  ✅ all filters produce distinct matrices at full strength

✅ test/datetime_extension_test.dart

DateTimeExtension
  ✅ secondsSinceEpoch returns correct value
  ✅ thisWeek and lastWeek return correct dates
  ✅ thisMonth and lastMonth return correct dates

✅ test/datetime_test.dart

thisWeek / lastWeek
  ✅ returns correct week boundaries
  ✅ handles Monday correctly
  ✅ handles Sunday correctly
thisMonth / lastMonth
  ✅ returns correct month boundaries for August
  ✅ returns correct lastMonth boundaries
  ✅ handles February in leap year
  ✅ handles February in non-leap year
  ✅ handles January lastMonth wraps to previous year
secondsSinceEpoch
  ✅ converts milliseconds to seconds
  ✅ handles epoch zero
format
  ✅ %Y full year
  ✅ %y two-digit year
  ✅ %m zero-padded month
  ✅ %d zero-padded day
  ✅ %H 24-hour format
  ✅ %I 12-hour format
  ✅ %p AM/PM indicator
  ✅ %M zero-padded minute
  ✅ %S zero-padded second
  ✅ %A full weekday name
  ✅ %a abbreviated weekday name
  ✅ %B full month name
  ✅ %b abbreviated month name
  ✅ %% literal percent
  ✅ combined pattern
  ✅ %I shows 12 for noon/midnight

✅ test/duration_test.dart

Duration.humanize
  ✅ single unit
  ✅ singular unit
  ✅ two units joined with conjunction
  ✅ three units with delimiter and conjunction
  ✅ zero duration returns smallest unit with 0
  ✅ negative duration uses absolute value
  ✅ filters out zero-value units
  ✅ lastPrefixComma adds comma before conjunction
  ✅ custom delimiter
  ✅ custom units subset
  ✅ zero duration with seconds in units
  ✅ large duration includes days and months

✅ test/file_utilities_test.dart

ThemedFile
  ✅ creates file with name and bytes
  ✅ creates file with optional path
  ✅ toString() includes name and size
ThemedFile.mimeType
  ✅ detects PNG image
  ✅ detects JPG image
  ✅ detects JPEG image
  ✅ detects GIF image
  ✅ detects SVG image
  ✅ detects PDF document
  ✅ detects custom .lc extension
  ✅ uses path over name when both provided
  ✅ handles unknown extension
  ✅ case insensitive extension detection
parseFileToBase64()
  ✅ converts bytes to base64
  ✅ includes file name in result
  ✅ includes mime type in result
  ✅ returns null when mime type cannot be determined
  ✅ handles empty file
  ✅ round-trip base64 encoding/decoding
parseFileToByteArray()
  ✅ returns file bytes as List<int>
  ✅ handles empty file
  ✅ preserves byte values
  ✅ returns a copy (new list)
globalMimeResolver
  ✅ includes custom .lc extension
  ✅ still supports standard extensions

✅ test/grid_test.dart

Sizes.gridSize
  ✅ each enum returns correct column count
Sizes.boxWidth
  ✅ col12 returns full width
  ✅ col6 returns half width
  ✅ col4 returns one-third width
  ✅ col3 returns one-quarter width
  ✅ col1 returns 1/12 of width
  ✅ formula is (width / 12) * gridSize

✅ test/helpers_test.dart

useBlack
  ✅ returns true for white (high luminance)
  ✅ returns false for black (low luminance)
  ✅ returns true for yellow (high luminance)
  ✅ returns false for dark blue (low luminance)
  ✅ respects custom tolerance
validateColor
  ✅ returns black for light colors
  ✅ returns white for dark colors
getPrimaryColor
  ✅ returns kPrimaryColor when null
  ✅ returns provided color when non-null
getAccentColor
  ✅ returns kAccentColor when null
  ✅ returns provided color when non-null
generateSwatch
  ✅ without shader all shades are the same color
  ✅ with shader shades have increasing alpha
  ✅ swatch has all 10 shade levels

✅ test/orm_test.dart

setErrors() and getErrors()
  ✅ stores and retrieves errors correctly
  ✅ retrieves empty list for non-existent key
  ✅ handles multiple errors for same key
  ✅ replaces existing errors when setErrors called again
hasErrors()
  ✅ returns true when key has errors
  ✅ returns false when key has no errors
  ✅ returns false for non-existent key
hasContainerErrors()
  ✅ returns true when any key starts with prefix
  ✅ returns false when no keys match prefix
  ✅ exact match works as prefix
  ✅ returns false when errors map is empty
Error code handling without i18n
  ✅ returns error code as fallback when no i18n set
  ✅ minLength error includes parameters in fallback
  ✅ maxLength error includes parameters in fallback
  ✅ minLength with multiple parameters in fallback
Multiple error codes
  ✅ handles mix of standard and length errors
Raw errors access
  ✅ rawErrors returns the internal error map
  ✅ rawErrors is empty after setting empty map
Edge cases
  ✅ handles empty error list for key
  ✅ handles error with empty code
  ✅ handles special characters in error keys

✅ test/password_input_test.dart

ThemedPasswordInput
  ✅ renders with label
  ✅ toggles password visibility on eye icon tap
  ✅ shows shield check icon for valid password
  ✅ shows close circle icon for invalid password
  ✅ shows close circle icon for empty password
  ✅ hides strength indicator when showLevels is false
  ✅ calls onChanged when text is entered

✅ test/separator_extension_test.dart

num.w (width)
  ✅ creates SizedBox with width
  ✅ handles integer values
  ✅ handles double values
  ✅ handles zero
  ✅ width alias is equivalent to w
num.h (height)
  ✅ creates SizedBox with height
  ✅ handles integer values
  ✅ handles double values
  ✅ handles zero
  ✅ height alias is equivalent to h
num.wh (square)
  ✅ creates SizedBox with equal width and height
  ✅ handles integer values
  ✅ handles double values
  ✅ handles zero
  ✅ square alias is equivalent to wh
Different num types
  ✅ works with int
  ✅ works with double
  ✅ works with num variable
Edge cases
  ✅ handles very small values
  ✅ handles very large values
  ✅ handles negative values (though unusual in UI)
Common usage patterns
  ✅ can be used for spacing between widgets
  ✅ can create responsive spacing
  ✅ can create square placeholders

✅ test/table_controller_test.dart

ThemedTable2Controller
  ✅ addListener adds listener to list
  ✅ removeListener removes specific listener
  ✅ clearListeners removes all listeners
  ✅ sort triggers ThemedTable2SortEvent with correct parameters
  ✅ sort with default parameters
  ✅ refresh triggers ThemedTable2RefreshEvent
  ✅ multiple listeners all receive events
  ✅ dispose clears all listeners
  ✅ events fire in order listeners were added

✅ test/theme_color_test.dart

getThemeColor() - Predefined themes
  ✅ PINK returns Colors.pink
  ✅ RED returns Colors.red
  ✅ DEEPORANGE returns Colors.deepOrange
  ✅ ORANGE returns Colors.orange
  ✅ AMBER returns Colors.amber
  ✅ YELLOW returns Colors.yellow
  ✅ LIME returns Colors.lime
  ✅ LIGHTGREEN returns Colors.lightGreen
  ✅ GREEN returns Colors.green
  ✅ TEAL returns Colors.teal
  ✅ CYAN returns Colors.cyan
  ✅ LIGHTBLUE returns Colors.lightBlue
  ✅ BLUE returns Colors.blue
  ✅ INDIGO returns Colors.indigo
  ✅ DEEPBLUE returns Colors.deepPurple
  ✅ PURPLE returns Colors.purple
  ✅ BLUEGREY returns Colors.blueGrey
  ✅ GREY returns Colors.grey
  ✅ BROWN returns Colors.brown
getThemeColor() - CUSTOM theme
  ✅ CUSTOM with provided color generates swatch from that color
  ✅ CUSTOM without explicit color uses kPrimaryColor
getThemeColor() - Invalid/default handling
  ✅ Invalid theme returns swatch from kPrimaryColor
  ✅ Empty string theme returns swatch from kPrimaryColor
  ✅ Lowercase theme name does not match (case-sensitive)
getThemeColor() - Return type validation
  ✅ All valid themes return MaterialColor type
  ✅ MaterialColor has all required shades (50-900)

✅ test/widgets/alerts_test.dart

ThemedAlert widget
  ✅ renders info alert
  ✅ renders success alert
  ✅ renders custom alert with icon and color

✅ test/widgets/avatar_test.dart

ThemedAvatar - Basic rendering
  ✅ renders with default size
  ✅ renders with custom size
  ✅ renders fallback initials when no avatar provided
  ✅ renders NA when name is null
ThemedAvatar - Icon rendering
  ✅ renders icon when provided
  ✅ icon size is 70% of avatar size by default
  ✅ respects custom icon size
ThemedAvatar - Name cleaning
  ✅ cleans special characters from name
  ✅ handles single character name
  ✅ returns NA for name with only special characters
  ✅ takes first 2 characters and uppercases
ThemedAvatar - Tap handlers
  ✅ calls onTap when tapped
  ✅ calls onLongTap when long pressed
  ✅ calls onSecondaryTap when secondary tapped
ThemedAvatar - Elevation and styling
  ✅ applies custom color
  ✅ elevation must be between 0 and 5
  ✅ radius must be greater than or equal to 0
ThemedAvatar - Priority order
  ✅ icon takes priority over name fallback

✅ test/widgets/button_test.dart

ThemedButton widget
  ✅ renders with labelText
  ✅ renders with icon
  ✅ renders as disabled
  ✅ renders loading state
  ✅ renders with custom color
  ✅ renders with different styles
  ✅ renders with factory constructors

✅ test/widgets/chip_test.dart

ThemedChip widget
  ✅ renders with label
  ✅ renders with custom color

✅ test/widgets/color_picker_test.dart

ThemedColorPicker rendering
  ✅ renders without crashing
  ✅ shows label text
  ✅ shows hex value in text field
  ✅ shows kPrimaryColor hex when value is null
  ✅ shows color swatch in prefix
ThemedColorPicker disabled
  ✅ disabled picker does not open dialog on tap
  ✅ enabled picker opens dialog on tap
ThemedColorPicker lifecycle
  ✅ mounts and unmounts without errors
  ✅ repeated mount/unmount cycles do not throw
  ✅ didUpdateWidget updates text field when value changes externally
  ✅ didUpdateWidget resets to kPrimaryColor when value changes to null
  ✅ didUpdateWidget does not rebuild when same value is passed

✅ test/widgets/field_error_test.dart

ThemedFieldDisplayError
  ✅ displays single error message
  ✅ displays multiple errors joined by comma
  ✅ hides errors when hideDetails is true
  ✅ shows nothing when errors list is empty
  ✅ applies custom padding
  ✅ applies maxLines constraint
  ✅ error text is red
  ✅ default maxLines is 1

✅ test/widgets/layo_test.dart

Layo widget
  ✅ throws assertion error for invalid elevation
  ✅ renders with default values
  ✅ renders with custom emotion

✅ test/widgets/number_input_test.dart

ThemedNumberInput rendering
  ✅ renders without crashing
  ✅ shows label text
  ✅ shows initial value formatted in the text field
  ✅ shows empty field when value is null
  ✅ shows suffixText when provided
  ✅ shows prefixText when provided
  ✅ shows required asterisk when isRequired is true
  ✅ shows error text when errors list is non-empty
  ✅ hides error space when hideDetails is true
ThemedNumberInput onChanged via keyboard
  ✅ calls onChanged with parsed num when user types a number
  ✅ calls onChanged(null) when user clears the field
  ✅ does NOT call onChanged when user types only a minus sign
  ✅ does NOT call onChanged when input cannot be parsed (C3 regression)
  ✅ calls onChanged with negative number
ThemedNumberInput step buttons
  ✅ increment button increases value by step
  ✅ decrement button decreases value by step
  ✅ step defaults to 1 when not provided
  ✅ value starts at 0 when null and step button is tapped
  ✅ increment is disabled at maximum — does not call onChanged
  ✅ decrement is disabled at minimum — does not call onChanged
  ✅ step buttons are hidden when hidePrefixSuffixActions is true
  ✅ step buttons are hidden when disabled is true
ThemedNumberInput cursor position after step
  ✅ cursor is at end after incrementing from 9 to 10 (digit count changes)
  ✅ cursor is at end after incrementing from 99 to 100
  ✅ cursor is at end after decrementing from 10 to 9 (digit count shrinks)
  ✅ cursor is at end after incrementing into thousands (999 to 1,000)
ThemedNumberInput decimal separators
  ✅ dot separator formats 1234.5 as "1,234.5"
  ✅ comma separator formats 1234.5 as "1.234,5"
ThemedNumberInput lifecycle
  ✅ widget mounts and unmounts without errors
  ✅ repeated mount/unmount cycles do not throw
  ✅ controller text clears when value changes to null

✅ test/widgets/responsive_row_test.dart

ResponsiveRow
  ✅ Renders basic ResponsiveRow with children
  ✅ ResponsiveRow with empty children renders empty Wrap
  ✅ ResponsiveRow with single child
  ✅ ResponsiveRow respects spacing parameter
  ✅ ResponsiveRow respects spacing = 0
  ✅ ResponsiveRow default spacing is 0
  ✅ ResponsiveRow spacing applies to Wrap.runSpacing
  ✅ ResponsiveRow default spacing gives runSpacing of 0
  ✅ ResponsiveRow respects mainAxisAlignment
  ✅ ResponsiveRow respects crossAxisAlignment
  ✅ ResponsiveRow has full width (width: double.infinity)
  ✅ ResponsiveRow.builder creates correct number of children
  ✅ ResponsiveRow.builder with itemCount=0
  ✅ ResponsiveRow.builder respects mainAxisAlignment
  ✅ ResponsiveRow.builder respects spacing
  ✅ ResponsiveRow uses Wrap as layout widget
  ✅ ResponsiveRow.builder with large itemCount
ResponsiveCol
  ✅ ResponsiveCol renders child
  ✅ ResponsiveCol uses xs by default
  ✅ ResponsiveCol falls back to xs if sm is null
  ✅ ResponsiveCol with all breakpoints specified
  ✅ ResponsiveCol uses LayoutBuilder for responsive sizing
  ✅ ResponsiveCol preserves child widget type
  ✅ ResponsiveCol with different size values
Sizes enum
  ✅ Sizes.col1 returns gridSize 1
  ✅ Sizes.col6 returns gridSize 6
  ✅ Sizes.col12 returns gridSize 12
  ✅ boxWidth calculates correct width for col6 at 1200px
  ✅ boxWidth calculates correct width for col12 at 1200px
  ✅ boxWidth calculates correct width for col3 at 600px
  ✅ boxWidth calculates correct width for col1 at 1200px
  ✅ boxWidth with col2 at 1200px equals 200
  ✅ boxWidth with col4 at 800px equals 266.67
  ✅ All sizes have valid gridSize
ResponsiveRow and ResponsiveCol integration
  ✅ ResponsiveRow with multiple ResponsiveCol children renders correctly
  ✅ ResponsiveRow with many children
  ✅ ResponsiveRow.builder with all parameters
  ✅ ResponsiveCol with ResponsiveRow preserves layout structure

✅ test/widgets/table2_test.dart

ThemedTable2 rendering
  ✅ renders item values after compute completes
  ✅ shows CircularProgressIndicator while loading
  ✅ renders without errors when items is empty
ThemedTable2 column key collision regression
  ✅ two columns with identical headerText show distinct data
ThemedTable2 search
  ✅ filters items matching the query
  ✅ search matches values from all columns
  ✅ shows all items when search is cleared
ThemedTable2 sort
  ✅ controller.sort ascending orders items A→Z
  ✅ controller.sort descending orders items Z→A
  ✅ numeric values sort as numbers not as strings
  ✅ controller.refresh re-runs sort without changing order
ThemedTable2 didUpdateWidget
  ✅ reflects new items when widget rebuilds with a different list
  ✅ handles growing list without losing existing rows
  ✅ detects edit in middle of same-length list (DeepCollectionEquality regression)
ThemedTable2 onFilteredCountChanged
  ✅ fires with full count on initial load
  ✅ null callback does not throw
  ✅ fires with 0 on empty items list
  ✅ fires filtered count after search narrows results
  ✅ fires updated count when items list grows via didUpdateWidget
  ✅ fires with same count after controller.sort
  ✅ does not fire after widget is disposed

✅ test/widgets/tabs_test.dart

ThemedTabView widget
  ✅ renders with multiple tabs
  ✅ displays initial tab content
  ✅ switches tabs on tap
  ✅ calls onTabIndex callback when tab changes
  ✅ renders arrow buttons when showArrows is true
  ✅ arrow buttons exist and are functional
  ✅ left arrow is disabled on first tab
  ✅ right arrow is disabled on last tab
  ✅ handles initialPosition correctly
  ✅ clamps invalid initialPosition to valid range
  ✅ persists tab position on widget rebuild
  ✅ resets tab position when tabs list changes and persistTabPosition is false
  ✅ renders additionalWidgets
  ✅ renders with different tab styles
  ✅ ThemedTab renders with leading icon
  ✅ ThemedTab renders with trailing icon
  ✅ renders with custom padding and alignment
  ✅ arrow button state updates when navigating between tabs (bug regression)
  ✅ wrapArrowNavigation wraps from last tab to first tab
  ✅ wrapArrowNavigation wraps from first tab to last tab
  ✅ wrapArrowNavigation keeps arrows enabled at boundaries