Skip to content

Commit 467bea3

Browse files
committed
Extract long code examples to separate .dart files
- Create progress_factory_variants.dart for async factory examples - Create progress_undoable.dart for undoable command example - Create progress_dio_integration.dart for Dio cancellation example - Update progress_control.md to use VitePress includes - Keep short API usage snippets inline (3 lines or less) - All extracted examples verified to compile
1 parent 8b55c8f commit 467bea3

File tree

4 files changed

+193
-112
lines changed

4 files changed

+193
-112
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import 'dart:io';
2+
import 'package:command_it/command_it.dart';
3+
4+
// Mock Dio classes for compilation
5+
class Dio {
6+
Future<dynamic> download(
7+
String url,
8+
String path, {
9+
CancelToken? cancelToken,
10+
void Function(int, int)? onReceiveProgress,
11+
}) async {
12+
// Simulate download
13+
if (onReceiveProgress != null) {
14+
for (int i = 0; i <= 100; i += 10) {
15+
await Future.delayed(Duration(milliseconds: 50));
16+
onReceiveProgress(i * 1024 * 1024, 100 * 1024 * 1024);
17+
}
18+
}
19+
return null;
20+
}
21+
}
22+
23+
class CancelToken {
24+
void cancel([String? reason]) {}
25+
static bool isCancel(Exception e) => false;
26+
}
27+
28+
class DioException implements Exception {
29+
DioException();
30+
}
31+
32+
// #region example
33+
final downloadCommand = Command.createAsyncWithProgress<String, File>(
34+
(url, handle) async {
35+
final dio = Dio();
36+
final cancelToken = CancelToken();
37+
38+
// Forward command cancellation to Dio
39+
handle.isCanceled.listen((canceled, _) {
40+
if (canceled) cancelToken.cancel('User canceled');
41+
});
42+
43+
try {
44+
final response = await dio.download(
45+
url,
46+
'/downloads/file.zip',
47+
cancelToken: cancelToken,
48+
onReceiveProgress: (received, total) {
49+
if (total != -1) {
50+
handle.updateProgress(received / total);
51+
handle.updateStatusMessage(
52+
'Downloaded ${(received / 1024 / 1024).toStringAsFixed(1)} MB '
53+
'of ${(total / 1024 / 1024).toStringAsFixed(1)} MB',
54+
);
55+
}
56+
},
57+
);
58+
return File('/downloads/file.zip');
59+
} on DioException catch (e) {
60+
if (CancelToken.isCancel(e)) {
61+
return File(''); // Handle cancellation
62+
}
63+
rethrow;
64+
}
65+
},
66+
initialValue: File(''),
67+
);
68+
// #endregion example
69+
70+
void main() {
71+
// Example usage
72+
downloadCommand.run('https://example.com/file.zip');
73+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import 'package:command_it/command_it.dart';
2+
import '_shared/stubs.dart';
3+
4+
// #region example
5+
// Full signature: parameter + result
6+
final processCommand = Command.createAsyncWithProgress<int, String>(
7+
(count, handle) async {
8+
for (int i = 0; i < count; i++) {
9+
if (handle.isCanceled.value) return 'Canceled';
10+
11+
await processItem(Item());
12+
handle.updateProgress((i + 1) / count);
13+
handle.updateStatusMessage('Processing item ${i + 1} of $count');
14+
}
15+
return 'Processed $count items';
16+
},
17+
initialValue: '',
18+
);
19+
20+
// No parameter
21+
final syncCommand = Command.createAsyncNoParamWithProgress<String>(
22+
(handle) async {
23+
handle.updateStatusMessage('Syncing...');
24+
handle.updateProgress(0.5);
25+
await simulateDelay(100);
26+
handle.updateProgress(1.0);
27+
return 'Synced';
28+
},
29+
initialValue: '',
30+
);
31+
32+
// No result (void)
33+
final deleteCommand = Command.createAsyncNoResultWithProgress<int>(
34+
(itemId, handle) async {
35+
handle.updateStatusMessage('Deleting item $itemId...');
36+
await simulateDelay(100);
37+
handle.updateProgress(1.0);
38+
},
39+
);
40+
41+
// No parameter, no result
42+
final refreshCommand = Command.createAsyncNoParamNoResultWithProgress(
43+
(handle) async {
44+
handle.updateStatusMessage('Refreshing...');
45+
await simulateDelay(100);
46+
handle.updateProgress(1.0);
47+
},
48+
);
49+
// #endregion example
50+
51+
void main() {
52+
// Example usage
53+
processCommand.run(5);
54+
syncCommand.run();
55+
deleteCommand.run(123);
56+
refreshCommand.run();
57+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import 'dart:io';
2+
import 'package:command_it/command_it.dart';
3+
import '_shared/stubs.dart';
4+
5+
class UploadState {
6+
final String uploadId;
7+
UploadState(this.uploadId);
8+
}
9+
10+
// Mock API methods
11+
Future<String> startUpload(File file) async {
12+
await simulateDelay(50);
13+
return 'upload_123';
14+
}
15+
16+
Future<void> cancelUpload(String uploadId) async {
17+
await simulateDelay(50);
18+
}
19+
20+
Future<void> deleteUpload(String uploadId) async {
21+
await simulateDelay(50);
22+
}
23+
24+
int calculateChunks(File file) => 10;
25+
26+
// #region example
27+
final uploadCommand =
28+
Command.createUndoableWithProgress<File, String, UploadState>(
29+
(file, handle, undoStack) async {
30+
handle.updateStatusMessage('Starting upload...');
31+
final uploadId = await startUpload(file);
32+
undoStack.push(UploadState(uploadId));
33+
34+
final chunks = calculateChunks(file);
35+
for (int i = 0; i < chunks; i++) {
36+
if (handle.isCanceled.value) {
37+
await cancelUpload(uploadId);
38+
return 'Canceled';
39+
}
40+
41+
await uploadChunk(file, i);
42+
handle.updateProgress((i + 1) / chunks);
43+
handle.updateStatusMessage('Uploaded ${i + 1}/$chunks chunks');
44+
}
45+
46+
return 'Upload complete';
47+
},
48+
undo: (undoStack, reason) async {
49+
final state = undoStack.pop();
50+
await deleteUpload(state.uploadId);
51+
return 'Upload deleted';
52+
},
53+
initialValue: '',
54+
);
55+
// #endregion example
56+
57+
void main() {
58+
// Example usage
59+
uploadCommand.run(File('example.txt'));
60+
}

docs/documentation/command_it/progress_control.md

Lines changed: 3 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -43,86 +43,13 @@ Use the `WithProgress` factory variants to create commands that receive a `Progr
4343

4444
### Async Commands with Progress
4545

46-
```dart
47-
// Full signature: parameter + result
48-
final processCommand = Command.createAsyncWithProgress<int, String>(
49-
(count, handle) async {
50-
for (int i = 0; i < count; i++) {
51-
if (handle.isCanceled.value) return 'Canceled';
52-
53-
await processItem(i);
54-
handle.updateProgress((i + 1) / count);
55-
handle.updateStatusMessage('Processing item ${i + 1} of $count');
56-
}
57-
return 'Processed $count items';
58-
},
59-
initialValue: '',
60-
);
61-
62-
// No parameter
63-
final syncCommand = Command.createAsyncNoParamWithProgress<String>(
64-
(handle) async {
65-
handle.updateStatusMessage('Syncing...');
66-
handle.updateProgress(0.5);
67-
await syncData();
68-
handle.updateProgress(1.0);
69-
return 'Synced';
70-
},
71-
initialValue: '',
72-
);
73-
74-
// No result (void)
75-
final deleteCommand = Command.createAsyncNoResultWithProgress<int>(
76-
(itemId, handle) async {
77-
handle.updateStatusMessage('Deleting item $itemId...');
78-
await api.delete(itemId);
79-
handle.updateProgress(1.0);
80-
},
81-
);
82-
83-
// No parameter, no result
84-
final refreshCommand = Command.createAsyncNoParamNoResultWithProgress(
85-
(handle) async {
86-
handle.updateStatusMessage('Refreshing...');
87-
await api.refresh();
88-
handle.updateProgress(1.0);
89-
},
90-
);
91-
```
46+
<<< @/../code_samples/lib/command_it/progress_factory_variants.dart#example
9247

9348
### Undoable Commands with Progress
9449

9550
Combine undo capability with progress tracking:
9651

97-
```dart
98-
final uploadCommand = Command.createUndoableWithProgress<File, String, UploadState>(
99-
(file, handle, undoStack) async {
100-
handle.updateStatusMessage('Starting upload...');
101-
final uploadId = await api.startUpload(file);
102-
undoStack.push(UploadState(uploadId));
103-
104-
final chunks = calculateChunks(file);
105-
for (int i = 0; i < chunks; i++) {
106-
if (handle.isCanceled.value) {
107-
await api.cancelUpload(uploadId);
108-
return 'Canceled';
109-
}
110-
111-
await uploadChunk(file, i);
112-
handle.updateProgress((i + 1) / chunks);
113-
handle.updateStatusMessage('Uploaded ${i + 1}/$chunks chunks');
114-
}
115-
116-
return 'Upload complete';
117-
},
118-
undo: (undoStack, reason) async {
119-
final state = undoStack.pop();
120-
await api.deleteUpload(state.uploadId);
121-
return 'Upload deleted';
122-
},
123-
initialValue: '',
124-
);
125-
```
52+
<<< @/../code_samples/lib/command_it/progress_undoable.dart#example
12653

12754
All four undoable variants are available:
12855
- `createUndoableWithProgress<TParam, TResult, TUndoState>()`
@@ -280,43 +207,7 @@ Text('${(progress * 100).toInt()}% complete')
280207

281208
The `isCanceled` property is a `ValueListenable`, allowing you to forward cancellation to external libraries like Dio:
282209

283-
```dart
284-
final downloadCommand = Command.createAsyncWithProgress<String, File>(
285-
(url, handle) async {
286-
final dio = Dio();
287-
final cancelToken = CancelToken();
288-
289-
// Forward command cancellation to Dio
290-
handle.isCanceled.listen((canceled, _) {
291-
if (canceled) cancelToken.cancel('User canceled');
292-
});
293-
294-
try {
295-
final response = await dio.download(
296-
url,
297-
'/downloads/file.zip',
298-
cancelToken: cancelToken,
299-
onReceiveProgress: (received, total) {
300-
if (total != -1) {
301-
handle.updateProgress(received / total);
302-
handle.updateStatusMessage(
303-
'Downloaded ${(received / 1024 / 1024).toStringAsFixed(1)} MB '
304-
'of ${(total / 1024 / 1024).toStringAsFixed(1)} MB'
305-
);
306-
}
307-
},
308-
);
309-
return File('/downloads/file.zip');
310-
} on DioException catch (e) {
311-
if (CancelToken.isCancel(e)) {
312-
return File(''); // Handle cancellation
313-
}
314-
rethrow;
315-
}
316-
},
317-
initialValue: File(''),
318-
);
319-
```
210+
<<< @/../code_samples/lib/command_it/progress_dio_integration.dart#example
320211

321212
### With CommandBuilder
322213

0 commit comments

Comments
 (0)