upgraded Flutter to stable v3.22.0

This commit is contained in:
Thibault Deckers 2024-05-18 22:43:29 +02:00
parent 9a4657379b
commit 56762eea9c
82 changed files with 361 additions and 410 deletions

@ -1 +1 @@
Subproject commit 54e66469a933b60ddf175f858f82eaeb97e48c8d
Subproject commit 5dcb86f68f239346676ceb1ed1ea385bd215fba1

View file

@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
## <a id="unreleased"></a>[Unreleased]
### Changed
- upgraded Flutter to stable v3.22.0
### Removed
- support for Android KitKat (API 19)
## <a id="v1.11.1"></a>[v1.11.1] - 2024-05-03
### Added

View file

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

View file

@ -72,12 +72,10 @@
-->
<!--
allow install on API 19, despite the `minSdk` declared in dependencies:
- the Security library is from API 21
allow install on API 21, despite the `minSdk` declared in dependencies:
- FFmpegKit for Flutter is from API 24 (when not LTS)
- Google Maps is from API 20
-->
<uses-sdk tools:overrideLibrary="androidx.security, com.arthenica.ffmpegkit.flutter, io.flutter.plugins.googlemaps" />
<uses-sdk tools:overrideLibrary="com.arthenica.ffmpegkit.flutter" />
<!-- from Android 11, we should define <queries> to make other apps visible to this app -->
<queries>
@ -321,8 +319,8 @@
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<!-- as of Flutter v3.19.0 (stable),
Impeller fails to render videos & platform views, has poor performance -->
<!-- as of Flutter v3.22.0 (stable),
Impeller fails to render videos (via `ffmpegkit`), and has random glitches -->
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />

View file

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

View file

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

View file

@ -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() {

View file

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

View file

@ -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() {

View file

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

View file

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

View file

@ -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<String, Any?> = 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<FieldMap>()
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)
}

View file

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

View file

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

View file

@ -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<String, String>): 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)
}
}

View file

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

View file

@ -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<SafePngMetadataReader>()
// 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
)

View file

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

View file

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

View file

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

View file

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

View file

@ -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<String> {
val grantedDirs = HashSet<String>()
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)

View file

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

View file

@ -26,5 +26,5 @@ android {
}
dependencies {
implementation 'androidx.annotation:annotation:1.7.1'
implementation 'androidx.annotation:annotation:1.8.0'
}

View file

