diff --git a/.flutter b/.flutter
index 54e66469a..5dcb86f68 160000
--- a/.flutter
+++ b/.flutter
@@ -1 +1 @@
-Subproject commit 54e66469a933b60ddf175f858f82eaeb97e48c8d
+Subproject commit 5dcb86f68f239346676ceb1ed1ea385bd215fba1
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b09bea370..a41aac3eb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
+### Changed
+
+- upgraded Flutter to stable v3.22.0
+
+### Removed
+
+- support for Android KitKat (API 19)
+
## [v1.11.1] - 2024-05-03
### Added
diff --git a/android/app/build.gradle b/android/app/build.gradle
index 4c588fa0e..7175da16d 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -66,9 +66,6 @@ android {
defaultConfig {
applicationId packageName
- // minSdk constraints:
- // - Flutter & other plugins: 19 (cf `flutter.minSdkVersion`)
- // - google_maps_flutter v2.1.1: 20
minSdk flutter.minSdkVersion
targetSdk 34
versionCode flutterVersionCode.toInteger()
@@ -201,7 +198,7 @@ dependencies {
implementation "androidx.appcompat:appcompat:1.6.1"
implementation 'androidx.core:core-ktx:1.13.1'
- implementation 'androidx.lifecycle:lifecycle-process:2.7.0'
+ implementation 'androidx.lifecycle:lifecycle-process:2.8.0'
implementation 'androidx.media:media:1.7.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.security:security-crypto:1.1.0-alpha06'
@@ -229,7 +226,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.2'
- kapt 'androidx.annotation:annotation:1.7.1'
+ kapt 'androidx.annotation:annotation:1.8.0'
ksp "com.github.bumptech.glide:ksp:$glide_version"
compileOnly rootProject.findProject(':streams_channel')
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 5e2437a2b..e0a82ddb2 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -72,12 +72,10 @@
-->
-
+
@@ -321,8 +319,8 @@
-
+
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt b/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt
index d7be83a8c..a0c1a0ab9 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/AnalysisWorker.kt
@@ -161,13 +161,12 @@ class AnalysisWorker(context: Context, parameters: WorkerParameters) : Coroutine
applicationContext.getString(R.string.analysis_notification_action_stop),
WorkManager.getInstance(applicationContext).createCancelPendingIntent(id)
).build()
- val icon = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) R.drawable.ic_notification else R.mipmap.ic_launcher_round
val contentTitle = title ?: applicationContext.getText(R.string.analysis_notification_default_title)
val notification = NotificationCompat.Builder(applicationContext, NOTIFICATION_CHANNEL)
.setContentTitle(contentTitle)
.setTicker(contentTitle)
.setContentText(message)
- .setSmallIcon(icon)
+ .setSmallIcon(R.drawable.ic_notification)
.setOngoing(true)
.setContentIntent(openAppIntent)
.addAction(stopAction)
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/HomeWidgetConfigureActivity.kt b/android/app/src/main/kotlin/deckers/thibault/aves/HomeWidgetConfigureActivity.kt
index 5d1518fcc..dad5ed84e 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/HomeWidgetConfigureActivity.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/HomeWidgetConfigureActivity.kt
@@ -4,8 +4,6 @@ import android.appwidget.AppWidgetManager
import android.content.Intent
import android.os.Bundle
import deckers.thibault.aves.model.FieldMap
-import deckers.thibault.aves.utils.FlutterUtils
-import deckers.thibault.aves.utils.FlutterUtils.enableSoftwareRendering
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
@@ -13,9 +11,6 @@ class HomeWidgetSettingsActivity : MainActivity() {
private var appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID
public override fun onCreate(savedInstanceState: Bundle?) {
- if (FlutterUtils.isSoftwareRenderingRequired()) {
- intent.enableSoftwareRendering()
- }
super.onCreate(savedInstanceState)
// cancel if user does not complete widget setup
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt b/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt
index c54b6820c..c6858f552 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/MainActivity.kt
@@ -17,13 +17,37 @@ import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import app.loup.streams_channel.StreamsChannel
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
-import deckers.thibault.aves.channel.calls.*
+import deckers.thibault.aves.channel.calls.AccessibilityHandler
+import deckers.thibault.aves.channel.calls.AnalysisHandler
+import deckers.thibault.aves.channel.calls.AppAdapterHandler
+import deckers.thibault.aves.channel.calls.DebugHandler
+import deckers.thibault.aves.channel.calls.DeviceHandler
+import deckers.thibault.aves.channel.calls.EmbeddedDataHandler
+import deckers.thibault.aves.channel.calls.GeocodingHandler
+import deckers.thibault.aves.channel.calls.GlobalSearchHandler
+import deckers.thibault.aves.channel.calls.HomeWidgetHandler
+import deckers.thibault.aves.channel.calls.MediaEditHandler
+import deckers.thibault.aves.channel.calls.MediaFetchBytesHandler
+import deckers.thibault.aves.channel.calls.MediaFetchObjectHandler
+import deckers.thibault.aves.channel.calls.MediaSessionHandler
+import deckers.thibault.aves.channel.calls.MediaStoreHandler
+import deckers.thibault.aves.channel.calls.MetadataEditHandler
+import deckers.thibault.aves.channel.calls.MetadataFetchHandler
+import deckers.thibault.aves.channel.calls.SecurityHandler
+import deckers.thibault.aves.channel.calls.StorageHandler
import deckers.thibault.aves.channel.calls.window.ActivityWindowHandler
import deckers.thibault.aves.channel.calls.window.WindowHandler
-import deckers.thibault.aves.channel.streams.*
+import deckers.thibault.aves.channel.streams.ActivityResultStreamHandler
+import deckers.thibault.aves.channel.streams.AnalysisStreamHandler
+import deckers.thibault.aves.channel.streams.ErrorStreamHandler
+import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
+import deckers.thibault.aves.channel.streams.ImageOpStreamHandler
+import deckers.thibault.aves.channel.streams.IntentStreamHandler
+import deckers.thibault.aves.channel.streams.MediaCommandStreamHandler
+import deckers.thibault.aves.channel.streams.MediaStoreChangeStreamHandler
+import deckers.thibault.aves.channel.streams.MediaStoreStreamHandler
+import deckers.thibault.aves.channel.streams.SettingsChangeStreamHandler
import deckers.thibault.aves.model.FieldMap
-import deckers.thibault.aves.utils.FlutterUtils.enableSoftwareRendering
-import deckers.thibault.aves.utils.FlutterUtils.isSoftwareRenderingRequired
import deckers.thibault.aves.utils.LogUtils
import deckers.thibault.aves.utils.getParcelableExtraCompat
import io.flutter.embedding.android.FlutterFragmentActivity
@@ -52,13 +76,6 @@ open class MainActivity : FlutterFragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
Log.i(LOG_TAG, "onCreate intent=$intent")
- if (isSoftwareRenderingRequired()) {
- intent.enableSoftwareRendering()
- // running the app from Android Studio automatically adds to the intent the `start-paused` flag
- // so the IDE can connect to the app, but launching on KitKat emulators fails because of a timeout
- intent.removeExtra("start-paused")
- }
-
intent.extras?.takeUnless { it.isEmpty }?.let {
Log.i(LOG_TAG, "onCreate intent extras=$it")
}
@@ -168,11 +185,9 @@ open class MainActivity : FlutterFragmentActivity() {
// as of Flutter v3.0.1, the window `viewInsets` and `viewPadding`
// are incorrect on startup in some environments (e.g. API 29 emulator),
// so we manually request to apply the insets to update the window metrics
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
- Handler(Looper.getMainLooper()).postDelayed({
- window.decorView.requestApplyInsets()
- }, 100)
- }
+ Handler(Looper.getMainLooper()).postDelayed({
+ window.decorView.requestApplyInsets()
+ }, 100)
}
override fun onStop() {
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt b/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt
index 4429cd878..c7f2f8fd4 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/SearchSuggestionsProvider.kt
@@ -34,7 +34,7 @@ class SearchSuggestionsProvider : ContentProvider() {
val columns = arrayOf(
SearchManager.SUGGEST_COLUMN_INTENT_DATA,
SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA,
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) SearchManager.SUGGEST_COLUMN_CONTENT_TYPE else "mimeType",
+ SearchManager.SUGGEST_COLUMN_CONTENT_TYPE,
SearchManager.SUGGEST_COLUMN_TEXT_1,
SearchManager.SUGGEST_COLUMN_TEXT_2,
SearchManager.SUGGEST_COLUMN_ICON_1,
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/WallpaperActivity.kt b/android/app/src/main/kotlin/deckers/thibault/aves/WallpaperActivity.kt
index c37539172..4aa32be1a 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/WallpaperActivity.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/WallpaperActivity.kt
@@ -2,21 +2,26 @@ package deckers.thibault.aves
import android.content.Intent
import android.net.Uri
-import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.util.Log
import app.loup.streams_channel.StreamsChannel
import deckers.thibault.aves.channel.AvesByteSendingMethodCodec
-import deckers.thibault.aves.channel.calls.*
+import deckers.thibault.aves.channel.calls.AccessibilityHandler
+import deckers.thibault.aves.channel.calls.DeviceHandler
+import deckers.thibault.aves.channel.calls.EmbeddedDataHandler
+import deckers.thibault.aves.channel.calls.MediaFetchBytesHandler
+import deckers.thibault.aves.channel.calls.MediaFetchObjectHandler
+import deckers.thibault.aves.channel.calls.MediaSessionHandler
+import deckers.thibault.aves.channel.calls.MetadataFetchHandler
+import deckers.thibault.aves.channel.calls.StorageHandler
+import deckers.thibault.aves.channel.calls.WallpaperHandler
import deckers.thibault.aves.channel.calls.window.ActivityWindowHandler
import deckers.thibault.aves.channel.calls.window.WindowHandler
import deckers.thibault.aves.channel.streams.ImageByteStreamHandler
import deckers.thibault.aves.channel.streams.MediaCommandStreamHandler
import deckers.thibault.aves.model.FieldMap
-import deckers.thibault.aves.utils.FlutterUtils
-import deckers.thibault.aves.utils.FlutterUtils.enableSoftwareRendering
import deckers.thibault.aves.utils.LogUtils
import deckers.thibault.aves.utils.getParcelableExtraCompat
import io.flutter.embedding.android.FlutterFragmentActivity
@@ -30,9 +35,6 @@ class WallpaperActivity : FlutterFragmentActivity() {
private lateinit var mediaSessionHandler: MediaSessionHandler
override fun onCreate(savedInstanceState: Bundle?) {
- if (FlutterUtils.isSoftwareRenderingRequired()) {
- intent.enableSoftwareRendering()
- }
super.onCreate(savedInstanceState)
Log.i(LOG_TAG, "onCreate intent=$intent")
@@ -83,11 +85,9 @@ class WallpaperActivity : FlutterFragmentActivity() {
// as of Flutter v3.0.1, the window `viewInsets` and `viewPadding`
// are incorrect on startup in some environments (e.g. API 29 emulator),
// so we manually request to apply the insets to update the window metrics
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
- Handler(Looper.getMainLooper()).postDelayed({
- window.decorView.requestApplyInsets()
- }, 100)
- }
+ Handler(Looper.getMainLooper()).postDelayed({
+ window.decorView.requestApplyInsets()
+ }, 100)
}
override fun onDestroy() {
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt
index c640d31c7..21b7dd13e 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/AnalysisHandler.kt
@@ -1,7 +1,7 @@
package deckers.thibault.aves.channel.calls
import android.content.Context
-import androidx.core.app.ComponentActivity
+import androidx.activity.ComponentActivity
import androidx.work.ExistingWorkPolicy
import androidx.work.OneTimeWorkRequest
import androidx.work.OneTimeWorkRequestBuilder
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt
index 3292bb715..fd36169d4 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DebugHandler.kt
@@ -79,15 +79,9 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
"obbDir" to context.obbDir,
"externalCacheDir" to context.externalCacheDir,
"externalFilesDir" to context.getExternalFilesDir(null),
+ "codeCacheDir" to context.codeCacheDir,
+ "noBackupFilesDir" to context.noBackupFilesDir,
).apply {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- putAll(
- hashMapOf(
- "codeCacheDir" to context.codeCacheDir,
- "noBackupFilesDir" to context.noBackupFilesDir,
- )
- )
- }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
put("dataDir", context.dataDir)
}
@@ -108,8 +102,6 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
}
private fun getCodecs(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
- val codecs = ArrayList()
-
fun getFields(info: MediaCodecInfo): FieldMap {
val fields: FieldMap = hashMapOf(
"name" to info.name,
@@ -126,18 +118,7 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
return fields
}
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- codecs.addAll(MediaCodecList(MediaCodecList.REGULAR_CODECS).codecInfos.map(::getFields))
- } else {
- @Suppress("deprecation")
- val count = MediaCodecList.getCodecCount()
- for (i in 0 until count) {
- @Suppress("deprecation")
- val info = MediaCodecList.getCodecInfoAt(i)
- codecs.add(getFields(info))
- }
- }
-
+ val codecs = MediaCodecList(MediaCodecList.REGULAR_CODECS).codecInfos.map(::getFields).toList()
result.success(codecs)
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt
index 3b1306a99..603739bde 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/DeviceHandler.kt
@@ -69,16 +69,11 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
}
private fun getLocales(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
- fun toMap(locale: Locale): FieldMap {
- val fields: HashMap = hashMapOf(
- "language" to locale.language,
- "country" to locale.country,
- )
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- fields["script"] = locale.script
- }
- return fields
- }
+ fun toMap(locale: Locale): FieldMap = hashMapOf(
+ "language" to locale.language,
+ "country" to locale.country,
+ "script" to locale.script,
+ )
val locales = ArrayList()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
@@ -106,11 +101,7 @@ class DeviceHandler(private val context: Context) : MethodCallHandler {
}
private fun isSystemFilePickerEnabled(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
- val enabled = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).resolveActivity(context.packageManager) != null
- } else {
- false
- }
+ val enabled = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).resolveActivity(context.packageManager) != null
result.success(enabled)
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/StorageHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/StorageHandler.kt
index 81da9f0b0..4d0001ce0 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/StorageHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/calls/StorageHandler.kt
@@ -47,9 +47,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
private fun getDataUsage(@Suppress("unused_parameter") call: MethodCall, result: MethodChannel.Result) {
var internalCache = getFolderSize(context.cacheDir)
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- internalCache += getFolderSize(context.codeCacheDir)
- }
+ internalCache += getFolderSize(context.codeCacheDir)
val externalCache = context.externalCacheDirs.map(::getFolderSize).sum()
val dataDir = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) context.dataDir else File(context.applicationInfo.dataDir)
@@ -105,12 +103,7 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
val volumeFile = File(volumePath)
try {
val isPrimary = volumePath == primaryVolumePath
- val isRemovable = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- Environment.isExternalStorageRemovable(volumeFile)
- } else {
- // random guess
- !isPrimary
- }
+ val isRemovable = Environment.isExternalStorageRemovable(volumeFile)
volumes.add(
hashMapOf(
"path" to volumePath,
@@ -202,11 +195,6 @@ class StorageHandler(private val context: Context) : MethodCallHandler {
return
}
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- result.error("revokeDirectoryAccess-unsupported", "volume access is not allowed before Android Lollipop", null)
- return
- }
-
val success = PermissionManager.revokeDirectoryAccess(context, path)
result.success(success)
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ActivityResultStreamHandler.kt b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ActivityResultStreamHandler.kt
index 7d442e98b..29005f9ae 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ActivityResultStreamHandler.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/channel/streams/ActivityResultStreamHandler.kt
@@ -61,11 +61,6 @@ class ActivityResultStreamHandler(private val activity: Activity, arguments: Any
return
}
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
- error("requestDirectoryAccess-unsupported", "directory access is not allowed before Android Lollipop", null)
- return
- }
-
PermissionManager.requestDirectoryAccess(activity, ensureTrailingSeparator(path), {
success(true)
endOfStream()
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/ExifInterfaceHelper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/ExifInterfaceHelper.kt
index ce361ea32..f0d28fb3e 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/ExifInterfaceHelper.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/ExifInterfaceHelper.kt
@@ -4,14 +4,18 @@ import android.util.Log
import androidx.exifinterface.media.ExifInterface
import com.drew.lang.Rational
import com.drew.metadata.Directory
-import com.drew.metadata.exif.*
+import com.drew.metadata.exif.ExifDirectoryBase
+import com.drew.metadata.exif.ExifIFD0Directory
+import com.drew.metadata.exif.ExifThumbnailDirectory
+import com.drew.metadata.exif.GpsDirectory
+import com.drew.metadata.exif.PanasonicRawIFD0Directory
import com.drew.metadata.exif.makernotes.OlympusCameraSettingsMakernoteDirectory
import com.drew.metadata.exif.makernotes.OlympusImageProcessingMakernoteDirectory
import com.drew.metadata.exif.makernotes.OlympusMakernoteDirectory
import deckers.thibault.aves.utils.LogUtils
import java.text.ParseException
import java.text.SimpleDateFormat
-import java.util.*
+import java.util.Locale
import kotlin.math.abs
import kotlin.math.floor
import kotlin.math.roundToLong
@@ -22,7 +26,7 @@ object ExifInterfaceHelper {
val GPS_DATE_FORMAT = SimpleDateFormat("yyyy:MM:dd", Locale.ROOT)
val GPS_TIME_FORMAT = SimpleDateFormat("HH:mm:ss", Locale.ROOT)
- private const val precisionErrorTolerance = 1e-10
+ private const val PRECISION_ERROR_TOLERANCE = 1e-10
// ExifInterface always states it has the following attributes
// and returns "0" instead of "null" when they are actually missing
@@ -220,7 +224,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().associateWith { it.createDirectory() }
+ val dirs = DirType.entries.associateWith { it.createDirectory() }
// exclude Exif directory when it only includes image size
val isUselessExif = fun(it: Map): Boolean {
@@ -308,7 +312,7 @@ object ExifInterfaceHelper {
val numerator = 1L
val f = numerator / d
val denominator = f.roundToLong()
- if (abs(f - denominator) < precisionErrorTolerance) {
+ if (abs(f - denominator) < PRECISION_ERROR_TOLERANCE) {
return Rational(numerator, denominator)
}
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt
index 5ebe7537a..0d2608a06 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/Helper.kt
@@ -60,7 +60,7 @@ object Helper {
private val PNG_RAW_PROFILE_PATTERN = Regex("^\\n(.*?)\\n\\s*(\\d+)\\n(.*)", RegexOption.DOT_MATCHES_ALL)
// providing the stream length is risky, as it may crash if it is incorrect
- private const val safeReadStreamLength = -1L
+ private const val SAFE_READ_STREAM_LENGTH = -1L
fun readMimeType(input: InputStream): String? {
val bufferedInputStream = if (input is BufferedInputStream) input else BufferedInputStream(input)
@@ -84,7 +84,7 @@ object Helper {
FileType.Orf,
FileType.Rw2 -> safeReadTiff(inputStream)
- else -> ImageMetadataReader.readMetadata(inputStream, safeReadStreamLength, fileType)
+ else -> ImageMetadataReader.readMetadata(inputStream, SAFE_READ_STREAM_LENGTH, fileType)
}
metadata.addDirectory(FileTypeDirectory(fileType))
@@ -116,7 +116,7 @@ object Helper {
@Throws(IOException::class, TiffProcessingException::class)
fun safeReadTiff(input: InputStream): com.drew.metadata.Metadata {
- val reader = RandomAccessStreamReader(input, RandomAccessStreamReader.DEFAULT_CHUNK_LENGTH, safeReadStreamLength)
+ val reader = RandomAccessStreamReader(input, RandomAccessStreamReader.DEFAULT_CHUNK_LENGTH, SAFE_READ_STREAM_LENGTH)
val metadata = com.drew.metadata.Metadata()
val handler = SafeExifTiffHandler(metadata, null, 0)
TiffReader().processTiff(reader, handler, 0)
@@ -294,9 +294,7 @@ object Helper {
if (!modelTiePoints && !modelTransformation) return false
val modelPixelScale = this.containsTag(ExifGeoTiffTags.TAG_MODEL_PIXEL_SCALE)
- if ((modelTransformation && modelPixelScale) || (modelPixelScale && !modelTiePoints)) return false
-
- return true
+ return !((modelTransformation && modelPixelScale) || (modelPixelScale && !modelTiePoints))
}
// TODO TLAD use `GeoTiffDirectory` from the Java version of `metadata-extractor` when available
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafePngMetadataReader.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafePngMetadataReader.kt
index 97498c0e4..719f08a95 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafePngMetadataReader.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafePngMetadataReader.kt
@@ -31,6 +31,7 @@ import deckers.thibault.aves.utils.LogUtils
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
+import java.util.Locale
import java.util.zip.InflaterInputStream
import java.util.zip.ZipException
@@ -42,7 +43,7 @@ object SafePngMetadataReader {
private val LOG_TAG = LogUtils.createTag()
// arbitrary size to detect chunks that may yield an OOM
- private const val chunkSizeDangerThreshold = SafeXmpReader.SEGMENT_TYPE_SIZE_DANGER_THRESHOLD
+ private const val CHUNK_SIZE_DANGER_THRESHOLD = SafeXmpReader.SEGMENT_TYPE_SIZE_DANGER_THRESHOLD
private val latin1Encoding = Charsets.ISO_8859_1
private val utf8Encoding = Charsets.UTF_8
@@ -85,7 +86,7 @@ object SafePngMetadataReader {
val bytes = chunk.bytes
// TLAD insert start
- if (bytes.size > chunkSizeDangerThreshold) {
+ if (bytes.size > CHUNK_SIZE_DANGER_THRESHOLD) {
Log.w(LOG_TAG, "PNG chunk $chunkType is too large, with a size of ${bytes.size} B")
return
}
@@ -290,11 +291,12 @@ object SafePngMetadataReader {
val second = reader.uInt8.toInt()
val directory = PngDirectory(PngChunkType.tIME)
if (DateUtil.isValidDate(year, month - 1, day) && DateUtil.isValidTime(hour, minute, second)) {
- val dateString = String.format("%04d:%02d:%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
+ val dateString = String.format(Locale.ROOT, "%04d:%02d:%02d %02d:%02d:%02d", year, month, day, hour, minute, second)
directory.setString(PngDirectory.TAG_LAST_MODIFICATION_TIME, dateString)
} else {
directory.addError(
String.format(
+ Locale.ROOT,
"PNG tIME data describes an invalid date/time: year=%d month=%d day=%d hour=%d minute=%d second=%d",
year, month, day, hour, minute, second
)
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafeXmpReader.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafeXmpReader.kt
index e36402907..603e3edba 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafeXmpReader.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/SafeXmpReader.kt
@@ -16,6 +16,7 @@ import com.drew.metadata.xmp.XmpDirectory
import com.drew.metadata.xmp.XmpReader
import deckers.thibault.aves.utils.LogUtils
import java.io.IOException
+import java.util.Locale
class SafeXmpReader : XmpReader() {
// adapted from `XmpReader` to detect and skip large extended XMP
@@ -133,7 +134,7 @@ class SafeXmpReader : XmpReader() {
System.arraycopy(segmentBytes, totalOffset, extendedXMPBuffer, chunkOffset, segmentLength - totalOffset)
} else {
val directory = XmpDirectory()
- directory.addError(String.format("Inconsistent length for the Extended XMP buffer: %d instead of %d", fullLength, extendedXMPBuffer.size))
+ directory.addError(String.format(Locale.ROOT, "Inconsistent length for the Extended XMP buffer: %d instead of %d", fullLength, extendedXMPBuffer.size))
metadata.addDirectory(directory)
}
}
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/mpf/MpfDirectory.kt b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/mpf/MpfDirectory.kt
index 53904b56f..c0ea08c38 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/mpf/MpfDirectory.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/metadata/metadataextractor/mpf/MpfDirectory.kt
@@ -16,8 +16,6 @@ class MpfDirectory : Directory() {
return _tagNameMap
}
- fun getNumberOfImages() = getInt(TAG_NUMBER_OF_IMAGES)
-
companion object {
const val TAG_MPF_VERSION = 0xb000
const val TAG_NUMBER_OF_IMAGES = 0xb001
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/model/AvesEntry.kt b/android/app/src/main/kotlin/deckers/thibault/aves/model/AvesEntry.kt
index 424fdb08a..8d41846ab 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/model/AvesEntry.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/model/AvesEntry.kt
@@ -15,7 +15,7 @@ class AvesEntry(map: FieldMap) {
val trashed = map["trashed"] as Boolean
val trashPath = map["trashPath"] as String?
- val isRotated: Boolean
+ private val isRotated: Boolean
get() = rotationDegrees % 180 == 90
val displayWidth: Int
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/FlutterUtils.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/FlutterUtils.kt
index d3c56d23c..e7b179259 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/FlutterUtils.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/FlutterUtils.kt
@@ -1,8 +1,6 @@
package deckers.thibault.aves.utils
import android.content.Context
-import android.content.Intent
-import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
@@ -71,29 +69,4 @@ object FlutterUtils {
r.run()
}
}
-
- fun Intent.enableSoftwareRendering() {
- putExtra("enable-software-rendering", true)
- Log.i(LOG_TAG, "Enable software rendering")
- }
-
- fun isSoftwareRenderingRequired() = Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT && isEmulator
-
- private val isEmulator: Boolean
- get() = (Build.BRAND.startsWith("generic") && Build.DEVICE.startsWith("generic")
- || Build.FINGERPRINT.startsWith("generic")
- || Build.FINGERPRINT.startsWith("unknown")
- || Build.HARDWARE.contains("goldfish")
- || Build.HARDWARE.contains("ranchu")
- || Build.MODEL.contains("google_sdk")
- || Build.MODEL.contains("Emulator")
- || Build.MODEL.contains("Android SDK built for x86")
- || Build.MANUFACTURER.contains("Genymotion")
- || Build.PRODUCT.contains("sdk_google")
- || Build.PRODUCT.contains("google_sdk")
- || Build.PRODUCT.contains("sdk")
- || Build.PRODUCT.contains("sdk_x86")
- || Build.PRODUCT.contains("vbox86p")
- || Build.PRODUCT.contains("emulator")
- || Build.PRODUCT.contains("simulator"))
}
\ No newline at end of file
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt
index 91e5dd4d5..4ae662b5f 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/PermissionManager.kt
@@ -28,7 +28,6 @@ object PermissionManager {
Environment.DIRECTORY_PICTURES,
)
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
suspend fun requestDirectoryAccess(activity: Activity, path: String, onGranted: (uri: Uri) -> Unit, onDenied: () -> Unit) {
Log.i(LOG_TAG, "request user to select and grant access permission to path=$path")
@@ -151,7 +150,6 @@ object PermissionManager {
}
}
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun revokeDirectoryAccess(context: Context, path: String): Boolean {
return StorageUtils.convertDirPathToTreeDocumentUri(context, path)?.let {
releaseUriPermission(context, it)
@@ -162,11 +160,9 @@ object PermissionManager {
// returns paths matching directory URIs granted by the user
fun getGrantedDirs(context: Context): Set {
val grantedDirs = HashSet()
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- for (uriPermission in context.contentResolver.persistedUriPermissions) {
- val dirPath = StorageUtils.convertTreeDocumentUriToDirPath(context, uriPermission.uri)
- dirPath?.let { grantedDirs.add(it) }
- }
+ for (uriPermission in context.contentResolver.persistedUriPermissions) {
+ val dirPath = StorageUtils.convertTreeDocumentUriToDirPath(context, uriPermission.uri)
+ dirPath?.let { grantedDirs.add(it) }
}
return grantedDirs
}
@@ -216,19 +212,6 @@ object PermissionManager {
)
})
}
- } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT
- || Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT_WATCH
- ) {
- // removable storage requires access permission, at the file level
- // without directory access, we consider the whole volume restricted
- val primaryVolume = StorageUtils.getPrimaryVolumePath(context)
- val nonPrimaryVolumes = StorageUtils.getVolumePaths(context).filter { it != primaryVolume }
- dirs.addAll(nonPrimaryVolumes.map {
- hashMapOf(
- "volumePath" to it,
- "relativeDir" to "",
- )
- })
}
return dirs
}
@@ -236,7 +219,6 @@ object PermissionManager {
// As of Android 11, `MediaStore.getDocumentUri` fails if any of the persisted
// URI permissions we hold points to a folder that no longer exists,
// so we should remove these obsolete URIs before proceeding.
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun sanitizePersistedUriPermissions(context: Context) {
try {
for (uriPermission in context.contentResolver.persistedUriPermissions) {
@@ -252,7 +234,6 @@ object PermissionManager {
}
}
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
private fun releaseUriPermission(context: Context, it: Uri) {
val flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
context.contentResolver.releasePersistableUriPermission(it, flags)
diff --git a/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt b/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt
index a24cceda8..ff888a95f 100644
--- a/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt
+++ b/android/app/src/main/kotlin/deckers/thibault/aves/utils/StorageUtils.kt
@@ -16,7 +16,6 @@ import android.provider.DocumentsContract
import android.provider.MediaStore
import android.text.TextUtils
import android.util.Log
-import androidx.annotation.RequiresApi
import com.commonsware.cwac.document.DocumentFileCompat
import deckers.thibault.aves.model.provider.ImageProvider
import deckers.thibault.aves.utils.FileUtils.transferFrom
@@ -29,7 +28,7 @@ import java.io.FileInputStream
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
-import java.util.*
+import java.util.Locale
import java.util.regex.Pattern
object StorageUtils {
@@ -381,7 +380,6 @@ object StorageUtils {
// e.g.
// /storage/emulated/0/ -> content://com.android.externalstorage.documents/tree/primary%3A
// /storage/10F9-3F13/Pictures/ -> content://com.android.externalstorage.documents/tree/10F9-3F13%3APictures
- @RequiresApi(Build.VERSION_CODES.LOLLIPOP)
fun convertDirPathToTreeDocumentUri(context: Context, dirPath: String): Uri? {
val uuid = getVolumeUuidForDocumentUri(context, dirPath)
if (uuid != null) {
@@ -446,7 +444,7 @@ object StorageUtils {
fun getDocumentFile(context: Context, anyPath: String, mediaUri: Uri): DocumentFileCompat? {
try {
- if (requireAccessPermission(context, anyPath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (requireAccessPermission(context, anyPath)) {
// need a document URI (not a media content URI) to open a `DocumentFile` output stream
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && isMediaStoreContentUri(mediaUri)) {
// cleanest API to get it
@@ -485,7 +483,7 @@ object StorageUtils {
fun createDirectoryDocIfAbsent(context: Context, dirPath: String): DocumentFileCompat? {
try {
val cleanDirPath = ensureTrailingSeparator(dirPath)
- return if (requireAccessPermission(context, cleanDirPath) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ return if (requireAccessPermission(context, cleanDirPath)) {
val grantedDir = getGrantedDirForPath(context, cleanDirPath) ?: return null
val rootTreeDocumentUri = convertDirPathToTreeDocumentUri(context, grantedDir) ?: return null
var parentFile: DocumentFileCompat? = DocumentFileCompat.fromTreeUri(context, rootTreeDocumentUri) ?: return null
diff --git a/android/exifinterface/build.gradle b/android/exifinterface/build.gradle
index 76ba4c97f..88a67339e 100644
--- a/android/exifinterface/build.gradle
+++ b/android/exifinterface/build.gradle
@@ -26,5 +26,5 @@ android {
}
dependencies {
- implementation 'androidx.annotation:annotation:1.7.1'
+ implementation 'androidx.annotation:annotation:1.8.0'
}
\ No newline at end of file
diff --git a/lib/theme/themes.dart b/lib/theme/themes.dart
index 6875c6ae0..f1d14873b 100644
--- a/lib/theme/themes.dart
+++ b/lib/theme/themes.dart
@@ -1,4 +1,3 @@
-
import 'package:aves/widgets/aves_app.dart';
import 'package:aves_utils/aves_utils.dart';
import 'package:flutter/material.dart';
@@ -26,16 +25,21 @@ class Themes {
}
}
- static Color _schemeCardLayer(ColorScheme colors) => ElevationOverlay.applySurfaceTint(colors.surface, colors.surfaceTint, 1);
+ static bool _isDarkTheme(ColorScheme colors) => colors.brightness == Brightness.dark && colors.surface != Colors.black;
+
+ static Color firstLayerColor(BuildContext context) => _schemeFirstLayer(Theme.of(context).colorScheme);
+
+ static Color _schemeFirstLayer(ColorScheme colors) => _isDarkTheme(colors) ? colors.surfaceContainer : colors.surface;
+
+ static Color _schemeCardLayer(ColorScheme colors) => _isDarkTheme(colors) ? _schemeSecondLayer(colors) : colors.surfaceContainerLow;
static Color secondLayerColor(BuildContext context) => _schemeSecondLayer(Theme.of(context).colorScheme);
- // `DialogTheme` M3 defaults use `6.0` elevation
- static Color _schemeSecondLayer(ColorScheme colors) => ElevationOverlay.applySurfaceTint(colors.surface, colors.surfaceTint, 6);
+ static Color _schemeSecondLayer(ColorScheme colors) => _isDarkTheme(colors) ? colors.surfaceContainerHigh : colors.surfaceContainer;
static Color thirdLayerColor(BuildContext context) => _schemeThirdLayer(Theme.of(context).colorScheme);
- static Color _schemeThirdLayer(ColorScheme colors) => ElevationOverlay.applySurfaceTint(colors.surface, colors.surfaceTint, 12);
+ static Color _schemeThirdLayer(ColorScheme colors) => _isDarkTheme(colors) ? colors.surfaceContainerHighest : colors.surfaceContainerHigh;
static Color _unselectedWidgetColor(ColorScheme colors) => colors.onSurface.withOpacity(0.6);
@@ -55,14 +59,15 @@ class Themes {
colorScheme: colors,
dividerColor: colors.outlineVariant,
indicatorColor: colors.primary,
- scaffoldBackgroundColor: colors.background,
+ scaffoldBackgroundColor: _schemeFirstLayer(colors),
// TYPOGRAPHY & ICONOGRAPHY
typography: _typography,
// COMPONENT THEMES
checkboxTheme: _checkboxTheme(colors),
+ drawerTheme: _drawerTheme(colors),
floatingActionButtonTheme: _floatingActionButtonTheme(colors),
navigationRailTheme: NavigationRailThemeData(
- backgroundColor: colors.background,
+ backgroundColor: _schemeFirstLayer(colors),
selectedIconTheme: IconThemeData(color: colors.primary),
unselectedIconTheme: IconThemeData(color: _unselectedWidgetColor(colors)),
selectedLabelTextStyle: TextStyle(color: colors.primary),
@@ -78,16 +83,21 @@ class Themes {
side: BorderSide(width: 2.0, color: _unselectedWidgetColor(colors)),
);
+ static DrawerThemeData _drawerTheme(ColorScheme colors) => DrawerThemeData(
+ backgroundColor: _schemeSecondLayer(colors),
+ );
+
static const _listTileTheme = ListTileThemeData(
contentPadding: EdgeInsets.symmetric(horizontal: 16),
);
static PopupMenuThemeData _popupMenuTheme(ColorScheme colors, TextTheme textTheme) {
return PopupMenuThemeData(
- labelTextStyle: MaterialStateProperty.resolveWith((states) {
+ color: _schemeSecondLayer(colors),
+ labelTextStyle: WidgetStateProperty.resolveWith((states) {
// adapted from M3 defaults
final TextStyle style = textTheme.labelLarge!;
- if (states.contains(MaterialState.disabled)) {
+ if (states.contains(WidgetState.disabled)) {
return style.apply(color: colors.onSurface.withOpacity(0.38));
}
return style.apply(color: colors.onSurface);
@@ -105,23 +115,23 @@ class Themes {
// adapted from M3 defaults
static RadioThemeData _radioTheme(ColorScheme colors) => RadioThemeData(
- fillColor: MaterialStateProperty.resolveWith((states) {
- if (states.contains(MaterialState.selected)) {
- if (states.contains(MaterialState.disabled)) {
+ fillColor: WidgetStateProperty.resolveWith((states) {
+ if (states.contains(WidgetState.selected)) {
+ if (states.contains(WidgetState.disabled)) {
return colors.onSurface.withOpacity(0.38);
}
return colors.primary;
}
- if (states.contains(MaterialState.disabled)) {
+ if (states.contains(WidgetState.disabled)) {
return colors.onSurface.withOpacity(0.38);
}
- if (states.contains(MaterialState.pressed)) {
+ if (states.contains(WidgetState.pressed)) {
return colors.onSurface;
}
- if (states.contains(MaterialState.hovered)) {
+ if (states.contains(WidgetState.hovered)) {
return colors.onSurface;
}
- if (states.contains(MaterialState.focused)) {
+ if (states.contains(WidgetState.focused)) {
return colors.onSurface;
}
return _unselectedWidgetColor(colors);
@@ -166,13 +176,15 @@ class Themes {
textTheme: textTheme,
// COMPONENT THEMES
appBarTheme: AppBarTheme(
+ backgroundColor: _schemeFirstLayer(colors),
// `foregroundColor` is used by icons
foregroundColor: _lightActionIconColor,
// `titleTextStyle.color` is used by text
titleTextStyle: _titleTextStyle.copyWith(color: _lightTitleColor),
- systemOverlayStyle: deviceInitialized ? AvesApp.systemUIStyleForBrightness(colors.brightness, colors.background) : null,
+ systemOverlayStyle: deviceInitialized ? AvesApp.systemUIStyleForBrightness(colors.brightness, _schemeFirstLayer(colors)) : null,
),
dialogTheme: DialogTheme(
+ backgroundColor: _schemeSecondLayer(colors),
titleTextStyle: _titleTextStyle.copyWith(color: _lightTitleColor),
),
listTileTheme: _listTileTheme.copyWith(
@@ -217,13 +229,15 @@ class Themes {
textTheme: textTheme,
// COMPONENT THEMES
appBarTheme: AppBarTheme(
+ backgroundColor: _schemeFirstLayer(colors),
// `foregroundColor` is used by icons
foregroundColor: _darkTitleColor,
// `titleTextStyle.color` is used by text
titleTextStyle: _titleTextStyle.copyWith(color: _darkTitleColor),
- systemOverlayStyle: deviceInitialized ? AvesApp.systemUIStyleForBrightness(colors.brightness, colors.background) : null,
+ systemOverlayStyle: deviceInitialized ? AvesApp.systemUIStyleForBrightness(colors.brightness, _schemeFirstLayer(colors)) : null,
),
dialogTheme: DialogTheme(
+ backgroundColor: _schemeSecondLayer(colors),
titleTextStyle: _titleTextStyle.copyWith(color: _darkTitleColor),
),
listTileTheme: _listTileTheme,
@@ -251,13 +265,8 @@ class Themes {
static ThemeData blackTheme(Color accentColor, bool deviceInitialized) {
final colors = _darkColorScheme(accentColor).copyWith(
- background: Colors.black,
- );
- final baseTheme = _baseDarkTheme(colors, deviceInitialized);
- return baseTheme.copyWith(
- appBarTheme: baseTheme.appBarTheme.copyWith(
- backgroundColor: colors.background,
- ),
+ surface: Colors.black,
);
+ return _baseDarkTheme(colors, deviceInitialized);
}
}
diff --git a/lib/widgets/about/about_tv_page.dart b/lib/widgets/about/about_tv_page.dart
index 04ebd24c8..e8f0d8c68 100644
--- a/lib/widgets/about/about_tv_page.dart
+++ b/lib/widgets/about/about_tv_page.dart
@@ -1,4 +1,5 @@
import 'package:aves/model/device.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/about/app_ref.dart';
import 'package:aves/widgets/about/credits.dart';
import 'package:aves/widgets/about/translators.dart';
@@ -192,7 +193,7 @@ class _ContentState extends State<_Content> {
return Theme(
data: theme.copyWith(
listTileTheme: listTileTheme.copyWith(
- tileColor: theme.colorScheme.background,
+ tileColor: Themes.firstLayerColor(context),
),
),
child: const TvLicensePage(),
diff --git a/lib/widgets/about/licenses.dart b/lib/widgets/about/licenses.dart
index 4bdad8da7..3661364a3 100644
--- a/lib/widgets/about/licenses.dart
+++ b/lib/widgets/about/licenses.dart
@@ -2,6 +2,7 @@ import 'package:aves/app_flavor.dart';
import 'package:aves/model/app/dependencies.dart';
import 'package:aves/ref/brand_colors.dart';
import 'package:aves/theme/colors.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/about/title.dart';
import 'package:aves/widgets/common/basic/link_chip.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
@@ -87,8 +88,8 @@ class _LicensesState extends State {
MaterialPageRoute(
builder: (context) => Theme(
data: Theme.of(context).copyWith(
- // as of Flutter v3.7.8, `cardColor` is used as a background color by `LicensePage`
- cardColor: Theme.of(context).colorScheme.background,
+ // as of Flutter v3.22.0, `cardColor` is used as a background color by `LicensePage`
+ cardColor: Themes.firstLayerColor(context),
),
child: const LicensePage(),
),
diff --git a/lib/widgets/about/translators.dart b/lib/widgets/about/translators.dart
index 43903893f..2e582a454 100644
--- a/lib/widgets/about/translators.dart
+++ b/lib/widgets/about/translators.dart
@@ -31,7 +31,7 @@ class AboutTranslators extends StatelessWidget {
static Widget buildBody(BuildContext context) {
return _RandomTextSpanHighlighter(
spans: Contributors.translators.map((v) => v.name).toList(),
- color: Theme.of(context).colorScheme.onBackground,
+ color: Theme.of(context).colorScheme.onSurface,
);
}
}
diff --git a/lib/widgets/about/tv_license_page.dart b/lib/widgets/about/tv_license_page.dart
index e487f9760..e40b67d26 100644
--- a/lib/widgets/about/tv_license_page.dart
+++ b/lib/widgets/about/tv_license_page.dart
@@ -1,5 +1,6 @@
import 'dart:developer' show Flow, Timeline;
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/basic/scaffold.dart';
import 'package:aves/widgets/common/behaviour/intents.dart';
import 'package:flutter/foundation.dart';
@@ -77,7 +78,7 @@ class _TvLicensePageState extends State {
final isSelected = index == selectedIndex;
final theme = Theme.of(context);
return Ink(
- color: isSelected ? theme.highlightColor : theme.colorScheme.background,
+ color: isSelected ? theme.highlightColor : Themes.firstLayerColor(context),
child: ListTile(
title: Text(packageName),
subtitle: Text(MaterialLocalizations.of(context).licensesPackageDetailText(bindings.length)),
@@ -298,7 +299,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
),
body: Center(
child: Material(
- color: theme.colorScheme.background,
+ color: Themes.firstLayerColor(context),
elevation: 4.0,
child: Container(
constraints: BoxConstraints.loose(const Size.fromWidth(600.0)),
@@ -328,7 +329,7 @@ class _PackageLicensePageState extends State<_PackageLicensePage> {
SliverAppBar(
automaticallyImplyLeading: false,
pinned: true,
- backgroundColor: theme.colorScheme.background,
+ backgroundColor: Themes.firstLayerColor(context),
title: _PackageLicensePageTitle(
title: title,
subtitle: subtitle,
diff --git a/lib/widgets/aves_app.dart b/lib/widgets/aves_app.dart
index c86b02c0c..1a853f8e1 100644
--- a/lib/widgets/aves_app.dart
+++ b/lib/widgets/aves_app.dart
@@ -96,12 +96,12 @@ class AvesApp extends StatefulWidget {
State createState() => _AvesAppState();
static void setSystemUIStyle(ThemeData theme) {
- final style = systemUIStyleForBrightness(theme.brightness, theme.colorScheme.background);
+ final style = systemUIStyleForBrightness(theme.brightness, theme.colorScheme.surfaceContainer);
SystemChrome.setSystemUIOverlayStyle(style);
}
static SystemUiOverlayStyle systemUIStyleForBrightness(Brightness themeBrightness, Color backgroundColor) {
- final barBrightness = themeBrightness == Brightness.light ? Brightness.dark : Brightness.light;
+ final barBrightness = themeBrightness == Brightness.dark ? Brightness.light : Brightness.dark;
const statusBarColor = Colors.transparent;
// as of Flutter v3.3.0-0.2.pre, setting `SystemUiOverlayStyle` (whether manually or automatically because of `AppBar`)
// prevents the canvas from drawing behind the nav bar on Android <10 (API <29),
diff --git a/lib/widgets/common/action_mixins/feedback.dart b/lib/widgets/common/action_mixins/feedback.dart
index 5959b4745..90495cb1f 100644
--- a/lib/widgets/common/action_mixins/feedback.dart
+++ b/lib/widgets/common/action_mixins/feedback.dart
@@ -87,7 +87,7 @@ mixin FeedbackMixin {
action: action != null
? TextButton(
style: ButtonStyle(
- foregroundColor: MaterialStateProperty.all(snackBarTheme.actionTextColor),
+ foregroundColor: WidgetStateProperty.all(snackBarTheme.actionTextColor),
),
onPressed: () {
notificationOverlayEntry?.dismiss();
diff --git a/lib/widgets/common/action_mixins/overlay_snack_bar.dart b/lib/widgets/common/action_mixins/overlay_snack_bar.dart
index 4ca2ef6c3..97a71a97c 100644
--- a/lib/widgets/common/action_mixins/overlay_snack_bar.dart
+++ b/lib/widgets/common/action_mixins/overlay_snack_bar.dart
@@ -132,12 +132,10 @@ class _OverlaySnackBarState extends State {
primary: colorScheme.onPrimary,
secondary: buttonColor,
surface: colorScheme.onSurface,
- background: defaults.backgroundColor!,
error: colorScheme.onError,
onPrimary: colorScheme.primary,
onSecondary: colorScheme.secondary,
onSurface: colorScheme.surface,
- onBackground: colorScheme.background,
onError: colorScheme.error,
brightness: brightness,
),
@@ -363,17 +361,17 @@ class _SnackbarDefaultsM3 extends SnackBarThemeData {
Color get backgroundColor => _colors.inverseSurface;
@override
- Color get actionTextColor => MaterialStateColor.resolveWith((states) {
- if (states.contains(MaterialState.disabled)) {
+ Color get actionTextColor => WidgetStateColor.resolveWith((states) {
+ if (states.contains(WidgetState.disabled)) {
return _colors.inversePrimary;
}
- if (states.contains(MaterialState.pressed)) {
+ if (states.contains(WidgetState.pressed)) {
return _colors.inversePrimary;
}
- if (states.contains(MaterialState.hovered)) {
+ if (states.contains(WidgetState.hovered)) {
return _colors.inversePrimary;
}
- if (states.contains(MaterialState.focused)) {
+ if (states.contains(WidgetState.focused)) {
return _colors.inversePrimary;
}
return _colors.inversePrimary;
diff --git a/lib/widgets/common/basic/markdown_container.dart b/lib/widgets/common/basic/markdown_container.dart
index 613680250..de44dcd4f 100644
--- a/lib/widgets/common/basic/markdown_container.dart
+++ b/lib/widgets/common/basic/markdown_container.dart
@@ -38,7 +38,7 @@ class MarkdownContainer extends StatelessWidget {
child = Theme(
data: Theme.of(context).copyWith(
scrollbarTheme: ScrollbarThemeData(
- thumbVisibility: MaterialStateProperty.all(true),
+ thumbVisibility: WidgetStateProperty.all(true),
radius: const Radius.circular(16),
crossAxisMargin: 6,
mainAxisMargin: 16,
diff --git a/lib/widgets/common/basic/popup/expansion_panel.dart b/lib/widgets/common/basic/popup/expansion_panel.dart
index 3d4501def..63bc94e6a 100644
--- a/lib/widgets/common/basic/popup/expansion_panel.dart
+++ b/lib/widgets/common/basic/popup/expansion_panel.dart
@@ -46,8 +46,8 @@ class _PopupMenuExpansionPanelState extends State>
@override
Widget build(BuildContext context) {
final style = PopupMenuTheme.of(context).labelTextStyle!.resolve(
- {
- if (!widget.enabled) MaterialState.disabled,
+ {
+ if (!widget.enabled) WidgetState.disabled,
},
)!;
final animationDuration = context.select((v) => v.expansionTileAnimation);
diff --git a/lib/widgets/common/basic/wheel.dart b/lib/widgets/common/basic/wheel.dart
index 6007e9dfd..8570b2415 100644
--- a/lib/widgets/common/basic/wheel.dart
+++ b/lib/widgets/common/basic/wheel.dart
@@ -103,7 +103,7 @@ class _WheelSelectorState extends State> {
child: Theme(
data: Theme.of(context).copyWith(
scrollbarTheme: ScrollbarThemeData(
- thumbVisibility: MaterialStateProperty.all(false),
+ thumbVisibility: WidgetStateProperty.all(false),
),
),
child: ListWheelScrollView(
diff --git a/lib/widgets/common/grid/sections/mosaic/scale_overlay.dart b/lib/widgets/common/grid/sections/mosaic/scale_overlay.dart
index 13d372f95..cb8defc1c 100644
--- a/lib/widgets/common/grid/sections/mosaic/scale_overlay.dart
+++ b/lib/widgets/common/grid/sections/mosaic/scale_overlay.dart
@@ -51,7 +51,7 @@ class MosaicScaleOverlay extends StatelessWidget {
child: Stack(
alignment: Alignment.center,
children: [
- _buildBar(extentMax, colorScheme.onBackground.withOpacity(.2)),
+ _buildBar(extentMax, colorScheme.onSurface.withOpacity(.2)),
_buildBar(scaledSize.width, colorScheme.primary),
],
),
diff --git a/lib/widgets/common/identity/aves_app_bar.dart b/lib/widgets/common/identity/aves_app_bar.dart
index 01664c414..357c502d7 100644
--- a/lib/widgets/common/identity/aves_app_bar.dart
+++ b/lib/widgets/common/identity/aves_app_bar.dart
@@ -1,5 +1,6 @@
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/durations.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/aves_app.dart';
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
import 'package:aves/widgets/common/basic/insets.dart';
@@ -227,7 +228,7 @@ class _AvesFloatingBarState extends State with RouteAware {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
- final backgroundColor = theme.appBarTheme.backgroundColor ?? theme.colorScheme.surface;
+ final backgroundColor = theme.appBarTheme.backgroundColor ?? Themes.firstLayerColor(context);
return ValueListenableBuilder(
valueListenable: _isBlurAllowedNotifier,
builder: (context, isBlurAllowed, child) {
diff --git a/lib/widgets/common/identity/aves_caption.dart b/lib/widgets/common/identity/aves_caption.dart
index 095caff9e..5a53ad17f 100644
--- a/lib/widgets/common/identity/aves_caption.dart
+++ b/lib/widgets/common/identity/aves_caption.dart
@@ -15,7 +15,7 @@ class AvesCaption extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final subtitleStyle = theme.textTheme.bodySmall!;
- final subtitleChangeShadowColor = theme.colorScheme.onBackground;
+ final subtitleChangeShadowColor = theme.colorScheme.onSurface;
return ChangeHighlightText(
// provide key to refresh on theme brightness change
key: ValueKey(subtitleChangeShadowColor),
diff --git a/lib/widgets/common/identity/aves_expansion_tile.dart b/lib/widgets/common/identity/aves_expansion_tile.dart
index 92c8aa18b..ad856f693 100644
--- a/lib/widgets/common/identity/aves_expansion_tile.dart
+++ b/lib/widgets/common/identity/aves_expansion_tile.dart
@@ -1,4 +1,5 @@
import 'package:aves/theme/durations.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/identity/highlight_title.dart';
import 'package:expansion_tile_card/expansion_tile_card.dart';
import 'package:flutter/material.dart';
@@ -56,7 +57,7 @@ class AvesExpansionTile extends StatelessWidget {
expandable: enabled,
initiallyExpanded: initiallyExpanded,
finalPadding: const EdgeInsets.symmetric(vertical: 6.0),
- baseColor: theme.colorScheme.background,
+ baseColor: Themes.firstLayerColor(context),
expandedTextColor: colorScheme.onSurface,
duration: animationDuration,
shadowColor: theme.shadowColor,
diff --git a/lib/widgets/common/identity/aves_filter_chip.dart b/lib/widgets/common/identity/aves_filter_chip.dart
index e8d230fce..84c353497 100644
--- a/lib/widgets/common/identity/aves_filter_chip.dart
+++ b/lib/widgets/common/identity/aves_filter_chip.dart
@@ -12,6 +12,7 @@ import 'package:aves/model/settings/enums/accessibility_animations.dart';
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/icons.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/view/view.dart';
import 'package:aves/widgets/collection/filter_bar.dart';
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
@@ -48,6 +49,7 @@ class AvesFilterChip extends StatefulWidget {
final CollectionFilter filter;
final bool showText, showGenericIcon, useFilterColor;
final AvesFilterDecoration? decoration;
+ final Color? background;
final String? banner;
final Widget? leadingOverride, details;
final double padding;
@@ -71,6 +73,7 @@ class AvesFilterChip extends StatefulWidget {
this.showGenericIcon = true,
this.useFilterColor = true,
this.decoration,
+ this.background,
this.banner,
this.leadingOverride,
this.details,
@@ -233,7 +236,7 @@ class _AvesFilterChipState extends State {
@override
Widget build(BuildContext context) {
final decoration = widget.decoration;
- final chipBackground = Theme.of(context).colorScheme.background;
+ final chipBackground = widget.background ?? Themes.firstLayerColor(context);
final onTap = widget.onTap != null
? () {
diff --git a/lib/widgets/common/identity/buttons/outlined_button.dart b/lib/widgets/common/identity/buttons/outlined_button.dart
index 9d4299cb1..428089ab9 100644
--- a/lib/widgets/common/identity/buttons/outlined_button.dart
+++ b/lib/widgets/common/identity/buttons/outlined_button.dart
@@ -16,13 +16,13 @@ class AvesOutlinedButton extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final style = ButtonStyle(
- side: MaterialStateProperty.resolveWith((states) {
+ side: WidgetStateProperty.resolveWith((states) {
return BorderSide(
- color: states.contains(MaterialState.disabled) ? theme.disabledColor : theme.colorScheme.primary,
+ color: states.contains(WidgetState.disabled) ? theme.disabledColor : theme.colorScheme.primary,
);
}),
- foregroundColor: MaterialStateProperty.resolveWith((states) {
- return states.contains(MaterialState.disabled) ? theme.disabledColor : theme.colorScheme.onBackground;
+ foregroundColor: WidgetStateProperty.resolveWith((states) {
+ return states.contains(WidgetState.disabled) ? theme.disabledColor : theme.colorScheme.onSurface;
}),
);
return icon != null
diff --git a/lib/widgets/common/identity/buttons/overlay_button.dart b/lib/widgets/common/identity/buttons/overlay_button.dart
index e9fa810aa..839a5513f 100644
--- a/lib/widgets/common/identity/buttons/overlay_button.dart
+++ b/lib/widgets/common/identity/buttons/overlay_button.dart
@@ -161,7 +161,7 @@ class OverlayTextButton extends StatelessWidget {
});
static const _borderRadius = 123.0;
- static final _minSize = MaterialStateProperty.all(const Size(kMinInteractiveDimension, kMinInteractiveDimension));
+ static final _minSize = WidgetStateProperty.all(const Size(kMinInteractiveDimension, kMinInteractiveDimension));
@override
Widget build(BuildContext context) {
@@ -173,12 +173,12 @@ class OverlayTextButton extends StatelessWidget {
child: OutlinedButton(
onPressed: onPressed,
style: ButtonStyle(
- backgroundColor: MaterialStateProperty.all(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
- foregroundColor: MaterialStateProperty.all(theme.colorScheme.onSurface),
- overlayColor: theme.isDark ? MaterialStateProperty.all(Colors.white.withOpacity(0.12)) : null,
+ backgroundColor: WidgetStateProperty.all(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
+ foregroundColor: WidgetStateProperty.all(theme.colorScheme.onSurface),
+ overlayColor: theme.isDark ? WidgetStateProperty.all(Colors.white.withOpacity(0.12)) : null,
minimumSize: _minSize,
- side: MaterialStateProperty.all(AvesBorder.curvedSide(context)),
- shape: MaterialStateProperty.all(const RoundedRectangleBorder(
+ side: WidgetStateProperty.all(AvesBorder.curvedSide(context)),
+ shape: WidgetStateProperty.all(const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
)),
),
diff --git a/lib/widgets/common/identity/highlight_title.dart b/lib/widgets/common/identity/highlight_title.dart
index 1882dc322..76c1fa4c9 100644
--- a/lib/widgets/common/identity/highlight_title.dart
+++ b/lib/widgets/common/identity/highlight_title.dart
@@ -1,6 +1,7 @@
import 'package:aves/model/settings/settings.dart';
import 'package:aves/theme/colors.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/basic/text/outlined.dart';
import 'package:aves/widgets/common/extensions/theme.dart';
import 'package:aves/widgets/common/fx/highlight_decoration.dart';
@@ -61,7 +62,7 @@ class HighlightTitle extends StatelessWidget {
style: style,
),
],
- outlineColor: Theme.of(context).colorScheme.background,
+ outlineColor: Themes.firstLayerColor(context),
softWrap: false,
overflow: TextOverflow.fade,
maxLines: 1,
diff --git a/lib/widgets/common/map/buttons/coordinate_filter.dart b/lib/widgets/common/map/buttons/coordinate_filter.dart
index 938abb715..df2f3661b 100644
--- a/lib/widgets/common/map/buttons/coordinate_filter.dart
+++ b/lib/widgets/common/map/buttons/coordinate_filter.dart
@@ -60,49 +60,43 @@ class _OverlayCoordinateFilterChipState extends State>(
+ selector: (context, v) => v.scale,
+ builder: (context, scale, child) => SizeTransition(
+ sizeFactor: scale,
+ axisAlignment: 1,
+ child: FadeTransition(
+ opacity: scale,
+ child: child,
+ ),
),
- ),
- child: Align(
- alignment: Alignment.topLeft,
- child: Selector>(
- selector: (context, v) => v.scale,
- builder: (context, scale, child) => SizeTransition(
- sizeFactor: scale,
- axisAlignment: 1,
- child: FadeTransition(
- opacity: scale,
- child: child,
- ),
- ),
- child: ValueListenableBuilder(
- valueListenable: _idleBoundsNotifier,
- builder: (context, bounds, child) {
- if (bounds == null) return const SizedBox();
- final filter = CoordinateFilter(
- bounds.sw,
- bounds.ne,
- // more stable format when bounds change
- minuteSecondPadding: true,
- );
- return Padding(
- padding: EdgeInsets.all(widget.padding),
- child: BlurredRRect.all(
- enabled: blurred,
- borderRadius: AvesFilterChip.defaultRadius,
- child: AvesFilterChip(
- filter: filter,
- useFilterColor: false,
- maxWidth: double.infinity,
- onTap: (filter) => FilterSelectedNotification(CoordinateFilter(bounds.sw, bounds.ne)).dispatch(context),
- ),
+ child: ValueListenableBuilder(
+ valueListenable: _idleBoundsNotifier,
+ builder: (context, bounds, child) {
+ if (bounds == null) return const SizedBox();
+ final filter = CoordinateFilter(
+ bounds.sw,
+ bounds.ne,
+ // more stable format when bounds change
+ minuteSecondPadding: true,
+ );
+ return Padding(
+ padding: EdgeInsets.all(widget.padding),
+ child: BlurredRRect.all(
+ enabled: blurred,
+ borderRadius: AvesFilterChip.defaultRadius,
+ child: AvesFilterChip(
+ filter: filter,
+ useFilterColor: false,
+ background: Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred),
+ maxWidth: double.infinity,
+ onTap: (filter) => FilterSelectedNotification(CoordinateFilter(bounds.sw, bounds.ne)).dispatch(context),
),
- );
- },
- ),
+ ),
+ );
+ },
),
),
);
diff --git a/lib/widgets/common/thumbnail/error.dart b/lib/widgets/common/thumbnail/error.dart
index f6064f4e8..9acc11b09 100644
--- a/lib/widgets/common/thumbnail/error.dart
+++ b/lib/widgets/common/thumbnail/error.dart
@@ -67,7 +67,7 @@ class _ErrorThumbnailState extends State {
}
return Container(
alignment: Alignment.center,
- color: Theme.of(context).colorScheme.background,
+ color: Themes.firstLayerColor(context),
width: extent,
height: extent,
child: child,
diff --git a/lib/widgets/debug/colors.dart b/lib/widgets/debug/colors.dart
index 2b37bd3eb..52bebdc38 100644
--- a/lib/widgets/debug/colors.dart
+++ b/lib/widgets/debug/colors.dart
@@ -20,23 +20,39 @@ class _DebugColorSectionState extends State with AutomaticKee
('onPrimary', scheme.onPrimary),
('primaryContainer', scheme.primaryContainer),
('onPrimaryContainer', scheme.onPrimaryContainer),
+ ('primaryFixed', scheme.primaryFixed),
+ ('primaryFixedDim', scheme.primaryFixedDim),
+ ('onPrimaryFixed', scheme.onPrimaryFixed),
+ ('onPrimaryFixedVariant', scheme.onPrimaryFixedVariant),
('secondary', scheme.secondary),
('onSecondary', scheme.onSecondary),
('secondaryContainer', scheme.secondaryContainer),
('onSecondaryContainer', scheme.onSecondaryContainer),
+ ('secondaryFixed', scheme.secondaryFixed),
+ ('secondaryFixedDim', scheme.secondaryFixedDim),
+ ('onSecondaryFixed', scheme.onSecondaryFixed),
+ ('onSecondaryFixedVariant', scheme.onSecondaryFixedVariant),
('tertiary', scheme.tertiary),
('onTertiary', scheme.onTertiary),
('tertiaryContainer', scheme.tertiaryContainer),
('onTertiaryContainer', scheme.onTertiaryContainer),
+ ('tertiaryFixed', scheme.tertiaryFixed),
+ ('tertiaryFixedDim', scheme.tertiaryFixedDim),
+ ('onTertiaryFixed', scheme.onTertiaryFixed),
+ ('onTertiaryFixedVariant', scheme.onTertiaryFixedVariant),
('error', scheme.error),
('onError', scheme.onError),
('errorContainer', scheme.errorContainer),
('onErrorContainer', scheme.onErrorContainer),
- ('background', scheme.background),
- ('onBackground', scheme.onBackground),
('surface', scheme.surface),
('onSurface', scheme.onSurface),
- ('surfaceVariant', scheme.surfaceVariant),
+ ('surfaceDim', scheme.surfaceDim),
+ ('surfaceBright', scheme.surfaceBright),
+ ('surfaceContainerLowest', scheme.surfaceContainerLowest),
+ ('surfaceContainerLow', scheme.surfaceContainerLow),
+ ('surfaceContainer', scheme.surfaceContainer),
+ ('surfaceContainerHigh', scheme.surfaceContainerHigh),
+ ('surfaceContainerHighest', scheme.surfaceContainerHighest),
('onSurfaceVariant', scheme.onSurfaceVariant),
('outline', scheme.outline),
('outlineVariant', scheme.outlineVariant),
diff --git a/lib/widgets/dialogs/aves_dialog.dart b/lib/widgets/dialogs/aves_dialog.dart
index 4279be0f6..924f96102 100644
--- a/lib/widgets/dialogs/aves_dialog.dart
+++ b/lib/widgets/dialogs/aves_dialog.dart
@@ -74,7 +74,7 @@ class AvesDialog extends StatelessWidget {
child = Theme(
data: Theme.of(context).copyWith(
scrollbarTheme: ScrollbarThemeData(
- thumbVisibility: MaterialStateProperty.all(true),
+ thumbVisibility: WidgetStateProperty.all(true),
radius: const Radius.circular(16),
crossAxisMargin: 4,
// adapt margin when corner is around content itself, not outside for the title
diff --git a/lib/widgets/dialogs/convert_entry_dialog.dart b/lib/widgets/dialogs/convert_entry_dialog.dart
index ef9ffc8f8..5576aace9 100644
--- a/lib/widgets/dialogs/convert_entry_dialog.dart
+++ b/lib/widgets/dialogs/convert_entry_dialog.dart
@@ -99,7 +99,7 @@ class _ConvertEntryDialogState extends State {
const contentHorizontalPadding = EdgeInsets.symmetric(horizontal: AvesDialog.defaultHorizontalContentPadding);
final colorScheme = Theme.of(context).colorScheme;
final trailingStyle = TextStyle(color: colorScheme.onSurfaceVariant);
- final trailingChangeShadowColor = colorScheme.onBackground;
+ final trailingChangeShadowColor = colorScheme.onSurface;
// used by the drop down to match input decoration
final textFieldDecorationBorder = Border(
diff --git a/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart b/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart
index 272b9576b..7ed6cb274 100644
--- a/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart
+++ b/lib/widgets/dialogs/entry_editors/remove_metadata_dialog.dart
@@ -2,6 +2,7 @@ import 'package:aves/model/settings/settings.dart';
import 'package:aves/ref/brand_colors.dart';
import 'package:aves/theme/colors.dart';
import 'package:aves/theme/durations.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/view/view.dart';
import 'package:aves/widgets/common/basic/text/outlined.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
@@ -113,7 +114,7 @@ class _RemoveEntryMetadataDialogState extends State {
),
),
],
- outlineColor: Theme.of(context).colorScheme.background,
+ outlineColor: Themes.firstLayerColor(context),
);
if (context.select((v) => v.themeColorMode == AvesThemeColorMode.polychrome)) {
final colors = context.watch();
diff --git a/lib/widgets/dialogs/filter_editors/pattern_dialog.dart b/lib/widgets/dialogs/filter_editors/pattern_dialog.dart
index 4518c75db..7bfd49a8a 100644
--- a/lib/widgets/dialogs/filter_editors/pattern_dialog.dart
+++ b/lib/widgets/dialogs/filter_editors/pattern_dialog.dart
@@ -36,7 +36,7 @@ class _PatternDialogState extends State {
child: PatternLock(
relativePadding: .4,
selectedColor: colorScheme.primary,
- notSelectedColor: colorScheme.onBackground,
+ notSelectedColor: colorScheme.onSurface,
pointRadius: 8,
fillPoints: true,
onInputComplete: (input) => _submit(input.join()),
diff --git a/lib/widgets/dialogs/filter_editors/pin_dialog.dart b/lib/widgets/dialogs/filter_editors/pin_dialog.dart
index 04b9d206b..00b8bc2a8 100644
--- a/lib/widgets/dialogs/filter_editors/pin_dialog.dart
+++ b/lib/widgets/dialogs/filter_editors/pin_dialog.dart
@@ -50,8 +50,8 @@ class _PinDialogState extends State {
autoFocus: true,
autoDismissKeyboard: !widget.needConfirmation || _confirming,
pinTheme: PinTheme(
- activeColor: colorScheme.onBackground,
- inactiveColor: colorScheme.onBackground,
+ activeColor: colorScheme.onSurface,
+ inactiveColor: colorScheme.onSurface,
selectedColor: colorScheme.primary,
selectedFillColor: colorScheme.primary,
borderRadius: BorderRadius.circular(8),
diff --git a/lib/widgets/navigation/drawer/app_drawer.dart b/lib/widgets/navigation/drawer/app_drawer.dart
index 4d64959ca..7a0978786 100644
--- a/lib/widgets/navigation/drawer/app_drawer.dart
+++ b/lib/widgets/navigation/drawer/app_drawer.dart
@@ -124,7 +124,7 @@ class _AppDrawerState extends State {
final onPrimary = colorScheme.onPrimary;
final drawerButtonStyle = ButtonStyle(
- padding: MaterialStateProperty.all(const EdgeInsetsDirectional.only(start: 12, end: 16)),
+ padding: WidgetStateProperty.all(const EdgeInsetsDirectional.only(start: 12, end: 16)),
);
return Container(
padding: const EdgeInsets.symmetric(horizontal: 16),
@@ -163,9 +163,9 @@ class _AppDrawerState extends State {
OutlinedButtonTheme(
data: OutlinedButtonThemeData(
style: ButtonStyle(
- foregroundColor: MaterialStateProperty.all(onPrimary),
- overlayColor: MaterialStateProperty.all(onPrimary.withOpacity(.12)),
- side: MaterialStateProperty.all(BorderSide(width: 1, color: onPrimary.withOpacity(.24))),
+ foregroundColor: WidgetStateProperty.all(onPrimary),
+ overlayColor: WidgetStateProperty.all(onPrimary.withOpacity(.12)),
+ side: WidgetStateProperty.all(BorderSide(width: 1, color: onPrimary.withOpacity(.24))),
),
),
child: Wrap(
diff --git a/lib/widgets/settings/common/quick_actions/editor_page.dart b/lib/widgets/settings/common/quick_actions/editor_page.dart
index 6d6aa5e74..1b13567f6 100644
--- a/lib/widgets/settings/common/quick_actions/editor_page.dart
+++ b/lib/widgets/settings/common/quick_actions/editor_page.dart
@@ -275,7 +275,7 @@ class _QuickActionEditorBodyState extends State {
valueListenable: _indexNotifier,
builder: (context, selectedIndex, child) {
final rail = NavigationRail(
- backgroundColor: Theme.of(context).colorScheme.background,
extended: true,
destinations: sections
.map((section) => NavigationRailDestination(
diff --git a/lib/widgets/stats/date/histogram.dart b/lib/widgets/stats/date/histogram.dart
index 4147dda96..93db96de7 100644
--- a/lib/widgets/stats/date/histogram.dart
+++ b/lib/widgets/stats/date/histogram.dart
@@ -5,6 +5,7 @@ import 'package:aves/model/entry/entry.dart';
import 'package:aves/model/entry/sort.dart';
import 'package:aves/model/filters/date.dart';
import 'package:aves/theme/durations.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/utils/time_utils.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/fx/transitions.dart';
@@ -196,11 +197,11 @@ class _HistogramState extends State with AutomaticKeepAliveClientMixi
final colorScheme = Theme.of(context).colorScheme;
final accentColor = colorScheme.primary;
- final axisColor = charts.ColorUtil.fromDartColor(drawPoints ? colorScheme.onBackground : Colors.transparent);
- final measureLineColor = charts.ColorUtil.fromDartColor(drawPoints ? colorScheme.onBackground.withOpacity(.1) : Colors.transparent);
+ final axisColor = charts.ColorUtil.fromDartColor(drawPoints ? colorScheme.onSurface : Colors.transparent);
+ final measureLineColor = charts.ColorUtil.fromDartColor(drawPoints ? colorScheme.onSurface.withOpacity(.1) : Colors.transparent);
final histogramLineColor = charts.ColorUtil.fromDartColor(drawLine ? accentColor : Colors.white);
final histogramPointStrikeColor = charts.ColorUtil.fromDartColor(drawPoints ? colorScheme.onSurface : Colors.transparent);
- final histogramPointFillColor = charts.ColorUtil.fromDartColor(colorScheme.background);
+ final histogramPointFillColor = charts.ColorUtil.fromDartColor(Themes.firstLayerColor(context));
final series = [
if (drawLine || drawArea)
diff --git a/lib/widgets/stats/percent_text.dart b/lib/widgets/stats/percent_text.dart
index 8bdb0b410..362194d12 100644
--- a/lib/widgets/stats/percent_text.dart
+++ b/lib/widgets/stats/percent_text.dart
@@ -1,4 +1,5 @@
import 'package:aves/theme/styles.dart';
+import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/basic/text/outlined.dart';
import 'package:aves/widgets/common/extensions/theme.dart';
import 'package:flutter/material.dart';
@@ -15,17 +16,16 @@ class LinearPercentIndicatorText extends StatelessWidget {
@override
Widget build(BuildContext context) {
- final theme = Theme.of(context);
return OutlinedText(
textSpans: [
TextSpan(
text: percentFormat.format(percent),
style: TextStyle(
- shadows: theme.isDark ? AStyles.embossShadows : null,
+ shadows: Theme.of(context).isDark ? AStyles.embossShadows : null,
),
)
],
- outlineColor: theme.colorScheme.background,
+ outlineColor: Themes.firstLayerColor(context),
);
}
}
diff --git a/lib/widgets/viewer/info/info_app_bar.dart b/lib/widgets/viewer/info/info_app_bar.dart
index c3c06e24d..a6e8195f0 100644
--- a/lib/widgets/viewer/info/info_app_bar.dart
+++ b/lib/widgets/viewer/info/info_app_bar.dart
@@ -13,6 +13,7 @@ import 'package:aves/widgets/common/app_bar/sliver_app_bar_title.dart';
import 'package:aves/widgets/common/basic/font_size_icon_theme.dart';
import 'package:aves/widgets/common/basic/popup/menu_row.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
+import 'package:aves/widgets/common/search/route.dart';
import 'package:aves/widgets/viewer/action/entry_info_action_delegate.dart';
import 'package:aves/widgets/viewer/info/info_search.dart';
import 'package:aves/widgets/viewer/info/metadata/metadata_dir.dart';
@@ -112,14 +113,15 @@ class InfoAppBar extends StatelessWidget {
void _goToSearch(BuildContext context) {
final isSelecting = context.read?>()?.isSelecting ?? false;
- showSearch(
- context: context,
- delegate: InfoSearchDelegate(
- searchFieldLabel: context.l10n.viewerInfoSearchFieldLabel,
- searchFieldStyle: Themes.searchFieldStyle(context),
- entry: entry,
- metadataNotifier: metadataNotifier,
- isSelecting: isSelecting,
+ Navigator.maybeOf(context)?.push(
+ SearchPageRoute(
+ delegate: InfoSearchDelegate(
+ searchFieldLabel: context.l10n.viewerInfoSearchFieldLabel,
+ searchFieldStyle: Themes.searchFieldStyle(context),
+ entry: entry,
+ metadataNotifier: metadataNotifier,
+ isSelecting: isSelecting,
+ ),
),
);
}
diff --git a/lib/widgets/viewer/info/info_search.dart b/lib/widgets/viewer/info/info_search.dart
index 081f3410b..868d8fda3 100644
--- a/lib/widgets/viewer/info/info_search.dart
+++ b/lib/widgets/viewer/info/info_search.dart
@@ -3,28 +3,30 @@ import 'package:aves/theme/icons.dart';
import 'package:aves/widgets/common/extensions/build_context.dart';
import 'package:aves/widgets/common/identity/empty.dart';
import 'package:aves/widgets/common/providers/media_query_data_provider.dart';
+import 'package:aves/widgets/common/search/delegate.dart';
import 'package:aves/widgets/viewer/info/embedded/embedded_data_opener.dart';
import 'package:aves/widgets/viewer/info/metadata/metadata_dir.dart';
import 'package:aves/widgets/viewer/info/metadata/metadata_dir_tile.dart';
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
-class InfoSearchDelegate extends SearchDelegate {
+class InfoSearchDelegate extends AvesSearchDelegate {
final AvesEntry entry;
final ValueNotifier