support Android 13
This commit is contained in:
parent
188a52deb0
commit
c6a5316570
26 changed files with 168 additions and 59 deletions
|
@ -6,7 +6,9 @@ All notable changes to this project will be documented in this file.
|
|||
|
||||
### Added
|
||||
|
||||
- set wallpaper from any media
|
||||
- optional dynamic accent color on Android 12+
|
||||
- support Android 13 (API 33)
|
||||
- Turkish translation (thanks metezd)
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -41,7 +41,7 @@ if (keystorePropertiesFile.exists()) {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 32
|
||||
compileSdkVersion 33
|
||||
|
||||
sourceSets {
|
||||
main.java.srcDirs += 'src/main/kotlin'
|
||||
|
@ -57,7 +57,7 @@ android {
|
|||
// which implementation `DocumentBuilderImpl` is provided by the OS and is not customizable on Android,
|
||||
// but the implementation on API <19 is not robust enough and fails to build XMP documents
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 32
|
||||
targetSdkVersion 33
|
||||
versionCode flutterVersionCode.toInteger()
|
||||
versionName flutterVersionName
|
||||
manifestPlaceholders = [googleApiKey: keystoreProperties['googleApiKey']]
|
||||
|
@ -154,7 +154,7 @@ repositories {
|
|||
|
||||
dependencies {
|
||||
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.2'
|
||||
implementation 'androidx.core:core-ktx:1.7.0'
|
||||
implementation 'androidx.core:core-ktx:1.8.0'
|
||||
implementation 'androidx.exifinterface:exifinterface:1.3.3'
|
||||
implementation 'androidx.multidex:multidex:2.0.1'
|
||||
implementation 'com.caverock:androidsvg-aar:1.4'
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
Scoped storage on Android Q is inconvenient because users need to confirm edition on each individual file.
|
||||
So we request `WRITE_EXTERNAL_STORAGE` until Q (29), and enable `requestLegacyExternalStorage`
|
||||
-->
|
||||
|
||||
<!-- TODO TLAD [tiramisu] need notification permission? -->
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<!-- TODO TLAD [tiramisu] READ_MEDIA_IMAGE, READ_MEDIA_VIDEO instead of READ_EXTERNAL_STORAGE? -->
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
<uses-permission
|
||||
android:name="android.permission.READ_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="32" />
|
||||
<uses-permission
|
||||
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
|
||||
android:maxSdkVersion="29"
|
||||
|
@ -18,6 +18,10 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.SET_WALLPAPER" />
|
||||
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<!-- to show foreground service progress via notification -->
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<!-- to access media with original metadata with scoped storage (Android Q+) -->
|
||||
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
|
||||
|
||||
|
@ -138,6 +142,7 @@
|
|||
<intent-filter>
|
||||
<action android:name="android.intent.action.ATTACH_DATA" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
||||
<data android:mimeType="image/*" />
|
||||
<data android:mimeType="video/*" />
|
||||
</intent-filter>
|
||||
|
|
|
@ -159,7 +159,7 @@ class AnalysisService : MethodChannel.MethodCallHandler, Service() {
|
|||
COMMAND_START -> {
|
||||
runBlocking {
|
||||
FlutterUtils.runOnUiThread {
|
||||
val entryIds = data.get(KEY_ENTRY_IDS)?.takeIf { it is IntArray }?.let { (it as IntArray).toList() }
|
||||
val entryIds = data.getIntArray(KEY_ENTRY_IDS)?.toList()
|
||||
backgroundChannel?.invokeMethod(
|
||||
"start", hashMapOf(
|
||||
"entryIds" to entryIds,
|
||||
|
|
|
@ -15,6 +15,7 @@ import app.loup.streams_channel.StreamsChannel
|
|||
import deckers.thibault.aves.channel.calls.*
|
||||
import deckers.thibault.aves.channel.streams.*
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.getParcelableExtraCompat
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.plugin.common.EventChannel
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
|
@ -215,7 +216,7 @@ class MainActivity : FlutterActivity() {
|
|||
}
|
||||
}
|
||||
Intent.ACTION_VIEW, Intent.ACTION_SEND, "com.android.camera.action.REVIEW" -> {
|
||||
(intent.data ?: (intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri))?.let { uri ->
|
||||
(intent.data ?: intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM))?.let { uri ->
|
||||
// MIME type is optional
|
||||
val type = intent.type ?: intent.resolveType(context)
|
||||
return hashMapOf(
|
||||
|
|
|
@ -8,6 +8,7 @@ import app.loup.streams_channel.StreamsChannel
|
|||
import deckers.thibault.aves.channel.calls.*
|
||||
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.getParcelableExtraCompat
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
|
||||
|
@ -79,7 +80,7 @@ class WallpaperActivity : FlutterActivity() {
|
|||
private fun extractIntentData(intent: Intent?): MutableMap<String, Any?> {
|
||||
when (intent?.action) {
|
||||
Intent.ACTION_ATTACH_DATA, Intent.ACTION_SET_WALLPAPER -> {
|
||||
(intent.data ?: (intent.getParcelableExtra<Parcelable>(Intent.EXTRA_STREAM) as? Uri))?.let { uri ->
|
||||
(intent.data ?: intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM))?.let { uri ->
|
||||
// MIME type is optional
|
||||
val type = intent.type ?: intent.resolveType(context)
|
||||
return hashMapOf(
|
||||
|
|
|
@ -30,6 +30,8 @@ import deckers.thibault.aves.model.FieldMap
|
|||
import deckers.thibault.aves.utils.BitmapUtils
|
||||
import deckers.thibault.aves.utils.BitmapUtils.getBytes
|
||||
import deckers.thibault.aves.utils.LogUtils
|
||||
import deckers.thibault.aves.utils.getApplicationInfoCompat
|
||||
import deckers.thibault.aves.utils.queryIntentActivitiesCompat
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
|
@ -77,7 +79,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
}
|
||||
|
||||
val pm = context.packageManager
|
||||
for (resolveInfo in pm.queryIntentActivities(intent, 0)) {
|
||||
for (resolveInfo in pm.queryIntentActivitiesCompat(intent, 0)) {
|
||||
val appInfo = resolveInfo.activityInfo.applicationInfo
|
||||
val packageName = appInfo.packageName
|
||||
if (!packages.containsKey(packageName)) {
|
||||
|
@ -149,7 +151,7 @@ class AppAdapterHandler(private val context: Context) : MethodCallHandler {
|
|||
val size = (sizeDip * density).roundToInt()
|
||||
var data: ByteArray? = null
|
||||
try {
|
||||
val iconResourceId = context.packageManager.getApplicationInfo(packageName, 0).icon
|
||||
val iconResourceId = context.packageManager.getApplicationInfoCompat(packageName, 0).icon
|
||||
if (iconResourceId != Resources.ID_NULL) {
|
||||
val uri = Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_ANDROID_RESOURCE)
|
||||
|
|
|
@ -1,12 +1,17 @@
|
|||
package deckers.thibault.aves.channel.calls
|
||||
|
||||
import android.content.Context
|
||||
import android.location.Address
|
||||
import android.location.Geocoder
|
||||
import android.os.Build
|
||||
import deckers.thibault.aves.channel.calls.Coresult.Companion.safe
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
|
||||
|
@ -48,36 +53,48 @@ class GeocodingHandler(private val context: Context) : MethodCallHandler {
|
|||
Geocoder(context)
|
||||
}
|
||||
|
||||
val addresses = try {
|
||||
geocoder!!.getFromLocation(latitude, longitude, maxResults) ?: ArrayList()
|
||||
} catch (e: IOException) {
|
||||
// `grpc failed`, etc.
|
||||
result.error("getAddress-network", "failed to get address because of network issues", e.message)
|
||||
return
|
||||
} catch (e: Exception) {
|
||||
result.error("getAddress-exception", "failed to get address", e.message)
|
||||
return
|
||||
fun processAddresses(addresses: List<Address>) {
|
||||
if (addresses.isEmpty()) {
|
||||
result.error("getAddress-empty", "failed to find any address for latitude=$latitude, longitude=$longitude", null)
|
||||
} else {
|
||||
val addressMapList: ArrayList<Map<String, String?>> = ArrayList(addresses.map { address ->
|
||||
hashMapOf(
|
||||
"addressLine" to (0..address.maxAddressLineIndex).joinToString(", ") { i -> address.getAddressLine(i) },
|
||||
"adminArea" to address.adminArea,
|
||||
"countryCode" to address.countryCode,
|
||||
"countryName" to address.countryName,
|
||||
"featureName" to address.featureName,
|
||||
"locality" to address.locality,
|
||||
"postalCode" to address.postalCode,
|
||||
"subAdminArea" to address.subAdminArea,
|
||||
"subLocality" to address.subLocality,
|
||||
"subThoroughfare" to address.subThoroughfare,
|
||||
"thoroughfare" to address.thoroughfare,
|
||||
)
|
||||
})
|
||||
result.success(addressMapList)
|
||||
}
|
||||
}
|
||||
|
||||
if (addresses.isEmpty()) {
|
||||
result.error("getAddress-empty", "failed to find any address for latitude=$latitude, longitude=$longitude", null)
|
||||
} else {
|
||||
val addressMapList: ArrayList<Map<String, String?>> = ArrayList(addresses.map { address ->
|
||||
hashMapOf(
|
||||
"addressLine" to (0..address.maxAddressLineIndex).joinToString(", ") { i -> address.getAddressLine(i) },
|
||||
"adminArea" to address.adminArea,
|
||||
"countryCode" to address.countryCode,
|
||||
"countryName" to address.countryName,
|
||||
"featureName" to address.featureName,
|
||||
"locality" to address.locality,
|
||||
"postalCode" to address.postalCode,
|
||||
"subAdminArea" to address.subAdminArea,
|
||||
"subLocality" to address.subLocality,
|
||||
"subThoroughfare" to address.subThoroughfare,
|
||||
"thoroughfare" to address.thoroughfare,
|
||||
)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
geocoder!!.getFromLocation(latitude, longitude, maxResults, object : Geocoder.GeocodeListener {
|
||||
override fun onGeocode(addresses: List<Address?>) = processAddresses(addresses.filterNotNull())
|
||||
|
||||
override fun onError(errorMessage: String?) {
|
||||
result.error("getAddress-asyncerror", "failed to get address", errorMessage)
|
||||
}
|
||||
})
|
||||
result.success(addressMapList)
|
||||
} else {
|
||||
try {
|
||||
@Suppress("deprecation")
|
||||
val addresses = geocoder!!.getFromLocation(latitude, longitude, maxResults) ?: ArrayList()
|
||||
processAddresses(addresses)
|
||||
} catch (e: IOException) {
|
||||
// `grpc failed`, etc.
|
||||
result.error("getAddress-network", "failed to get address because of network issues", e.message)
|
||||
} catch (e: Exception) {
|
||||
result.error("getAddress-exception", "failed to get address", e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -220,7 +220,7 @@ object ExifInterfaceHelper {
|
|||
// initialize metadata-extractor directories that we will fill
|
||||
// by tags converted from the ExifInterface attributes
|
||||
// so that we can rely on metadata-extractor descriptions
|
||||
val dirs = DirType.values().associate { Pair(it, it.createDirectory()) }
|
||||
val dirs = DirType.values().associateWith { it.createDirectory() }
|
||||
|
||||
// exclude Exif directory when it only includes image size
|
||||
val isUselessExif = fun(it: Map<String, String>): Boolean {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
package deckers.thibault.aves.utils
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.ApplicationInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
|
||||
inline fun <reified T> Intent.getParcelableExtraCompat(name: String): T? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getParcelableExtra(name, T::class.java)
|
||||
} else {
|
||||
@Suppress("deprecation")
|
||||
getParcelableExtra<Parcelable>(name) as? T
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
getApplicationInfo(packageName, PackageManager.ApplicationInfoFlags.of(flags.toLong()))
|
||||
} else {
|
||||
@Suppress("deprecation")
|
||||
getApplicationInfo(packageName, flags)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun PackageManager.queryIntentActivitiesCompat(intent: Intent, flags: Int): List<ResolveInfo> {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
queryIntentActivities(intent, PackageManager.ResolveInfoFlags.of(flags.toLong()))
|
||||
} else {
|
||||
@Suppress("deprecation")
|
||||
queryIntentActivities(intent, flags)
|
||||
}
|
||||
}
|
32
android/app/src/main/res/drawable/ic_launcher_mono.xml
Normal file
32
android/app/src/main/res/drawable/ic_launcher_mono.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="100dp"
|
||||
android:height="100dp"
|
||||
android:viewportWidth="100"
|
||||
android:viewportHeight="100">
|
||||
<group
|
||||
android:scaleX=".44"
|
||||
android:scaleY=".44"
|
||||
android:translateX="28"
|
||||
android:translateY="30">
|
||||
<path
|
||||
android:pathData="M3.925,16.034 L60.825,72.933a2.421,2.421 0.001,0 0,3.423 0l10.604,-10.603a6.789,6.789 90.001,0 0,0 -9.601L34.066,11.942A8.264,8.264 22.5,0 0,28.222 9.522H6.623A3.815,3.815 112.5,0 0,3.925 16.034Z"
|
||||
android:strokeWidth="5"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:pathData="m36.36,65.907v28.743a2.557,2.557 22.5,0 0,4.364 1.808L53.817,83.364a6.172,6.172 90,0 0,0 -8.729L42.532,63.35a3.616,3.616 157.5,0 0,-6.172 2.557z"
|
||||
android:strokeWidth="5"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:pathData="M79.653,40.078V11.335A2.557,2.557 22.5,0 0,75.289 9.527L62.195,22.62a6.172,6.172 90,0 0,0 8.729l11.285,11.285a3.616,3.616 157.5,0 0,6.172 -2.557z"
|
||||
android:strokeWidth="5"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineJoin="round" />
|
||||
<path
|
||||
android:pathData="M96.613,16.867 L89.085,9.339a1.917,1.917 157.5,0 0,-3.273 1.356v6.172a4.629,4.629 45,0 0,4.629 4.629h4.255a2.712,2.712 112.5,0 0,1.917 -4.629z"
|
||||
android:strokeWidth="5"
|
||||
android:strokeColor="#000000"
|
||||
android:strokeLineJoin="round" />
|
||||
</group>
|
||||
</vector>
|
|
@ -2,4 +2,5 @@
|
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_mono" />
|
||||
</adaptive-icon>
|
|
@ -2,4 +2,5 @@
|
|||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@color/ic_launcher_background"/>
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
||||
<monochrome android:drawable="@drawable/ic_launcher_mono" />
|
||||
</adaptive-icon>
|
|
@ -1,17 +1,17 @@
|
|||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.6.21'
|
||||
ext.kotlin_version = '1.7.0'
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven { url 'https://developer.huawei.com/repo/' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.2.0'
|
||||
classpath 'com.android.tools.build:gradle:7.2.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
// GMS & Firebase Crashlytics (used by some flavors only)
|
||||
classpath 'com.google.gms:google-services:4.3.10'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.1'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.0'
|
||||
// HMS (used by some flavors only)
|
||||
classpath 'com.huawei.agconnect:agcp:1.5.2.300'
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>Navigation und Suche</b> ist ein wichtiger Bestandteil von <i>Aves</i>. Das Ziel besteht darin, dass Benutzer problemlos von Alben zu Fotos zu Tags zu Karten usw. wechseln können.
|
||||
|
||||
<i>Aves</i> lässt sich mit Android (von <b>API 19 bis 32</b>, d. h. von KitKat bis Android 12L) mit Funktionen wie <b>App-Verknüpfungen</b> und <b>globaler Suche</b> integrieren. Es funktioniert auch als <b>Medienbetrachter und -auswahl</b>.
|
||||
<i>Aves</i> lässt sich mit Android (von <b>API 19 bis 33</b>, d. h. von KitKat bis Android 13) mit Funktionen wie <b>App-Verknüpfungen</b> und <b>globaler Suche</b> integrieren. Es funktioniert auch als <b>Medienbetrachter und -auswahl</b>.
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>Navigation and search</b> is an important part of <i>Aves</i>. The goal is for users to easily flow from albums to photos to tags to maps, etc.
|
||||
|
||||
<i>Aves</i> integrates with Android (from <b>API 19 to 32</b>, i.e. from KitKat to Android 12L) with features such as <b>app shortcuts</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
||||
<i>Aves</i> integrates with Android (from <b>API 19 to 33</b>, i.e. from KitKat to Android 13) with features such as <b>app shortcuts</b> and <b>global search</b> handling. It also works as a <b>media viewer and picker</b>.
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
La <b>navegación y búsqueda</b> son partes importantes de <i>Aves</i>. Su propósito es que los usuarios puedan fácimente ir de álbumes a fotos, etiquetas, mapas, etc.
|
||||
|
||||
<i>Aves</i> se integra con Android (desde <b>API 19 a 32</b>, por ej. desde KitKat hasta Android 12L) con características como <b>vínculos de aplicación</b> y manejo de <b>búsqueda global</b>. También funciona como un <b>visor y seleccionador multimedia</b>.
|
||||
<i>Aves</i> se integra con Android (desde <b>API 19 a 33</b>, por ej. desde KitKat hasta Android 13) con características como <b>vínculos de aplicación</b> y manejo de <b>búsqueda global</b>. También funciona como un <b>visor y seleccionador multimedia</b>.
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>Navigasi dan pencarian</b> merupakan bagian penting dari <i>Aves</i>. Tujuannya adalah agar pengguna dengan mudah mengalir dari album ke foto ke tag ke peta, dll.
|
||||
|
||||
<i>Aves</i> terintegrasi dengan Android (dari <b>API 19 ke 32</b>, yaitu dari KitKat ke Android 12L) dengan fitur-fitur seperti <b>pintasan aplikasi</b> dan <b>pencarian global</b> penanganan. Ini juga berfungsi sebagai <b>penampil dan pemilih media</b>.
|
||||
<i>Aves</i> terintegrasi dengan Android (dari <b>API 19 ke 33</b>, yaitu dari KitKat ke Android 13) dengan fitur-fitur seperti <b>pintasan aplikasi</b> dan <b>pencarian global</b> penanganan. Ini juga berfungsi sebagai <b>penampil dan pemilih media</b>.
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>Navigazione e ricerca</b> sono una parte importante di <i>Aves</i>. L'obiettivo è che gli utenti passino facilmente dagli album alle foto, ai tag, alle mappe, ecc.
|
||||
|
||||
<i>Aves</i> si integra con Android (da <b>API 19 a 32</b>, cioè da KitKat ad Android 12L) con caratteristiche come <b>collegamenti alle app</b> e la gestione della <b>ricerca globale</b>. Funziona anche come <b>visualizzazione e raccolta di media</b>.
|
||||
<i>Aves</i> si integra con Android (da <b>API 19 a 33</b>, cioè da KitKat ad Android 13) con caratteristiche come <b>collegamenti alle app</b> e la gestione della <b>ricerca globale</b>. Funziona anche come <b>visualizzazione e raccolta di media</b>.
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
<b>ナビゲーションと検索</b>は、Avesの重要な部分です。アルバムから写真、タグ、地図などへ簡単に移動できます。
|
||||
|
||||
<i>Aves</i>は、<b>アプリショートカット</b>や<b>グローバル検索</b>などの機能を、Android(<b>API 19から32まで</b>、つまりAndroid 4.4から12 Lまで)と統合しています。また、<b>メディアビューワー</b>や<b>メディアピッカー</b>としても機能します。
|
||||
<i>Aves</i>は、<b>アプリショートカット</b>や<b>グローバル検索</b>などの機能を、Android(<b>API 19から33まで</b>、つまりAndroid 4.4から13 Lまで)と統合しています。また、<b>メディアビューワー</b>や<b>メディアピッカー</b>としても機能します。
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>Navegação e pesquisa</b> é uma parte importante do <i>Aves</i>. O objetivo é que os usuários fluam facilmente de álbuns para fotos, etiquetas, mapas, etc.
|
||||
|
||||
<i>Aves</i> integra com Android (de <b>API 19 para 32</b>, i.e. de KitKat para Android 12L) com recursos como <b>atalhos de apps</b> e <b>pesquisa global</b> manipulação. Também funciona como um <b>visualizador e selecionador de mídia</b>.
|
||||
<i>Aves</i> integra com Android (de <b>API 19 para 33</b>, i.e. de KitKat para Android 13) com recursos como <b>atalhos de apps</b> e <b>pesquisa global</b> manipulação. Também funciona como um <b>visualizador e selecionador de mídia</b>.
|
||||
|
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>Gezinme ve arama</b> <i>Aves'in</i> önemli bir parçasıdır. Amaç, kullanıcıların albümlerden fotoğraflara, etiketlerden haritalara vb. kolayca geçmesini sağlamaktır.
|
||||
|
||||
<i>Aves</i>, <b>uygulama kısayolları</b> ve <b>global arama<b> işleme gibi özelliklerle Android (<b>API 19'dan 32'ye</b>, yani KitKat'tan Android 12L'ye kadar) ile entegre olur. Ayrıca bir <b>medya görüntüleyici ve alıcı</b> olarak da çalışır.
|
||||
<i>Aves</i>, <b>uygulama kısayolları</b> ve <b>global arama<b> işleme gibi özelliklerle Android (<b>API 19'dan 33'ye</b>, yani KitKat'tan Android 13'ye kadar) ile entegre olur. Ayrıca bir <b>medya görüntüleyici ve alıcı</b> olarak da çalışır.
|
|
@ -2,4 +2,4 @@
|
|||
|
||||
<b>导航与搜索</b>是 <i>Aves</i> 的核心功能之一,旨在帮助用户在相册、照片、标签、地图等之间轻松切换。
|
||||
|
||||
<i> Aves</i> 与 Android(<b>API 19-32</b>,即从 KitKat 到 Android 12L)集成,具有<b>快捷方式</b>和<b>全局搜索</b>等功能。它还可用作<b>媒体查看器和选择器<b>。
|
||||
<i> Aves</i> 与 Android(<b>API 19-33</b>,即从 KitKat 到 Android 13)集成,具有<b>快捷方式</b>和<b>全局搜索</b>等功能。它还可用作<b>媒体查看器和选择器<b>。
|
||||
|
|
|
@ -416,6 +416,7 @@ abstract class CollectionSource with SourceBase, AlbumMixin, LocationMixin, TagM
|
|||
}
|
||||
}
|
||||
if (startAnalysisService) {
|
||||
// TODO TLAD [tiramisu] explain foreground service and request POST_NOTIFICATIONS permission
|
||||
await AnalysisService.startService(
|
||||
force: force,
|
||||
entryIds: entries?.map((entry) => entry.id).toList(),
|
||||
|
|
10
pubspec.lock
10
pubspec.lock
|
@ -785,11 +785,13 @@ packages:
|
|||
source: hosted
|
||||
version: "9.2.0"
|
||||
permission_handler_android:
|
||||
dependency: transitive
|
||||
dependency: "direct overridden"
|
||||
description:
|
||||
name: permission_handler_android
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
path: permission_handler_android
|
||||
ref: HEAD
|
||||
resolved-ref: "279cf44656272c6b89c73b16097108f3c973c31f"
|
||||
url: "https://github.com/deckerst/flutter-permission-handler"
|
||||
source: git
|
||||
version: "9.0.2+1"
|
||||
permission_handler_apple:
|
||||
dependency: transitive
|
||||
|
|
|
@ -84,6 +84,13 @@ dependencies:
|
|||
url_launcher:
|
||||
xml:
|
||||
|
||||
dependency_overrides:
|
||||
# TODO TLAD as of 2022/06/11, latest version (v9.0.2+1) does not support Android 13 storage permissions
|
||||
permission_handler_android:
|
||||
git:
|
||||
url: https://github.com/deckerst/flutter-permission-handler
|
||||
path: permission_handler_android
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
sdk: flutter
|
||||
|
|
Loading…
Reference in a new issue