Skip to content

Commit 8ce8bfc

Browse files
authored
Merge pull request #3 from hooshyar/agent/dot-finish/s1
feat: 1.1.0 prep: sizing, reduced motion, customDotSize, AI presets, green CI
2 parents cd9e146 + 1408c8c commit 8ce8bfc

21 files changed

Lines changed: 1303 additions & 265 deletions

‎.github/workflows/ci.yml‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,27 @@ on:
77
branches: [main]
88

99
jobs:
10+
portable-filenames:
11+
name: Windows-safe tracked file names
12+
runs-on: ubuntu-latest
13+
timeout-minutes: 5
14+
steps:
15+
- name: Checkout
16+
uses: actions/checkout@v4
17+
18+
- name: Fail on paths Windows cannot check out
19+
# A backlog file with `"` and `:` in its name made
20+
# `git pull` fail for every Windows user. Reject <>:"\|?* , a trailing
21+
# space or dot, and reserved device names in any tracked path.
22+
run: |
23+
bad="$(git -c core.quotepath=off ls-files | grep -E '[<>:"\\|?*]|[ .]$|(^|/)(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])(\.[^/]*)?(/|$)' || true)"
24+
if [ -n "$bad" ]; then
25+
echo "::error::Tracked paths that Windows cannot create:"
26+
echo "$bad"
27+
exit 1
28+
fi
29+
echo "All tracked paths are Windows-safe."
30+
1031
analyze-and-test:
1132
runs-on: ubuntu-latest
1233
steps:

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,4 @@ migrate_working_dir/
3333
# Claude Code local session state
3434
.claude/scheduled_tasks.lock
3535
.claude/settings.local.json
36+
.claude/agent-memory/

‎.pubignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
/SPECS.md
1010
/tool/
1111
/doc/
12+
/docs/
13+
/backlog/
14+
15+
# README hero GIFs are referenced by absolute raw.githubusercontent.com URLs.
16+
*.gif
1217

1318
# --- Mirror of .gitignore patterns we still want excluded from pub ---
1419
# (When .pubignore is present, it fully replaces .gitignore for archive

