Merge branch 'develop'
This commit is contained in:
commit
689346f410
20 changed files with 99 additions and 84 deletions
|
@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file.
|
||||||
|
|
||||||
## <a id="unreleased"></a>[Unreleased]
|
## <a id="unreleased"></a>[Unreleased]
|
||||||
|
|
||||||
|
## <a id="v1.6.8"></a>[v1.6.8] - 2022-05-27
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- wrong window metrics on startup in some cases
|
||||||
|
- home albums not updated on startup in some cases
|
||||||
|
- crash when cataloguing large TIFF
|
||||||
|
|
||||||
## <a id="v1.6.7"></a>[v1.6.7] - 2022-05-25
|
## <a id="v1.6.7"></a>[v1.6.7] - 2022-05-25
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -5,9 +5,7 @@ import android.app.SearchManager
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.*
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.Parcelable
|
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.core.content.pm.ShortcutInfoCompat
|
import androidx.core.content.pm.ShortcutInfoCompat
|
||||||
|
@ -125,6 +123,15 @@ class MainActivity : FlutterActivity() {
|
||||||
Log.i(LOG_TAG, "onStart")
|
Log.i(LOG_TAG, "onStart")
|
||||||
super.onStart()
|
super.onStart()
|
||||||
analysisHandler.attachToActivity()
|
analysisHandler.attachToActivity()
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
|
|
@ -284,7 +284,7 @@ class DebugHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
metadataMap["mimeType"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir ->
|
metadataMap["mimeType"] = metadata.getDirectoriesOfType(FileTypeDirectory::class.java).joinToString { dir ->
|
||||||
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
|
if (dir.containsTag(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)) {
|
||||||
dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)
|
dir.getString(FileTypeDirectory.TAG_DETECTED_FILE_MIME_TYPE)
|
||||||
|
|
|
@ -150,7 +150,7 @@ class EmbeddedDataHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
// data can be large and stored in "Extended XMP",
|
// data can be large and stored in "Extended XMP",
|
||||||
// which is returned as a second XMP directory
|
// which is returned as a second XMP directory
|
||||||
val xmpDirs = metadata.getDirectoriesOfType(XmpDirectory::class.java)
|
val xmpDirs = metadata.getDirectoriesOfType(XmpDirectory::class.java)
|
||||||
|
|
|
@ -126,7 +126,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 }
|
foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 }
|
||||||
foundXmp = metadata.directories.any { it is XmpDirectory && it.tagCount > 0 }
|
foundXmp = metadata.directories.any { it is XmpDirectory && it.tagCount > 0 }
|
||||||
val uuidDirCount = HashMap<String, Int>()
|
val uuidDirCount = HashMap<String, Int>()
|
||||||
|
@ -451,7 +451,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 }
|
foundExif = metadata.directories.any { it is ExifDirectoryBase && it.tagCount > 0 }
|
||||||
|
|
||||||
// File type
|
// File type
|
||||||
|
@ -718,7 +718,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(ExifSubIFDDirectory::class.java)) {
|
||||||
foundExif = true
|
foundExif = true
|
||||||
dir.getSafeRational(ExifDirectoryBase.TAG_FNUMBER) { metadataMap[KEY_APERTURE] = it.numerator.toDouble() / it.denominator }
|
dir.getSafeRational(ExifDirectoryBase.TAG_FNUMBER) { metadataMap[KEY_APERTURE] = it.numerator.toDouble() / it.denominator }
|
||||||
|
@ -768,7 +768,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
val fields = HashMap<Int, Any?>()
|
val fields = HashMap<Int, Any?>()
|
||||||
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(ExifIFD0Directory::class.java)) {
|
||||||
if (dir.containsGeoTiffTags()) {
|
if (dir.containsGeoTiffTags()) {
|
||||||
|
@ -831,7 +831,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
val fields: FieldMap = hashMapOf(
|
val fields: FieldMap = hashMapOf(
|
||||||
"projectionType" to XMP.GPANO_PROJECTION_TYPE_DEFAULT,
|
"projectionType" to XMP.GPANO_PROJECTION_TYPE_DEFAULT,
|
||||||
)
|
)
|
||||||
|
@ -895,7 +895,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
val xmpStrings = metadata.getDirectoriesOfType(XmpDirectory::class.java).mapNotNull { XMPMetaFactory.serializeToString(it.xmpMeta, xmpSerializeOptions) }
|
val xmpStrings = metadata.getDirectoriesOfType(XmpDirectory::class.java).mapNotNull { XMPMetaFactory.serializeToString(it.xmpMeta, xmpSerializeOptions) }
|
||||||
result.success(xmpStrings.toMutableList())
|
result.success(xmpStrings.toMutableList())
|
||||||
return
|
return
|
||||||
|
@ -1000,7 +1000,7 @@ class MetadataFetchHandler(private val context: Context) : MethodCallHandler {
|
||||||
if (canReadWithMetadataExtractor(mimeType)) {
|
if (canReadWithMetadataExtractor(mimeType)) {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
val tag = when (field) {
|
val tag = when (field) {
|
||||||
ExifInterface.TAG_DATETIME -> ExifIFD0Directory.TAG_DATETIME
|
ExifInterface.TAG_DATETIME -> ExifIFD0Directory.TAG_DATETIME
|
||||||
ExifInterface.TAG_DATETIME_DIGITIZED -> ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED
|
ExifInterface.TAG_DATETIME_DIGITIZED -> ExifSubIFDDirectory.TAG_DATETIME_DIGITIZED
|
||||||
|
|
|
@ -48,15 +48,15 @@ object MetadataExtractorHelper {
|
||||||
return FileTypeDetector.detectFileType(bufferedInputStream).mimeType
|
return FileTypeDetector.detectFileType(bufferedInputStream).mimeType
|
||||||
}
|
}
|
||||||
|
|
||||||
fun safeRead(input: InputStream, sizeBytes: Long?): com.drew.metadata.Metadata {
|
fun safeRead(input: InputStream): com.drew.metadata.Metadata {
|
||||||
val streamLength = sizeBytes ?: -1
|
|
||||||
val bufferedInputStream = if (input is BufferedInputStream) input else BufferedInputStream(input)
|
val bufferedInputStream = if (input is BufferedInputStream) input else BufferedInputStream(input)
|
||||||
val fileType = FileTypeDetector.detectFileType(bufferedInputStream)
|
val fileType = FileTypeDetector.detectFileType(bufferedInputStream)
|
||||||
|
|
||||||
val metadata = if (fileType == FileType.Jpeg) {
|
val metadata = if (fileType == FileType.Jpeg) {
|
||||||
safeReadJpeg(bufferedInputStream)
|
safeReadJpeg(bufferedInputStream)
|
||||||
} else {
|
} else {
|
||||||
ImageMetadataReader.readMetadata(bufferedInputStream, streamLength, fileType)
|
// providing the stream length is risky, as it may crash if it is incorrect
|
||||||
|
ImageMetadataReader.readMetadata(bufferedInputStream, -1L, fileType)
|
||||||
}
|
}
|
||||||
|
|
||||||
metadata.addDirectory(FileTypeDirectory(fileType))
|
metadata.addDirectory(FileTypeDirectory(fileType))
|
||||||
|
|
|
@ -140,7 +140,7 @@ object MultiPage {
|
||||||
fun getMotionPhotoOffset(context: Context, uri: Uri, mimeType: String, sizeBytes: Long): Long? {
|
fun getMotionPhotoOffset(context: Context, uri: Uri, mimeType: String, sizeBytes: Long): Long? {
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, mimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
for (dir in metadata.getDirectoriesOfType(XmpDirectory::class.java)) {
|
for (dir in metadata.getDirectoriesOfType(XmpDirectory::class.java)) {
|
||||||
var offsetFromEnd: Long? = null
|
var offsetFromEnd: Long? = null
|
||||||
val xmpMeta = dir.xmpMeta
|
val xmpMeta = dir.xmpMeta
|
||||||
|
@ -194,7 +194,7 @@ object MultiPage {
|
||||||
return pages
|
return pages
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isMultiPageTiff(context: Context, uri: Uri) = getTiffPageInfo(context, uri, 0)?.outDirectoryCount ?: 1 > 1
|
fun isMultiPageTiff(context: Context, uri: Uri) = (getTiffPageInfo(context, uri, 0)?.outDirectoryCount ?: 1) > 1
|
||||||
|
|
||||||
private fun getTiffPageInfo(context: Context, uri: Uri, page: Int): TiffBitmapFactory.Options? {
|
private fun getTiffPageInfo(context: Context, uri: Uri, page: Int): TiffBitmapFactory.Options? {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -97,10 +97,10 @@ class SourceEntry {
|
||||||
get() = if (uri.scheme == ContentResolver.SCHEME_CONTENT) uri.tryParseId() else null
|
get() = if (uri.scheme == ContentResolver.SCHEME_CONTENT) uri.tryParseId() else null
|
||||||
|
|
||||||
val isSized: Boolean
|
val isSized: Boolean
|
||||||
get() = width ?: 0 > 0 && height ?: 0 > 0
|
get() = (width ?: 0) > 0 && (height ?: 0) > 0
|
||||||
|
|
||||||
private val hasDuration: Boolean
|
private val hasDuration: Boolean
|
||||||
get() = durationMillis ?: 0 > 0
|
get() = (durationMillis ?: 0) > 0
|
||||||
|
|
||||||
val isVideo: Boolean
|
val isVideo: Boolean
|
||||||
get() = MimeTypes.isVideo(sourceMimeType)
|
get() = MimeTypes.isVideo(sourceMimeType)
|
||||||
|
@ -161,7 +161,7 @@ class SourceEntry {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Metadata.openSafeInputStream(context, uri, sourceMimeType, sizeBytes)?.use { input ->
|
Metadata.openSafeInputStream(context, uri, sourceMimeType, sizeBytes)?.use { input ->
|
||||||
val metadata = MetadataExtractorHelper.safeRead(input, sizeBytes)
|
val metadata = MetadataExtractorHelper.safeRead(input)
|
||||||
|
|
||||||
// do not switch on specific MIME types, as the reported MIME type could be wrong
|
// do not switch on specific MIME types, as the reported MIME type could be wrong
|
||||||
// (e.g. PNG registered as JPG)
|
// (e.g. PNG registered as JPG)
|
||||||
|
|
|
@ -84,7 +84,7 @@ object MimeTypes {
|
||||||
// as of Flutter v1.22.0, with additional custom handling for SVG
|
// as of Flutter v1.22.0, with additional custom handling for SVG
|
||||||
fun canDecodeWithFlutter(mimeType: String, rotationDegrees: Int?, isFlipped: Boolean?) = when (mimeType) {
|
fun canDecodeWithFlutter(mimeType: String, rotationDegrees: Int?, isFlipped: Boolean?) = when (mimeType) {
|
||||||
JPEG, GIF, WEBP, BMP, WBMP, ICO, SVG -> true
|
JPEG, GIF, WEBP, BMP, WBMP, ICO, SVG -> true
|
||||||
PNG -> rotationDegrees ?: 0 == 0 && !(isFlipped ?: false)
|
PNG -> (rotationDegrees ?: 0) == 0 && !(isFlipped ?: false)
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
5
fastlane/metadata/android/en-US/changelogs/1074.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/1074.txt
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
In v1.6.8:
|
||||||
|
- bottom navigation bar
|
||||||
|
- fast scroll with breadcrumbs
|
||||||
|
- settings search
|
||||||
|
Full changelog available on GitHub
|
|
@ -408,6 +408,8 @@
|
||||||
"settingsSystemDefault": "Система",
|
"settingsSystemDefault": "Система",
|
||||||
"settingsDefault": "По умолчанию",
|
"settingsDefault": "По умолчанию",
|
||||||
|
|
||||||
|
"settingsSearchFieldLabel": "Поиск настроек",
|
||||||
|
"settingsSearchEmpty": "Нет соответствующих настроек",
|
||||||
"settingsActionExport": "Экспорт",
|
"settingsActionExport": "Экспорт",
|
||||||
"settingsActionImport": "Импорт",
|
"settingsActionImport": "Импорт",
|
||||||
|
|
||||||
|
@ -417,6 +419,7 @@
|
||||||
|
|
||||||
"settingsSectionNavigation": "Навигация",
|
"settingsSectionNavigation": "Навигация",
|
||||||
"settingsHome": "Домашний каталог",
|
"settingsHome": "Домашний каталог",
|
||||||
|
"settingsShowBottomNavigationBar": "Показать нижнюю панель навигации",
|
||||||
"settingsKeepScreenOnTile": "Держать экран включенным",
|
"settingsKeepScreenOnTile": "Держать экран включенным",
|
||||||
"settingsKeepScreenOnTitle": "Держать экран включенным",
|
"settingsKeepScreenOnTitle": "Держать экран включенным",
|
||||||
"settingsDoubleBackExit": "Дважды нажмите «Назад», чтобы выйти",
|
"settingsDoubleBackExit": "Дважды нажмите «Назад», чтобы выйти",
|
||||||
|
@ -439,6 +442,7 @@
|
||||||
"settingsThumbnailOverlayTile": "Наложение",
|
"settingsThumbnailOverlayTile": "Наложение",
|
||||||
"settingsThumbnailOverlayTitle": "Наложение",
|
"settingsThumbnailOverlayTitle": "Наложение",
|
||||||
"settingsThumbnailShowFavouriteIcon": "Показать значок избранного",
|
"settingsThumbnailShowFavouriteIcon": "Показать значок избранного",
|
||||||
|
"settingsThumbnailShowTagIcon": "Показать значок тега",
|
||||||
"settingsThumbnailShowLocationIcon": "Показать значок местоположения",
|
"settingsThumbnailShowLocationIcon": "Показать значок местоположения",
|
||||||
"settingsThumbnailShowMotionPhotoIcon": "Показать значок «живого фото»",
|
"settingsThumbnailShowMotionPhotoIcon": "Показать значок «живого фото»",
|
||||||
"settingsThumbnailShowRating": "Показать рейтинг",
|
"settingsThumbnailShowRating": "Показать рейтинг",
|
||||||
|
|
|
@ -26,10 +26,14 @@ mixin AlbumMixin on SourceBase {
|
||||||
return compareAsciiUpperCase(va, vb);
|
return compareAsciiUpperCase(va, vb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notifyAlbumsChanged() {
|
||||||
|
eventBus.fire(AlbumsChangedEvent());
|
||||||
|
}
|
||||||
|
|
||||||
void _onAlbumChanged({bool notify = true}) {
|
void _onAlbumChanged({bool notify = true}) {
|
||||||
invalidateAlbumDisplayNames();
|
invalidateAlbumDisplayNames();
|
||||||
if (notify) {
|
if (notify) {
|
||||||
eventBus.fire(AlbumsChangedEvent());
|
notifyAlbumsChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,6 +184,11 @@ class MediaStoreSource extends CollectionSource {
|
||||||
}
|
}
|
||||||
await analyze(analysisController, entries: analysisEntries);
|
await analyze(analysisController, entries: analysisEntries);
|
||||||
|
|
||||||
|
// the home page may not reflect the current derived filters
|
||||||
|
// as the initial addition of entries is silent,
|
||||||
|
// so we manually notify change for potential home screen filters
|
||||||
|
notifyAlbumsChanged();
|
||||||
|
|
||||||
debugPrint('$runtimeType refresh ${stopwatch.elapsed} done for ${knownEntries.length} known, ${allNewEntries.length} new, ${removedEntries.length} removed');
|
debugPrint('$runtimeType refresh ${stopwatch.elapsed} done for ${knownEntries.length} known, ${allNewEntries.length} new, ${removedEntries.length} removed');
|
||||||
},
|
},
|
||||||
onError: (error) => debugPrint('$runtimeType stream error=$error'),
|
onError: (error) => debugPrint('$runtimeType stream error=$error'),
|
||||||
|
|
|
@ -55,6 +55,16 @@ class AvesApp extends StatefulWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AvesApp> createState() => _AvesAppState();
|
State<AvesApp> createState() => _AvesAppState();
|
||||||
|
|
||||||
|
static void showSystemUI() {
|
||||||
|
if (device.supportEdgeToEdgeUIMode) {
|
||||||
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
||||||
|
} else {
|
||||||
|
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hideSystemUI() => SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
class _AvesAppState extends State<AvesApp> with WidgetsBindingObserver {
|
||||||
|
|
|
@ -35,7 +35,8 @@ class AlbumListPage extends StatelessWidget {
|
||||||
builder: (context, s, child) {
|
builder: (context, s, child) {
|
||||||
return ValueListenableBuilder<bool>(
|
return ValueListenableBuilder<bool>(
|
||||||
valueListenable: androidFileUtils.areAppNamesReadyNotifier,
|
valueListenable: androidFileUtils.areAppNamesReadyNotifier,
|
||||||
builder: (context, areAppNamesReady, child) => StreamBuilder(
|
builder: (context, areAppNamesReady, child) {
|
||||||
|
return StreamBuilder(
|
||||||
stream: source.eventBus.on<AlbumsChangedEvent>(),
|
stream: source.eventBus.on<AlbumsChangedEvent>(),
|
||||||
builder: (context, snapshot) {
|
builder: (context, snapshot) {
|
||||||
final gridItems = getAlbumGridItems(context, source);
|
final gridItems = getAlbumGridItems(context, source);
|
||||||
|
@ -57,7 +58,8 @@ class AlbumListPage extends StatelessWidget {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,6 @@ import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/app_mode.dart';
|
import 'package:aves/app_mode.dart';
|
||||||
import 'package:aves/model/actions/move_type.dart';
|
import 'package:aves/model/actions/move_type.dart';
|
||||||
import 'package:aves/model/device.dart';
|
|
||||||
import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
import 'package:aves/model/filters/trash.dart';
|
import 'package:aves/model/filters/trash.dart';
|
||||||
|
@ -13,6 +12,7 @@ import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/services/common/services.dart';
|
import 'package:aves/services/common/services.dart';
|
||||||
import 'package:aves/theme/durations.dart';
|
import 'package:aves/theme/durations.dart';
|
||||||
import 'package:aves/utils/change_notifier.dart';
|
import 'package:aves/utils/change_notifier.dart';
|
||||||
|
import 'package:aves/widgets/aves_app.dart';
|
||||||
import 'package:aves/widgets/collection/collection_page.dart';
|
import 'package:aves/widgets/collection/collection_page.dart';
|
||||||
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
import 'package:aves/widgets/common/action_mixins/feedback.dart';
|
||||||
import 'package:aves/widgets/common/basic/insets.dart';
|
import 'package:aves/widgets/common/basic/insets.dart';
|
||||||
|
@ -584,22 +584,10 @@ class _EntryViewerStackState extends State<EntryViewerStack> with FeedbackMixin,
|
||||||
windowService.keepScreenOn(false);
|
windowService.keepScreenOn(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
_showSystemUI();
|
AvesApp.showSystemUI();
|
||||||
windowService.requestOrientation();
|
windowService.requestOrientation();
|
||||||
}
|
}
|
||||||
|
|
||||||
// system UI
|
|
||||||
|
|
||||||
static void _showSystemUI() {
|
|
||||||
if (device.supportEdgeToEdgeUIMode) {
|
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
|
||||||
} else {
|
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _hideSystemUI() => SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
|
||||||
|
|
||||||
// overlay
|
// overlay
|
||||||
|
|
||||||
Future<void> _initOverlay() async {
|
Future<void> _initOverlay() async {
|
||||||
|
@ -611,7 +599,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with FeedbackMixin,
|
||||||
|
|
||||||
Future<void> _onOverlayVisibleChange({bool animate = true}) async {
|
Future<void> _onOverlayVisibleChange({bool animate = true}) async {
|
||||||
if (_overlayVisible.value) {
|
if (_overlayVisible.value) {
|
||||||
_showSystemUI();
|
AvesApp.showSystemUI();
|
||||||
if (animate) {
|
if (animate) {
|
||||||
await _overlayAnimationController.forward();
|
await _overlayAnimationController.forward();
|
||||||
} else {
|
} else {
|
||||||
|
@ -623,7 +611,7 @@ class _EntryViewerStackState extends State<EntryViewerStack> with FeedbackMixin,
|
||||||
_frozenViewInsets = mediaQuery.viewInsets;
|
_frozenViewInsets = mediaQuery.viewInsets;
|
||||||
_frozenViewPadding = mediaQuery.viewPadding;
|
_frozenViewPadding = mediaQuery.viewPadding;
|
||||||
});
|
});
|
||||||
_hideSystemUI();
|
AvesApp.hideSystemUI();
|
||||||
if (animate) {
|
if (animate) {
|
||||||
await _overlayAnimationController.reverse();
|
await _overlayAnimationController.reverse();
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import 'dart:math';
|
import 'dart:math';
|
||||||
|
|
||||||
import 'package:aves/model/device.dart';
|
|
||||||
import 'package:aves/model/entry.dart';
|
import 'package:aves/model/entry.dart';
|
||||||
import 'package:aves/model/entry_images.dart';
|
import 'package:aves/model/entry_images.dart';
|
||||||
import 'package:aves/model/panorama.dart';
|
import 'package:aves/model/panorama.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
|
import 'package:aves/widgets/aves_app.dart';
|
||||||
import 'package:aves/widgets/common/basic/insets.dart';
|
import 'package:aves/widgets/common/basic/insets.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:aves/widgets/common/extensions/media_query.dart';
|
import 'package:aves/widgets/common/extensions/media_query.dart';
|
||||||
|
@ -13,7 +13,6 @@ import 'package:aves/widgets/viewer/overlay/common.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/scheduler.dart';
|
import 'package:flutter/scheduler.dart';
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:panorama/panorama.dart';
|
import 'package:panorama/panorama.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
@ -164,21 +163,11 @@ class _PanoramaPageState extends State<PanoramaPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onLeave() {
|
void _onLeave() {
|
||||||
_showSystemUI();
|
AvesApp.showSystemUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
// system UI
|
// system UI
|
||||||
|
|
||||||
static void _showSystemUI() {
|
|
||||||
if (device.supportEdgeToEdgeUIMode) {
|
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
|
|
||||||
} else {
|
|
||||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual, overlays: SystemUiOverlay.values);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _hideSystemUI() => SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
|
||||||
|
|
||||||
// overlay
|
// overlay
|
||||||
|
|
||||||
Future<void> _initOverlay() async {
|
Future<void> _initOverlay() async {
|
||||||
|
@ -190,9 +179,9 @@ class _PanoramaPageState extends State<PanoramaPage> {
|
||||||
|
|
||||||
Future<void> _onOverlayVisibleChange() async {
|
Future<void> _onOverlayVisibleChange() async {
|
||||||
if (_overlayVisible.value) {
|
if (_overlayVisible.value) {
|
||||||
_showSystemUI();
|
AvesApp.showSystemUI();
|
||||||
} else {
|
} else {
|
||||||
_hideSystemUI();
|
AvesApp.hideSystemUI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ repository: https://github.com/deckerst/aves
|
||||||
# - github changelog: /CHANGELOG.md
|
# - github changelog: /CHANGELOG.md
|
||||||
# - play changelog: /whatsnew/whatsnew-en-US
|
# - play changelog: /whatsnew/whatsnew-en-US
|
||||||
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/1XXX.txt
|
# - izzy changelog: /fastlane/metadata/android/en-US/changelogs/1XXX.txt
|
||||||
version: 1.6.7+73
|
version: 1.6.8+74
|
||||||
publish_to: none
|
publish_to: none
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
|
|
|
@ -2,12 +2,5 @@
|
||||||
"es": [
|
"es": [
|
||||||
"settingsShowBottomNavigationBar",
|
"settingsShowBottomNavigationBar",
|
||||||
"settingsThumbnailShowTagIcon"
|
"settingsThumbnailShowTagIcon"
|
||||||
],
|
|
||||||
|
|
||||||
"ru": [
|
|
||||||
"settingsSearchFieldLabel",
|
|
||||||
"settingsSearchEmpty",
|
|
||||||
"settingsShowBottomNavigationBar",
|
|
||||||
"settingsThumbnailShowTagIcon"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
In v1.6.7:
|
In v1.6.8:
|
||||||
- bottom navigation bar
|
- bottom navigation bar
|
||||||
- fast scroll with breadcrumbs
|
- fast scroll with breadcrumbs
|
||||||
- settings search
|
- settings search
|
||||||
|
|
Loading…
Reference in a new issue