@ -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<Color>((states) {
if (states.contains(MaterialState.selected)) {
if (states.contains(MaterialState.disabled)) {
fillColor: WidgetStateProperty.resolveWith<Color>((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);
}
}

View file

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

View file

@ -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<Licenses> {
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(),
),

View file

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

View file

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

View file

@ -96,12 +96,12 @@ class AvesApp extends StatefulWidget {
State<AvesApp> 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),

View file

@ -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();

View file

@ -132,12 +132,10 @@ class _OverlaySnackBarState extends State<OverlaySnackBar> {
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;

View file

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

View file

@ -46,8 +46,8 @@ class _PopupMenuExpansionPanelState<T> extends State<PopupMenuExpansionPanel<T>>
@override
Widget build(BuildContext context) {
final style = PopupMenuTheme.of(context).labelTextStyle!.resolve(
<MaterialState>{
if (!widget.enabled) MaterialState.disabled,
<WidgetState>{
if (!widget.enabled) WidgetState.disabled,
},
)!;
final animationDuration = context.select<DurationsData, Duration>((v) => v.expansionTileAnimation);

View file

@ -103,7 +103,7 @@ class _WheelSelectorState<T> extends State<WheelSelector<T>> {
child: Theme(
data: Theme.of(context).copyWith(
scrollbarTheme: ScrollbarThemeData(
thumbVisibility: MaterialStateProperty.all(false),
thumbVisibility: WidgetStateProperty.all(false),
),
),
child: ListWheelScrollView(

View file

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

View file

@ -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<AvesFloatingBar> 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<bool>(
valueListenable: _isBlurAllowedNotifier,
builder: (context, isBlurAllowed, child) {

View file

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

View file

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

View file

@ -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<AvesFilterChip> {
@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
? () {

View file

@ -16,13 +16,13 @@ class AvesOutlinedButton extends StatelessWidget {
Widget build(BuildContext context) {
final theme = Theme.of(context);
final style = ButtonStyle(
side: MaterialStateProperty.resolveWith<BorderSide>((states) {
side: WidgetStateProperty.resolveWith<BorderSide>((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<Color>((states) {
return states.contains(MaterialState.disabled) ? theme.disabledColor : theme.colorScheme.onBackground;
foregroundColor: WidgetStateProperty.resolveWith<Color>((states) {
return states.contains(WidgetState.disabled) ? theme.disabledColor : theme.colorScheme.onSurface;
}),
);
return icon != null

View file

@ -161,7 +161,7 @@ class OverlayTextButton extends StatelessWidget {
});
static const _borderRadius = 123.0;
static final _minSize = MaterialStateProperty.all<Size>(const Size(kMinInteractiveDimension, kMinInteractiveDimension));
static final _minSize = WidgetStateProperty.all<Size>(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<Color>(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
foregroundColor: MaterialStateProperty.all<Color>(theme.colorScheme.onSurface),
overlayColor: theme.isDark ? MaterialStateProperty.all<Color>(Colors.white.withOpacity(0.12)) : null,
backgroundColor: WidgetStateProperty.all<Color>(Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred)),
foregroundColor: WidgetStateProperty.all<Color>(theme.colorScheme.onSurface),
overlayColor: theme.isDark ? WidgetStateProperty.all<Color>(Colors.white.withOpacity(0.12)) : null,
minimumSize: _minSize,
side: MaterialStateProperty.all<BorderSide>(AvesBorder.curvedSide(context)),
shape: MaterialStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
side: WidgetStateProperty.all<BorderSide>(AvesBorder.curvedSide(context)),
shape: WidgetStateProperty.all<OutlinedBorder>(const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(_borderRadius)),
)),
),

View file

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

View file

@ -60,49 +60,43 @@ class _OverlayCoordinateFilterChipState extends State<OverlayCoordinateFilterChi
Widget build(BuildContext context) {
final blurred = settings.enableBlurEffect;
final theme = Theme.of(context);
return Theme(
data: theme.copyWith(
colorScheme: theme.colorScheme.copyWith(
background: Themes.overlayBackgroundColor(brightness: theme.brightness, blurred: blurred),
return Align(
alignment: Alignment.topLeft,
child: Selector<MapThemeData, Animation<double>>(
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<MapThemeData, Animation<double>>(
selector: (context, v) => v.scale,
builder: (context, scale, child) => SizeTransition(
sizeFactor: scale,
axisAlignment: 1,
child: FadeTransition(
opacity: scale,
child: child,
),
),
child: ValueListenableBuilder<ZoomedBounds?>(
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<ZoomedBounds?>(
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),
),
);
},
),
),
);
},
),
),
);

View file

@ -67,7 +67,7 @@ class _ErrorThumbnailState extends State<ErrorThumbnail> {
}
return Container(
alignment: Alignment.center,
color: Theme.of(context).colorScheme.background,
color: Themes.firstLayerColor(context),
width: extent,
height: extent,
child: child,

View file

@ -20,23 +20,39 @@ class _DebugColorSectionState extends State<DebugColorSection> 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),

View file

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

View file

@ -99,7 +99,7 @@ class _ConvertEntryDialogState extends State<ConvertEntryDialog> {
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(

View file

@ -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<RemoveEntryMetadataDialog> {
),
),
],
outlineColor: Theme.of(context).colorScheme.background,
outlineColor: Themes.firstLayerColor(context),
);
if (context.select<Settings, bool>((v) => v.themeColorMode == AvesThemeColorMode.polychrome)) {
final colors = context.watch<AvesColorsData>();

View file

@ -36,7 +36,7 @@ class _PatternDialogState extends State<PatternDialog> {
child: PatternLock(
relativePadding: .4,
selectedColor: colorScheme.primary,
notSelectedColor: colorScheme.onBackground,
notSelectedColor: colorScheme.onSurface,
pointRadius: 8,
fillPoints: true,
onInputComplete: (input) => _submit(input.join()),

View file

@ -50,8 +50,8 @@ class _PinDialogState extends State<PinDialog> {
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),

View file

@ -124,7 +124,7 @@ class _AppDrawerState extends State<AppDrawer> {
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<AppDrawer> {
OutlinedButtonTheme(
data: OutlinedButtonThemeData(
style: ButtonStyle(
foregroundColor: MaterialStateProperty.all<Color>(onPrimary),
overlayColor: MaterialStateProperty.all<Color>(onPrimary.withOpacity(.12)),
side: MaterialStateProperty.all<BorderSide>(BorderSide(width: 1, color: onPrimary.withOpacity(.24))),
foregroundColor: WidgetStateProperty.all<Color>(onPrimary),
overlayColor: WidgetStateProperty.all<Color>(onPrimary.withOpacity(.12)),
side: WidgetStateProperty.all<BorderSide>(BorderSide(width: 1, color: onPrimary.withOpacity(.24))),
),
),
child: Wrap(

View file

@ -275,7 +275,7 @@ class _QuickActionEditorBodyState<T extends Object> extends State<QuickActionEdi
effect: WormEffect(
dotWidth: 8,
dotHeight: 8,
dotColor: colorScheme.onBackground.withOpacity(.2),
dotColor: colorScheme.onSurface.withOpacity(.2),
activeDotColor: colorScheme.primary,
),
),

View file

@ -1,5 +1,6 @@
import 'package:aves/theme/durations.dart';
import 'package:aves/theme/styles.dart';
import 'package:aves/theme/themes.dart';
import 'package:aves/widgets/common/extensions/theme.dart';
import 'package:aves/widgets/common/identity/aves_filter_chip.dart';
import 'package:decorated_icon/decorated_icon.dart';
@ -17,12 +18,10 @@ class SettingsTileLeading extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
return AnimatedContainer(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: colorScheme.background,
color: Themes.firstLayerColor(context),
border: Border.fromBorderSide(BorderSide(
color: color,
width: AvesFilterChip.outlineWidth,
@ -34,7 +33,7 @@ class SettingsTileLeading extends StatelessWidget {
icon,
size: 18,
color: DefaultTextStyle.of(context).style.color,
shadows: theme.isDark ? AStyles.embossShadows : null,
shadows: Theme.of(context).isDark ? AStyles.embossShadows : null,
),
);
}

View file

@ -80,7 +80,6 @@ class _ContentState extends State<_Content> {
valueListenable: _indexNotifier,
builder: (context, selectedIndex, child) {
final rail = NavigationRail(
backgroundColor: Theme.of(context).colorScheme.background,
extended: true,
destinations: sections
.map((section) => NavigationRailDestination(

View file

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

View file

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

View file

@ -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<Selection<AvesEntry>?>()?.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,
),
),
);
}

View file

@ -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<Map<String, MetadataDirectory>> metadataNotifier;
final bool isSelecting;
Map<String, MetadataDirectory> get metadata => metadataNotifier.value;
static const pageRouteName = '/info/search';
InfoSearchDelegate({
required String searchFieldLabel,
required TextStyle searchFieldStyle,
required super.searchFieldLabel,
required super.searchFieldStyle,
required this.entry,
required this.metadataNotifier,
required this.isSelecting,
}) : super(
searchFieldLabel: searchFieldLabel,
searchFieldStyle: searchFieldStyle,
routeName: pageRouteName,
);
@override

View file

@ -64,7 +64,6 @@ class _TvMetadataPageState extends State<TvMetadataPage> {
if (selectedDir == null) return const SizedBox();
final rail = NavigationRail(
backgroundColor: Theme.of(context).colorScheme.background,
extended: true,
destinations: titles.mapIndexed((i, title) {
final dir = metadata[titles[i]]!;

View file

@ -65,10 +65,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
nested:
dependency: transitive
description:

View file

@ -153,10 +153,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
mgrs_dart:
dependency: transitive
description:

View file

@ -58,10 +58,10 @@ packages:
dependency: "direct main"
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
sky_engine:
dependency: transitive
description: flutter

View file

@ -48,6 +48,6 @@ android {
}
defaultConfig {
minSdk 19
minSdk 21
}
}

View file

@ -50,10 +50,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
plugin_platform_interface:
dependency: "direct main"
description:

View file

@ -50,10 +50,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
path:
dependency: transitive
description:

View file

@ -57,10 +57,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
path:
dependency: transitive
description:

View file

@ -131,26 +131,26 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.1"
lints:
dependency: transitive
description:
@ -179,10 +179,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
path:
dependency: transitive
description:
@ -248,10 +248,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
version: "0.7.0"
vector_math:
dependency: transitive
description:
@ -264,10 +264,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "13.0.0"
version: "14.2.1"
web:
dependency: transitive
description:
@ -278,4 +278,4 @@ packages:
version: "0.5.1"
sdks:
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.3.0"
flutter: ">=3.18.0-18.0.pre.54"

View file

@ -48,6 +48,6 @@ android {
}
defaultConfig {
minSdk 19
minSdk 21
}
}

View file

@ -50,10 +50,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
plugin_platform_interface:
dependency: "direct main"
description:

View file

@ -160,10 +160,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
mgrs_dart:
dependency: transitive
description:

View file

@ -323,10 +323,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
mgrs_dart:
dependency: transitive
description:
@ -464,10 +464,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.0"
version: "5.5.1"
win32_registry:
dependency: transitive
description:
@ -485,5 +485,5 @@ packages:
source: hosted
version: "2.0.0"
sdks:
dart: ">=3.3.0 <4.0.0"
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0"

View file

@ -199,10 +199,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
mgrs_dart:
dependency: transitive
description:

View file

@ -167,10 +167,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
mgrs_dart:
dependency: transitive
description:

View file

@ -50,10 +50,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
sky_engine:
dependency: transitive
description: flutter

View file

@ -50,10 +50,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
sky_engine:
dependency: transitive
description: flutter

View file

@ -72,10 +72,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
sky_engine:
dependency: transitive
description: flutter

View file

@ -96,10 +96,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
plugin_platform_interface:
dependency: transitive
description:

View file

@ -88,10 +88,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
sky_engine:
dependency: transitive
description: flutter

View file

@ -212,10 +212,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
package_info_plus:
dependency: transitive
description:
@ -433,10 +433,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.0"
version: "5.5.1"
xml:
dependency: transitive
description:
@ -446,5 +446,5 @@ packages:
source: hosted
version: "6.5.0"
sdks:
dart: ">=3.3.0 <4.0.0"
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.19.0"

View file

@ -177,7 +177,7 @@ packages:
description:
path: charts_common
ref: aves
resolved-ref: "6c44dc05289c1a5dbf0b027dbba083669843072c"
resolved-ref: ba7833d74e17ff497d3f4fb48f362d2dfdf3c6e3
url: "https://github.com/deckerst/flutter_google_charts.git"
source: git
version: "0.12.0"
@ -186,7 +186,7 @@ packages:
description:
path: charts_flutter
ref: aves
resolved-ref: "6c44dc05289c1a5dbf0b027dbba083669843072c"
resolved-ref: ba7833d74e17ff497d3f4fb48f362d2dfdf3c6e3
url: "https://github.com/deckerst/flutter_google_charts.git"
source: git
version: "0.12.0"
@ -436,18 +436,18 @@ packages:
dependency: "direct main"
description:
name: flex_color_picker
sha256: "5c846437069fb7afdd7ade6bf37e628a71d2ab0787095ddcb1253bf9345d5f3a"
sha256: "31b27677d8d8400e4cff5edb3f189f606dd964d608779b6ae1b7ddad37ea48c6"
url: "https://pub.dev"
source: hosted
version: "3.4.1"
version: "3.5.0"
flex_seed_scheme:
dependency: transitive
description:
name: flex_seed_scheme
sha256: "4cee2f1d07259f77e8b36f4ec5f35499d19e74e17c7dce5b819554914082bc01"
sha256: fb66cdb8ca89084e79efcad2bc2d9deb144666875116f08cdd8d9f8238c8b3ab
url: "https://pub.dev"
source: hosted
version: "1.5.0"
version: "2.0.0"
floating:
dependency: "direct main"
description:
@ -511,7 +511,7 @@ packages:
description:
path: "."
ref: HEAD
resolved-ref: "2956bcff219761aa90a1c95ad2d90b0050ae208f"
resolved-ref: f35b88327b98a1494426cf40ff7c30281cc7f937
url: "https://github.com/deckerst/flutter_localization_nn.git"
source: git
version: "0.0.1"
@ -566,10 +566,10 @@ packages:
dependency: transitive
description:
name: frontend_server_client
sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612"
sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694
url: "https://pub.dev"
source: hosted
version: "3.2.0"
version: "4.0.0"
fuchsia_remote_debug_protocol:
dependency: transitive
description: flutter
@ -715,10 +715,10 @@ packages:
dependency: "direct main"
description:
name: intl
sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
url: "https://pub.dev"
source: hosted
version: "0.18.1"
version: "0.19.0"
io:
dependency: transitive
description:
@ -755,26 +755,26 @@ packages:
dependency: "direct main"
description:
name: leak_tracker
sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa"
sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev"
source: hosted
version: "10.0.0"
version: "10.0.4"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0
sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.3"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
version: "3.0.1"
lints:
dependency: transitive
description:
@ -915,10 +915,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.12.0"
mgrs_dart:
dependency: transitive
description:
@ -1093,10 +1093,10 @@ packages:
dependency: transitive
description:
name: pdf_widget_wrapper
sha256: "9c3ca36e5000c9682d52bbdc486867ba7c5ee4403d1a5d6d03ed72157753377b"
sha256: c930860d987213a3d58c7ec3b7ecf8085c3897f773e8dc23da9cae60a5d6d0f5
url: "https://pub.dev"
source: hosted
version: "1.0.3"
version: "1.0.4"
percent_indicator:
dependency: "direct main"
description:
@ -1531,26 +1531,26 @@ packages:
dependency: "direct dev"
description:
name: test
sha256: a1f7595805820fcc05e5c52e3a231aedd0b72972cb333e8c738a8b1239448b6f
sha256: "7ee446762c2c50b3bd4ea96fe13ffac69919352bd3b4b17bac3f3465edc58073"
url: "https://pub.dev"
source: hosted
version: "1.24.9"
version: "1.25.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev"
source: hosted
version: "0.6.1"
version: "0.7.0"
test_core:
dependency: transitive
description:
name: test_core
sha256: a757b14fc47507060a162cc2530d9a4a2f92f5100a952c7443b5cad5ef5b106a
sha256: "2bc4b4ecddd75309300d8096f781c0e3280ca1ef85beda558d33fcbedc2eead4"
url: "https://pub.dev"
source: hosted
version: "0.5.9"
version: "0.6.0"
transparent_image:
dependency: "direct main"
description:
@ -1675,10 +1675,10 @@ packages:
dependency: transitive
description:
name: vm_service
sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957
sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev"
source: hosted
version: "13.0.0"
version: "14.2.1"
volume_controller:
dependency: "direct main"
description:
@ -1747,10 +1747,10 @@ packages:
dependency: transitive
description:
name: win32
sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
url: "https://pub.dev"
source: hosted
version: "5.5.0"
version: "5.5.1"
win32_registry:
dependency: transitive
description:
@ -1792,5 +1792,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.3.0 <4.0.0"
flutter: ">=3.19.6"
dart: ">=3.4.0 <4.0.0"
flutter: ">=3.22.0"

View file

@ -13,7 +13,7 @@ publish_to: none
environment:
# this project bundles Flutter SDK via `flutter_wrapper`
# cf https://github.com/passsy/flutter_wrapper
flutter: 3.19.6
flutter: 3.22.0
sdk: '>=3.3.0 <4.0.0'
# use `scripts/apply_flavor_{flavor}.sh` to set the right dependencies for the flavor