style: address IDE warnings
Remove unused imports and an unused spacing constant, drop redundant if checks and redundant opt-in markers, replace loop variables with destructuring, convert a string concatenation to a template, use Configuration.screenHeightDp instead of LocalWindowInfo.containerSize, and opt in to ExperimentalSerializationApi for decodeFromStream.
This commit is contained in:
1 parent
4b627b4d05
commit
3d83d04cea
15 files changed
+58
-84
No files matched your search
@@ -59,13 +59,12 @@ class NotificationHelper(private val context: Context) : NotificationPort {
|
|||||||
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
|
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as? NotificationManager
|
||||||
manager?.createNotificationChannel(channel)
|
manager?.createNotificationChannel(channel)
|
||||||
}
|
}
|
||||||
private fun canShowNotification(): Boolean {
|
private fun canShowNotification(): Boolean =
|
||||||
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU) return true
|
android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.TIRAMISU ||
|
||||||
return ContextCompat.checkSelfPermission(
|
ContextCompat.checkSelfPermission(
|
||||||
context,
|
context,
|
||||||
android.Manifest.permission.POST_NOTIFICATIONS
|
android.Manifest.permission.POST_NOTIFICATIONS
|
||||||
) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
) == android.content.pm.PackageManager.PERMISSION_GRANTED
|
||||||
}
|
|
||||||
override fun showProgress(percent: Int, titleRes: Int) {
|
override fun showProgress(percent: Int, titleRes: Int) {
|
||||||
showUnifiedProgressNotification(
|
showUnifiedProgressNotification(
|
||||||
title = context.getString(titleRes),
|
title = context.getString(titleRes),
|
||||||
|
|||||||
@@ -454,11 +454,7 @@ class IndexSearcher(private val context: Context) {
|
|||||||
val originalWord = readPooledString(source, source.readUnsignedShort())
|
val originalWord = readPooledString(source, source.readUnsignedShort())
|
||||||
val offset = ArticleOffset(source.readLong())
|
val offset = ArticleOffset(source.readLong())
|
||||||
val length = ArticleLength(source.readInt())
|
val length = ArticleLength(source.readInt())
|
||||||
val isAlias = if (metadata.version >= 6) {
|
val isAlias = metadata.version >= 6 && source.readUnsignedByte() and ENTRY_FLAG_ALIAS != 0
|
||||||
source.readUnsignedByte() and ENTRY_FLAG_ALIAS != 0
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
return IndexEntry(word, originalWord, offset, length, isAlias = isAlias)
|
return IndexEntry(word, originalWord, offset, length, isAlias = isAlias)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,8 +468,11 @@ class IndexSearcher(private val context: Context) {
|
|||||||
|
|
||||||
private fun openSource(pathOrUri: String): RandomAccessSource {
|
private fun openSource(pathOrUri: String): RandomAccessSource {
|
||||||
val file = File(pathOrUri)
|
val file = File(pathOrUri)
|
||||||
if (!file.exists()) throw DictionaryError.FileSystemError.NotFound(pathOrUri)
|
return if (file.exists()) {
|
||||||
return FileSource(file)
|
FileSource(file)
|
||||||
|
} else {
|
||||||
|
throw DictionaryError.FileSystemError.NotFound(pathOrUri)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private fun openInputStream(pathOrUri: String): java.io.InputStream {
|
private fun openInputStream(pathOrUri: String): java.io.InputStream {
|
||||||
val file = File(pathOrUri)
|
val file = File(pathOrUri)
|
||||||
|
|||||||
@@ -112,20 +112,20 @@ class KotlinDictionaryEngine(private val context: Context) : ProgressIndexingEng
|
|||||||
maxResults: Int
|
maxResults: Int
|
||||||
): List<IndexEntry> = withContext(Dispatchers.IO) {
|
): List<IndexEntry> = withContext(Dispatchers.IO) {
|
||||||
val allResults = mutableListOf<IndexEntry>()
|
val allResults = mutableListOf<IndexEntry>()
|
||||||
for (dict in dictionaries) {
|
for ((name, path, indexPath, _, _, metadata) in dictionaries) {
|
||||||
try {
|
try {
|
||||||
val indexPath = resolveIndexPath(dict.indexPath)
|
val resolvedIndexPath = resolveIndexPath(indexPath)
|
||||||
val entry = indexSearcher.findFirstEntry(indexPath, query)
|
val entry = indexSearcher.findFirstEntry(resolvedIndexPath, query)
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
allResults.add(entry.withDictionary(dict.metadata.name.ifBlank { dict.name }, dict.path))
|
allResults.add(entry.withDictionary(metadata.name.ifBlank { name }, path))
|
||||||
}
|
}
|
||||||
if (allResults.size >= maxResults) break
|
if (allResults.size >= maxResults) break
|
||||||
} catch (e: OutOfMemoryError) {
|
} catch (e: OutOfMemoryError) {
|
||||||
Log.e(TAG, "search() - OOM for ${dict.indexPath}", e)
|
Log.e(TAG, "search() - OOM for $indexPath", e)
|
||||||
trimMemory(80)
|
trimMemory(80)
|
||||||
break
|
break
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.w(TAG, "search() - error for ${dict.indexPath}: ${e.message}")
|
Log.w(TAG, "search() - error for $indexPath: ${e.message}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
allResults
|
allResults
|
||||||
|
|||||||
@@ -538,12 +538,12 @@ class LocalDictionaryRepository(
|
|||||||
val dictionaries = mutableDictionaries.value
|
val dictionaries = mutableDictionaries.value
|
||||||
if (dictionaries.isEmpty()) return@withContext
|
if (dictionaries.isEmpty()) return@withContext
|
||||||
|
|
||||||
for (dict in dictionaries) {
|
for ((_, _, indexPath) in dictionaries) {
|
||||||
try {
|
try {
|
||||||
val indexPath = resolveIndexPath(dict.indexPath)
|
val resolvedIndexPath = resolveIndexPath(indexPath)
|
||||||
val indexSearcher = engine.getIndexSearcher()
|
val indexSearcher = engine.getIndexSearcher()
|
||||||
if (!indexSearcher.isMetadataLoaded(indexPath)) {
|
if (!indexSearcher.isMetadataLoaded(resolvedIndexPath)) {
|
||||||
engine.preloadIndexMetadata(indexPath)
|
engine.preloadIndexMetadata(resolvedIndexPath)
|
||||||
}
|
}
|
||||||
yield()
|
yield()
|
||||||
} catch (_: Exception) { /* Ignore preload failure */ }
|
} catch (_: Exception) { /* Ignore preload failure */ }
|
||||||
|
|||||||
+7
-7
@@ -54,17 +54,17 @@ class DictionaryCleaner(
|
|||||||
for ((prefix, items) in parsedByPrefix) {
|
for ((prefix, items) in parsedByPrefix) {
|
||||||
val latestDsl = latestDslDateByPrefix[prefix] ?: continue
|
val latestDsl = latestDslDateByPrefix[prefix] ?: continue
|
||||||
val dslDates = dslDatesByPrefix[prefix].orEmpty()
|
val dslDates = dslDatesByPrefix[prefix].orEmpty()
|
||||||
for (item in items) {
|
for ((name, _, date, ext) in items) {
|
||||||
if (DateUtils.isDateBefore(item.date, latestDsl)) {
|
if (DateUtils.isDateBefore(date, latestDsl)) {
|
||||||
toDelete.add(item.name)
|
toDelete.add(name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (item.ext in indexExtensions && item.date != latestDsl) {
|
if (ext in indexExtensions && date != latestDsl) {
|
||||||
toDelete.add(item.name)
|
toDelete.add(name)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (item.ext in indexExtensions && item.date !in dslDates) {
|
if (ext in indexExtensions && date !in dslDates) {
|
||||||
toDelete.add(item.name)
|
toDelete.add(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-21
@@ -46,14 +46,13 @@ class DictionaryExtractor(
|
|||||||
reportProgress(processedIndex.toFloat() / totalFiles)
|
reportProgress(processedIndex.toFloat() / totalFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (file in gzFiles) {
|
for ((fileName, uri) in gzFiles) {
|
||||||
val fileName = file.name
|
|
||||||
val baseName = fileName.dropLast(DictionaryConfig.GZ_EXTENSION.length)
|
val baseName = fileName.dropLast(DictionaryConfig.GZ_EXTENSION.length)
|
||||||
val lowerBaseName = baseName.lowercase()
|
val lowerBaseName = baseName.lowercase()
|
||||||
if (baseName.isBlank() ||
|
if (baseName.isBlank() ||
|
||||||
lowerBaseName.endsWith(DictionaryConfig.GZ_EXTENSION) ||
|
lowerBaseName.endsWith(DictionaryConfig.GZ_EXTENSION) ||
|
||||||
lowerBaseName.endsWith(".txt")) {
|
lowerBaseName.endsWith(".txt")) {
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
markFileProcessed()
|
markFileProcessed()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -65,19 +64,19 @@ class DictionaryExtractor(
|
|||||||
val dslFileName = "$dslBaseName${DictionaryConfig.DSL_EXTENSION}"
|
val dslFileName = "$dslBaseName${DictionaryConfig.DSL_EXTENSION}"
|
||||||
val existingDslFile = fileStorageManager.findFile(folderUri, dslFileName)
|
val existingDslFile = fileStorageManager.findFile(folderUri, dslFileName)
|
||||||
if (existingDslFile != null && existingDslFile.exists()) {
|
if (existingDslFile != null && existingDslFile.exists()) {
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
markFileProcessed()
|
markFileProcessed()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
val dslUri = fileStorageManager.createFileInFolder(folderUri, dslFileName, overwrite = false)
|
val dslUri = fileStorageManager.createFileInFolder(folderUri, dslFileName, overwrite = false)
|
||||||
?: continue
|
?: continue
|
||||||
val extractResult = ArchiveUtils.extractGzWithBom(context, file.uri, dslUri)
|
val extractResult = ArchiveUtils.extractGzWithBom(context, uri, dslUri)
|
||||||
if (extractResult.isSuccess) {
|
if (extractResult.isSuccess) {
|
||||||
val extractedFile = fileStorageManager.getDocumentFile(dslUri)
|
val extractedFile = fileStorageManager.getDocumentFile(dslUri)
|
||||||
if (extractedFile != null && extractedFile.exists()) {
|
if (extractedFile != null && extractedFile.exists()) {
|
||||||
if (extractedFile.length() == 0L) {
|
if (extractedFile.length() == 0L) {
|
||||||
ArchiveUtils.deleteFile(context, dslUri)
|
ArchiveUtils.deleteFile(context, dslUri)
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
markFileProcessed()
|
markFileProcessed()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -92,7 +91,7 @@ class DictionaryExtractor(
|
|||||||
ArchiveUtils.deleteFile(context, dslUri)
|
ArchiveUtils.deleteFile(context, dslUri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
} else {
|
} else {
|
||||||
Log.e("DictionaryExtractor", "File extraction error: $fileName")
|
Log.e("DictionaryExtractor", "File extraction error: $fileName")
|
||||||
ArchiveUtils.deleteFile(context, dslUri)
|
ArchiveUtils.deleteFile(context, dslUri)
|
||||||
@@ -100,12 +99,11 @@ class DictionaryExtractor(
|
|||||||
markFileProcessed()
|
markFileProcessed()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (file in rawDslFiles) {
|
for ((dslFileName, uri) in rawDslFiles) {
|
||||||
val dslFileName = file.name
|
|
||||||
val dzFileName = "$dslFileName.dz"
|
val dzFileName = "$dslFileName.dz"
|
||||||
val existingDz = fileStorageManager.findFile(folderUri, dzFileName)
|
val existingDz = fileStorageManager.findFile(folderUri, dzFileName)
|
||||||
if (existingDz != null && existingDz.exists()) {
|
if (existingDz != null && existingDz.exists()) {
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
markFileProcessed()
|
markFileProcessed()
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -113,11 +111,11 @@ class DictionaryExtractor(
|
|||||||
val fileBaseProgress = processedIndex.toFloat() / totalFiles
|
val fileBaseProgress = processedIndex.toFloat() / totalFiles
|
||||||
val fileProgressWeight = 1f / totalFiles
|
val fileProgressWeight = 1f / totalFiles
|
||||||
reportProgress(fileBaseProgress)
|
reportProgress(fileBaseProgress)
|
||||||
val compressResult = ensureDslDictZip(file.uri, dslFileName, folderUri) { compressProgress ->
|
val compressResult = ensureDslDictZip(uri, dslFileName, folderUri) { compressProgress ->
|
||||||
reportProgress(fileBaseProgress + (compressProgress * fileProgressWeight))
|
reportProgress(fileBaseProgress + (compressProgress * fileProgressWeight))
|
||||||
}
|
}
|
||||||
if (compressResult.isSuccess) {
|
if (compressResult.isSuccess) {
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
}
|
}
|
||||||
markFileProcessed()
|
markFileProcessed()
|
||||||
}
|
}
|
||||||
@@ -130,11 +128,10 @@ class DictionaryExtractor(
|
|||||||
!lowerName.endsWith(DictionaryConfig.DICTZIP_EXTENSION) &&
|
!lowerName.endsWith(DictionaryConfig.DICTZIP_EXTENSION) &&
|
||||||
!lowerName.endsWith(".dsl.gz")
|
!lowerName.endsWith(".dsl.gz")
|
||||||
}
|
}
|
||||||
for (file in remainingRawDslFiles) {
|
for ((dslFileName, uri) in remainingRawDslFiles) {
|
||||||
val dslFileName = file.name
|
val compressResult = ensureDslDictZip(uri, dslFileName, folderUri, onProgress = null)
|
||||||
val compressResult = ensureDslDictZip(file.uri, dslFileName, folderUri, onProgress = null)
|
|
||||||
if (compressResult.isSuccess) {
|
if (compressResult.isSuccess) {
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,18 +149,18 @@ class DictionaryExtractor(
|
|||||||
try {
|
try {
|
||||||
withContext(Dispatchers.IO + NonCancellable) {
|
withContext(Dispatchers.IO + NonCancellable) {
|
||||||
val files = fileStorageManager.listFilesInFolder(folderUri)
|
val files = fileStorageManager.listFilesInFolder(folderUri)
|
||||||
for (file in files) {
|
for ((name, uri) in files) {
|
||||||
val n = file.name.lowercase()
|
val n = name.lowercase()
|
||||||
val isRawDsl = n.endsWith(DictionaryConfig.DSL_EXTENSION) &&
|
val isRawDsl = n.endsWith(DictionaryConfig.DSL_EXTENSION) &&
|
||||||
!n.endsWith(DictionaryConfig.DICTZIP_EXTENSION) &&
|
!n.endsWith(DictionaryConfig.DICTZIP_EXTENSION) &&
|
||||||
!n.endsWith(".dsl.gz")
|
!n.endsWith(".dsl.gz")
|
||||||
val isBareDz = n.endsWith(".dz") && !n.endsWith(DictionaryConfig.DICTZIP_EXTENSION)
|
val isBareDz = n.endsWith(".dz") && !n.endsWith(DictionaryConfig.DICTZIP_EXTENSION)
|
||||||
when {
|
when {
|
||||||
isBareDz -> ArchiveUtils.deleteFile(context, file.uri)
|
isBareDz -> ArchiveUtils.deleteFile(context, uri)
|
||||||
isRawDsl -> {
|
isRawDsl -> {
|
||||||
val pair = fileStorageManager.findFile(folderUri, file.name + ".dz")
|
val pair = fileStorageManager.findFile(folderUri, "$name.dz")
|
||||||
if (pair == null || !pair.exists()) {
|
if (pair == null || !pair.exists()) {
|
||||||
ArchiveUtils.deleteFile(context, file.uri)
|
ArchiveUtils.deleteFile(context, uri)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -144,9 +144,8 @@ class DictionaryRepository(
|
|||||||
if (filesToDelete.isNotEmpty()) {
|
if (filesToDelete.isNotEmpty()) {
|
||||||
var deletedCount = 0
|
var deletedCount = 0
|
||||||
|
|
||||||
for (file in filesToDelete) {
|
for ((fileName, uri) in filesToDelete) {
|
||||||
val fileName = file.name
|
val docFile = fileStorageManager.getDocumentFile(uri)
|
||||||
val docFile = fileStorageManager.getDocumentFile(file.uri)
|
|
||||||
if (docFile != null && docFile.exists()) {
|
if (docFile != null && docFile.exists()) {
|
||||||
val deleted = docFile.delete()
|
val deleted = docFile.delete()
|
||||||
if (deleted) {
|
if (deleted) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.example.research.ui.about
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import androidx.annotation.RawRes
|
import androidx.annotation.RawRes
|
||||||
|
import kotlinx.serialization.ExperimentalSerializationApi
|
||||||
import kotlinx.serialization.SerialName
|
import kotlinx.serialization.SerialName
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
@@ -75,6 +76,7 @@ internal object AboutLibrariesParser {
|
|||||||
ignoreUnknownKeys = true
|
ignoreUnknownKeys = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalSerializationApi::class)
|
||||||
fun read(context: Context, @RawRes resourceId: Int): AboutLibrariesData =
|
fun read(context: Context, @RawRes resourceId: Int): AboutLibrariesData =
|
||||||
context.resources.openRawResource(resourceId)
|
context.resources.openRawResource(resourceId)
|
||||||
.use { stream -> json.decodeFromStream(stream) }
|
.use { stream -> json.decodeFromStream(stream) }
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import androidx.compose.animation.core.animateFloatAsState
|
|||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
@@ -57,7 +56,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.flow.first
|
import kotlinx.coroutines.flow.first
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutScreen(
|
fun AboutScreen(
|
||||||
onNavigateBack: () -> Unit
|
onNavigateBack: () -> Unit
|
||||||
@@ -182,7 +181,6 @@ private fun AboutHeader(versionName: String) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun AboutLibraryRow(
|
private fun AboutLibraryRow(
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
|||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
@@ -349,7 +348,6 @@ fun ArticleTitleBar(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun ArticleScreen(
|
internal fun ArticleScreen(
|
||||||
articleState: ArticleState?,
|
articleState: ArticleState?,
|
||||||
|
|||||||
@@ -73,15 +73,11 @@ fun MainRoute(
|
|||||||
|
|
||||||
val showDictionaryName = remember(settingsState) {
|
val showDictionaryName = remember(settingsState) {
|
||||||
val activeDictionaries = settingsState.dictionaries.filter { it.isActive }
|
val activeDictionaries = settingsState.dictionaries.filter { it.isActive }
|
||||||
if (activeDictionaries.isEmpty()) {
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
activeDictionaries.any { dict ->
|
activeDictionaries.any { dict ->
|
||||||
val fileName = dict.path.substringAfterLast("/")
|
val fileName = dict.path.substringAfterLast("/")
|
||||||
!DictionaryConfig.isDabkrsDictionary(fileName)
|
!DictionaryConfig.isDabkrsDictionary(fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BoxWithConstraints {
|
BoxWithConstraints {
|
||||||
val isWide = maxWidth >= 600.dp
|
val isWide = maxWidth >= 600.dp
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
package com.example.research.ui.main.components
|
package com.example.research.ui.main.components
|
||||||
|
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.WindowInsetsSides
|
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.heightIn
|
import androidx.compose.foundation.layout.heightIn
|
||||||
import androidx.compose.foundation.layout.ime
|
import androidx.compose.foundation.layout.ime
|
||||||
import androidx.compose.foundation.layout.navigationBars
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.only
|
|
||||||
import androidx.compose.foundation.layout.offset
|
import androidx.compose.foundation.layout.offset
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
|
||||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.foundation.text.KeyboardOptions
|
import androidx.compose.foundation.text.KeyboardOptions
|
||||||
@@ -60,7 +54,6 @@ import androidx.compose.ui.semantics.testTagsAsResourceId
|
|||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.input.ImeAction
|
import androidx.compose.ui.text.input.ImeAction
|
||||||
import androidx.compose.ui.unit.Dp
|
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import com.example.research.R
|
import com.example.research.R
|
||||||
import com.example.research.common.ui.appTestTag
|
import com.example.research.common.ui.appTestTag
|
||||||
@@ -73,6 +66,7 @@ import com.example.research.ui.theme.Spacing
|
|||||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
private val TopBarHeight = Spacing.topBarHeight
|
private val TopBarHeight = Spacing.topBarHeight
|
||||||
private val TopBarShape = RoundedCornerShape(28.dp)
|
private val TopBarShape = RoundedCornerShape(28.dp)
|
||||||
@@ -145,7 +139,7 @@ fun MainTopBar(
|
|||||||
onShowHistory = {
|
onShowHistory = {
|
||||||
focusManager.clearFocus(force = true)
|
focusManager.clearFocus(force = true)
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
withTimeoutOrNull(350) {
|
withTimeoutOrNull(350.milliseconds) {
|
||||||
snapshotFlow { imeInsets.getBottom(density) > 0 }
|
snapshotFlow { imeInsets.getBottom(density) > 0 }
|
||||||
.first { visible -> !visible }
|
.first { visible -> !visible }
|
||||||
}
|
}
|
||||||
@@ -196,7 +190,6 @@ fun MainTopBar(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
private fun SearchField(
|
private fun SearchField(
|
||||||
searchState: TextFieldState,
|
searchState: TextFieldState,
|
||||||
enabled: Boolean,
|
enabled: Boolean,
|
||||||
@@ -298,20 +291,17 @@ private fun SearchHistorySheet(
|
|||||||
) {
|
) {
|
||||||
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val configuration = LocalConfiguration.current
|
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
|
||||||
var frozenHeight by remember { mutableStateOf<Dp?>(null) }
|
val navigationBarsBottom = WindowInsets.navigationBars.getBottom(density)
|
||||||
if (frozenHeight == null) {
|
val maxContentHeight = remember {
|
||||||
frozenHeight = if (isSearchBarAtBottom) {
|
|
||||||
configuration.screenHeightDp.dp -
|
|
||||||
HistorySheetChrome -
|
|
||||||
with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
|
||||||
} else {
|
|
||||||
with(density) {
|
with(density) {
|
||||||
(configuration.screenHeightDp.dp.toPx() - topBarBottomPx).toDp()
|
if (isSearchBarAtBottom) {
|
||||||
|
screenHeight - HistorySheetChrome - navigationBarsBottom.toDp()
|
||||||
|
} else {
|
||||||
|
screenHeight - topBarBottomPx.toDp()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val maxContentHeight = frozenHeight!!
|
|
||||||
|
|
||||||
ModalBottomSheet(
|
ModalBottomSheet(
|
||||||
onDismissRequest = onDismiss,
|
onDismissRequest = onDismiss,
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import androidx.compose.foundation.layout.Box
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.adaptive.ExperimentalMaterial3AdaptiveApi
|
|
||||||
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
|
import androidx.compose.material3.adaptive.currentWindowAdaptiveInfoV2
|
||||||
import androidx.compose.runtime.*
|
import androidx.compose.runtime.*
|
||||||
import androidx.compose.runtime.saveable.*
|
import androidx.compose.runtime.saveable.*
|
||||||
@@ -39,7 +38,6 @@ enum class Screen {
|
|||||||
Home, Settings, Article, About
|
Home, Settings, Article, About
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3AdaptiveApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AppNavigation(
|
fun AppNavigation(
|
||||||
searchViewModel: SearchViewModel,
|
searchViewModel: SearchViewModel,
|
||||||
|
|||||||
@@ -57,7 +57,6 @@ import kotlinx.coroutines.flow.StateFlow
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsRoute(
|
fun SettingsRoute(
|
||||||
viewModel: SettingsViewModel,
|
viewModel: SettingsViewModel,
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ object Spacing {
|
|||||||
// Semantic spacing constants for specific UI elements
|
// Semantic spacing constants for specific UI elements
|
||||||
val topBarPadding = 8.dp
|
val topBarPadding = 8.dp
|
||||||
val topBarHeight = 56.dp
|
val topBarHeight = 56.dp
|
||||||
val searchTextStart = 68.dp
|
|
||||||
val listItemVertical = 8.dp
|
val listItemVertical = 8.dp
|
||||||
|
|
||||||
val contentStart = 32.dp
|
val contentStart = 32.dp
|
||||||
|
|||||||
Reference in new issue
Block a user