Merge branch 'develop'
This commit is contained in:
commit
a70057c814
9 changed files with 49 additions and 20 deletions
|
@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [v1.4.7] - 2021-08-06
|
||||
## [v1.4.8] - 2021-08-08
|
||||
### Added
|
||||
- Map
|
||||
- Viewer: action to copy to clipboard
|
||||
|
@ -13,6 +13,8 @@ All notable changes to this project will be documented in this file.
|
|||
- auto album identification and naming
|
||||
- opening HEIC images from downloads content URI on Android R+
|
||||
|
||||
## [v1.4.7] - 2021-08-06 [YANKED]
|
||||
|
||||
## [v1.4.6] - 2021-07-22
|
||||
### Added
|
||||
- Albums / Countries / Tags: multiple selection
|
||||
|
|
|
@ -4,6 +4,8 @@ import android.content.*
|
|||
import android.content.pm.ApplicationInfo
|
||||
import android.content.res.Configuration
|
||||
import android.net.Uri
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import androidx.core.content.FileProvider
|
||||
import com.bumptech.glide.Glide
|
||||
|
@ -141,13 +143,21 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
return
|
||||
}
|
||||
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
|
||||
if (clipboard != null) {
|
||||
val clip = ClipData.newUri(context.contentResolver, label, getShareableUri(uri))
|
||||
clipboard.setPrimaryClip(clip)
|
||||
result.success(true)
|
||||
} else {
|
||||
result.success(false)
|
||||
// on older devices, `ClipboardManager` initialization must happen on the main thread
|
||||
// (e.g. Samsung S7 with Android 8.0 / API 26, but not on Tab A 10.1 with Android 8.1 / API 27)
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
try {
|
||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as? ClipboardManager
|
||||
if (clipboard != null) {
|
||||
val clip = ClipData.newUri(context.contentResolver, label, getShareableUri(uri))
|
||||
clipboard.setPrimaryClip(clip)
|
||||
result.success(true)
|
||||
} else {
|
||||
result.success(false)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
result.error("copyToClipboard-exception", "failed to set clip", e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ class ImageByteStreamHandler(private val activity: Activity, private val argumen
|
|||
error("streamImage-image-decode-null", "failed to get image from uri=$uri", null)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
error("streamImage-image-decode-exception", "failed to get image from uri=$uri", toErrorDetails(e))
|
||||
error("streamImage-image-decode-exception", "failed to get image from uri=$uri model=$model", toErrorDetails(e))
|
||||
} finally {
|
||||
Glide.with(activity).clear(target)
|
||||
}
|
||||
|
|
|
@ -429,11 +429,15 @@ object StorageUtils {
|
|||
// so we build a typical `images` or `videos` content URI from the original content ID.
|
||||
fun getGlideSafeUri(uri: Uri, mimeType: String): Uri {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && isMediaStoreContentUri(uri)) {
|
||||
uri.tryParseId()?.let { id ->
|
||||
return when {
|
||||
isImage(mimeType) -> ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
|
||||
isVideo(mimeType) -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
|
||||
else -> uri
|
||||
// we cannot safely apply this to a file content URI, as it may point to a file not indexed
|
||||
// by the Media Store (via `.nomedia`), and therefore has no matching image/video content URI
|
||||
if (uri.path?.contains("/downloads/") == true) {
|
||||
uri.tryParseId()?.let { id ->
|
||||
return when {
|
||||
isImage(mimeType) -> ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
|
||||
isVideo(mimeType) -> ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id)
|
||||
else -> uri
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ class AndroidFileUtils {
|
|||
Set<StorageVolume> storageVolumes = {};
|
||||
Set<Package> _packages = {};
|
||||
List<String> _potentialAppDirs = [];
|
||||
bool _initialized = false;
|
||||
|
||||
AChangeNotifier appNameChangeNotifier = AChangeNotifier();
|
||||
|
||||
|
@ -22,6 +23,8 @@ class AndroidFileUtils {
|
|||
AndroidFileUtils._private();
|
||||
|
||||
Future<void> init() async {
|
||||
if (_initialized) return;
|
||||
|
||||
separator = pContext.separator;
|
||||
storageVolumes = await storageService.getStorageVolumes();
|
||||
primaryStorage = storageVolumes.firstWhereOrNull((volume) => volume.isPrimary)?.path ?? separator;
|
||||
|
@ -32,12 +35,16 @@ class AndroidFileUtils {
|
|||
picturesPath = pContext.join(primaryStorage, 'Pictures');
|
||||
// from Aves
|
||||
videoCapturesPath = pContext.join(dcimPath, 'Video Captures');
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
Future<void> initAppNames() async {
|
||||
_packages = await AndroidAppService.getPackages();
|
||||
_potentialAppDirs = _launcherPackages.expand((package) => package.potentialDirs).toList();
|
||||
appNameChangeNotifier.notifyListeners();
|
||||
if (_packages.isEmpty) {
|
||||
_packages = await AndroidAppService.getPackages();
|
||||
_potentialAppDirs = _launcherPackages.expand((package) => package.potentialDirs).toList();
|
||||
appNameChangeNotifier.notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
bool isCameraPath(String path) => path.startsWith(dcimPath) && (path.endsWith('${separator}Camera') || path.endsWith('${separator}100ANDRO'));
|
||||
|
|
|
@ -161,6 +161,7 @@ class _HomePageState extends State<HomePage> {
|
|||
return SearchPageRoute(
|
||||
delegate: CollectionSearchDelegate(
|
||||
source: source,
|
||||
canPop: false,
|
||||
initialQuery: _shortcutSearchQuery,
|
||||
),
|
||||
);
|
||||
|
|
|
@ -28,6 +28,7 @@ class CollectionSearchDelegate {
|
|||
final CollectionSource source;
|
||||
final CollectionLens? parentCollection;
|
||||
final ValueNotifier<String?> expandedSectionNotifier = ValueNotifier(null);
|
||||
final bool canPop;
|
||||
|
||||
static const searchHistoryCount = 10;
|
||||
static final typeFilters = [
|
||||
|
@ -45,13 +46,17 @@ class CollectionSearchDelegate {
|
|||
CollectionSearchDelegate({
|
||||
required this.source,
|
||||
this.parentCollection,
|
||||
this.canPop = true,
|
||||
String? initialQuery,
|
||||
}) {
|
||||
query = initialQuery ?? '';
|
||||
}
|
||||
|
||||
Widget buildLeading(BuildContext context) {
|
||||
return Navigator.canPop(context)
|
||||
// use a property instead of checking `Navigator.canPop(context)`
|
||||
// because the navigator state changes as soon as we press back
|
||||
// so the leading may mistakenly switch to the close button
|
||||
return canPop
|
||||
? IconButton(
|
||||
icon: AnimatedIcon(
|
||||
icon: AnimatedIcons.menu_arrow,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
name: aves
|
||||
description: A visual media gallery and metadata explorer app.
|
||||
repository: https://github.com/deckerst/aves
|
||||
version: 1.4.7+51
|
||||
version: 1.4.8+52
|
||||
publish_to: none
|
||||
|
||||
environment:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Thanks for using Aves!
|
||||
v1.4.7:
|
||||
v1.4.8:
|
||||
- map page
|
||||
- viewer action to copy to clipboard
|
||||
- integration with OS global search
|
||||
|
|
Loading…
Reference in a new issue