The user transmits images that are subsequently uploaded to the server. At the same time, while some images are being uploaded, the user should be able to add other images.
I assume that this needs to be done using STREAM, but I don't understand how.
At the moment I have a UI, a Block, and a request to the server
I also need to get the loading process and display it in the UI, after 100% refresh the screen
Bloc
Future<void> _onSetScan(
SetScanEvent event,
Emitter<SigningDocumentsState> emit,
) async {
final picker = ImagePicker();
try {
final pickerFile = await picker.pickMultiImage();
final files = pickerFile.map<UploadFile>(
(xFile) {
return UploadFile(
file: File(xFile.path),
value: '0',
type: event.type,
);
},
).toList();
final receivedFiles = <UploadFile>[];
if (files.isNotEmpty) {
files.forEach((element) {
final size = element.file.lengthSync() / pow(1024, 2);
if (size > 5) {
final msg =
'Размер файла ${element.file.path.split('/').last} превышает 5 МБ';
emit(
SigningDocumentsState(
status: SigningDocumentsStatus.largeSize,
scans: state.scans,
filesUploadQueue: state.filesUploadQueue,
failureMessage: msg,
),
);
} else {
receivedFiles.add(element);
}
});
}
} on Exception {
emit(
SigningDocumentsState(
status: SigningDocumentsStatus.failure,
scans: state.scans,
filesUploadQueue: state.filesUploadQueue,
),
);
}
}
UI
class Contracts extends StatelessWidget {
const Contracts({
required this.title,
required this.type,
super.key,
});
final String title;
final String type;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return BlocBuilder<SigningDocumentsBloc, SigningDocumentsState>(
builder: (context, state) {
final contracts =
state.scans.where((item) => item.type == type).toList();
print(state.filesUploadQueue);
return Row(
children: [
SizedBox(
height: theme.spacings.x20,
width: theme.spacings.x10,
child: OutlinedButton(
style: OutlinedButton.styleFrom(
backgroundColor: theme.palette.bgQuaternary,
padding: EdgeInsets.symmetric(vertical: theme.spacings.x8),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(theme.spacings.x1),
),
side: BorderSide.none,
),
onPressed: () {
context
.read<SigningDocumentsBloc>()
.add(SetScanEvent(type: type));
},
child: SvgPicture.asset(
AssetNames.paperClip,
),
),
),
SizedBox(
width: theme.spacings.x3,
),
Expanded(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: [
//here
Row(
children: state.filesUploadQueue.where((item) => item.type == type).toList().map((contract) {
return UploadContainer(
value: double.parse(contract.value),
);
}).toList(),
),
Row(
children: contracts.map((contract) {
return Contract(
files: contract,
title: title,
length: contracts.length,
index: contracts.indexOf(contract),
);
}).toList(),
),
],
),
),
),
],
);
},
);
}
}
UploadContainer
class UploadContainer extends StatelessWidget {
const UploadContainer({
required this.value,
super.key,
});
final double value;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Padding(
padding: EdgeInsets.only(right: theme.spacings.x2),
child: Container(
width: theme.spacings.x20,
height: theme.spacings.x20,
decoration: BoxDecoration(
border: Border.all(
color: theme.palette.buttonDisabled,
),
borderRadius: BorderRadius.circular(
theme.spacings.x2,
),
),
child: Center(
child: Stack(
children: [
Center(
child: CircularProgressIndicator(
backgroundColor: theme.palette.bgPrimary,
valueColor: value < 0.51
? AlwaysStoppedAnimation(theme.palette.iconAccentThird)
: AlwaysStoppedAnimation(theme.palette.iconAccentSecond),
value: value,
strokeWidth: theme.spacings.x1,
),
),
Center(child: Text('${(value * 100).toInt()} %', style: theme.textTheme.bodySmall,)),
],
),
),
),
);
}
}
Repository
@override
Future<void> setScan({
required File file,
required String type,
}) async {
final name = file.path.split('/').last;
final scan = await MultipartFile.fromFile(
file.path,
filename: name,
);
final formData = FormData.fromMap({
'files[]': scan,
'name': name,
'service': 'test',
'type': type,
});
await _dio.post(
'https://test-url',
data: formData,
onSendProgress: (int sent, int total) {
final percentage = ((sent/total)*100).toStringAsFixed(2); //
},
);
I tried updating the state without a Stream, but when I add images in addition to those that are being loaded, they disappear from the download queue