1
- // Enhanced DataTransferManager with streaming support
2
1
import 'dart:async' ;
3
2
import 'package:badgemagic/bademagic_module/models/data.dart' ;
4
3
import 'package:badgemagic/bademagic_module/utils/data_to_bytearray_converter.dart' ;
5
4
import 'package:badgemagic/bademagic_module/utils/file_helper.dart' ;
5
+ import 'package:badgemagic/bademagic_module/utils/converters.dart' ;
6
+ import 'package:badgemagic/bademagic_module/utils/byte_array_utils.dart' ;
6
7
import 'package:badgemagic/providers/badge_message_provider.dart' ;
7
8
import 'package:badgemagic/providers/imageprovider.dart' ;
8
9
import 'package:flutter_blue_plus/flutter_blue_plus.dart' ;
@@ -12,7 +13,7 @@ import 'package:logger/logger.dart';
12
13
enum TransferMode { legacy, streaming }
13
14
14
15
class DataTransferManager {
15
- final Data ? data; // Make nullable for streaming-only usage
16
+ final Data ? data;
16
17
TransferMode mode;
17
18
18
19
BluetoothDevice ? connectedDevice;
@@ -30,19 +31,96 @@ class DataTransferManager {
30
31
final FileHelper fileHelper = FileHelper ();
31
32
final InlineImageProvider controllerData =
32
33
GetIt .instance <InlineImageProvider >();
34
+ final Converters _converters = Converters ();
33
35
final Logger logger = Logger ();
34
36
35
37
bool isStreamingActive = false ;
36
38
39
+ // NEW: Streaming state management
40
+ Map <String , dynamic >? _pendingStreamData;
41
+ bool _isStreamingReady = false ;
42
+
37
43
DataTransferManager (this .data, {this .mode = TransferMode .legacy});
38
44
39
45
// Factory constructors for convenience
40
46
factory DataTransferManager .forLegacy (Data data) =>
41
47
DataTransferManager (data, mode: TransferMode .legacy);
42
-
43
- factory DataTransferManager .forStreaming (Data data) =>
48
+ factory DataTransferManager .forStreaming () =>
44
49
DataTransferManager (null , mode: TransferMode .streaming);
45
50
51
+ // NEW: Store parameters for streaming use after connection
52
+ void setPendingStreamData (Map <String , dynamic > streamData) {
53
+ _pendingStreamData = streamData;
54
+ logger.d ("Stored pending stream data: ${streamData .keys }" );
55
+ }
56
+
57
+ Map <String , dynamic > getPendingStreamData () {
58
+ return _pendingStreamData ?? {};
59
+ }
60
+
61
+ // NEW: Check if streaming connection is established and ready
62
+ bool isStreamingConnectionReady () {
63
+ return _isStreamingReady &&
64
+ connectedDevice != null &&
65
+ streamingWriteCharacteristic != null &&
66
+ isStreamingActive;
67
+ }
68
+
69
+ // NEW: Mark streaming as ready (called from WriteState)
70
+ void setStreamingReady (bool ready) {
71
+ _isStreamingReady = ready;
72
+ logger.d ("Streaming ready state: $ready " );
73
+ }
74
+
75
+ // NEW: Process the actual streaming content using your Converters
76
+ Future <bool > processStreamingContent () async {
77
+ if (_pendingStreamData == null ) {
78
+ logger.e ("No pending stream data" );
79
+ return false ;
80
+ }
81
+
82
+ try {
83
+ Map <String , dynamic > params = _pendingStreamData! ;
84
+ logger.i ("Processing streaming content: '${params ['text' ]}'" );
85
+
86
+ String text = params['text' ] ?? "" ;
87
+ if (text.isEmpty) {
88
+ logger.w ("Empty text for streaming" );
89
+ return false ;
90
+ }
91
+
92
+ // Use your existing Converters class for text to hex conversion
93
+ List <String > hexStrings =
94
+ await _converters.messageTohex (text, params['isInverted' ] ?? false );
95
+
96
+ if (hexStrings.isEmpty) {
97
+ logger.w ("No hex data generated for streaming" );
98
+ return false ;
99
+ }
100
+
101
+ logger.d ("Generated ${hexStrings .length } hex strings for streaming" );
102
+
103
+ // Convert hex to bitmap using your existing utility
104
+ List <List <bool >> bitmap = hexStringToBool (hexStrings.join ());
105
+
106
+ // Convert bitmap to column format for streaming
107
+ List <int > columns = convertBitmapToColumns (bitmap);
108
+
109
+ logger.i ("Streaming ${columns .length } columns" );
110
+
111
+ // Stream the bitmap
112
+ bool success = await streamBitmap (columns);
113
+
114
+ // Clear pending data after processing
115
+ _pendingStreamData = null ;
116
+
117
+ return success;
118
+ } catch (e) {
119
+ logger.e ("Error processing streaming content: $e " );
120
+ return false ;
121
+ }
122
+ }
123
+
46
124
Future <List <List <int >>> generateDataChunk () async {
47
125
if (data == null ) throw Exception ("No data provided for legacy transfer" );
48
126
return converter.convert (data! );
@@ -57,6 +135,8 @@ class DataTransferManager {
57
135
notificationSubscription? .cancel ();
58
136
notificationSubscription = null ;
59
137
isStreamingActive = false ;
138
+ _isStreamingReady = false ;
139
+ _pendingStreamData = null ;
60
140
}
61
141
62
142
/// Handle error codes from streaming badge
@@ -88,14 +168,16 @@ class DataTransferManager {
88
168
}
89
169
}
90
170
91
- /// Stream bitmap data (for streaming mode )
171
+ /// Stream bitmap data (enhanced with better logging )
92
172
Future <bool > streamBitmap (List <int > bitmap) async {
93
173
if (! isStreamingActive || streamingWriteCharacteristic == null ) {
94
174
logger.e ("Streaming not active or characteristic unavailable" );
95
175
return false ;
96
176
}
97
177
98
178
try {
179
+ logger.i ("Streaming bitmap with ${bitmap .length } columns" );
180
+
99
181
List <int > command = [0x03 ]; // stream_bitmap function code
100
182
101
183
// Convert bitmap to 16-bit words (little-endian)
@@ -104,26 +186,41 @@ class DataTransferManager {
104
186
command.add ((column >> 8 ) & 0xFF );
105
187
}
106
188
189
+ logger.d ("Sending ${command .length } bytes to streaming characteristic" );
190
+
107
191
await streamingWriteCharacteristic!
108
192
.write (command, withoutResponse: false );
109
- logger.d ("Bitmap streamed successfully, ${bitmap .length } columns" );
193
+
194
+ // Wait for processing
195
+ await Future .delayed (const Duration (milliseconds: 200 ));
196
+
197
+ logger.i ("Bitmap streamed successfully, ${bitmap .length } columns" );
110
198
return true ;
111
199
} catch (e) {
112
200
logger.e ("Failed to stream bitmap: $e " );
113
201
return false ;
114
202
}
115
203
}
116
204
117
- /// Enter streaming mode
205
+ /// Enter streaming mode (enhanced)
118
206
Future <bool > enterStreamingMode () async {
119
- if (streamingWriteCharacteristic == null ) return false ;
207
+ if (streamingWriteCharacteristic == null ) {
208
+ logger.e ("Streaming write characteristic not available" );
209
+ return false ;
210
+ }
120
211
121
212
try {
213
+ logger.i ("Entering streaming mode..." );
214
+
122
215
List <int > command = [0x02 , 0x00 ]; // Enter streaming mode
123
216
await streamingWriteCharacteristic!
124
217
.write (command, withoutResponse: false );
125
- await Future .delayed (const Duration (milliseconds: 100 ));
218
+
219
+ // Wait for device to enter streaming mode
220
+ await Future .delayed (const Duration (milliseconds: 200 ));
221
+
126
222
isStreamingActive = true ;
223
+ logger.i ("Successfully entered streaming mode" );
127
224
return true ;
128
225
} catch (e) {
129
226
logger.e ("Failed to enter streaming mode: $e " );
@@ -136,10 +233,18 @@ class DataTransferManager {
136
233
if (streamingWriteCharacteristic == null ) return false ;
137
234
138
235
try {
236
+ logger.i ("Exiting streaming mode..." );
237
+
139
238
List <int > command = [0x02 , 0x01 ]; // Exit streaming mode
140
239
await streamingWriteCharacteristic!
141
240
.write (command, withoutResponse: false );
241
+
242
+ await Future .delayed (const Duration (milliseconds: 100 ));
243
+
142
244
isStreamingActive = false ;
245
+ _isStreamingReady = false ;
246
+
247
+ logger.i ("Successfully exited streaming mode" );
143
248
return true ;
144
249
} catch (e) {
145
250
logger.e ("Failed to exit streaming mode: $e " );
0 commit comments