Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 47 additions & 3 deletions app/src/main/java/app/grapheneos/camera/CamConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Expand Down Expand Up @@ -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 = ""
}
Expand Down Expand Up @@ -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(
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
128 changes: 103 additions & 25 deletions app/src/main/java/app/grapheneos/camera/ui/activities/MoreSettings.kt
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,18 @@ 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

private lateinit var pQField: EditText
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)) {
Expand All @@ -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))
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/res/drawable/video_storage_icon.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vector
xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportHeight="960"
android:viewportWidth="960">

<path
android:fillColor="?attr/colorControlNormal"
android:pathData="M460,580L740,400L460,220L460,580ZM320,720Q287,720 263.5,696.5Q240,673 240,640L240,160Q240,127 263.5,103.5Q287,80 320,80L800,80Q833,80 856.5,103.5Q880,127 880,160L880,640Q880,673 856.5,696.5Q833,720 800,720L320,720ZM320,640L800,640Q800,640 800,640Q800,640 800,640L800,160Q800,160 800,160Q800,160 800,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640ZM160,880Q127,880 103.5,856.5Q80,833 80,800L80,240L160,240L160,800Q160,800 160,800Q160,800 160,800L720,800L720,880L160,880ZM320,160L320,160Q320,160 320,160Q320,160 320,160L320,640Q320,640 320,640Q320,640 320,640L320,640Q320,640 320,640Q320,640 320,640L320,160Q320,160 320,160Q320,160 320,160Z"/>

</vector>
Loading