1
0

CashedNetworkImageWidget.dart 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import 'dart:ui' as ui;
  2. import 'dart:ui';
  3. import 'package:flutter/foundation.dart';
  4. import 'package:flutter/material.dart';
  5. import 'package:flutter_bloc/flutter_bloc.dart';
  6. import 'package:network_image_cached/src/http_request.dart';
  7. import 'src/bloc/cashed_image_bloc.dart'
  8. show
  9. CashedImageBloc,
  10. CashedImageGetErrorState,
  11. CashedImageGetState,
  12. CashedImageState,
  13. GetStartImageEvent;
  14. class CachedNetworkImageWidget extends StatelessWidget {
  15. final String imageUrl;
  16. final int count;
  17. final BoxFit fit;
  18. final double? width;
  19. final double? height;
  20. final Widget? placeholder;
  21. final Widget? errorWidget;
  22. final bool cached;
  23. final String? cachkey;
  24. final Widget? loadwidget;
  25. const CachedNetworkImageWidget({
  26. super.key,
  27. required this.imageUrl,
  28. required this.cachkey,
  29. required this.fit,
  30. this.count = 10,
  31. this.height,
  32. this.width,
  33. this.errorWidget,
  34. this.placeholder,
  35. this.cached = true,
  36. this.loadwidget = const CircularProgressIndicator(),
  37. });
  38. @override
  39. Widget build(BuildContext context) {
  40. return BlocProvider(
  41. create: (context) => CashedImageBloc()
  42. ..add(
  43. GetStartImageEvent(
  44. url: imageUrl,
  45. cached: cached,
  46. count: count,
  47. cachkey: cachkey,
  48. ),
  49. ),
  50. child: Builder(
  51. builder: (context) {
  52. return BlocBuilder<CashedImageBloc, CashedImageState>(
  53. builder: (context, state) {
  54. if (state is CashedImageGetErrorState) {
  55. return SizedBox(
  56. width: width,
  57. height: height,
  58. child: errorWidget ?? Center(child: Icon(Icons.error)),
  59. );
  60. }
  61. if (state is CashedImageGetState) {
  62. return Image.memory(
  63. state.bytes,
  64. fit: fit,
  65. width: width,
  66. height: height,
  67. );
  68. }
  69. return SizedBox(
  70. width: width,
  71. height: height,
  72. child:
  73. placeholder ?? Center(child: CircularProgressIndicator()),
  74. );
  75. },
  76. );
  77. },
  78. ),
  79. );
  80. }
  81. }
  82. class CachedNetworkImageProvider
  83. extends ImageProvider<CachedNetworkImageProvider> {
  84. final String imageUrl;
  85. final int count;
  86. final BoxFit fit;
  87. final double? width;
  88. final double? height;
  89. final Widget? placeholder;
  90. final Widget? errorWidget;
  91. final bool cached;
  92. final String? cachkey;
  93. final Widget? loadwidget;
  94. const CachedNetworkImageProvider({
  95. required this.imageUrl,
  96. required this.cachkey,
  97. required this.fit,
  98. this.count = 10,
  99. this.height,
  100. this.width,
  101. this.errorWidget,
  102. this.placeholder,
  103. this.cached = true,
  104. this.loadwidget = const CircularProgressIndicator(),
  105. });
  106. @override
  107. ImageStreamCompleter loadImage(
  108. CachedNetworkImageProvider key,
  109. ImageDecoderCallback decode,
  110. ) {
  111. // 1. Создаём Future, который загрузит и декодирует изображение
  112. // 2. Возвращаем ImageStreamCompleter, который управляет потоком загрузки
  113. return MultiFrameImageStreamCompleter(
  114. codec: _loadAndDecodeImage(decode),
  115. scale: 1.0,
  116. informationCollector: () => <DiagnosticsNode>[
  117. DiagnosticsProperty<CachedNetworkImageProvider>(
  118. 'Image provider',
  119. key,
  120. showName: false,
  121. ),
  122. ],
  123. );
  124. }
  125. // Вспомогательный метод: загружает байты и декодирует в ui.Image
  126. Future<ui.Codec> _loadAndDecodeImage(ImageDecoderCallback decode) async {
  127. try {
  128. // 1. Отправляем HTTP‑запрос
  129. HttpGetImage httpGetImage = HttpGetImage(url: imageUrl, count: count);
  130. // 2. Декодируем байты в ui.Image
  131. Uint8List img = await httpGetImage.getDataObjectIsolate();
  132. final decodedImage = await decode(
  133. await ImmutableBuffer.fromUint8List(img),
  134. );
  135. return decodedImage;
  136. } catch (e) {
  137. // Если ошибка — бросаем исключение (будет обработано в Image widget)
  138. throw Exception('Failed to load image: $e');
  139. }
  140. }
  141. @override
  142. Future<CachedNetworkImageProvider> obtainKey(
  143. ImageConfiguration configuration,
  144. ) {
  145. return SynchronousFuture<CachedNetworkImageProvider>(this);
  146. }
  147. }