这是一个中等质量的版本更新,与思源 v3.0.8 版本对齐,包含思源 v3.0.7 和 v3.0.6 的累积更新。
更新重点分析
汐洛文件中转站
通用处理助手添加了文件中转站功能,借鉴了 ES 文件管理器的实现。这是新增功能,有很多不完善的地方,比如操作不当会产生大量应用缓存,目前还没有针对处理。保存到指定文件夹目前使用字符串硬拼接,在部分机型上可能无效。
提高前端控制台输出覆盖率
现在所有端使用 print 调试大法都更加方便了,副作用是有时候不得不筛选输出。
修复了上个版本存在的问题
上个版本在平板上启动闪退的问题在这个版本已经得到了修复。
提供汐洛版本号而非思源版本号导致的兼容性问题也得到了修复。
安卓端申请电源优化无限制权限与悬浮窗权限失败的问题也得到了修复。主要通过 EventBus 实现。
安卓端重启软件丢失锁定态的问题也得到了修复。主要通过 MMKV 读写实现。
更新摘要
@Sillot
改进功能 | Enhancement
- 接管
mobile
点击双链openMobileFileById
通过右上角托管 - 优化思源
auth.html
表现 - 更改插件加载优先级在
new App
- 优化安卓手机端部分场景通用菜单样式
- 安卓端伺服开启体验优化
- mobile about 页面显示内容调整
- 安卓端支持保存或导出到本机相册
修复错误 | Bugfix
闪亮之名 | Shinning
@Sillot-android
引入特性 | Feature
改进功能 | Enhancement
修复错误 | Bugfix
移除废止 | Abolishment
部分更新核心代码
文件中转站 UI 代码
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
@OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class)
@Composable
fun MyUI(intent: Intent?, fileType: String?, context: Context) {
val TAG = "MainPro-MyUI"
val uri = intent?.data
val coroutineScope = rememberCoroutineScope()
val fileName = uri?.let { getFileName(context, it) }
val fileSize = uri?.let { getFileSize(it) }
// val mimeType = intent?.data?.let { getMimeType(context, it) }
// val fileType = mimeType?.let { getFileType(it) }
val Thumbnail_Height = 250
val Button_Width = 300
val btn_lspace = 0.1.em
val btn_PaddingTopH = 3.dp
val btn_PaddingTopV = 6.dp
val btn_TextFontsizeH = 20.sp
val btn_TextFontsizeV = 18.sp
val btn_Color1 = Color.White
val btn_bgColor1 = Color(0xFF2196F3)
val btn_bgColor2 = Color(0xFF1976D2)
val btn_bgColor3 = Color(0xFF2391B5)
val btn_bgColor4 = Color(0xFF237A58)
val btnText1 = "分享"
val btnText2 = "复制到剪贴板"
val btnText3 = "保存到指定文件夹"
val btnText4 = "存入工作空间级资源目录"
var progressValue by remember { mutableStateOf(0) }
var isButton3OnClickRunning by remember { mutableStateOf(false) }
var isButton4OnClickRunning by remember { mutableStateOf(false) }
var destinationDir by remember {
mutableStateOf(File(context.getExternalFilesDir(null), "sillot/data/assets"))
}
var sourceFile by remember {
mutableStateOf(uri?.let { getFileFromUri(context, it) })
}
var selectedFolder by remember { mutableStateOf<Uri?>(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.data?.let { uri ->
// Get the selected folder path from the URI
selectedFolder = uri
}
}
}
val isLandscape = LocalConfiguration.current.orientation == Configuration.ORIENTATION_LANDSCAPE
LaunchedEffect(key1 = isButton3OnClickRunning) {
if (isButton3OnClickRunning && selectedFolder!=null) {
// 启动一个协程来执行任务
coroutineScope.launch {
withContext(Dispatchers.IO) {
var inputStream: BufferedInputStream? = null
var outputStream: BufferedOutputStream? = null
try {
inputStream = BufferedInputStream(FileInputStream(sourceFile))
val destinationFile =
(fileName ?: sourceFile?.name)?.let { File(destinationDir, it) }
outputStream = BufferedOutputStream(FileOutputStream(destinationFile))
val buffer = ByteArray(1024 * 64) // 64KB的缓冲区
val totalBytes = sourceFile?.length()
var bytesCopied = 0L
var bytesRead: Int
while (inputStream.read(buffer).also { bytesRead = it } != -1) {
outputStream.write(buffer, 0, bytesRead)
bytesCopied += bytesRead
if (totalBytes != null) {
progressValue = (bytesCopied.toFloat() / totalBytes.toFloat() * 100).toInt()
}
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
outputStream?.flush()
outputStream?.close()
inputStream?.close()
}
}
withContext(Dispatchers.Main) {
Toast.Show(context, "已复制到指定文件夹")
}
// 执行任务完成后,关闭遮罩
isButton3OnClickRunning = false
selectedFolder = null
}
}
}
LaunchedEffect(key1 = isButton4OnClickRunning) {
if (isButton4OnClickRunning) {
// 启动一个协程来执行任务
coroutineScope.launch {
withContext(Dispatchers.IO) {
var inputStream: BufferedInputStream? = null
var outputStream: BufferedOutputStream? = null
try {
inputStream = BufferedInputStream(FileInputStream(sourceFile))
val destinationFile =
(fileName ?: sourceFile?.name)?.let { File(destinationDir, it) }
outputStream = BufferedOutputStream(FileOutputStream(destinationFile))
val buffer = ByteArray(1024 * 64) // 64KB的缓冲区
val totalBytes = sourceFile?.length()
var bytesCopied = 0L
var bytesRead: Int
while (inputStream!!.read(buffer).also { bytesRead = it } != -1) {
outputStream!!.write(buffer, 0, bytesRead)
bytesCopied += bytesRead
if (totalBytes != null) {
progressValue = (bytesCopied.toFloat() / totalBytes.toFloat() * 100).toInt()
}
}
} catch (e: IOException) {
e.printStackTrace()
} finally {
outputStream?.flush()
outputStream?.close()
Button(modifier= Modifier
.width(Button_Width.dp)
.padding(top = btn_PaddingTopV),
colors = ButtonDefaults.buttonColors(
containerColor = btn_bgColor3,
contentColor = btn_Color1
), enabled = true, onClick = {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
launcher.launch(intent)
// 非阻塞
}) {
Text(
text = btnText3,
letterSpacing = btn_lspace,
fontSize = btn_TextFontsizeV
)
}
Button(modifier= Modifier
.width(Button_Width.dp)
.padding(top = btn_PaddingTopV),
colors = ButtonDefaults.buttonColors(
containerColor = btn_bgColor4,
contentColor = btn_Color1
), enabled = true, onClick = {
if (uri!=null) {
coroutineScope.launch {
destinationDir = File(context.getExternalFilesDir(null), "sillot/data/assets")
sourceFile = getFileFromUri(context, uri)
if (sourceFile == null || isFileSizeOverLimit(context.contentResolver, uri, 5858)) {
withContext(Dispatchers.Main) {
Toast.Show(context, "暂不支持超大文件或文件不存在")
}
} else {
Log.e(TAG,destinationDir.toString())
isButton4OnClickRunning = true // 值变化时会触发重组
}
}
}
}) {
Text(
text = btnText4,
letterSpacing = btn_lspace,
fontSize = btn_TextFontsizeV
)
}
Spacer(modifier = Modifier.height(16.dp))
selectedFolder?.let { folder ->
val folderPath = "/storage/emulated/0/" + (folder.lastPathSegment?.split(":")
?.last() ?: "")
if (folderPath!="") {
Log.e(TAG, "Selected Folder: $folderPath")
Text("Selected Folder: $folderPath")
destinationDir = File(folderPath)
sourceFile = uri?.let { it1 -> getFileFromUri(context, it1) }
isButton3OnClickRunning = true // 值变化时会触发重组
}
}
}
}
}
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于