‎AGENTS.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ import 'package:flutter_dot_loader/flutter_dot_loader.dart';
4141
const DotLoader(color: Colors.blue)
4242
```
4343

44+
Pick a named state when the chat state is known: `DotLoader.typing()`,
45+
`DotLoader.thinking()`, `DotLoader.searching()`, `DotLoader.generating()`
46+
(each takes `color`, `size`/`width`/`height`, `paused`, `semanticsLabel`).
47+
The box is only as tall as the dots, so it sits inline next to text. All
48+
loaders honour the OS reduced-motion setting (`respectReducedMotion`, default
49+
true) and `MatrixLoader` accepts `customDotSize: (row, col) => scale` for
50+
per-dot sizing.
51+
4452
That's it. No size tuning, no opacity tuning, no animation knobs. Wrap in a
4553
`SizedBox` only if the parent layout needs a tighter bound.
4654

‎CHANGELOG.md‎

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,36 @@
1+
## 1.1.0
2+
3+
- feat: `width` and `height` on `MatrixLoader`, `DotLoader`, and
4+
`TriangleLoader`. `size` remains as the square shorthand and existing call
5+
sites render identically; each new parameter falls back to `size` when not
6+
set.
7+
- fix: auto dot spacing is now computed per axis, so grids with
8+
`rows > columns` (for example `columns: 1, rows: 5, size: 64`) no longer
9+
paint outside the widget's bounding box. Tap hit-testing shares the same
10+
geometry.
11+
- feat: `DotLoader` derives its box height from `rows` and `dotSize` when
12+
`height` is not given, so the default 3x1 indicator takes a
13+
text-height-friendly box instead of a 64x64 square. Pass `height` to
14+
restore an explicit box.
15+
- fix: `MatrixShape.triangle` no longer divides by zero on 1-row or 1-column
16+
grids (previously the mask produced NaN comparisons and rendered nothing).
17+
- feat: `respectReducedMotion` (default `true`) on `MatrixLoader`, `DotLoader`
18+
and `TriangleLoader`. When `MediaQuery.disableAnimationsOf` is true the
19+
ticker stops and one static frame is painted (the end frame for
20+
`MatrixPlayback.once`, which fires `onComplete` once). Reacts to runtime
21+
changes of the setting.
22+
- feat: `customDotSize: double Function(int row, int col)?` on `MatrixLoader`
23+
and `DotLoader` scales or hides individual dots (answers issue #1). Painting
24+
only; hit-testing and auto-spacing keep using `dotSize`.
25+
- feat: AI-state presets `DotLoader.typing()`, `.thinking()`, `.searching()`
26+
and `.generating()` with curated grids, patterns, durations and default
27+
semantics labels.
28+
- docs: CI badge, "Works great with" chat-bubble recipe, README alias count
29+
(16), hero GIFs referenced by absolute URL and excluded from the pub
30+
archive, pubspec boilerplate removed, dart format drift fixed (CI green again).
31+
- test: widget coverage for `rows > columns`, 1xN, Nx1, and 1-row triangle
32+
grids asserting painted bounds stay inside the widget.
33+
134
## 1.0.0
235

336
First stable release. The API surface (`MatrixLoader`, `DotLoader`,

‎README.md‎

Lines changed: 48 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# flutter_dot_loader
22

3+
[![CI](https://github.com/hooshyar/flutter_dot_loader/actions/workflows/ci.yml/badge.svg)](https://github.com/hooshyar/flutter_dot_loader/actions/workflows/ci.yml)
34
[![pub.dev](https://img.shields.io/pub/v/flutter_dot_loader.svg?style=flat-square&color=ff3333&label=pub.dev)](https://pub.dev/packages/flutter_dot_loader)
45
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square)](https://opensource.org/licenses/MIT)
56
[![Flutter](https://img.shields.io/badge/Flutter-%E2%9D%A4-02569B?style=flat-square&logo=flutter)](https://flutter.dev)
@@ -12,8 +13,8 @@ From a 3-dot "thinking…" indicator for AI chats to a 60-pattern LED matrix wit
1213
### ▶️ [Try the live demo](https://hooshyar.github.io/flutter_dot_loader/) — browse all 60 patterns, tweak every knob, and draw your own frames right in the browser.
1314

1415
<p align="center">
15-
<img src="assets/1.gif" width="48%" alt="Gallery of 60 dot-matrix loader patterns" />
16-
<img src="assets/2.gif" width="48%" alt="Interactive Dot Matrix Studio editor" />
16+
<img src="https://raw.githubusercontent.com/hooshyar/flutter_dot_loader/main/assets/1.gif" width="48%" alt="Gallery of 60 dot-matrix loader patterns" />
17+
<img src="https://raw.githubusercontent.com/hooshyar/flutter_dot_loader/main/assets/2.gif" width="48%" alt="Interactive Dot Matrix Studio editor" />
1718
</p>
1819

1920
---
@@ -23,7 +24,7 @@ From a 3-dot "thinking…" indicator for AI chats to a 60-pattern LED matrix wit
2324
| Feature | Description |
2425
|---|---|
2526
| 💬 **AI-chat "thinking" indicator** | One-liner `DotLoader(color: …)` for chat / AI apps — sensible defaults, `const`-constructable |
26-
| 🎨 **60 Built-in Patterns** | 20 Square, 20 Circular, and 20 Triangle math-driven animations + 13 semantic aliases (`vortexSpin`, `bullsEye`, `coreRipple`…) |
27+
| 🎨 **60 Built-in Patterns** | 20 Square, 20 Circular, and 20 Triangle math-driven animations + 16 semantic aliases (`vortexSpin`, `bullsEye`, `coreRipple`…) |
2728
| 🖥️ **LED Dot-Matrix Feel** | Three-tier opacity remapping for a realistic glowing LED display effect |
2829
| 🧩 **Custom Frames** | Drive every dot from your own data (`customIntensity`) — sprites, Tetris, scrolling text |
2930
| 📝 **Scrolling Marquee Text** | Built-in 5×7 font covers A–Z, 0–9, and 30+ punctuation/symbols (e.g. `"LOADING: 42%"`, `"a@b.com"`) |
@@ -67,7 +68,7 @@ Add to your `pubspec.yaml`:
6768

6869
```yaml
6970
dependencies:
70-
flutter_dot_loader: ^1.0.0
71+
flutter_dot_loader: ^1.1.0
7172
```
7273
7374
Or run:
@@ -95,7 +96,36 @@ const DotLoader(color: Colors.blue)
9596
```
9697

