mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2026-05-16 04:52:39 +02:00
addressing pr comments
This commit is contained in:
@@ -231,6 +231,4 @@ dependencies {
|
||||
testImplementation "org.mockito:mockito-core:5.4.0"
|
||||
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
|
||||
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
|
||||
//ffmpeg
|
||||
implementation files('libs/ffmpeg-kit-full-6.0-2.aar')
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -30,7 +30,7 @@
|
||||
android:largeHeap="true">
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:authorities="@string/authority"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" />
|
||||
|
||||
@@ -13,8 +13,8 @@ import android.view.View
|
||||
import android.widget.ImageButton
|
||||
import android.widget.ImageView
|
||||
import android.widget.TextView
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.FileProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
@@ -42,10 +42,6 @@ import kotlinx.coroutines.withContext
|
||||
import userpackage.Protocol
|
||||
import userpackage.Protocol.ExportBundle
|
||||
import userpackage.Protocol.URLInfo
|
||||
import java.io.File
|
||||
import java.io.FileWriter
|
||||
import android.content.ContentValues
|
||||
import android.provider.MediaStore
|
||||
|
||||
class PolycentricBackupActivity : AppCompatActivity() {
|
||||
private lateinit var _buttonShare: BigButton;
|
||||
@@ -57,6 +53,20 @@ class PolycentricBackupActivity : AppCompatActivity() {
|
||||
private lateinit var _textQRHint: TextView;
|
||||
private lateinit var _loader: View
|
||||
|
||||
private val _createDocumentLauncher = registerForActivityResult(ActivityResultContracts.CreateDocument("text/plain")) { uri ->
|
||||
uri?.let { fileUri ->
|
||||
try {
|
||||
contentResolver.openOutputStream(fileUri)?.use { outputStream ->
|
||||
outputStream.write(_exportBundle.toByteArray())
|
||||
}
|
||||
UIDialogs.toast(this, getString(R.string.profile_saved_successfully))
|
||||
} catch (e: Exception) {
|
||||
Logger.e(TAG, "Failed to write to document", e)
|
||||
UIDialogs.toast(this, "Failed to save profile: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun attachBaseContext(newBase: Context?) {
|
||||
super.attachBaseContext(StateApp.instance.getLocaleContext(newBase))
|
||||
}
|
||||
@@ -149,7 +159,8 @@ class PolycentricBackupActivity : AppCompatActivity() {
|
||||
};
|
||||
|
||||
_buttonExportFile.onClick.subscribe {
|
||||
exportToFile()
|
||||
val fileName = "polycentric_profile_${System.currentTimeMillis()}.txt"
|
||||
_createDocumentLauncher.launch(fileName)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -263,81 +274,6 @@ class PolycentricBackupActivity : AppCompatActivity() {
|
||||
return "polycentric://" + data.toBase64Url()
|
||||
}
|
||||
|
||||
private fun exportToFile() {
|
||||
try {
|
||||
val fileName = "polycentric_profile_${System.currentTimeMillis()}.txt"
|
||||
val file = File(filesDir, fileName)
|
||||
|
||||
FileWriter(file).use { writer ->
|
||||
writer.write(_exportBundle)
|
||||
}
|
||||
|
||||
val uri = FileProvider.getUriForFile(
|
||||
this,
|
||||
"${packageName}.fileprovider",
|
||||
file
|
||||
)
|
||||
|
||||
// Show dialog with options
|
||||
UIDialogs.showDialog(
|
||||
this,
|
||||
R.drawable.ic_download,
|
||||
getString(R.string.export_profile),
|
||||
getString(R.string.choose_export_option),
|
||||
null,
|
||||
-1,
|
||||
UIDialogs.Action(getString(R.string.share), {
|
||||
// Share the file
|
||||
val shareIntent = Intent(Intent.ACTION_SEND).apply {
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
putExtra(Intent.EXTRA_SUBJECT, "Polycentric Profile Export")
|
||||
putExtra(Intent.EXTRA_TEXT, "Polycentric profile export file")
|
||||
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
|
||||
}
|
||||
startActivity(Intent.createChooser(shareIntent, getString(R.string.share_profile)))
|
||||
}, UIDialogs.ActionStyle.NONE, true),
|
||||
UIDialogs.Action(getString(R.string.save_to_device), {
|
||||
// Save to device
|
||||
saveToDevice(fileName)
|
||||
}, UIDialogs.ActionStyle.NONE, true)
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
Logger.e(TAG, "Failed to export to file", e)
|
||||
UIDialogs.toast(this, "Failed to export profile to file")
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveToDevice(fileName: String) {
|
||||
try {
|
||||
// Use MediaStore API to save to Downloads folder
|
||||
val contentValues = ContentValues().apply {
|
||||
put(MediaStore.Downloads.DISPLAY_NAME, fileName)
|
||||
put(MediaStore.Downloads.MIME_TYPE, "text/plain")
|
||||
put(MediaStore.Downloads.IS_PENDING, 1)
|
||||
}
|
||||
|
||||
val resolver = contentResolver
|
||||
val uri = resolver.insert(MediaStore.Downloads.EXTERNAL_CONTENT_URI, contentValues)
|
||||
|
||||
uri?.let { fileUri ->
|
||||
resolver.openOutputStream(fileUri)?.use { outputStream ->
|
||||
outputStream.write(_exportBundle.toByteArray())
|
||||
}
|
||||
|
||||
contentValues.clear()
|
||||
contentValues.put(MediaStore.Downloads.IS_PENDING, 0)
|
||||
resolver.update(fileUri, contentValues, null, null)
|
||||
|
||||
UIDialogs.toast(this, getString(R.string.profile_saved_to_downloads))
|
||||
} ?: run {
|
||||
UIDialogs.toast(this, getString(R.string.failed_to_save_profile))
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.e(TAG, "Failed to save to device", e)
|
||||
UIDialogs.toast(this, getString(R.string.failed_to_save_profile))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "PolycentricBackupActivity";
|
||||
|
||||
+37
-1
@@ -52,10 +52,46 @@ class PolycentricImportProfileActivity : AppCompatActivity() {
|
||||
private val _filePickerLauncher = registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
uri?.let { fileUri ->
|
||||
try {
|
||||
// Check file size before reading
|
||||
val fileSize = contentResolver.openFileDescriptor(fileUri, "r")?.statSize ?: 0
|
||||
val maxFileSize = 10 * 1024 * 1024 // 10MB limit
|
||||
|
||||
if (fileSize > maxFileSize) {
|
||||
UIDialogs.toast(this, "File too large. Maximum size is 10MB.")
|
||||
return@let
|
||||
}
|
||||
|
||||
if (fileSize == 0L) {
|
||||
UIDialogs.toast(this, "Selected file is empty.")
|
||||
return@let
|
||||
}
|
||||
|
||||
val content = contentResolver.openInputStream(fileUri)?.bufferedReader()?.readText()
|
||||
content?.let { fileContent ->
|
||||
import(fileContent.trim())
|
||||
val trimmedContent = fileContent.trim()
|
||||
|
||||
// Check if content is empty after trimming
|
||||
if (trimmedContent.isEmpty()) {
|
||||
UIDialogs.toast(this, "Selected file contains no data.")
|
||||
return@let
|
||||
}
|
||||
|
||||
// Check if content looks like a valid polycentric URL
|
||||
if (!trimmedContent.startsWith("polycentric://")) {
|
||||
UIDialogs.toast(this, "Selected file does not contain a valid polycentric profile URL.")
|
||||
return@let
|
||||
}
|
||||
|
||||
import(trimmedContent)
|
||||
} ?: run {
|
||||
UIDialogs.toast(this, "Could not read file content.")
|
||||
}
|
||||
} catch (e: SecurityException) {
|
||||
Logger.e(TAG, "Security exception reading file", e)
|
||||
UIDialogs.toast(this, "Permission denied to read file.")
|
||||
} catch (e: OutOfMemoryError) {
|
||||
Logger.e(TAG, "Out of memory reading file", e)
|
||||
UIDialogs.toast(this, "File too large to process.")
|
||||
} catch (e: Exception) {
|
||||
Logger.e(TAG, "Failed to read file", e)
|
||||
UIDialogs.toast(this, "Failed to read file: ${e.message}")
|
||||
|
||||
+19
-4
@@ -32,7 +32,13 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
setContentView(R.layout.activity_polycentric_moderation)
|
||||
setNavigationBarColorAndIcons()
|
||||
|
||||
_moderationsManager = ModerationsManager.getInstance()
|
||||
try {
|
||||
_moderationsManager = ModerationsManager.getInstance()
|
||||
} catch (e: IllegalStateException) {
|
||||
// ModerationsManager not initialized, finish activity
|
||||
finish()
|
||||
return
|
||||
}
|
||||
|
||||
_seekbarOffensive = findViewById(R.id.seekbar_offensive)
|
||||
_seekbarExplicit = findViewById(R.id.seekbar_explicit)
|
||||
@@ -44,7 +50,7 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
_textExplicitValue = findViewById(R.id.text_explicit_value)
|
||||
_textViolenceValue = findViewById(R.id.text_violence_value)
|
||||
|
||||
findViewById<ImageButton>(R.id.button_back).setOnClickListener {
|
||||
findViewById<ImageButton>(R.id.button_back)?.setOnClickListener {
|
||||
finish()
|
||||
}
|
||||
|
||||
@@ -53,6 +59,8 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun loadSettings() {
|
||||
if (isFinishing || isDestroyed) return
|
||||
|
||||
val levels = _moderationsManager.moderationLevels.value ?: mapOf()
|
||||
|
||||
val offensiveLevel = levels["hate"] ?: 2
|
||||
@@ -71,6 +79,7 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
private fun setupListeners() {
|
||||
_seekbarOffensive.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
if (isFinishing || isDestroyed) return
|
||||
updateDescriptionText(seekBar, _textOffensiveDesc, _textOffensiveValue, getOffensiveDescriptions())
|
||||
if (fromUser) {
|
||||
_moderationsManager.setModerationLevel("hate", progress)
|
||||
@@ -83,6 +92,7 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
|
||||
_seekbarExplicit.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
if (isFinishing || isDestroyed) return
|
||||
updateDescriptionText(seekBar, _textExplicitDesc, _textExplicitValue, getExplicitDescriptions())
|
||||
if (fromUser) {
|
||||
_moderationsManager.setModerationLevel("sexual", progress)
|
||||
@@ -95,6 +105,7 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
|
||||
_seekbarViolence.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
|
||||
if (isFinishing || isDestroyed) return
|
||||
updateDescriptionText(seekBar, _textViolenceDesc, _textViolenceValue, getViolenceDescriptions())
|
||||
if (fromUser) {
|
||||
_moderationsManager.setModerationLevel("violence", progress)
|
||||
@@ -107,9 +118,13 @@ class PolycentricModerationActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun updateDescriptionText(seekBar: SeekBar?, textDesc: TextView, textValue: TextView, descriptions: Array<String>) {
|
||||
if (isFinishing || isDestroyed) return
|
||||
|
||||
val progress = seekBar?.progress ?: 0
|
||||
textDesc.text = descriptions[progress]
|
||||
textValue.text = progress.toString()
|
||||
if (progress in descriptions.indices) {
|
||||
textDesc.text = descriptions[progress]
|
||||
textValue.text = progress.toString()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOffensiveDescriptions(): Array<String> {
|
||||
|
||||
Reference in New Issue
Block a user