Enable rendering of HEIC images
This commit is contained in:
parent
293e2cae95
commit
20f4f6324b
14 changed files with 226 additions and 74 deletions
17
android/.project
Normal file
17
android/.project
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>android</name>
|
||||
<comment>Project android created by Buildship.</comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
13
android/.settings/org.eclipse.buildship.core.prefs
Normal file
13
android/.settings/org.eclipse.buildship.core.prefs
Normal file
|
@ -0,0 +1,13 @@
|
|||
arguments=
|
||||
auto.sync=false
|
||||
build.scans.enabled=false
|
||||
connection.gradle.distribution=GRADLE_DISTRIBUTION(WRAPPER)
|
||||
connection.project.dir=
|
||||
eclipse.preferences.version=1
|
||||
gradle.user.home=
|
||||
java.home=/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home
|
||||
jvm.arguments=
|
||||
offline.mode=false
|
||||
override.workspace.settings=true
|
||||
show.console.view=true
|
||||
show.executions.view=true
|
6
android/app/.classpath
Normal file
6
android/app/.classpath
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
|
||||
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||
<classpathentry kind="output" path="bin/default"/>
|
||||
</classpath>
|
23
android/app/.project
Normal file
23
android/app/.project
Normal file
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>app</name>
|
||||
<comment>Project app created by Buildship.</comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
2
android/app/.settings/org.eclipse.buildship.core.prefs
Normal file
2
android/app/.settings/org.eclipse.buildship.core.prefs
Normal file
|
@ -0,0 +1,2 @@
|
|||
connection.project.dir=..
|
||||
eclipse.preferences.version=1
|
|
@ -1,16 +1,38 @@
|
|||
PODS:
|
||||
- Flutter (1.0.0)
|
||||
- flutter_image_compress (0.0.1):
|
||||
- Flutter
|
||||
- Mantle
|
||||
- SDWebImageWebPCoder
|
||||
- FMDB (2.7.5):
|
||||
- FMDB/standard (= 2.7.5)
|
||||
- FMDB/standard (2.7.5)
|
||||
- libwebp (1.1.0):
|
||||
- libwebp/demux (= 1.1.0)
|
||||
- libwebp/mux (= 1.1.0)
|
||||
- libwebp/webp (= 1.1.0)
|
||||
- libwebp/demux (1.1.0):
|
||||
- libwebp/webp
|
||||
- libwebp/mux (1.1.0):
|
||||
- libwebp/demux
|
||||
- libwebp/webp (1.1.0)
|
||||
- local_image_provider (0.0.1):
|
||||
- Flutter
|
||||
- Mantle (2.1.1):
|
||||
- Mantle/extobjc (= 2.1.1)
|
||||
- Mantle/extobjc (2.1.1)
|
||||
- path_provider (0.0.1):
|
||||
- Flutter
|
||||
- path_provider_macos (0.0.1):
|
||||
- Flutter
|
||||
- photo_manager (0.0.1):
|
||||
- Flutter
|
||||
- SDWebImage/Core (5.7.3)
|
||||
- SDWebImageWebPCoder (0.6.1):
|
||||
- libwebp (~> 1.0)
|
||||
- SDWebImage/Core (~> 5.7)
|
||||
- share_extend (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_macos (0.0.1):
|
||||
|
@ -23,10 +45,12 @@ PODS:
|
|||
|
||||
DEPENDENCIES:
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_image_compress (from `.symlinks/plugins/flutter_image_compress/ios`)
|
||||
- local_image_provider (from `.symlinks/plugins/local_image_provider/ios`)
|
||||
- path_provider (from `.symlinks/plugins/path_provider/ios`)
|
||||
- path_provider_macos (from `.symlinks/plugins/path_provider_macos/ios`)
|
||||
- photo_manager (from `.symlinks/plugins/photo_manager/ios`)
|
||||
- share_extend (from `.symlinks/plugins/share_extend/ios`)
|
||||
- shared_preferences (from `.symlinks/plugins/shared_preferences/ios`)
|
||||
- shared_preferences_macos (from `.symlinks/plugins/shared_preferences_macos/ios`)
|
||||
- shared_preferences_web (from `.symlinks/plugins/shared_preferences_web/ios`)
|
||||
|
@ -35,10 +59,16 @@ DEPENDENCIES:
|
|||
SPEC REPOS:
|
||||
trunk:
|
||||
- FMDB
|
||||
- libwebp
|
||||
- Mantle
|
||||
- SDWebImage
|
||||
- SDWebImageWebPCoder
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
Flutter:
|
||||
:path: Flutter
|
||||
flutter_image_compress:
|
||||
:path: ".symlinks/plugins/flutter_image_compress/ios"
|
||||
local_image_provider:
|
||||
:path: ".symlinks/plugins/local_image_provider/ios"
|
||||
path_provider:
|
||||
|
@ -47,6 +77,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/path_provider_macos/ios"
|
||||
photo_manager:
|
||||
:path: ".symlinks/plugins/photo_manager/ios"
|
||||
share_extend:
|
||||
:path: ".symlinks/plugins/share_extend/ios"
|
||||
shared_preferences:
|
||||
:path: ".symlinks/plugins/shared_preferences/ios"
|
||||
shared_preferences_macos:
|
||||
|
@ -58,11 +90,17 @@ EXTERNAL SOURCES:
|
|||
|
||||
SPEC CHECKSUMS:
|
||||
Flutter: 0e3d915762c693b495b44d77113d4970485de6ec
|
||||
flutter_image_compress: 082f8daaf6c1b0c9fe798251c750ef0ecd98d7ae
|
||||
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
|
||||
libwebp: 946cb3063cea9236285f7e9a8505d806d30e07f3
|
||||
local_image_provider: cf979b81bc1cacc81867d3511a1b6b7216411e93
|
||||
Mantle: 35238ae6f2e2b2d474fa7b67fee82a59fea71915
|
||||
path_provider: fb74bd0465e96b594bb3b5088ee4a4e7bb1f2a9d
|
||||
path_provider_macos: f760a3c5b04357c380e2fddb6f9db6f3015897e0
|
||||
photo_manager: f7c619c2cc8c2adb8d85c63363babac477de9c67
|
||||
SDWebImage: 97351f6582ceca541ea294ba66a1fcb342a331c2
|
||||
SDWebImageWebPCoder: d0dac55073088d24b2ac1b191a71a8f8d0adac21
|
||||
share_extend: b6748dc53695587891126a89533b862b92548c7b
|
||||
shared_preferences: 430726339841afefe5142b9c1f50cb6bd7793e01
|
||||
shared_preferences_macos: f3f29b71ccbb56bf40c9dd6396c9acf15e214087
|
||||
shared_preferences_web: 141cce0c3ed1a1c5bf2a0e44f52d31eeb66e5ea9
|
||||
|
|
|
@ -10,11 +10,7 @@
|
|||
06CC0CFA92976FDBA53FAAE5 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BB5F531E492C7002EAC4CE42 /* Pods_Runner.framework */; };
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
|
||||
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
|
||||
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
|
||||
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
|
||||
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
|
||||
|
@ -27,8 +23,6 @@
|
|||
dstPath = "";
|
||||
dstSubfolderSpec = 10;
|
||||
files = (
|
||||
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */,
|
||||
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */,
|
||||
);
|
||||
name = "Embed Frameworks";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -39,14 +33,12 @@
|
|||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
|
||||
6A8718E36D8B0CC6360ADB0D /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
|
||||
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = "<group>"; };
|
||||
9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = "<group>"; };
|
||||
97A6D25F159DA10C77E8A78D /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
|
||||
|
@ -62,8 +54,6 @@
|
|||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */,
|
||||
3B80C3941E831B6300D905FE /* App.framework in Frameworks */,
|
||||
06CC0CFA92976FDBA53FAAE5 /* Pods_Runner.framework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -74,9 +64,7 @@
|
|||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
3B80C3931E831B6300D905FE /* App.framework */,
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEBA1CF902C7004384FC /* Flutter.framework */,
|
||||
9740EEB21CF90195004384FC /* Debug.xcconfig */,
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
|
||||
9740EEB31CF90195004384FC /* Generated.xcconfig */,
|
||||
|
@ -133,7 +121,6 @@
|
|||
A3AB65855D82977B2D2D5B35 /* Pods-Runner.release.xcconfig */,
|
||||
6A8718E36D8B0CC6360ADB0D /* Pods-Runner.profile.xcconfig */,
|
||||
);
|
||||
name = Pods;
|
||||
path = Pods;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
|
@ -232,7 +219,7 @@
|
|||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin";
|
||||
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin";
|
||||
};
|
||||
481FE5B058006945E0569431 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
|
@ -376,7 +363,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 37L77XPSDP;
|
||||
|
@ -391,7 +378,7 @@
|
|||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = Orma.FlutterApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = orma.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -515,7 +502,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 37L77XPSDP;
|
||||
|
@ -530,7 +517,7 @@
|
|||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = Orma.FlutterApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = orma.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
@ -547,7 +534,7 @@
|
|||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
|
||||
DEVELOPMENT_TEAM = 37L77XPSDP;
|
||||
|
@ -562,7 +549,7 @@
|
|||
"$(inherited)",
|
||||
"$(PROJECT_DIR)/Flutter",
|
||||
);
|
||||
PRODUCT_BUNDLE_IDENTIFIER = Orma.FlutterApp;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = orma.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h";
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
<string>$(FLUTTER_BUILD_NUMBER)</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Photo Library Access Warning</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
|
@ -41,7 +43,5 @@
|
|||
</array>
|
||||
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||
<false/>
|
||||
<key>NSPhotoLibraryUsageDescription</key>
|
||||
<string>Photo Library Access Warning</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:collection';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'dart:typed_data';
|
||||
|
||||
typedef EvictionHandler<K, V>(K key, V value);
|
||||
|
||||
|
@ -37,31 +36,31 @@ class LRUMap<K, V> {
|
|||
}
|
||||
|
||||
class ImageLruCache {
|
||||
static LRUMap<_ImageCacheEntity, Image> _map = LRUMap(500);
|
||||
static LRUMap<_ImageCacheEntity, Uint8List> _map = LRUMap(500);
|
||||
|
||||
static Image getData(String path, [int size = 64]) {
|
||||
return _map.get(_ImageCacheEntity(path, size));
|
||||
static Uint8List getData(int id, [int size = 64]) {
|
||||
return _map.get(_ImageCacheEntity(id, size));
|
||||
}
|
||||
|
||||
static void setData(String path, int size, Image image) {
|
||||
_map.put(_ImageCacheEntity(path, size), image);
|
||||
static void setData(int id, int size, Uint8List imageData) {
|
||||
_map.put(_ImageCacheEntity(id, size), imageData);
|
||||
}
|
||||
}
|
||||
|
||||
class _ImageCacheEntity {
|
||||
String path;
|
||||
int id;
|
||||
int size;
|
||||
|
||||
_ImageCacheEntity(this.path, this.size);
|
||||
_ImageCacheEntity(this.id, this.size);
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) =>
|
||||
identical(this, other) ||
|
||||
other is _ImageCacheEntity &&
|
||||
runtimeType == other.runtimeType &&
|
||||
path == other.path &&
|
||||
id == other.id &&
|
||||
size == other.size;
|
||||
|
||||
@override
|
||||
int get hashCode => path.hashCode ^ size.hashCode;
|
||||
int get hashCode => id.hashCode ^ size.hashCode;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:crypto/crypto.dart';
|
||||
|
@ -47,14 +48,16 @@ class Photo {
|
|||
return photo;
|
||||
}
|
||||
|
||||
AssetEntity getAsset() {
|
||||
return AssetEntity(id: localId);
|
||||
}
|
||||
|
||||
static String getHash(File file) {
|
||||
return sha256.convert(file.readAsBytesSync()).toString();
|
||||
}
|
||||
|
||||
int get hashCode => generatedId;
|
||||
|
||||
@override
|
||||
bool operator ==(other) {
|
||||
return generatedId == other.generatedId;
|
||||
String toString() {
|
||||
return 'Photo(generatedId: $generatedId, uploadedFileId: $uploadedFileId, localId: $localId, path: $path, localPath: $localPath, relativePath: $relativePath, thumbnailPath: $thumbnailPath, hash: $hash, createTimestamp: $createTimestamp, syncTimestamp: $syncTimestamp)';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:logger/logger.dart';
|
||||
import 'package:myapp/core/lru_map.dart';
|
||||
import 'package:myapp/models/photo.dart';
|
||||
import 'package:photo_manager/photo_manager.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:share_extend/share_extend.dart';
|
||||
import 'extents_page_view.dart';
|
||||
import 'loading_widget.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
import 'package:flutter_image_compress/flutter_image_compress.dart';
|
||||
|
||||
class DetailPage extends StatefulWidget {
|
||||
final List<Photo> photos;
|
||||
|
@ -20,28 +25,38 @@ class DetailPage extends StatefulWidget {
|
|||
class _DetailPageState extends State<DetailPage> {
|
||||
bool _shouldDisableScroll = false;
|
||||
int _selectedIndex = 0;
|
||||
final _cachedImages = LRUMap<int, ZoomableImage>(5);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_selectedIndex = widget.selectedIndex;
|
||||
|
||||
Logger().i("Loading " + widget.photos[_selectedIndex].toString());
|
||||
var pageController = PageController(initialPage: _selectedIndex);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.share),
|
||||
onPressed: () {
|
||||
ShareExtend.share(
|
||||
widget.photos[_selectedIndex].localPath, "image");
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
appBar: _buildAppBar(),
|
||||
body: Center(
|
||||
child: Container(
|
||||
child: ExtentsPageView.extents(
|
||||
itemBuilder: (context, index) {
|
||||
return _buildItem(context, widget.photos[index]);
|
||||
if (_cachedImages.get(index) != null) {
|
||||
return _cachedImages.get(index);
|
||||
}
|
||||
final image = ZoomableImage(
|
||||
photo: widget.photos[index],
|
||||
shouldDisableScroll: (value) {
|
||||
setState(() {
|
||||
_shouldDisableScroll = value;
|
||||
});
|
||||
},
|
||||
);
|
||||
_cachedImages.put(index, image);
|
||||
return image;
|
||||
},
|
||||
onPageChanged: (int index) {
|
||||
_selectedIndex = index;
|
||||
|
@ -57,28 +72,68 @@ class _DetailPageState extends State<DetailPage> {
|
|||
);
|
||||
}
|
||||
|
||||
Widget _buildItem(BuildContext context, Photo photo) {
|
||||
var image = ImageLruCache.getData(photo.localPath) == null
|
||||
? Image.file(
|
||||
File(photo.localPath),
|
||||
filterQuality: FilterQuality.low,
|
||||
)
|
||||
: ImageLruCache.getData(photo.localPath);
|
||||
AppBar _buildAppBar() {
|
||||
return AppBar(
|
||||
actions: <Widget>[
|
||||
IconButton(
|
||||
icon: Icon(Icons.share),
|
||||
onPressed: () {
|
||||
ShareExtend.share(widget.photos[_selectedIndex].localPath, "image");
|
||||
},
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class ZoomableImage extends StatelessWidget {
|
||||
final Function(bool) shouldDisableScroll;
|
||||
|
||||
const ZoomableImage({
|
||||
Key key,
|
||||
@required this.photo,
|
||||
this.shouldDisableScroll,
|
||||
}) : super(key: key);
|
||||
|
||||
final Photo photo;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Logger().i("Building " + photo.generatedId.toString());
|
||||
if (ImageLruCache.getData(photo.generatedId) != null) {
|
||||
return _buildPhotoView(ImageLruCache.getData(photo.generatedId));
|
||||
}
|
||||
var future;
|
||||
if (path.extension(photo.localPath) == '.HEIC') {
|
||||
Logger().i("Decoding HEIC");
|
||||
future = photo.getAsset().originBytes.then((bytes) =>
|
||||
FlutterImageCompress.compressWithList(bytes)
|
||||
.then((result) => Uint8List.fromList(result)));
|
||||
} else {
|
||||
future = AssetEntity(id: photo.localId).originBytes;
|
||||
}
|
||||
return FutureBuilder<Uint8List>(
|
||||
future: future,
|
||||
builder: (_, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return _buildPhotoView(snapshot.data);
|
||||
} else if (snapshot.hasError) {
|
||||
return Text(snapshot.error);
|
||||
} else {
|
||||
return loadWidget;
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildPhotoView(Uint8List imageData) {
|
||||
ValueChanged<PhotoViewScaleState> scaleStateChangedCallback = (value) {
|
||||
var shouldDisableScroll;
|
||||
if (value == PhotoViewScaleState.initial) {
|
||||
shouldDisableScroll = false;
|
||||
} else {
|
||||
shouldDisableScroll = true;
|
||||
}
|
||||
if (shouldDisableScroll != _shouldDisableScroll) {
|
||||
setState(() {
|
||||
_shouldDisableScroll = shouldDisableScroll;
|
||||
});
|
||||
if (shouldDisableScroll != null) {
|
||||
shouldDisableScroll(value != PhotoViewScaleState.initial);
|
||||
}
|
||||
};
|
||||
return PhotoView(
|
||||
imageProvider: image.image,
|
||||
imageProvider: Image.memory(imageData).image,
|
||||
scaleStateChangedCallback: scaleStateChangedCallback,
|
||||
minScale: PhotoViewComputedScale.contained,
|
||||
);
|
||||
|
|
|
@ -26,14 +26,14 @@ class _ImageWidgetState extends State<ImageWidget> {
|
|||
);
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final path = widget.photo.localPath;
|
||||
final size = widget.size == null ? 124 : widget.size;
|
||||
final cachedImage = ImageLruCache.getData(path, size);
|
||||
final cachedImageData =
|
||||
ImageLruCache.getData(widget.photo.generatedId, size);
|
||||
|
||||
Widget image;
|
||||
|
||||
if (cachedImage != null) {
|
||||
image = cachedImage;
|
||||
if (cachedImageData != null) {
|
||||
image = Image.memory(cachedImageData);
|
||||
} else {
|
||||
if (widget.photo.localId != null) {
|
||||
image = FutureBuilder<Uint8List>(
|
||||
|
@ -41,11 +41,12 @@ class _ImageWidgetState extends State<ImageWidget> {
|
|||
.thumbDataWithSize(size, size),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
ImageLruCache.setData(
|
||||
widget.photo.generatedId, size, snapshot.data);
|
||||
Image image = Image.memory(snapshot.data,
|
||||
width: size.toDouble(),
|
||||
height: size.toDouble(),
|
||||
fit: BoxFit.cover);
|
||||
ImageLruCache.setData(path, size, image);
|
||||
return image;
|
||||
} else {
|
||||
return loadingWidget;
|
||||
|
@ -64,7 +65,7 @@ class _ImageWidgetState extends State<ImageWidget> {
|
|||
@override
|
||||
void didUpdateWidget(ImageWidget oldWidget) {
|
||||
super.didUpdateWidget(oldWidget);
|
||||
if (widget.photo.localPath != oldWidget.photo.localPath) {
|
||||
if (widget.photo.generatedId != oldWidget.photo.generatedId) {
|
||||
setState(() {});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,6 +83,13 @@ packages:
|
|||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_image_compress:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_image_compress
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.6.7"
|
||||
flutter_test:
|
||||
dependency: "direct dev"
|
||||
description: flutter
|
||||
|
|
|
@ -37,6 +37,7 @@ dependencies:
|
|||
share_extend: "^1.1.2"
|
||||
draggable_scrollbar: ^0.0.4
|
||||
photo_view: ^0.9.2
|
||||
flutter_image_compress: ^0.6.5+1
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
|
Loading…
Add table
Reference in a new issue