Skip to content

Commit

Permalink
Merge pull request #116 from mumu-lhl/fix-export
Browse files Browse the repository at this point in the history
  • Loading branch information
mumu-lhl authored Jan 18, 2025
2 parents 734b943 + 2eeeb1b commit e545508
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 74 deletions.
143 changes: 89 additions & 54 deletions android/app/src/main/kotlin/org/eu/mumulhl/ciyue/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import android.os.Bundle
import androidx.documentfile.provider.DocumentFile
import com.anggrayudi.storage.callback.SingleFileConflictCallback
import com.anggrayudi.storage.callback.SingleFolderConflictCallback
import com.anggrayudi.storage.result.SingleFolderResult
import com.anggrayudi.storage.file.DocumentFileCompat
import com.anggrayudi.storage.file.copyFolderTo
import io.flutter.embedding.android.FlutterActivity
Expand All @@ -17,87 +16,123 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.onCompletion
import kotlinx.coroutines.launch
import timber.log.Timber
import java.io.File

class MainActivity : FlutterActivity() {
private val CHANNEL = "org.eu.mumulhl.ciyue"
private var methodChannel: MethodChannel? = null
private val REQUEST_CODE_OPEN_DOCUMENT_TREE = 0


private val OPEN_DOCUMENT_TREE = 0
private val CREATE_FILE = 1

private val job = Job()
private val ioScope = CoroutineScope(Dispatchers.IO + job)
private val uiScope = CoroutineScope(Dispatchers.IO + job)

var exportContent = ""

private fun openDirectory() {
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
startActivityForResult(intent, REQUEST_CODE_OPEN_DOCUMENT_TREE)
startActivityForResult(intent, OPEN_DOCUMENT_TREE)
}

private fun createFile() {
val intent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
setType("application/json")
putExtra(Intent.EXTRA_TITLE, "ciyue.json")
}
startActivityForResult(intent, CREATE_FILE)
}

override fun onActivityResult(
requestCode: Int, resultCode: Int, resultData: Intent?
requestCode: Int, resultCode: Int, data: Intent?
) {
super.onActivityResult(requestCode, resultCode, resultData)

if (requestCode == REQUEST_CODE_OPEN_DOCUMENT_TREE && resultCode == Activity.RESULT_OK) {
resultData?.data?.also { uri ->
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION
applicationContext.contentResolver.takePersistableUriPermission(uri, takeFlags)

val documents = DocumentFile.fromTreeUri(applicationContext, uri)!!

val cacheDir = File(applicationContext.cacheDir, "dictionaries_cache")
if (!cacheDir.exists()) {
cacheDir.mkdir()
super.onActivityResult(requestCode, resultCode, data)

if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
OPEN_DOCUMENT_TREE -> openDocumentTree(data)
CREATE_FILE -> {
data?.data?.also { uri ->
contentResolver.openOutputStream(uri)?.use { outputStream ->
outputStream.write(exportContent.toByteArray())
exportContent = ""
}
}
}
val targetFolder = DocumentFileCompat.fromFile(applicationContext, cacheDir)!!

ioScope.launch {
documents.copyFolderTo(
applicationContext,
targetFolder,
onConflict = object : SingleFolderConflictCallback(uiScope) {
override fun onParentConflict(
destinationFolder: DocumentFile,
action: ParentFolderConflictAction,
canMerge: Boolean
) {
action.confirmResolution(ConflictResolution.SKIP)
}
}
}
}

private fun openDocumentTree(data: Intent?) {
data?.data?.also { uri ->
val takeFlags: Int = Intent.FLAG_GRANT_READ_URI_PERMISSION
applicationContext.contentResolver.takePersistableUriPermission(
uri, takeFlags
)

override fun onContentConflict(
destinationFolder: DocumentFile,
conflictedFiles: MutableList<FileConflict>,
action: FolderContentConflictAction
) {
val newSolution = ArrayList<FileConflict>(conflictedFiles.size)
conflictedFiles.forEach {
it.solution = SingleFileConflictCallback.ConflictResolution.SKIP
}
newSolution.addAll(conflictedFiles)
action.confirmResolution(newSolution)
val documents = DocumentFile.fromTreeUri(applicationContext, uri)!!

val cacheDir = File(applicationContext.cacheDir, "dictionaries_cache")
if (!cacheDir.exists()) {
cacheDir.mkdir()
}
val targetFolder =
DocumentFileCompat.fromFile(applicationContext, cacheDir)!!

ioScope.launch {
documents.copyFolderTo(applicationContext,
targetFolder,
onConflict = object : SingleFolderConflictCallback(uiScope) {
override fun onParentConflict(
destinationFolder: DocumentFile,
action: ParentFolderConflictAction,
canMerge: Boolean
) {
action.confirmResolution(ConflictResolution.SKIP)
}

override fun onContentConflict(
destinationFolder: DocumentFile,
conflictedFiles: MutableList<FileConflict>,
action: FolderContentConflictAction
) {
val newSolution =
ArrayList<FileConflict>(conflictedFiles.size)
conflictedFiles.forEach {
it.solution =
SingleFileConflictCallback.ConflictResolution.SKIP
}
}).onCompletion {
}.collect { _ ->
}
newSolution.addAll(conflictedFiles)
action.confirmResolution(newSolution)

}
methodChannel?.invokeMethod("inputDirectory", null)
}
}).onCompletion {}.collect { _ -> }
}
methodChannel!!.invokeMethod("inputDirectory", null)
}
}

override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)

methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL)
methodChannel!!.setMethodCallHandler { call, result ->
if (call.method == "openDirectory") {
openDirectory()
result.success(0)
} else {
result.notImplemented()
methodChannel = MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).apply {
setMethodCallHandler { call, result ->
when (call.method) {
"openDirectory" -> {
openDirectory()
result.success(0)
}

"createFile" -> {
exportContent = call.arguments as String
createFile()
result.success(0)
}

else -> result.notImplemented()
}
}
}
}
Expand Down
22 changes: 2 additions & 20 deletions lib/pages/main/settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:flutter_gen/gen_l10n/app_localizations.dart";
import "package:go_router/go_router.dart";
import "package:path/path.dart";
import "package:url_launcher/url_launcher.dart";

const feedbackUri = "https://github.com/mumu-lhl/Ciyue/issues";
Expand Down Expand Up @@ -86,37 +85,20 @@ class ClearHistory extends StatelessWidget {
}

class Export extends StatelessWidget {
const Export({
super.key,
});
const Export({super.key});

@override
Widget build(BuildContext context) {
return ListTile(
leading: Icon(Icons.file_upload),
title: Text(AppLocalizations.of(context)!.export),
onTap: () async {
final directoryPath = await getDirectoryPath();
if (directoryPath == null || dictManager.isEmpty) {
return;
}

final dictionaryName = basename(dictManager.dicts.values.first.path),
filename = setExtension(dictionaryName, ".json"),
saveLocation = join(directoryPath, filename);

if (settings.autoExport) {
prefs.setString("autoExportPath", saveLocation);
}

final words = await wordbookDao.getAllWords(),
tags = await wordbookTagsDao.getAllTags();

if (words.isNotEmpty) {
final wordsOutput = jsonEncode(words), tagsOutput = jsonEncode(tags);

final file = File(saveLocation);
await file.writeAsString("$wordsOutput\n$tagsOutput");
platform.invokeMethod("createFile", "$wordsOutput\n$tagsOutput");
}
},
);
Expand Down

0 comments on commit e545508

Please sign in to comment.