Vovan 1 month ago
commit
1820f2ab65

+ 31 - 0
.gitignore

@@ -0,0 +1,31 @@
+# Miscellaneous
+*.class
+*.log
+*.pyc
+*.swp
+.DS_Store
+.atom/
+.buildlog/
+.history
+.svn/
+migrate_working_dir/
+
+# IntelliJ related
+*.iml
+*.ipr
+*.iws
+.idea/
+
+# The .vscode folder contains launch configuration and tasks you configure in
+# VS Code which you may wish to be included in version control, so this line
+# is commented out by default.
+#.vscode/
+
+# Flutter/Dart/Pub related
+# Libraries should not include pubspec.lock, per https://dart.dev/guides/libraries/private-files#pubspeclock.
+/pubspec.lock
+**/doc/api/
+.dart_tool/
+.flutter-plugins-dependencies
+/build/
+/coverage/

+ 10 - 0
.metadata

@@ -0,0 +1,10 @@
+# This file tracks properties of this Flutter project.
+# Used by Flutter tool to assess capabilities and perform upgrades etc.
+#
+# This file should be version controlled and should not be manually edited.
+
+version:
+  revision: "19074d12f7eaf6a8180cd4036a430c1d76de904e"
+  channel: "stable"
+
+project_type: package

+ 3 - 0
CHANGELOG.md

@@ -0,0 +1,3 @@
+## 0.0.1
+
+* TODO: Describe initial release.

+ 1 - 0
LICENSE

@@ -0,0 +1 @@
+TODO: Add your license here.

+ 39 - 0
README.md

