diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 6b4c0f7..f2872cf 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 8.0
+ 9.0
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 56e5c2a..7701645 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -1,8 +1,5 @@
PODS:
- Flutter (1.0.0)
- - FMDB (2.7.5):
- - FMDB/standard (= 2.7.5)
- - FMDB/standard (2.7.5)
- image_picker (0.0.1):
- Flutter
- package_info_plus (0.4.5):
@@ -13,9 +10,6 @@ PODS:
- Flutter
- shared_preferences (0.0.1):
- Flutter
- - sqflite (0.0.2):
- - Flutter
- - FMDB (>= 2.7.5)
- url_launcher (0.0.1):
- Flutter
@@ -26,13 +20,8 @@ DEPENDENCIES:
- path_provider (from `.symlinks/plugins/path_provider/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
- - sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher (from `.symlinks/plugins/url_launcher/ios`)
-SPEC REPOS:
- trunk:
- - FMDB
-
EXTERNAL SOURCES:
Flutter:
:path: Flutter
@@ -46,22 +35,18 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences:
:path: ".symlinks/plugins/shared_preferences/ios"
- sqflite:
- :path: ".symlinks/plugins/sqflite/ios"
url_launcher:
:path: ".symlinks/plugins/url_launcher/ios"
SPEC CHECKSUMS:
Flutter: 50d75fe2f02b26cc09d224853bb45737f8b3214a
- FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_picker: e06f7a68f000bd36f552c1847e33cda96ed31f1f
package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e
path_provider: abfe2b5c733d04e238b0d8691db0cfd63a27a93c
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d
- sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904
url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef
PODFILE CHECKSUM: aafe91acc616949ddb318b77800a7f51bffa2a4c
-COCOAPODS: 1.11.0
+COCOAPODS: 1.11.2
diff --git a/lib/pages/add_account.dart b/lib/pages/add_account.dart
index 25822d3..beca259 100644
--- a/lib/pages/add_account.dart
+++ b/lib/pages/add_account.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart';
@@ -9,6 +8,7 @@ import '../hooks/delayed_loading.dart';
import '../hooks/stores.dart';
import '../l10n/l10n.dart';
import '../stores/config_store.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/fullscreenable_image.dart';
import '../widgets/radio_picker.dart';
import 'add_instance.dart';
@@ -96,7 +96,7 @@ class AddAccountPage extends HookWidget {
url: icon.value!,
child: CachedNetworkImage(
imageUrl: icon.value!,
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
),
),
diff --git a/lib/pages/add_instance.dart b/lib/pages/add_instance.dart
index 12a4637..7fdb8b6 100644
--- a/lib/pages/add_instance.dart
+++ b/lib/pages/add_instance.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart';
@@ -6,6 +5,7 @@ import 'package:lemmy_api_client/v3.dart';
import '../hooks/debounce.dart';
import '../hooks/stores.dart';
import '../util/cleanup_url.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/fullscreenable_image.dart';
/// A page that let's user add a new instance. Pops a url of the added instance
@@ -76,7 +76,7 @@ class AddInstancePage extends HookWidget {
url: icon.value!,
child: CachedNetworkImage(
imageUrl: icon.value!,
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
))
else if (isSite.value == false)
diff --git a/lib/pages/community.dart b/lib/pages/community.dart
index 2c4b981..fcbc965 100644
--- a/lib/pages/community.dart
+++ b/lib/pages/community.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -18,6 +17,7 @@ import '../util/more_icon.dart';
import '../util/share.dart';
import '../widgets/avatar.dart';
import '../widgets/bottom_modal.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/fullscreenable_image.dart';
import '../widgets/info_table_popup.dart';
import '../widgets/markdown_text.dart';
@@ -270,7 +270,7 @@ class _CommunityOverview extends StatelessWidget {
url: community.community.banner!,
child: CachedNetworkImage(
imageUrl: community.community.banner!,
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
),
SafeArea(
diff --git a/lib/pages/home_tab.dart b/lib/pages/home_tab.dart
index 2334d38..039a1ac 100644
--- a/lib/pages/home_tab.dart
+++ b/lib/pages/home_tab.dart
@@ -1,6 +1,5 @@
import 'dart:math' show max;
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart';
@@ -11,6 +10,7 @@ import '../hooks/stores.dart';
import '../l10n/l10n.dart';
import '../util/goto.dart';
import '../widgets/bottom_modal.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/infinite_scroll.dart';
import '../widgets/sortable_infinite_list.dart';
import 'add_account.dart';
diff --git a/lib/pages/inbox.dart b/lib/pages/inbox.dart
index b7fbdc7..ddb5e73 100644
--- a/lib/pages/inbox.dart
+++ b/lib/pages/inbox.dart
@@ -1,6 +1,5 @@
import 'dart:math' show pi;
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart';
@@ -16,6 +15,7 @@ import '../util/extensions/datetime.dart';
import '../util/goto.dart';
import '../util/more_icon.dart';
import '../widgets/bottom_modal.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/comment/comment.dart';
import '../widgets/infinite_scroll.dart';
import '../widgets/info_table_popup.dart';
@@ -307,7 +307,7 @@ class PrivateMessageTile extends HookWidget {
),
),
),
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
),
Text(
diff --git a/lib/pages/instance.dart b/lib/pages/instance.dart
index 1c86694..2d3c3fa 100644
--- a/lib/pages/instance.dart
+++ b/lib/pages/instance.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:lemmy_api_client/v3.dart';
@@ -14,6 +13,7 @@ import '../util/share.dart';
import '../util/text_color.dart';
import '../widgets/avatar.dart';
import '../widgets/bottom_modal.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/fullscreenable_image.dart';
import '../widgets/info_table_popup.dart';
import '../widgets/markdown_text.dart';
@@ -126,7 +126,7 @@ class InstancePage extends HookWidget {
url: siteView.site.banner!,
child: CachedNetworkImage(
imageUrl: siteView.site.banner!,
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
),
SafeArea(
@@ -143,7 +143,7 @@ class InstancePage extends HookWidget {
width: 100,
height: 100,
imageUrl: siteView.site.icon!,
- errorWidget: (_, __, ___) =>
+ errorBuilder: (_, ___) =>
const Icon(Icons.warning),
),
),
diff --git a/lib/pages/manage_account.dart b/lib/pages/manage_account.dart
index 57a6809..3605418 100644
--- a/lib/pages/manage_account.dart
+++ b/lib/pages/manage_account.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:image_picker/image_picker.dart';
@@ -14,6 +13,7 @@ import '../util/more_icon.dart';
import '../util/pictrs.dart';
import '../widgets/bottom_modal.dart';
import '../widgets/bottom_safe.dart';
+import '../widgets/cached_network_image.dart';
import '../widgets/editor.dart';
/// Page for managing things like username, email, avatar etc
@@ -506,7 +506,7 @@ class _ImagePicker extends HookWidget {
if (url.value != null)
CachedNetworkImage(
imageUrl: url.value!,
- errorWidget: (_, __, ___) => const Icon(Icons.error),
+ errorBuilder: (_, ___) => const Icon(Icons.error),
),
],
);
diff --git a/lib/pages/media_view.dart b/lib/pages/media_view.dart
index bdb417d..b735112 100644
--- a/lib/pages/media_view.dart
+++ b/lib/pages/media_view.dart
@@ -1,6 +1,6 @@
import 'dart:math' show max, min;
-import 'package:cached_network_image/cached_network_image.dart';
+import 'package:extended_image/extended_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -144,7 +144,7 @@ class MediaViewPage extends HookWidget {
: (_, __, ___) => showButtons.value = !showButtons.value,
minScale: PhotoViewComputedScale.contained,
initialScale: PhotoViewComputedScale.contained,
- imageProvider: CachedNetworkImageProvider(url),
+ imageProvider: ExtendedNetworkImageProvider(url, cache: true),
heroAttributes: PhotoViewHeroAttributes(tag: url),
loadingBuilder: (context, event) =>
const Center(child: CircularProgressIndicator()),
diff --git a/lib/widgets/avatar.dart b/lib/widgets/avatar.dart
index e25ff82..d812c6b 100644
--- a/lib/widgets/avatar.dart
+++ b/lib/widgets/avatar.dart
@@ -1,8 +1,8 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import '../hooks/stores.dart';
+import 'cached_network_image.dart';
/// User's avatar. Respects the `showAvatars` setting from configStore
/// If passed url is null, a blank box is displayed to prevent weird indents
@@ -50,7 +50,7 @@ class Avatar extends HookWidget {
width: radius * 2,
imageUrl: imageUrl,
fit: BoxFit.cover,
- errorWidget: (_, __, ___) => blankWidget,
+ errorBuilder: (_, __) => blankWidget,
),
);
}
diff --git a/lib/widgets/cached_network_image.dart b/lib/widgets/cached_network_image.dart
new file mode 100644
index 0000000..6886315
--- /dev/null
+++ b/lib/widgets/cached_network_image.dart
@@ -0,0 +1,68 @@
+import 'package:extended_image/extended_image.dart';
+import 'package:flutter/material.dart';
+
+typedef ImageBuilder = Widget Function(
+ BuildContext context, ImageProvider imageProvider);
+
+typedef LoadingBuilder = Widget Function(
+ BuildContext context, ImageChunkEvent? progress);
+
+typedef ErrorBuilder = Widget Function(
+ BuildContext context, Object? lastException);
+
+extension Progress on ImageChunkEvent {
+ double? get progress {
+ if (expectedTotalBytes == null ||
+ cumulativeBytesLoaded > expectedTotalBytes!) {
+ return null;
+ }
+
+ return cumulativeBytesLoaded / expectedTotalBytes!;
+ }
+}
+
+class CachedNetworkImage extends StatelessWidget {
+ final String imageUrl;
+ final double? height;
+ final double? width;
+ final BoxFit? fit;
+ final bool cache;
+
+ final ErrorBuilder? errorBuilder;
+ final LoadingBuilder? loadingBuilder;
+ final ImageBuilder? imageBuilder;
+
+ const CachedNetworkImage({
+ required this.imageUrl,
+ this.errorBuilder,
+ this.loadingBuilder,
+ this.imageBuilder,
+ this.height,
+ this.width,
+ this.fit,
+ this.cache = true,
+ Key? key,
+ }) : super(key: key);
+
+ @override
+ Widget build(BuildContext context) {
+ return ExtendedImage.network(
+ imageUrl,
+ height: height,
+ width: width,
+ fit: fit,
+ cache: cache,
+ loadStateChanged: (state) {
+ switch (state.extendedImageLoadState) {
+ case LoadState.loading:
+ return loadingBuilder?.call(context, state.loadingProgress) ??
+ SizedBox(height: height, width: width);
+ case LoadState.completed:
+ return imageBuilder?.call(context, state.imageProvider);
+ case LoadState.failed:
+ return errorBuilder?.call(context, state.lastException);
+ }
+ },
+ );
+ }
+}
diff --git a/lib/widgets/markdown_text.dart b/lib/widgets/markdown_text.dart
index 23367ae..a0da202 100644
--- a/lib/widgets/markdown_text.dart
+++ b/lib/widgets/markdown_text.dart
@@ -1,11 +1,11 @@
import 'dart:io';
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_markdown/flutter_markdown.dart';
import 'package:markdown/markdown.dart' as md;
import '../url_launcher.dart';
+import 'cached_network_image.dart';
import 'fullscreenable_image.dart';
/// A Markdown renderer with link/image handling
@@ -52,7 +52,7 @@ class MarkdownText extends StatelessWidget {
url: uri.toString(),
child: CachedNetworkImage(
imageUrl: uri.toString(),
- errorWidget: (context, url, error) => Row(
+ errorBuilder: (context, error) => Row(
children: [
const Icon(Icons.warning),
Text("couldn't load image, ${error.toString()}")
diff --git a/lib/widgets/post.dart b/lib/widgets/post.dart
index d35a97a..dbabb9a 100644
--- a/lib/widgets/post.dart
+++ b/lib/widgets/post.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
@@ -23,6 +22,7 @@ import '../util/more_icon.dart';
import '../util/share.dart';
import 'avatar.dart';
import 'bottom_modal.dart';
+import 'cached_network_image.dart';
import 'fullscreenable_image.dart';
import 'info_table_popup.dart';
import 'markdown_text.dart';
@@ -309,7 +309,7 @@ class PostWidget extends HookWidget {
width: 70,
height: 70,
fit: BoxFit.cover,
- errorWidget: (context, url, error) =>
+ errorBuilder: (context, error) =>
Text(error.toString()),
),
),
@@ -397,9 +397,9 @@ class PostWidget extends HookWidget {
url: post.post.url!,
child: CachedNetworkImage(
imageUrl: post.post.url!,
- errorWidget: (_, __, ___) => const Icon(Icons.warning),
- progressIndicatorBuilder: (context, url, progress) =>
- CircularProgressIndicator(value: progress.progress),
+ errorBuilder: (_, ___) => const Icon(Icons.warning),
+ loadingBuilder: (context, progress) =>
+ CircularProgressIndicator(value: progress?.progress),
),
);
}
diff --git a/lib/widgets/user_profile.dart b/lib/widgets/user_profile.dart
index 1f03ba8..7eb6c7d 100644
--- a/lib/widgets/user_profile.dart
+++ b/lib/widgets/user_profile.dart
@@ -1,4 +1,3 @@
-import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:intl/intl.dart';
@@ -14,6 +13,7 @@ import '../util/extensions/datetime.dart';
import '../util/goto.dart';
import '../util/text_color.dart';
import 'avatar.dart';
+import 'cached_network_image.dart';
import 'fullscreenable_image.dart';
import 'markdown_text.dart';
import 'sortable_infinite_list.dart';
@@ -147,7 +147,7 @@ class _UserOverview extends HookWidget {
url: userView.person.banner!,
child: CachedNetworkImage(
imageUrl: userView.person.banner!,
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
)
else
@@ -208,7 +208,7 @@ class _UserOverview extends HookWidget {
url: userView.person.avatar!,
child: CachedNetworkImage(
imageUrl: userView.person.avatar!,
- errorWidget: (_, __, ___) => const SizedBox.shrink(),
+ errorBuilder: (_, ___) => const SizedBox.shrink(),
),
),
),
diff --git a/pubspec.lock b/pubspec.lock
index 604d757..9a5a53b 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -99,27 +99,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "8.1.2"
- cached_network_image:
- dependency: "direct main"
- description:
- name: cached_network_image
- url: "https://pub.dartlang.org"
- source: hosted
- version: "3.1.0"
- cached_network_image_platform_interface:
- dependency: transitive
- description:
- name: cached_network_image_platform_interface
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.0.0"
- cached_network_image_web:
- dependency: transitive
- description:
- name: cached_network_image_web
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.0.1"
characters:
dependency: transitive
description:
@@ -204,6 +183,20 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
+ extended_image:
+ dependency: "direct main"
+ description:
+ name: extended_image
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "5.1.2"
+ extended_image_library:
+ dependency: transitive
+ description:
+ name: extended_image_library
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "3.1.0"
fake_async:
dependency: transitive
description:
@@ -237,20 +230,6 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
- flutter_blurhash:
- dependency: transitive
- description:
- name: flutter_blurhash
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.6.0"
- flutter_cache_manager:
- dependency: transitive
- description:
- name: flutter_cache_manager
- url: "https://pub.dartlang.org"
- source: hosted
- version: "3.1.2"
flutter_hooks:
dependency: "direct main"
description:
@@ -357,6 +336,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "0.13.3"
+ http_client_helper:
+ dependency: transitive
+ description:
+ name: http_client_helper
+ url: "https://pub.dartlang.org"
+ source: hosted
+ version: "2.0.2"
http_multi_server:
dependency: transitive
description:
@@ -525,13 +511,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
- octo_image:
- dependency: transitive
- description:
- name: octo_image
- url: "https://pub.dartlang.org"
- source: hosted
- version: "1.0.0+1"
package_config:
dependency: transitive
description:
@@ -695,13 +674,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.0"
- rxdart:
- dependency: transitive
- description:
- name: rxdart
- url: "https://pub.dartlang.org"
- source: hosted
- version: "0.27.2"
share_plus:
dependency: "direct main"
description:
@@ -826,20 +798,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.8.1"
- sqflite:
- dependency: transitive
- description:
- name: sqflite
- url: "https://pub.dartlang.org"
- source: hosted
- version: "2.0.0+4"
- sqflite_common:
- dependency: transitive
- description:
- name: sqflite_common
- url: "https://pub.dartlang.org"
- source: hosted
- version: "2.0.1+1"
stack_trace:
dependency: transitive
description:
@@ -868,13 +826,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.1.0"
- synchronized:
- dependency: transitive
- description:
- name: synchronized
- url: "https://pub.dartlang.org"
- source: hosted
- version: "3.0.0"
term_glyph:
dependency: transitive
description:
@@ -952,13 +903,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.2"
- uuid:
- dependency: transitive
- description:
- name: uuid
- url: "https://pub.dartlang.org"
- source: hosted
- version: "3.0.4"
vector_math:
dependency: transitive
description:
@@ -1010,4 +954,4 @@ packages:
version: "3.1.0"
sdks:
dart: ">=2.14.0 <3.0.0"
- flutter: ">=2.0.0"
+ flutter: ">=2.5.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 35357a5..cf4e6b1 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -30,7 +30,6 @@ dependencies:
ref: bugfix/flutter-2.5-update
markdown: ^4.0.0
flutter_markdown: ^0.6.1
- cached_network_image: ^3.0.0
modal_bottom_sheet: ^2.0.0
# native
@@ -65,6 +64,7 @@ dependencies:
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2
+ extended_image: ^5.1.2
dev_dependencies:
flutter_test: