Merge branch 'develop'

This commit is contained in:
Thibault Deckers 2021-08-08 15:26:12 +09:00
commit a70057c814
9 changed files with 49 additions and 20 deletions

View file

@ -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

View file

@ -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,6 +143,10 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
return
}
// 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))
@ -149,6 +155,10 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
} else {
result.success(false)
}
} catch (e: Exception) {
result.error("copyToClipboard-exception", "failed to set clip", e.message)
}
}
}
private fun edit(call: MethodCall, result: MethodChannel.Result) {

View file

@ -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)
}

View file

@ -429,6 +429,9 @@ 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)) {
// 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)
@ -437,6 +440,7 @@ object StorageUtils {
}
}
}
}
return uri
}

View file

@ -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,13 +35,17 @@ class AndroidFileUtils {
picturesPath = pContext.join(primaryStorage, 'Pictures');
// from Aves
videoCapturesPath = pContext.join(dcimPath, 'Video Captures');
_initialized = true;
}
Future<void> initAppNames() async {
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'));

View file

@ -161,6 +161,7 @@ class _HomePageState extends State<HomePage> {
return SearchPageRoute(
delegate: CollectionSearchDelegate(
source: source,
canPop: false,
initialQuery: _shortcutSearchQuery,
),
);

View file

@ -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,

View file

@ -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:

View file

@ -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