9798
3 dots, horizontal wave, 1.5s cycle. Inactive color is automatically derived
98-
from the supplied color at 10% alpha.
99+
from the supplied color at 10% alpha. The box is only as tall as the dots, so it
100+
sits inline next to text; pass `width`/`height` to change it.
101+
102+
Name the state instead of picking a pattern:
103+
104+
```dart
105+
const DotLoader.thinking(color: Colors.blue) // calm 3-dot ribbon
106+
const DotLoader.searching(color: Colors.blue) // 5-dot scanner sweep
107+
const DotLoader.generating(color: Colors.blue) // quick 5-dot wave
108+
const DotLoader.typing(color: Colors.blue) // classic 3-dot wave
109+
```
110+
111+
### Works great with
112+
113+
Drop a `DotLoader` into a chat bubble while a reply is on its way, then swap in
114+
streamed text from [`flutter_streaming_text_markdown`](https://pub.dev/packages/flutter_streaming_text_markdown)
115+
or a full chat screen from [`flutter_gen_ai_chat_ui`](https://pub.dev/packages/flutter_gen_ai_chat_ui):
116+
117+
```dart
118+
Container(
119+
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
120+
decoration: BoxDecoration(
121+
color: Theme.of(context).colorScheme.surfaceContainerHighest,
122+
borderRadius: BorderRadius.circular(16),
123+
),
124+
child: waitingForFirstToken
125+
? DotLoader.thinking(color: Theme.of(context).colorScheme.primary)
126+
: StreamingTextMarkdown.chatGPT(text: reply),
127+
)
128+
```
99129

100130
### 1. Drop-in Loader
101131

@@ -188,7 +218,9 @@ const DotLoader(
188218
)
189219
```
190220

191-
Available on `MatrixLoader`, `DotLoader`, and `TriangleLoader`; follows the same convention as Flutter's `ProgressIndicator.semanticsLabel`.
221+
Available on `MatrixLoader`, `DotLoader`, and `TriangleLoader`; follows the same convention as Flutter's `ProgressIndicator.semanticsLabel`. The `DotLoader.typing/thinking/searching/generating` presets ship with a default label.
222+
223+
**Reduced motion.** When the OS "reduce motion" setting is on (`MediaQuery.disableAnimations`), every loader stops its ticker and paints one static frame (the end frame for `MatrixPlayback.once`, which also fires `onComplete` right away). It reacts if the setting changes while the app runs. Opt out per widget with `respectReducedMotion: false`.
192224

193225
### 5. Pick from 60 Patterns
194226

@@ -341,14 +373,18 @@ The primary widget for dot-matrix loading animations.
341373
| `pattern` | `MatrixPattern` | `square1` | Animation pattern; use `custom` with `customIntensity` |
342374
| `activeColor` | `Color` | `Colors.white` | Color of lit/active dots |
343375
| `inactiveColor` | `Color` | `Color(0xFF27272A)` | Color of dim/inactive dots |
344-
| `size` | `double` | `64.0` | Width and height of the bounding box |
376+
| `size` | `double` | `64.0` | Square bounding-box shorthand; fallback for `width`/`height` |
377+
| `width` | `double?` | `null` | Bounding box width; falls back to `size` when `null` |
378+
| `height` | `double?` | `null` | Bounding box height; falls back to `size` when `null` (`DotLoader` derives it from `rows` instead) |
345379
| `dotSize` | `double` | `4.0` | Diameter of each dot in logical pixels |
346-
| `spacing` | `double?` | auto | Gap between dots; auto-calculated from `size` if `null` |
380+
| `spacing` | `double?` | auto | Gap between dots; auto-calculated per axis to fit the box if `null` |
347381
| `duration` | `Duration` | `1500ms` | Duration of one complete animation cycle |
348382
| `hoverAnimated` | `bool` | `true` | Enables hover ripple on web/desktop |
349383
| `opacityBase` | `double` | `0.08` | Minimum opacity for unlit dots |
350384
| `opacityMid` | `double` | `0.34` | Mid-point opacity for the LED glow curve |
351385
| `opacityPeak` | `double` | `0.94` | Maximum opacity for fully lit dots |
386+
| `customDotSize` | `double Function(int row, int col)?` | `null` | Per-dot size scale (1.0 = `dotSize`, 0 hides the dot). Painting only: tap hit-testing and auto-spacing keep using `dotSize` |
387+
| `respectReducedMotion` | `bool` | `true` | Stop animating and paint one static frame when the OS asks for reduced motion |
352388
| `customMask` | `bool Function(int row, int col)?` | `null` | Custom function to determine if a dot is rendered |
353389
| `customIntensity` | `double Function(int row, int col, double progress)?` | `null` | Custom function to drive dot intensity (use with `MatrixPattern.custom`) |
354390
| `semanticsLabel` | `String?` | `null` | Label announced by screen readers; `null` = decorative (no semantics node) |
@@ -387,7 +423,10 @@ A geometric loader using a tessellated grid of equilateral triangles.
387423
| Parameter | Type | Default | Description |
388424
|---|---|---|---|
389425
| `color` | `Color` | `Colors.indigoAccent` | Color of the triangles |
390-
| `size` | `double` | `200.0` | Width and height of the bounding box |
426+
| `size` | `double` | `200.0` | Square bounding-box shorthand; fallback for `width`/`height` |
427+
| `width` | `double?` | `null` | Bounding box width; falls back to `size` when `null` |
428+
| `height` | `double?` | `null` | Bounding box height; falls back to `size` when `null` |
429+
| `respectReducedMotion` | `bool` | `true` | Stop animating and paint one static frame when the OS asks for reduced motion |
391430
| `triangleSize` | `double` | `30.0` | Side length of each equilateral triangle |
392431
| `duration` | `Duration` | `4s` | Duration of one animation cycle |
393432
| `wireframe` | `bool` | `false` | If `true`, renders only triangle outlines |

‎analysis_options.yaml‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ analyzer:
1010
errors:
1111
deprecated_member_use: warning
1212
deprecated_member_use_from_same_package: warning
13+
exclude:
14+
- build/**
1315

1416
linter:
1517
rules:

‎backlog/tasks/task-001 - Fix red CI on main (dart format drift).md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: TASK-001
33
title: Fix red CI on main (dart format drift)
4-
status: To Do
4+
status: Done
55
priority: high
66
labels: [improvement-plan-2026-09]
77
created_date: '2026-09-24'
@@ -19,3 +19,7 @@ Acceptance criteria:
1919
- [ ] Ship as 1.0.1
2020

2121
See docs/IMPROVEMENT-PLAN-2026-09.md (P0-1, B1, B5, B6).
22+
23+
## Final Summary
24+
25+
Formatting fixed with the resolved package config, CI badge and README alias count (16) added, pubspec boilerplate removed. Included in 1.1.0 rather than a separate 1.0.1.

‎backlog/tasks/task-002 - Honor reduced motion (MediaQuery.disableAnimations).md‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: TASK-002
33
title: Honor reduced motion (MediaQuery.disableAnimations)
4-
status: To Do
4+
status: Done
55
priority: high
66
labels: [improvement-plan-2026-09]
77
created_date: '2026-09-24'
@@ -18,3 +18,7 @@ Acceptance criteria:
1818
- [ ] Widget tests for on/off; README a11y row + CHANGELOG updated
1919

2020
See docs/IMPROVEMENT-PLAN-2026-09.md (P0-2).
21+
22+
## Final Summary
23+
24+
`respectReducedMotion` (default true) on MatrixLoader, DotLoader and TriangleLoader with runtime reaction and tests. Ships in 1.1.0.

backlog/tasks/task-003 - Non-square sizing and fix grid overflow when rows > columns.md renamed to backlog/tasks/task-003 - non-square-sizing-and-grid-overflow.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
id: TASK-003
33
title: Non-square sizing and fix grid overflow when rows > columns
4-
status: To Do
4+
status: Done
55
priority: high
66
labels: [improvement-plan-2026-09]
77
created_date: '2026-09-24'
@@ -20,3 +20,7 @@ Acceptance criteria:
2020
- [ ] Ship in 1.1.0
2121

2222
See docs/IMPROVEMENT-PLAN-2026-09.md (P0-3, B2, B3).
23+
24+
## Final Summary
25+
26+
`width`/`height` with `size` shorthand, per-axis spacing, shared tap geometry, inline DotLoader box (default 64x4), triangle mask fix, tests. Ships in 1.1.0.

0 commit comments

Comments
 (0)