@@ -0,0 +1,39 @@
+<!--
+This README describes the package. If you publish this package to pub.dev,
+this README's contents appear on the landing page for your package.
+
+For information about how to write a good package README, see the guide for
+[writing package pages](https://dart.dev/tools/pub/writing-package-pages).
+
+For general information about developing packages, see the Dart guide for
+[creating packages](https://dart.dev/guides/libraries/create-packages)
+and the Flutter guide for
+[developing packages and plugins](https://flutter.dev/to/develop-packages).
+-->
+
+TODO: Put a short description of the package here that helps potential users
+know whether this package might be useful for them.
+
+## Features
+
+TODO: List what your package can do. Maybe include images, gifs, or videos.
+
+## Getting started
+
+TODO: List prerequisites and provide or point to information on how to
+start using the package.
+
+## Usage
+
+TODO: Include short and useful examples for package users. Add longer examples
+to `/example` folder.
+
+```dart
+const like = 'sample';
+```
+
+## Additional information
+
+TODO: Tell users more about the package: where to find more information, how to
+contribute to the package, how to file issues, what response they can expect
+from the package authors, and more.

+ 4 - 0
analysis_options.yaml

@@ -0,0 +1,4 @@
+include: package:flutter_lints/flutter.yaml
+
+# Additional information about this file can be found at
+# https://dart.dev/guides/language/analysis-options

+ 81 - 0
lib/CashedNetworkImageWidget.dart

@@ -0,0 +1,81 @@
+import 'package:flutter/material.dart';
+
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'src/bloc/cashed_image_bloc.dart'
+    show
+        CashedImageBloc,
+        CashedImageGetErrorState,
+        CashedImageGetState,
+        CashedImageState,
+        GetStartImageEvent;
+
+class CachedNetworkImageWidget extends StatelessWidget {
+  final String imageUrl;
+  final int count;
+  final BoxFit fit;
+  final double? width;
+  final double? height;
+  final Widget? placeholder;
+  final Widget? errorWidget;
+  final bool cached;
+  final String? cachkey;
+
+  const CachedNetworkImageWidget({
+    super.key,
+    required this.imageUrl,
+    required this.cachkey,
+    required this.fit,
+    this.count = 10,
+    this.height,
+    this.width,
+    this.errorWidget,
+    this.placeholder,
+    this.cached = true,
+  });
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocProvider(
+      create: (context) => CashedImageBloc()
+        ..add(
+          GetStartImageEvent(
+            url: imageUrl,
+            cached: cached,
+            count: count,
+            cachkey: cachkey,
+          ),
+        ),
+      child: Builder(
+        builder: (context) {
+          return BlocBuilder<CashedImageBloc, CashedImageState>(
+            builder: (context, state) {
+              if (state is CashedImageGetErrorState) {
+                return SizedBox(
+                  width: width,
+                  height: height,
+                  child: errorWidget ?? Center(child: Icon(Icons.error)),
+                );
+              }
+
+              if (state is CashedImageGetState) {
+                return Image.memory(
+                  state.bytes,
+                  fit: fit,
+                  width: width,
+                  height: height,
+                );
+              }
+              return SizedBox(
+                width: width,
+                height: height,
+                child:
+                    placeholder ?? Center(child: CircularProgressIndicator()),
+              );
+            },
+          );
+        },
+      ),
+    );
+  }
+}

+ 49 - 0
lib/src/bloc/cashed_image_bloc.dart

@@ -0,0 +1,49 @@
+import 'package:bloc/bloc.dart';
+import 'package:equatable/equatable.dart';
+
+import 'package:flutter/foundation.dart';
+import 'package:flutter_cache_manager/flutter_cache_manager.dart';
+import 'package:network_image_cached/src/http_request.dart';
+
+part 'cashed_image_event.dart';
+part 'cashed_image_state.dart';
+
+class CashedImageBloc extends Bloc<CashedImageEvent, CashedImageState> {
+  DefaultCacheManager defaultCacheManager = DefaultCacheManager();
+  CashedImageBloc() : super(CashedImageInitial()) {
+    on<GetStartImageEvent>((event, emit) async {
+      emit(CashedImageLoadingState());
+
+      HttpGetImage httpGetImage = HttpGetImage(
+        url: event.url,
+        count: event.count,
+      );
+
+      if (event.cached) {
+        FileInfo? fileInfo = await defaultCacheManager.getFileFromCache(
+          event.url,
+        );
+
+        if (fileInfo != null) {
+          emit(CashedImageGetState(bytes: await fileInfo.file.readAsBytes()));
+          return;
+        }
+      }
+
+      try {
+        Uint8List uint8list = await httpGetImage.getDataObjectIsolate();
+        if (event.cached) {
+          if (event.cachkey != null) {
+            defaultCacheManager.putFile(event.cachkey!, uint8list);
+          } else {
+            defaultCacheManager.putFile(event.url, uint8list);
+          }
+        }
+
+        emit(CashedImageGetState(bytes: uint8list));
+      } catch (e) {
+        emit(CashedImageGetErrorState());
+      }
+    });
+  }
+}

+ 23 - 0
lib/src/bloc/cashed_image_event.dart

@@ -0,0 +1,23 @@
+part of 'cashed_image_bloc.dart';
+
+sealed class CashedImageEvent extends Equatable {
+  const CashedImageEvent();
+
+  @override
+  List<Object> get props => [];
+}
+
+class GetStartImageEvent extends CashedImageEvent {
+  final String url;
+  final bool cached;
+  final int count;
+  final String? cachkey;
+  const GetStartImageEvent({
+    required this.url,
+    required this.cached,
+    required this.count,
+    required this.cachkey,
+  });
+  @override
+  List<Object> get props => [url, cached];
+}

+ 22 - 0
lib/src/bloc/cashed_image_state.dart

@@ -0,0 +1,22 @@
+part of 'cashed_image_bloc.dart';
+
+sealed class CashedImageState extends Equatable {
+  const CashedImageState();
+
+  @override
+  List<Object> get props => [];
+}
+
+final class CashedImageInitial extends CashedImageState {}
+
+final class CashedImageLoadingState extends CashedImageState {}
+
+final class CashedImageGetState extends CashedImageState {
+  final Uint8List bytes;
+
+  const CashedImageGetState({required this.bytes});
+}
+
+final class CashedImageGetErrorState extends CashedImageState {
+  const CashedImageGetErrorState();
+}

+ 61 - 0
lib/src/http_request.dart

@@ -0,0 +1,61 @@
+import 'dart:isolate';
+import 'dart:typed_data';
+import 'package:http/http.dart' as http;
+
+class HttpGetImage {
+  final String url;
+  final int count;
+  HttpGetImage({required this.url, required this.count});
+
+  Future<Uint8List> getDataObjectIsolate() async {
+    final ReceivePort receivePort = ReceivePort();
+
+    final Isolate isolate = await Isolate.spawn(_isolateFetchVideo, {
+      'sendPort': receivePort.sendPort,
+      'url': url,
+    });
+
+    try {
+      final dynamic result = await receivePort.first;
+      isolate.kill();
+
+      if (result is Uint8List) {
+        return result;
+      } else {
+        throw Exception();
+      }
+    } catch (e) {
+      isolate.kill();
+      throw Exception();
+    } finally {
+      receivePort.close();
+    }
+  }
+
+  Future<void> _isolateFetchVideo(Map<String, dynamic> message) async {
+    final SendPort sendPort = message['sendPort'];
+    final String url = message['url'];
+    int count = message['count'];
+    int time = 10;
+    late http.Response response;
+
+    do {
+      if (time > count) {
+        sendPort.send(null);
+        break;
+      }
+      try {
+        response = await http
+            .get(Uri.parse(url))
+            .timeout(Duration(seconds: time));
+        if (response.statusCode == 200) {
+          sendPort.send(response.bodyBytes);
+          break;
+        }
+        time++;
+      } catch (e) {
+        sendPort.send(null);
+      }
+    } while (response.statusCode != 200);
+  }
+}

+ 58 - 0
pubspec.yaml

@@ -0,0 +1,58 @@
+name: network_image_cached
+description: "A new Flutter package project."
+version: 0.0.1
+homepage:
+
+environment:
+  sdk: ^3.10.1
+  flutter: ">=1.17.0"
+
+dependencies:
+  equatable: ^2.0.8
+  flutter:
+    sdk: flutter
+  flutter_bloc: ^9.1.1
+  flutter_cache_manager: ^3.4.1
+  http: ^1.6.0
+
+dev_dependencies:
+  flutter_test:
+    sdk: flutter
+  flutter_lints: ^6.0.0
+
+# For information on the generic Dart part of this file, see the
+# following page: https://dart.dev/tools/pub/pubspec
+
+# The following section is specific to Flutter packages.
+flutter:
+
+  # To add assets to your package, add an assets section, like this:
+  # assets:
+  #   - images/a_dot_burr.jpeg
+  #   - images/a_dot_ham.jpeg
+  #
+  # For details regarding assets in packages, see
+  # https://flutter.dev/to/asset-from-package
+  #
+  # An image asset can refer to one or more resolution-specific "variants", see
+  # https://flutter.dev/to/resolution-aware-images
+
+  # To add custom fonts to your package, add a fonts section here,
+  # in this "flutter" section. Each entry in this list should have a
+  # "family" key with the font family name, and a "fonts" key with a
+  # list giving the asset and other descriptors for the font. For
+  # example:
+  # fonts:
+  #   - family: Schyler
+  #     fonts:
+  #       - asset: fonts/Schyler-Regular.ttf
+  #       - asset: fonts/Schyler-Italic.ttf
+  #         style: italic
+  #   - family: Trajan Pro
+  #     fonts:
+  #       - asset: fonts/TrajanPro.ttf
+  #       - asset: fonts/TrajanPro_Bold.ttf
+  #         weight: 700
+  #
+  # For details regarding fonts in packages, see
+  # https://flutter.dev/to/font-from-package

+ 12 - 0
test/network_image_cached_test.dart

@@ -0,0 +1,12 @@
+import 'package:flutter_test/flutter_test.dart';
+
+import 'package:network_image_cached/network_image_cached.dart';
+
+void main() {
+  test('adds one to input values', () {
+    final calculator = Calculator();
+    expect(calculator.addOne(2), 3);
+    expect(calculator.addOne(-7), -6);
+    expect(calculator.addOne(0), 1);
+  });
+}