add search and sort
This commit is contained in:
parent
f133a4446b
commit
2190a509ef
21 changed files with 825 additions and 183 deletions
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CompilerConfiguration">
|
||||
<bytecodeTargetLevel target="17" />
|
||||
<bytecodeTargetLevel target="21" />
|
||||
</component>
|
||||
</project>
|
|
@ -4,8 +4,9 @@
|
|||
<component name="GradleSettings">
|
||||
<option name="linkedExternalProjectsSettings">
|
||||
<GradleProjectSettings>
|
||||
<option name="testRunner" value="CHOOSE_PER_TEST" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
|
||||
<option name="gradleJvm" value="#JAVA_HOME" />
|
||||
<option name="modules">
|
||||
<set>
|
||||
<option value="$PROJECT_DIR$" />
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="jbr-21" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||
</component>
|
||||
<component name="ProjectType">
|
||||
|
|
|
@ -69,6 +69,7 @@ dependencies {
|
|||
implementation(libs.ui.graphics)
|
||||
implementation(libs.ui.tooling.preview)
|
||||
implementation(libs.material3)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.ext.junit)
|
||||
androidTestImplementation(libs.espresso.core)
|
||||
|
|
|
@ -2,75 +2,76 @@
|
|||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@drawable/ic_launcher_foreground"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@drawable/ic_launcher_foreground"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MyApplication"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".compose.SearchActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_search"
|
||||
android:theme="@style/Theme.MyApplication" />
|
||||
<activity
|
||||
android:name=".compose.RequirePermissionActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.MyApplication">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".compose.ViewFileActivity"
|
||||
android:exported="false" />
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@drawable/ic_launcher_foreground"
|
||||
android:label="@string/app_name"
|
||||
android:roundIcon="@drawable/ic_launcher_foreground"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.MyApplication"
|
||||
tools:targetApi="31">
|
||||
<activity
|
||||
android:name=".compose.SettingActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_setting"
|
||||
android:theme="@style/Theme.MyApplication" />
|
||||
<activity
|
||||
android:name=".compose.SearchActivity"
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_search"
|
||||
android:theme="@style/Theme.MyApplication" />
|
||||
<activity
|
||||
android:name=".compose.RequirePermissionActivity"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.MyApplication">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<activity
|
||||
android:name=".main_page"
|
||||
android:exported="false" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".compose.ViewFileActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".main_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".store_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".document_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".picture_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".video_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".music_page"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".store_page"
|
||||
android:exported="false" />
|
||||
|
||||
<activity
|
||||
android:name=".document_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".picture_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".video_page"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".music_page"
|
||||
android:exported="false" />
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.example.myapplication.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
<uses-permission
|
||||
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
|
||||
tools:ignore="ScopedStorage" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
|
||||
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" />
|
||||
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="com.example.myapplication.provider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||
android:resource="@xml/provider_paths" />
|
||||
</provider>
|
||||
</application>
|
||||
|
||||
</manifest>
|
|
@ -0,0 +1,37 @@
|
|||
package com.example.myapplication
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.booleanPreferencesKey
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
val Context.settingStore: DataStore<Preferences> by preferencesDataStore(name = "app_settings")
|
||||
|
||||
class SettingStorage(private val context: Context) {
|
||||
val showExtension = booleanPreferencesKey("show_extension")
|
||||
|
||||
|
||||
fun <T> get(key: Preferences.Key<T>): T? =
|
||||
runBlocking {
|
||||
context.settingStore.data
|
||||
.map { value ->
|
||||
value[key]
|
||||
}
|
||||
.first()
|
||||
}
|
||||
|
||||
fun <T> set(key: Preferences.Key<T>, value: T) =
|
||||
CoroutineScope(Dispatchers.Default).launch {
|
||||
context.settingStore.edit {
|
||||
it[key] = value
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,13 @@ import android.os.Bundle
|
|||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.compose.ui.SearchFileColumn
|
||||
import com.example.myapplication.fileSystem.byTypeFileLister.DocumentLister
|
||||
import com.example.myapplication.fileSystem.byTypeFileLister.ImageLister
|
||||
import com.example.myapplication.fileSystem.byTypeFileLister.MusicLister
|
||||
|
@ -20,10 +27,22 @@ class SearchActivity : ComponentActivity() {
|
|||
"document" -> DocumentLister.regex
|
||||
else -> null
|
||||
}
|
||||
val searchFileColumn = SearchFileColumn(this,when (type) {
|
||||
"music" -> getString(R.string.music)
|
||||
"image" -> getString(R.string.picture)
|
||||
"video" -> getString(R.string.video)
|
||||
"document" -> getString(R.string.document)
|
||||
else -> ""
|
||||
},searchTypeRegex)
|
||||
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.background(Color(getColor(R.color.WhiteSmoke)))
|
||||
)
|
||||
{ searchFileColumn.Draw() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package com.example.myapplication.compose
|
||||
|
||||
import android.os.Bundle
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.compose.setContent
|
||||
import androidx.activity.enableEdgeToEdge
|
||||
|
||||
class SettingActivity : ComponentActivity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
enableEdgeToEdge()
|
||||
setContent {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -63,6 +63,9 @@ import com.example.myapplication.fileSystem.WrappedFile.Type
|
|||
import com.example.myapplication.main_page
|
||||
import com.example.myapplication.utils.AlertHelper
|
||||
import com.example.myapplication.utils.ClipHelper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import org.apache.commons.io.IOUtils
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
|
@ -74,17 +77,26 @@ class FileColumn(val context: Context) {
|
|||
fun Draw(startFolder: String) {
|
||||
var path by remember { mutableStateOf(startFolder) }
|
||||
var shouldUpdate by remember { mutableStateOf(false) }
|
||||
|
||||
// 检查当前在的目录,有问题就不渲染
|
||||
val cwd = File(path)
|
||||
if (!cwd.isDirectory) {
|
||||
return
|
||||
}
|
||||
var isOkay by remember { mutableStateOf(false) }
|
||||
|
||||
LaunchedEffect(path, shouldUpdate) {
|
||||
var isOkay by remember { mutableStateOf(false) }
|
||||
var sortByTime by remember { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(path, shouldUpdate, sortByTime) {
|
||||
isOkay = false
|
||||
fileList.clear()
|
||||
cwd.listFiles()?.forEach { f ->
|
||||
fileList.add(WrappedFile(f))
|
||||
val wfList = cwd.listFiles()?.map { WrappedFile(it) }
|
||||
if (wfList!=null) {
|
||||
if (sortByTime) {
|
||||
fileList.addAll(wfList.sortedBy { it.lastModifiedTime })
|
||||
} else {
|
||||
fileList.addAll(wfList.sortedBy { it.size })
|
||||
}
|
||||
}
|
||||
isOkay = true
|
||||
}
|
||||
|
@ -120,11 +132,42 @@ class FileColumn(val context: Context) {
|
|||
Text(
|
||||
text = path,
|
||||
fontSize = 24.sp,
|
||||
modifier = Modifier.padding(start = 16.dp),
|
||||
modifier = Modifier.padding(start = 10.dp)
|
||||
.fillMaxWidth(0.75f),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
IconButton(
|
||||
onClick = {
|
||||
sortByTime = !sortByTime
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Toast.makeText(
|
||||
context, context.getString(
|
||||
if (sortByTime) {
|
||||
R.string.sort_by_time
|
||||
} else {
|
||||
R.string.sort_by_size
|
||||
}
|
||||
), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
},
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(
|
||||
if (sortByTime) {
|
||||
R.drawable.baseline_access_time_24
|
||||
} else {
|
||||
R.drawable.baseline_storage_24
|
||||
}
|
||||
), "sortMethod"
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
if (!isOkay) {
|
||||
Column(
|
||||
|
|
|
@ -0,0 +1,358 @@
|
|||
package com.example.myapplication.compose.ui
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.border
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.statusBarsPadding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TextField
|
||||
import androidx.compose.material3.TextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateListOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.res.vectorResource
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import androidx.core.content.FileProvider
|
||||
import com.example.myapplication.R
|
||||
import com.example.myapplication.fileSystem.CutHelper
|
||||
import com.example.myapplication.fileSystem.WrappedFile
|
||||
import com.example.myapplication.fileSystem.WrappedFile.Type
|
||||
import com.example.myapplication.fileSystem.searchFile
|
||||
import com.example.myapplication.main_page
|
||||
import com.example.myapplication.utils.AlertHelper
|
||||
import com.example.myapplication.utils.ClipHelper
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
class SearchFileColumn(
|
||||
val context: Context,
|
||||
private val searchTypeName: String,
|
||||
private val searchRegex: Regex?
|
||||
) {
|
||||
private val fileList = mutableStateListOf<WrappedFile>()
|
||||
private val searchText = mutableStateOf("")
|
||||
|
||||
@Composable
|
||||
fun Draw() {
|
||||
var list by remember { mutableStateOf<List<String>>(emptyList()) }
|
||||
var isOkay by remember { mutableStateOf(false) }
|
||||
var sortByTime by remember { mutableStateOf(true) }
|
||||
|
||||
LaunchedEffect(isOkay, list,sortByTime) {
|
||||
isOkay = false
|
||||
fileList.clear()
|
||||
val wfList = list.map { WrappedFile(File(it)) }
|
||||
if (sortByTime) {
|
||||
fileList.addAll(wfList.sortedBy { it.lastModifiedTime })
|
||||
} else {
|
||||
fileList.addAll(wfList.sortedBy { it.size })
|
||||
}
|
||||
isOkay = true
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.statusBarsPadding()
|
||||
.navigationBarsPadding()
|
||||
.background(Color(context.getColor(R.color.WhiteSmoke)))
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 10.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
IconButton(
|
||||
onClick = {
|
||||
val intent = Intent(
|
||||
context,
|
||||
main_page::class.java
|
||||
)
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(R.drawable.ic_left_arrow), "back"
|
||||
)
|
||||
}
|
||||
|
||||
Text(
|
||||
text = context.getString(R.string.search_result, searchTypeName),
|
||||
fontSize = 28.sp,
|
||||
modifier = Modifier
|
||||
.padding(start = 10.dp)
|
||||
.padding(vertical = 5.dp),
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
|
||||
IconButton(
|
||||
onClick = {
|
||||
sortByTime = !sortByTime
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
Toast.makeText(
|
||||
context, context.getString(
|
||||
if (sortByTime) {
|
||||
R.string.sort_by_time
|
||||
} else {
|
||||
R.string.sort_by_size
|
||||
}
|
||||
), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
},
|
||||
) {
|
||||
Image(
|
||||
imageVector = ImageVector.vectorResource(
|
||||
if (sortByTime) {
|
||||
R.drawable.baseline_access_time_24
|
||||
} else {
|
||||
R.drawable.baseline_storage_24
|
||||
}
|
||||
), "sortMethod"
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
if (!isOkay) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
verticalArrangement = Arrangement.Center
|
||||
) {
|
||||
Text(
|
||||
text = context.getString(R.string.loading),
|
||||
fontSize = 34.sp
|
||||
)
|
||||
}
|
||||
} else {
|
||||
DrawColumns(fileList,
|
||||
searchText = searchText.value,
|
||||
onSearch = { name, searchWhat ->
|
||||
searchText.value = searchWhat
|
||||
searchFile(name, searchRegex) {
|
||||
list = it
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
if (list.isEmpty()) {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.search_no_result), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
} else {
|
||||
Toast.makeText(
|
||||
context,
|
||||
context.getString(R.string.search_some_result, list.size), Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
isOkay = !isOkay
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
val file = File(it)
|
||||
if (file.isFile) {
|
||||
val uri = FileProvider.getUriForFile(
|
||||
context,
|
||||
context.packageName + ".provider",
|
||||
file
|
||||
)
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
intent.setDataAndType(uri, WrappedFile(file).mime)
|
||||
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DrawColumns(
|
||||
fileList: List<WrappedFile>,
|
||||
update: (() -> Unit)? = null,
|
||||
searchText: String = "",
|
||||
onSearch: ((String, String) -> Unit)? = null,
|
||||
onItemClick: ((String) -> Unit)? = null
|
||||
) {
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(vertical = 5.dp)
|
||||
) {
|
||||
// 最顶上那个
|
||||
item {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 3.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
var searchInput by remember { mutableStateOf(searchText) }
|
||||
|
||||
TextField(
|
||||
value = searchInput,
|
||||
maxLines = 1,
|
||||
onValueChange = { searchInput = it },
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 15.dp, vertical = 10.dp)
|
||||
.fillParentMaxWidth(0.9f),
|
||||
colors = TextFieldDefaults.colors(
|
||||
focusedContainerColor = Color(0xFFFFFAFA),
|
||||
unfocusedContainerColor = Color.White,
|
||||
focusedIndicatorColor = Color(0xFF03A9F4),
|
||||
unfocusedIndicatorColor = Color.Transparent
|
||||
),
|
||||
textStyle = TextStyle(fontSize = 18.sp),
|
||||
trailingIcon = {
|
||||
Image(
|
||||
ImageVector.vectorResource(R.drawable.ic_search),
|
||||
context.getString(R.string.search),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
if (searchInput.isNotEmpty()) {
|
||||
if (searchInput == "." || searchInput == "..") {
|
||||
Toast
|
||||
.makeText(
|
||||
context,
|
||||
context.getString(R.string.error_search_input_illegal),
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
}
|
||||
onSearch?.invoke(searchInput, searchInput)
|
||||
} else {
|
||||
Toast
|
||||
.makeText(
|
||||
context,
|
||||
context.getString(R.string.error_need_search_input), Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 下面的内容
|
||||
items(fileList) { file ->
|
||||
FileSingleView(
|
||||
file,
|
||||
update = update,
|
||||
onItemClick = onItemClick
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun FileSingleView(
|
||||
file: WrappedFile,
|
||||
update: (() -> Unit)? = null,
|
||||
onItemClick: ((String) -> Unit)? = null
|
||||
) {
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.border(
|
||||
width = Dp.Hairline,
|
||||
color = Color.Gray,
|
||||
shape = RectangleShape
|
||||
)
|
||||
.padding(vertical = 3.dp)
|
||||
.clickable {
|
||||
onItemClick?.invoke(file.path)
|
||||
},
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Image(
|
||||
ImageVector.vectorResource(
|
||||
when (file.mime.split('/').first()) {
|
||||
"dir" -> R.drawable.type_directory
|
||||
"image" -> R.drawable.type_image
|
||||
"video" -> R.drawable.type_video
|
||||
"audio" -> R.drawable.type_audio
|
||||
else -> R.drawable.type_file
|
||||
}
|
||||
), file.mime,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 8.dp)
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 15.dp)
|
||||
.fillMaxWidth(0.8f)
|
||||
) {
|
||||
Text(
|
||||
text = file.name,
|
||||
fontSize = 24.sp,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
Text(
|
||||
text = file.getModifiedTimeString(context),
|
||||
fontSize = 15.sp,
|
||||
color = Color.Gray,
|
||||
maxLines = 1
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(Modifier.weight(1f))
|
||||
|
||||
IconButton(
|
||||
onClick = {
|
||||
if (file.type == Type.FILE) { // 普通文件
|
||||
AlertHelper.showOnlyInfoNewAlert(context,
|
||||
onInfo = {
|
||||
AlertHelper.showFileInfoAlert(context, file.path)
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier.padding(horizontal = 10.dp)
|
||||
) {
|
||||
Image(
|
||||
ImageVector.vectorResource(R.drawable.outline_info_24), "info"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.example.myapplication.compose.ui
|
||||
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material3.Switch
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
class Setting(
|
||||
private val rowModifier: Modifier = Modifier.fillMaxWidth(),
|
||||
private val nameModifier: Modifier = Modifier,
|
||||
private val nameTextStyle: TextStyle = TextStyle.Default,
|
||||
private val descriptionModifier: Modifier = Modifier,
|
||||
private val descriptionTextStyle: TextStyle = TextStyle.Default,
|
||||
private val switchModifier: Modifier = Modifier
|
||||
) {
|
||||
|
||||
@Composable
|
||||
fun BooleanSetting(
|
||||
name: String,
|
||||
initialState: Boolean = true,
|
||||
description: String? = null,
|
||||
onCheckedChange: ((Boolean) -> Unit)? = null
|
||||
) {
|
||||
var checkState by remember { mutableStateOf(initialState) }
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
modifier = rowModifier
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.fillMaxWidth(0.8f)
|
||||
) {
|
||||
Text(
|
||||
text = name,
|
||||
modifier = nameModifier,
|
||||
style = nameTextStyle
|
||||
)
|
||||
Spacer(modifier = Modifier.size(5.dp))
|
||||
Text(
|
||||
text = description ?: "",
|
||||
modifier = descriptionModifier,
|
||||
style = descriptionTextStyle
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.weight(1f))
|
||||
Switch(
|
||||
checked = checkState,
|
||||
onCheckedChange = {
|
||||
checkState = it
|
||||
onCheckedChange?.invoke(it)
|
||||
},
|
||||
modifier = switchModifier
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -222,7 +222,7 @@ class document_page : AppCompatActivity() {
|
|||
loadingTextView.visibility = View.GONE
|
||||
Toast.makeText(
|
||||
this@document_page,
|
||||
"已选择按时间排序",
|
||||
getString(R.string.sort_by_time),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
@ -245,7 +245,7 @@ class document_page : AppCompatActivity() {
|
|||
loadingTextView.visibility = View.GONE
|
||||
Toast.makeText(
|
||||
this@document_page,
|
||||
"已选择按大小排序",
|
||||
getString(R.string.sort_by_size),
|
||||
Toast.LENGTH_SHORT
|
||||
).show()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package com.example.myapplication.fileSystem
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Environment
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.coroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
fun searchFile(name: String,typeRegex: Regex? = null, onFinished: (List<String>) -> Unit){
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
val resultList = searchDir(name,Environment.getExternalStorageDirectory().path)
|
||||
if (typeRegex == null){
|
||||
onFinished.invoke(resultList)
|
||||
}else{
|
||||
val finalResult = resultList.filter { it.contains(typeRegex) }
|
||||
onFinished.invoke(finalResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun searchDir(name: String, directory: String): List<String> {
|
||||
val list = mutableListOf<String>()
|
||||
val dir = File(directory)
|
||||
if (!dir.isDirectory || dir.name.startsWith('.')){
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
val inside = dir.listFiles()
|
||||
if (inside == null || inside.isEmpty()){
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
inside.forEach {
|
||||
if (it.isDirectory){
|
||||
list.addAll(coroutineScope{ searchDir(name, it.path) })
|
||||
}else if (it.isFile){
|
||||
if (it.name.contains(name) && !it.name.startsWith('.') ){
|
||||
list.add(it.path)
|
||||
}
|
||||
}
|
||||
}
|
||||
return list
|
||||
}
|
|
@ -10,6 +10,8 @@ import androidx.appcompat.app.AppCompatActivity;
|
|||
import androidx.core.graphics.Insets;
|
||||
import androidx.core.view.ViewCompat;
|
||||
import androidx.core.view.WindowInsetsCompat;
|
||||
|
||||
import com.example.myapplication.compose.SearchActivity;
|
||||
import com.example.myapplication.compose.ViewFileActivity;
|
||||
import com.example.myapplication.fileSystem.DeleteHelper;
|
||||
import java.io.File;
|
||||
|
@ -41,6 +43,7 @@ public class main_page extends AppCompatActivity {
|
|||
findViewById(R.id.MainPageRecordingButton).setOnClickListener(buttonClickerHandler);
|
||||
findViewById(R.id.MainPageDCIMButton).setOnClickListener(buttonClickerHandler);
|
||||
findViewById(R.id.MainPagePicturesButton).setOnClickListener(buttonClickerHandler);
|
||||
findViewById(R.id.MainPageSearchButton).setOnClickListener(buttonClickerHandler);
|
||||
}
|
||||
|
||||
@Override protected void onDestroy() {
|
||||
|
@ -124,6 +127,10 @@ public class main_page extends AppCompatActivity {
|
|||
intent.putExtras(bundle);
|
||||
startActivity(intent);
|
||||
}
|
||||
if (view.getId() == R.id.MainPageSearchButton) {
|
||||
Intent intent = new Intent(context, SearchActivity.class);
|
||||
startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -125,6 +125,26 @@ class AlertHelper {
|
|||
.show()
|
||||
}
|
||||
|
||||
fun showOnlyInfoNewAlert(
|
||||
context: Context,
|
||||
onInfo: () -> Unit,
|
||||
) {
|
||||
val builder = Builder(context)
|
||||
builder.setTitle(context.getString(R.string.select_action))
|
||||
.setItems(
|
||||
arrayOf<CharSequence>(
|
||||
context.getString(R.string.action_info)
|
||||
)
|
||||
) { _: DialogInterface?, which: Int ->
|
||||
when (which) {
|
||||
1 -> onInfo()
|
||||
}
|
||||
}
|
||||
.setNegativeButton(context.getString(R.string.action_cancel))
|
||||
{ dialog: DialogInterface, which: Int -> dialog.dismiss() }
|
||||
.show()
|
||||
}
|
||||
|
||||
fun showDeleteAlert(context: Context, file: String, onConfirm: (() -> Unit)?) {
|
||||
val builder = Builder(context)
|
||||
builder.setTitle(context.getString(R.string.confirm_to_delete))
|
||||
|
|
7
app/src/main/res/drawable/baseline_access_time_24.xml
Normal file
7
app/src/main/res/drawable/baseline_access_time_24.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="40dp" android:tint="#1A1B3F" android:viewportHeight="24" android:viewportWidth="24" android:width="40dp">
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/>
|
||||
|
||||
<path android:fillColor="@android:color/white" android:pathData="M12.5,7H11v6l5.25,3.15 0.75,-1.23 -4.5,-2.67z"/>
|
||||
|
||||
</vector>
|
|
@ -1,7 +1,12 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="40dp" android:tint="#000000" android:viewportHeight="23" android:viewportWidth="23" android:width="40dp">
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="40dp"
|
||||
android:height="40dp"
|
||||
android:tint="#000000"
|
||||
android:viewportWidth="23"
|
||||
android:viewportHeight="23">
|
||||
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z"/>
|
||||
|
||||
android:pathData="M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z" />
|
||||
|
||||
</vector>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
android:scrollbars="none"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/searchDocument"
|
||||
app:layout_constraintTop_toBottomOf="@+id/MainPageSearchButton"
|
||||
>
|
||||
|
||||
<LinearLayout
|
||||
|
@ -329,19 +329,21 @@
|
|||
</ScrollView>
|
||||
|
||||
|
||||
<SearchView
|
||||
android:id="@+id/searchDocument"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginTop="15dp"
|
||||
android:background="@drawable/search_border"
|
||||
android:iconifiedByDefault="false"
|
||||
android:queryHint="搜索文件"
|
||||
android:textColor="@color/black"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/MainPageTitleRow"
|
||||
/>
|
||||
<Button
|
||||
android:id="@+id/MainPageSearchButton"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:backgroundTint="@color/white"
|
||||
android:drawableLeft="@drawable/ic_search"
|
||||
android:gravity="center"
|
||||
android:layout_marginHorizontal="60dp"
|
||||
android:text="@string/search_file"
|
||||
android:textColor="@color/black"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/MainPageTitleRow"
|
||||
/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -1,42 +1,42 @@
|
|||
<resources>
|
||||
<string name="app_name">文件管理器</string>
|
||||
<string name="hello">文件管理器</string>
|
||||
<string name="search">浏览</string>
|
||||
<string name="edit">编辑</string>
|
||||
<string name="picture">图片</string>
|
||||
<string name="video">视频</string>
|
||||
<string name="music">音乐</string>
|
||||
<string name="document">文件</string>
|
||||
<string name="app">其他</string>
|
||||
<string name="location">位置</string>
|
||||
<string name="store">内部存储</string>
|
||||
<string name="delete">最近删除</string>
|
||||
<string name="download">下载与接收</string>
|
||||
<string name="source">来源</string>
|
||||
<string name="qq">QQ</string>
|
||||
<string name="wechat">微信</string>
|
||||
<string name="internet">浏览器</string>
|
||||
<string name="radio">录音机</string>
|
||||
<string name="installpackage">安装包</string>
|
||||
<string name="Camera">Camera</string>
|
||||
<string name="Screenshots">屏幕截图</string>
|
||||
<!-- Strings used for fragments for navigation -->
|
||||
<string name="first_fragment_label">First Fragment</string>
|
||||
<string name="second_fragment_label">Second Fragment</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="previous">Previous</string>
|
||||
<string name="Delete">删除</string>
|
||||
<string name="copy">复制</string>
|
||||
<string name="cut">剪切</string>
|
||||
<string name="paste">粘贴</string>
|
||||
<string name="tiktok">抖音</string>
|
||||
<string name="alipay">支付宝</string>
|
||||
<string name="taobao">淘宝</string>
|
||||
<string name="little_red_book">小红书</string>
|
||||
<string name="unload">卸载</string>
|
||||
<string name="store_package">压缩包</string>
|
||||
<string name="phone_information">通话与信息</string>
|
||||
<string name="lorem_ipsum">
|
||||
<string name="app_name">文件管理器</string>
|
||||
<string name="hello">文件管理器</string>
|
||||
<string name="search">浏览</string>
|
||||
<string name="edit">编辑</string>
|
||||
<string name="picture">图片</string>
|
||||
<string name="video">视频</string>
|
||||
<string name="music">音乐</string>
|
||||
<string name="document">文件</string>
|
||||
<string name="app">其他</string>
|
||||
<string name="location">位置</string>
|
||||
<string name="store">内部存储</string>
|
||||
<string name="delete">最近删除</string>
|
||||
<string name="download">下载与接收</string>
|
||||
<string name="source">来源</string>
|
||||
<string name="qq">QQ</string>
|
||||
<string name="wechat">微信</string>
|
||||
<string name="internet">浏览器</string>
|
||||
<string name="radio">录音机</string>
|
||||
<string name="installpackage">安装包</string>
|
||||
<string name="Camera">Camera</string>
|
||||
<string name="Screenshots">屏幕截图</string>
|
||||
<!-- Strings used for fragments for navigation -->
|
||||
<string name="first_fragment_label">First Fragment</string>
|
||||
<string name="second_fragment_label">Second Fragment</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="previous">Previous</string>
|
||||
<string name="Delete">删除</string>
|
||||
<string name="copy">复制</string>
|
||||
<string name="cut">剪切</string>
|
||||
<string name="paste">粘贴</string>
|
||||
<string name="tiktok">抖音</string>
|
||||
<string name="alipay">支付宝</string>
|
||||
<string name="taobao">淘宝</string>
|
||||
<string name="little_red_book">小红书</string>
|
||||
<string name="unload">卸载</string>
|
||||
<string name="store_package">压缩包</string>
|
||||
<string name="phone_information">通话与信息</string>
|
||||
<string name="lorem_ipsum">
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam in scelerisque sem. Mauris
|
||||
volutpat, dolor id interdum ullamcorper, risus dolor egestas lectus, sit amet mattis purus
|
||||
dui nec risus. Maecenas non sodales nisi, vel dictum dolor. Class aptent taciti sociosqu ad
|
||||
|
@ -72,60 +72,69 @@
|
|||
libero vel nunc consequat, quis tincidunt nisl eleifend. Cras bibendum enim a justo luctus
|
||||
vestibulum. Fusce dictum libero quis erat maximus, vitae volutpat diam dignissim.
|
||||
</string>
|
||||
<string name="title_activity_require_permission">RequirePermissionActivity</string>
|
||||
<string name="title_activity_require_permission">RequirePermissionActivity</string>
|
||||
|
||||
<string name="require_permission_readwrite">需要读取/写入存储权限以继续</string>
|
||||
<string name="require_manage_storage">需要管理存储权限以继续</string>
|
||||
<string name="give_permission">授权</string>
|
||||
<string name="require_permission_readwrite">需要读取/写入存储权限以继续</string>
|
||||
<string name="require_manage_storage">需要管理存储权限以继续</string>
|
||||
<string name="give_permission">授权</string>
|
||||
|
||||
<string name="used_storage_percentage">%d%%</string>
|
||||
<string name="used_storage">已使用\n%s / %s</string>
|
||||
<string name="used_storage_percentage">%d%%</string>
|
||||
<string name="used_storage">已使用\n%s / %s</string>
|
||||
|
||||
<string name="loading">加载中</string>
|
||||
<string name="loading">加载中</string>
|
||||
|
||||
<!-- Actions -->
|
||||
<string name="select_action">选择操作</string>
|
||||
<string name="action_copy">复制</string>
|
||||
<string name="action_paste">粘贴</string>
|
||||
<string name="action_delete">删除</string>
|
||||
<string name="action_cut">剪切</string>
|
||||
<string name="action_info">信息</string>
|
||||
<string name="action_new_file">新建文件</string>
|
||||
<string name="action_new_folder">新建文件夹</string>
|
||||
<string name="action_cancel">取消</string>
|
||||
<!-- Actions -->
|
||||
<string name="select_action">选择操作</string>
|
||||
<string name="action_copy">复制</string>
|
||||
<string name="action_paste">粘贴</string>
|
||||
<string name="action_delete">删除</string>
|
||||
<string name="action_cut">剪切</string>
|
||||
<string name="action_info">信息</string>
|
||||
<string name="action_new_file">新建文件</string>
|
||||
<string name="action_new_folder">新建文件夹</string>
|
||||
<string name="action_cancel">取消</string>
|
||||
|
||||
<!-- Confirmations -->
|
||||
<string name="confirm">确认</string>
|
||||
<string name="okay">好的</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="confirm_to_delete">确认删除</string>
|
||||
<string name="confirm_to_delete_file">确认删除文件: %s</string>
|
||||
<!-- Confirmations -->
|
||||
<string name="confirm">确认</string>
|
||||
<string name="okay">好的</string>
|
||||
<string name="cancel">取消</string>
|
||||
<string name="confirm_to_delete">确认删除</string>
|
||||
<string name="confirm_to_delete_file">确认删除文件: %s</string>
|
||||
|
||||
<string name="file_info">文件信息</string>
|
||||
<string name="file_info_text">
|
||||
<string name="file_info">文件信息</string>
|
||||
<string name="file_info_text">
|
||||
文件名:%s\n
|
||||
路径:%s\n
|
||||
大小:%s\n
|
||||
最后修改时间:%s
|
||||
</string>
|
||||
|
||||
<string name="advanced">查看什么</string>
|
||||
<string name="settings">软件设置</string>
|
||||
<string name="all_files">全部文件</string>
|
||||
<string name="storage_info">内部存储信息</string>
|
||||
<string name="advanced">查看什么</string>
|
||||
<string name="settings">软件设置</string>
|
||||
<string name="all_files">全部文件</string>
|
||||
<string name="storage_info">内部存储信息</string>
|
||||
|
||||
<string name="camera">相机</string>
|
||||
<string name="pictures">公用图片</string>
|
||||
<string name="documents">公用文档</string>
|
||||
<string name="prev_folder">上一级目录</string>
|
||||
<string name="camera">相机</string>
|
||||
<string name="pictures">公用图片</string>
|
||||
<string name="documents">公用文档</string>
|
||||
<string name="prev_folder">上一级目录</string>
|
||||
|
||||
<string name="input_name">请输入名称</string>
|
||||
<string name="create_directory">将在 %s 创建文件夹</string>
|
||||
<string name="create_file">将在 %s 创建文件</string>
|
||||
<string name="input_name">请输入名称</string>
|
||||
<string name="create_directory">将在 %s 创建文件夹</string>
|
||||
<string name="create_file">将在 %s 创建文件</string>
|
||||
|
||||
<string name="error_nothing_to_paste">未找到可粘贴的内容</string>
|
||||
<string name="error_need_input_name">请输入名称</string>
|
||||
<string name="error_already_exist">已存在此文件(夹)</string>
|
||||
<string name="title_activity_view_file">ViewFileActivity</string>
|
||||
<string name="title_activity_search">SearchActivity</string>
|
||||
<string name="error_nothing_to_paste">未找到可粘贴的内容</string>
|
||||
<string name="error_need_input_name">请输入名称</string>
|
||||
<string name="error_already_exist">已存在此文件(夹)</string>
|
||||
<string name="title_activity_view_file">ViewFileActivity</string>
|
||||
<string name="title_activity_search">SearchActivity</string>
|
||||
<string name="search_result">搜索%s结果</string>
|
||||
<string name="error_need_search_input">请输入要搜索的内容</string>
|
||||
<string name="error_search_input_illegal">输入的搜索内容不合法</string>
|
||||
<string name="search_file">搜索文件</string>
|
||||
<string name="search_no_result">未找到任何结果</string>
|
||||
<string name="search_some_result">找到%d个结果</string>
|
||||
<string name="sort_by_size">已选择按大小排序</string>
|
||||
<string name="sort_by_time">已选择按时间排序</string>
|
||||
<string name="title_activity_setting">SettingActivity</string>
|
||||
</resources>
|
|
@ -1,9 +1,9 @@
|
|||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.MyApplication" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your light theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||
</style>
|
||||
<!-- Base application theme. -->
|
||||
<style name="Base.Theme.MyApplication" parent="Theme.Material3.DayNight.NoActionBar">
|
||||
<!-- Customize your light theme here. -->
|
||||
<!-- <item name="colorPrimary">@color/my_light_primary</item> -->
|
||||
</style>
|
||||
|
||||
<style name="Theme.MyApplication" parent="Base.Theme.MyApplication" />
|
||||
<style name="Theme.MyApplication" parent="Base.Theme.MyApplication" />
|
||||
</resources>
|
|
@ -15,6 +15,7 @@ lifecycleRuntimeKtx = "2.8.6"
|
|||
activityCompose = "1.9.2"
|
||||
composeBom = "2024.09.03"
|
||||
commonsIO = "2.17.0"
|
||||
datastorePreferences = "1.1.1"
|
||||
|
||||
[libraries]
|
||||
junit = { group = "junit", name = "junit", version.ref = "junit" }
|
||||
|
@ -38,6 +39,7 @@ ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
|||
ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
commons-io = { group = "commons-io", name = "commons-io", version.ref = "commonsIO" }
|
||||
androidx-datastore-preferences = { module = "androidx.datastore:datastore-preferences", version.ref = "datastorePreferences" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
|
Loading…
Reference in a new issue