diff --git a/app/src/main/java/app/grapheneos/camera/CamConfig.kt b/app/src/main/java/app/grapheneos/camera/CamConfig.kt index 128205f5..224a645c 100644 --- a/app/src/main/java/app/grapheneos/camera/CamConfig.kt +++ b/app/src/main/java/app/grapheneos/camera/CamConfig.kt @@ -111,6 +111,10 @@ class CamConfig(private val mActivity: MainActivity) { const val ENABLE_ZSL = "enable_zsl" + const val SEPARATE_VIDEO_STORAGE = "separate_video_storage" + + const val VIDEO_STORAGE_LOCATION = "video_storage_location" + // const val IMAGE_FILE_FORMAT = "image_quality" // const val VIDEO_FILE_FORMAT = "video_quality" } @@ -156,6 +160,8 @@ class CamConfig(private val mActivity: MainActivity) { const val ENABLE_ZSL = false + const val SEPARATE_VIDEO_STORAGE = false + // const val IMAGE_FILE_FORMAT = "" // const val VIDEO_FILE_FORMAT = "" } @@ -510,6 +516,40 @@ class CamConfig(private val mActivity: MainActivity) { editor.apply() } + var videoStorageLocation: String + get() { + return commonPref.getString( + SettingValues.Key.VIDEO_STORAGE_LOCATION, + SettingValues.Default.STORAGE_LOCATION + )!! + } + set(value) { + val cur = videoStorageLocation + if (cur != SettingValues.Default.STORAGE_LOCATION) { + CapturedItems.savePreviousSafTree(Uri.parse(cur), commonPref) + } + + val editor = commonPref.edit() + editor.putString(SettingValues.Key.VIDEO_STORAGE_LOCATION, value) + editor.apply() + } + + var separateVideoStorage: Boolean + get() { + return commonPref.getBoolean( + SettingValues.Key.SEPARATE_VIDEO_STORAGE, + SettingValues.Default.SEPARATE_VIDEO_STORAGE + ) + } + set(value) { + val editor = commonPref.edit() + editor.putBoolean( + SettingValues.Key.SEPARATE_VIDEO_STORAGE, + value + ) + editor.apply() + } + var photoQuality: Int get() { return commonPref.getInt( @@ -1545,9 +1585,13 @@ class CamConfig(private val mActivity: MainActivity) { dialog.showIgnoringShortEdgeMode() } - fun onStorageLocationNotFound() { - // Reverting back to DEFAULT_MEDIA_STORE_CAPTURE_PATH - storageLocation = SettingValues.Default.STORAGE_LOCATION + fun onStorageLocationNotFound(inVideoMode: Boolean = false) { + // Reverting back to default path + if (inVideoMode && separateVideoStorage) { + videoStorageLocation = SettingValues.Default.STORAGE_LOCATION + } else { + storageLocation = SettingValues.Default.STORAGE_LOCATION + } val builder = MaterialAlertDialogBuilder(mActivity) .setTitle(R.string.folder_not_found) diff --git a/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt b/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt index 6a505d0c..8f7fd373 100644 --- a/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt +++ b/app/src/main/java/app/grapheneos/camera/capturer/VideoCapturer.kt @@ -109,7 +109,11 @@ class VideoCapturer(private val mActivity: MainActivity) { uri = ctx.outputUri shouldAddToGallery = false } else { - val storageLocation = camConfig.storageLocation + val storageLocation = if (camConfig.separateVideoStorage) { + camConfig.videoStorageLocation + } else { + camConfig.storageLocation + } if (storageLocation == CamConfig.SettingValues.Default.STORAGE_LOCATION) { val contentValues = ContentValues().apply { @@ -177,7 +181,7 @@ class VideoCapturer(private val mActivity: MainActivity) { } catch (exception: Exception) { val foreignUri = ctx is VideoCaptureActivity && ctx.isOutputUriAvailable() if (!foreignUri) { - camConfig.onStorageLocationNotFound() + camConfig.onStorageLocationNotFound(inVideoMode = true) } ctx.showMessage(R.string.unable_to_access_output_file) isRecording = false diff --git a/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt b/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt index 18b228fb..cec2e074 100644 --- a/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt +++ b/app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt @@ -36,7 +36,7 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { private lateinit var sLField: EditText - private lateinit var rSLocation: Button + private lateinit var vSLField: EditText private lateinit var rootView: View @@ -44,9 +44,10 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { private lateinit var iFField: EditText private lateinit var vFField: EditText - private val dirPickerHandler = registerForActivityResult( + private val defaultStorageDirPicker = registerForActivityResult( ActivityResultContracts.StartActivityForResult() - ) { + ) { it -> + val intent = it.data val uri = intent?.data?.let { if (it.toString().contains(CapturedItems.SAF_TREE_SEPARATOR)) { @@ -60,9 +61,9 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) val uriString = uri.toString() - camConfig.storageLocation = uriString - val uiString = storageLocationToUiString(this, uriString) + + camConfig.storageLocation = uriString sLField.setText(uiString) showMessage(getString(R.string.storage_location_updated, uiString)) @@ -72,6 +73,35 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { } } + private val videoStorageDirPicker = registerForActivityResult( + ActivityResultContracts.StartActivityForResult() + ) { it -> + + val intent = it.data + + val uri = intent?.data?.let { + if (it.toString().contains(CapturedItems.SAF_TREE_SEPARATOR)) { + null + } else { + it + } + } + + if (uri != null) { + contentResolver.takePersistableUriPermission(uri, + Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION) + + val uriString = uri.toString() + val uiString = storageLocationToUiString(this, uriString) + + camConfig.videoStorageLocation = uriString + vSLField.setText(uiString) + + showMessage(getString(R.string.storage_location_updated, uiString)) + } else { + showMessage(getString(R.string.no_directory_selected)) + } + } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -113,35 +143,48 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { sLField.setText(storageLocationToUiString(this, camConfig.storageLocation)) sLField.setOnClickListener { - val i = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE) - dirPickerHandler.launch(Intent.createChooser(i, getString(R.string.choose_storage_location))) + val dirPickerIntent = Intent.createChooser( + Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), + getString(R.string.choose_storage_location) + ) + defaultStorageDirPicker.launch(dirPickerIntent) } - snackBar = Snackbar.make(rootView, "", Snackbar.LENGTH_LONG) + vSLField = binding.videoStorageLocationField - rSLocation = binding.refreshStorageLocation - rSLocation.setOnClickListener { + vSLField.setText(storageLocationToUiString(this, camConfig.videoStorageLocation)) - val dialog = MaterialAlertDialogBuilder(this) + vSLField.setOnClickListener { + val dirPickerIntent = Intent.createChooser( + Intent(Intent.ACTION_OPEN_DOCUMENT_TREE), + getString(R.string.choose_storage_location) + ) + videoStorageDirPicker.launch(dirPickerIntent) + } - dialog.setTitle(R.string.are_you_sure) + binding.videoStorageSettingToggle.isChecked = camConfig.separateVideoStorage - dialog.setMessage(R.string.revert_to_default_directory) + binding.videoStorageSettingToggle.setOnClickListener { + binding.videoStorageSettingToggle.isChecked.let { + camConfig.separateVideoStorage = it + vSLField.isEnabled = it + binding.refreshVideoStorageLocation.isEnabled = it + } + } - dialog.setPositiveButton(R.string.yes) { _, _ -> - val defaultLocation = CamConfig.SettingValues.Default.STORAGE_LOCATION + if (!camConfig.separateVideoStorage) { + vSLField.isEnabled = false + binding.refreshVideoStorageLocation.isEnabled = false + } - if (camConfig.storageLocation != defaultLocation) { - showMessage(getString(R.string.reverted_to_default_directory)) - camConfig.storageLocation = defaultLocation - sLField.setText(storageLocationToUiString(this, defaultLocation)) - } else { - showMessage(getString(R.string.already_using_default_directory)) - } - } + snackBar = Snackbar.make(rootView, "", Snackbar.LENGTH_LONG) + + binding.refreshStorageLocation.setOnClickListener { + promptUserToResetStorageLocation() + } - dialog.setNegativeButton(R.string.no, null) - dialog.show() + binding.refreshVideoStorageLocation.setOnClickListener { + promptUserToResetStorageLocation(forVideo = true) } pQField = binding.photoQuality @@ -313,6 +356,41 @@ open class MoreSettings : AppCompatActivity(), TextView.OnEditorActionListener { // camConfig.videoFormat = vFField.text.toString() } + private fun promptUserToResetStorageLocation(forVideo: Boolean = false) { + val dialog = MaterialAlertDialogBuilder(this) + + dialog.setTitle(R.string.are_you_sure) + + dialog.setMessage(R.string.revert_to_default_directory) + + dialog.setPositiveButton(R.string.yes) { _, _ -> + val defaultLocation = CamConfig.SettingValues.Default.STORAGE_LOCATION + val currentLocation = if (forVideo) { + camConfig.videoStorageLocation + } else { + camConfig.storageLocation + } + + if (currentLocation != defaultLocation) { + showMessage(getString(R.string.reverted_to_default_directory)) + + if (forVideo) { + camConfig.videoStorageLocation = defaultLocation + vSLField.setText(storageLocationToUiString(this, defaultLocation)) + } else { + camConfig.storageLocation = defaultLocation + sLField.setText(storageLocationToUiString(this, defaultLocation)) + } + } else { + showMessage(getString(R.string.already_using_default_directory)) + } + } + + dialog.setNegativeButton(R.string.no, null) + dialog.show() + + } + override fun onEditorAction(p0: TextView?, id: Int, p2: KeyEvent?): Boolean { return if (id == EditorInfo.IME_ACTION_DONE) { clearFocus() diff --git a/app/src/main/res/drawable/video_storage_icon.xml b/app/src/main/res/drawable/video_storage_icon.xml new file mode 100644 index 00000000..a64074c2 --- /dev/null +++ b/app/src/main/res/drawable/video_storage_icon.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/layout/more_settings.xml b/app/src/main/res/layout/more_settings.xml index c3b8117f..64ff5acd 100644 --- a/app/src/main/res/layout/more_settings.xml +++ b/app/src/main/res/layout/more_settings.xml @@ -547,11 +547,67 @@ android:id="@+id/storage_location_icon" android:layout_width="48dp" android:layout_height="48dp" - android:contentDescription="@string/save_image_as_previewed" + android:contentDescription="@string/storage_location" android:paddingStart="4dp" android:paddingEnd="8dp" android:src="@drawable/storage" /> + + + + + + +