Camera HDR, grid & filters & Directory size calculation

This commit is contained in:
Hardcore Sushi 2020-08-11 20:40:14 +02:00
parent 0518a2a030
commit 6c43750290
15 changed files with 151 additions and 25 deletions

View File

@ -15,7 +15,7 @@ android {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 29
versionCode 1 versionCode 1
versionName "1.1.4" versionName "1.1.5"
ndk { ndk {
abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a' abiFilters 'x86_64', 'armeabi-v7a', 'arm64-v8a'
@ -41,7 +41,7 @@ dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "androidx.core:core-ktx:1.3.1" implementation "androidx.core:core-ktx:1.3.1"
implementation "androidx.appcompat:appcompat:1.1.0" implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.constraintlayout:constraintlayout:1.1.3" implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.sqlite:sqlite:2.1.0" implementation "androidx.sqlite:sqlite:2.1.0"

View File

@ -20,7 +20,7 @@
android:requestLegacyExternalStorage="true" android:requestLegacyExternalStorage="true"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme"> android:theme="@style/AppTheme">
<activity android:name=".CameraActivity"/> <activity android:name=".CameraActivity" android:screenOrientation="nosensor"/>
<activity <activity
android:name=".SettingsActivity" android:name=".SettingsActivity"
android:label="@string/title_activity_settings" android:label="@string/title_activity_settings"

View File

@ -11,6 +11,9 @@ import com.otaliastudios.cameraview.CameraListener
import com.otaliastudios.cameraview.PictureResult import com.otaliastudios.cameraview.PictureResult
import com.otaliastudios.cameraview.controls.Facing import com.otaliastudios.cameraview.controls.Facing
import com.otaliastudios.cameraview.controls.Flash import com.otaliastudios.cameraview.controls.Flash
import com.otaliastudios.cameraview.controls.Grid
import com.otaliastudios.cameraview.controls.Hdr
import com.otaliastudios.cameraview.filter.Filters
import kotlinx.android.synthetic.main.activity_camera.* import kotlinx.android.synthetic.main.activity_camera.*
import sushi.hardcore.droidfs.provider.RestrictedFileProvider import sushi.hardcore.droidfs.provider.RestrictedFileProvider
import sushi.hardcore.droidfs.util.GocryptfsVolume import sushi.hardcore.droidfs.util.GocryptfsVolume
@ -24,12 +27,16 @@ import java.util.*
class CameraActivity : BaseActivity() { class CameraActivity : BaseActivity() {
companion object { companion object {
private val flashModes = listOf(Flash.AUTO, Flash.ON, Flash.OFF) private val flashModes = listOf(Flash.AUTO, Flash.ON, Flash.OFF)
private val gridTitles = listOf(R.string.grid_none, R.string.grid_3x3, R.string.grid_4x4)
private val gridValues = listOf(Grid.OFF, Grid.DRAW_3X3, Grid.DRAW_4X4)
private val filterNames = Filters.values().map { it.toString().toLowerCase(Locale.ROOT).replace("_", " ").capitalize() as CharSequence }.toTypedArray()
private const val fileNameRandomMin = 100000 private const val fileNameRandomMin = 100000
private const val fileNameRandomMax = 999999 private const val fileNameRandomMax = 999999
private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss") private val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss")
private val random = Random() private val random = Random()
} }
private var currentFlashModeIndex = 0 private var currentFlashModeIndex = 0
private var currentFilterIndex = 0
private var timerDuration = 0 private var timerDuration = 0
set(value) { set(value) {
field = value field = value
@ -68,6 +75,14 @@ class CameraActivity : BaseActivity() {
take_photo_button.onClick = ::onClickTakePhoto take_photo_button.onClick = ::onClickTakePhoto
} }
private fun takePhoto() {
if (currentFilterIndex != 0){
camera.takePictureSnapshot()
} else {
camera.takePicture()
}
}
private fun onClickTakePhoto() { private fun onClickTakePhoto() {
val baseName = "IMG_"+dateFormat.format(Date())+"_" val baseName = "IMG_"+dateFormat.format(Date())+"_"
do { do {
@ -81,12 +96,12 @@ class CameraActivity : BaseActivity() {
Thread.sleep(1000) Thread.sleep(1000)
} }
runOnUiThread { runOnUiThread {
camera.takePicture() takePhoto()
text_timer.visibility = View.GONE text_timer.visibility = View.GONE
} }
}.start() }.start()
} else { } else {
camera.takePicture() takePhoto()
} }
} }
@ -113,13 +128,26 @@ class CameraActivity : BaseActivity() {
} }
} }
fun onClickHDR(view: View) {
camera.hdr = when (camera.hdr){
Hdr.ON -> {
image_hdr.setImageResource(R.drawable.icon_hdr_off)
Hdr.OFF
}
Hdr.OFF -> {
image_hdr.setImageResource(R.drawable.icon_hdr_on)
Hdr.ON
}
}
}
fun onClickTimer(view: View) { fun onClickTimer(view: View) {
val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null) val dialogEditTextView = layoutInflater.inflate(R.layout.dialog_edit_text, null)
val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text) val dialogEditText = dialogEditTextView.findViewById<EditText>(R.id.dialog_edit_text)
dialogEditText.inputType = InputType.TYPE_CLASS_NUMBER dialogEditText.inputType = InputType.TYPE_CLASS_NUMBER
val dialog = ColoredAlertDialogBuilder(this) val dialog = ColoredAlertDialogBuilder(this)
.setView(dialogEditTextView) .setView(dialogEditTextView)
.setTitle("Enter the timer duration (in s)") .setTitle(getString(R.string.enter_timer_duration))
.setPositiveButton(R.string.ok) { _, _ -> .setPositiveButton(R.string.ok) { _, _ ->
timerDuration = dialogEditText.text.toString().toInt() timerDuration = dialogEditText.text.toString().toInt()
} }
@ -134,6 +162,29 @@ class CameraActivity : BaseActivity() {
dialog.show() dialog.show()
} }
fun onClickGrid(view: View) {
ColoredAlertDialogBuilder(this)
.setTitle(getString(R.string.choose_grid))
.setSingleChoiceItems(gridTitles.map { getString(it) as CharSequence }.toTypedArray(), gridValues.indexOf(camera.grid)){ dialog, which ->
camera.grid = gridValues[which]
dialog.dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
fun onClickFilter(view: View) {
ColoredAlertDialogBuilder(this)
.setTitle(getString(R.string.choose_filter))
.setSingleChoiceItems(filterNames, currentFilterIndex){ dialog, which ->
camera.filter = Filters.values()[which].newInstance()
currentFilterIndex = which
dialog.dismiss()
}
.setNegativeButton(R.string.cancel, null)
.show()
}
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
if (!isFinishingIntentionally) { if (!isFinishingIntentionally) {

View File

@ -12,15 +12,15 @@ import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import sushi.hardcore.droidfs.ConstValues.Companion.getAssociatedDrawable import sushi.hardcore.droidfs.ConstValues.Companion.getAssociatedDrawable
import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.R import sushi.hardcore.droidfs.R
import sushi.hardcore.droidfs.explorers.ExplorerElement
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import sushi.hardcore.droidfs.widgets.ThemeColor import sushi.hardcore.droidfs.widgets.ThemeColor
import java.text.DateFormat import java.text.DateFormat
import java.util.* import java.util.*
class ExplorerElementAdapter(private val context: Context) : BaseAdapter() { class ExplorerElementAdapter(private val context: Context) : BaseAdapter() {
private val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, context.resources.configuration.locale) private val dateFormat: DateFormat = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.getDefault())
private lateinit var explorerElements: List<ExplorerElement> private lateinit var explorerElements: List<ExplorerElement>
private val inflater: LayoutInflater = LayoutInflater.from(context) private val inflater: LayoutInflater = LayoutInflater.from(context)
val selectedItems: MutableList<Int> = ArrayList() val selectedItems: MutableList<Int> = ArrayList()
@ -44,7 +44,11 @@ class ExplorerElementAdapter(private val context: Context) : BaseAdapter() {
textElementName.text = currentElement.name textElementName.text = currentElement.name
val textElementMtime = view.findViewById<TextView>(R.id.text_element_mtime) val textElementMtime = view.findViewById<TextView>(R.id.text_element_mtime)
val textElementSize = view.findViewById<TextView>(R.id.text_element_size) val textElementSize = view.findViewById<TextView>(R.id.text_element_size)
textElementSize.text = "" if (!currentElement.isParentFolder){
textElementSize.text = PathUtils.formatSize(currentElement.size)
} else {
textElementSize.text = ""
}
var drawableId = R.drawable.icon_folder var drawableId = R.drawable.icon_folder
when { when {
currentElement.isDirectory -> { currentElement.isDirectory -> {
@ -55,12 +59,11 @@ class ExplorerElementAdapter(private val context: Context) : BaseAdapter() {
} }
else -> { else -> {
textElementMtime.text = dateFormat.format(currentElement.mTime) textElementMtime.text = dateFormat.format(currentElement.mTime)
textElementSize.text = PathUtils.formatSize(currentElement.size)
drawableId = getAssociatedDrawable(currentElement.name) drawableId = getAssociatedDrawable(currentElement.name)
} }
} }
val elementIcon = view.findViewById<ImageView>(R.id.icon_element) val elementIcon = view.findViewById<ImageView>(R.id.icon_element)
val icon = context.getDrawable(drawableId) val icon = ContextCompat.getDrawable(context, drawableId)
icon?.colorFilter = PorterDuffColorFilter(themeColor, PorterDuff.Mode.SRC_IN) icon?.colorFilter = PorterDuffColorFilter(themeColor, PorterDuff.Mode.SRC_IN)
elementIcon.setImageDrawable(icon) elementIcon.setImageDrawable(icon)
if (selectedItems.contains(position)) { if (selectedItems.contains(position)) {

View File

@ -141,7 +141,6 @@ open class BaseExplorerActivity : BaseActivity() {
} }
.setTitle(getString(R.string.open_as)) .setTitle(getString(R.string.open_as))
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.create()
.show() .show()
} }
} }
@ -180,9 +179,18 @@ open class BaseExplorerActivity : BaseActivity() {
current_path_text.text = getString(R.string.location, currentDirectoryPath) current_path_text.text = getString(R.string.location, currentDirectoryPath)
Thread{ Thread{
var totalSize: Long = 0 var totalSize: Long = 0
for (e in gocryptfsVolume.recursiveMapFiles(currentDirectoryPath)){ for (element in explorerElements){
if (e.isRegularFile){ if (element.isDirectory){
totalSize += e.size var dirSize: Long = 0
for (subFile in gocryptfsVolume.recursiveMapFiles(element.fullPath)){
if (subFile.isRegularFile){
dirSize += subFile.size
}
}
element.size = dirSize
totalSize += dirSize
} else if (element.isRegularFile) {
totalSize += element.size
} }
} }
total_size_text.text = getString(R.string.total_size, PathUtils.formatSize(totalSize)) total_size_text.text = getString(R.string.total_size, PathUtils.formatSize(totalSize))
@ -432,4 +440,4 @@ open class BaseExplorerActivity : BaseActivity() {
} }
} }
} }
} }

View File

@ -129,7 +129,6 @@ class ExplorerActivity : BaseExplorerActivity() {
} }
.setTitle(getString(R.string.fab_dialog_title)) .setTitle(getString(R.string.fab_dialog_title))
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.create()
.show() .show()
} }
} }
@ -728,4 +727,4 @@ class ExplorerActivity : BaseExplorerActivity() {
unselectAll() unselectAll()
setCurrentPath(currentDirectoryPath) //refresh setCurrentPath(currentDirectoryPath) //refresh
} }
} }

View File

@ -3,7 +3,7 @@ package sushi.hardcore.droidfs.explorers
import sushi.hardcore.droidfs.util.PathUtils import sushi.hardcore.droidfs.util.PathUtils
import java.util.* import java.util.*
class ExplorerElement(val name: String, val elementType: Short, val size: Long, mtime: Long, private val parentPath: String) { class ExplorerElement(val name: String, val elementType: Short, var size: Long, mtime: Long, parentPath: String) {
val mTime = Date((mtime * 1000).toString().toLong()) val mTime = Date((mtime * 1000).toString().toLong())
val fullPath: String = PathUtils.path_join(parentPath, name) val fullPath: String = PathUtils.path_join(parentPath, name)

View File

@ -65,6 +65,7 @@ class ImageViewer: FileViewerActivity() {
for ((i, e) in mappedImages.withIndex()){ for ((i, e) in mappedImages.withIndex()){
if (filePath == e.fullPath){ if (filePath == e.fullPath){
currentMappedImageIndex = i currentMappedImageIndex = i
break
} }
} }
wasMapped = true wasMapped = true

View File

@ -10,7 +10,7 @@ object MiscUtils {
} }
fun decrementIndex(index: Int, list: List<Any>): Int { fun decrementIndex(index: Int, list: List<Any>): Int {
var i = index-1 var i = index-1
if (i <= 0){ if (i < 0){
i = list.size-1 i = list.size-1
} }
return i return i

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM8,20L4,20v-4h4v4zM8,14L4,14v-4h4v4zM8,8L4,8L4,4h4v4zM14,20h-4v-4h4v4zM14,14h-4v-4h4v4zM14,8h-4L10,4h4v4zM20,20h-4v-4h4v4zM20,14h-4v-4h4v4zM20,8h-4L16,4h4v4z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17.5,15v-2h1.1l0.9,2L21,15l-0.9,-2.1c0.5,-0.2 0.9,-0.8 0.9,-1.4v-1c0,-0.8 -0.7,-1.5 -1.5,-1.5L16,9v4.9l1.1,1.1h0.4zM17.5,10.5h2v1h-2v-1zM13,10.5v0.4l1.5,1.5v-1.9c0,-0.8 -0.7,-1.5 -1.5,-1.5h-1.9l1.5,1.5h0.4zM9.5,9.5l-7,-7 -1.1,1L6.9,9h-0.4v2h-2L4.5,9L3,9v6h1.5v-2.5h2L6.5,15L8,15v-4.9l1.5,1.5L9.5,15h3.4l7.6,7.6 1.1,-1.1 -12.1,-12z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M21,11.5v-1c0,-0.8 -0.7,-1.5 -1.5,-1.5L16,9v6h1.5v-2h1.1l0.9,2L21,15l-0.9,-2.1c0.5,-0.3 0.9,-0.8 0.9,-1.4zM19.5,11.5h-2v-1h2v1zM6.5,11h-2L4.5,9L3,9v6h1.5v-2.5h2L6.5,15L8,15L8,9L6.5,9v2zM13,9L9.5,9v6L13,15c0.8,0 1.5,-0.7 1.5,-1.5v-3c0,-0.8 -0.7,-1.5 -1.5,-1.5zM13,13.5h-2v-3h2v3z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M19.02,10v9L5,19L5,5h9L14,3L5.02,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-9h-2zM17,10l0.94,-2.06L20,7l-2.06,-0.94L17,4l-0.94,2.06L14,7l2.06,0.94zM13.25,10.75L12,8l-1.25,2.75L8,12l2.75,1.25L12,16l1.25,-2.75L16,12z"/>
</vector>

View File

@ -11,24 +11,62 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
app:cameraGesturePinch="zoom" app:cameraGesturePinch="zoom"
app:cameraGestureTap="autoFocus"
app:cameraAutoFocusMarker="@string/cameraview_default_autofocus_marker"
app:cameraHdr="on"
app:cameraPictureFormat="jpeg" app:cameraPictureFormat="jpeg"
app:cameraAudio="off"/> app:cameraAudio="off"/>
<RelativeLayout <androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="40dp" android:layout_height="40dp"
android:layout_alignParentTop="true"
android:layout_marginTop="20dp"> android:layout_marginTop="20dp">
<ImageView
android:id="@+id/image_hdr"
android:layout_width="30dp"
android:layout_height="30dp"
android:onClick="onClickHDR"
android:src="@drawable/icon_hdr_on"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/image_timer"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:id="@+id/image_timer" android:id="@+id/image_timer"
android:layout_width="30dp" android:layout_width="30dp"
android:layout_height="30dp" android:layout_height="30dp"
android:onClick="onClickTimer"
android:src="@drawable/icon_timer" android:src="@drawable/icon_timer"
android:layout_centerInParent="true" app:layout_constraintBottom_toBottomOf="parent"
android:onClick="onClickTimer"/> app:layout_constraintEnd_toStartOf="@id/image_grid"
app:layout_constraintStart_toEndOf="@id/image_hdr"
app:layout_constraintTop_toTopOf="parent" />
</RelativeLayout> <ImageView
android:id="@+id/image_grid"
android:layout_width="30dp"
android:layout_height="30dp"
android:onClick="onClickGrid"
android:src="@drawable/icon_grid_on"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/image_filter"
app:layout_constraintStart_toEndOf="@+id/image_timer"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/image_filter"
android:layout_width="30dp"
android:layout_height="30dp"
android:onClick="onClickFilter"
android:src="@drawable/icon_photo_filter"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/image_grid"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView <TextView
android:id="@+id/text_timer" android:id="@+id/text_timer"

View File

@ -155,4 +155,10 @@
<string name="move_failed">Move of %s failed.</string> <string name="move_failed">Move of %s failed.</string>
<string name="move_success_msg">The selected items have been successfully moved.</string> <string name="move_success_msg">The selected items have been successfully moved.</string>
<string name="move_success">Move successful !</string> <string name="move_success">Move successful !</string>
<string name="enter_timer_duration">Enter the timer duration (in s)</string>
<string name="grid_none">None</string>
<string name="grid_3x3">3x3</string>
<string name="grid_4x4">4x4</string>
<string name="choose_grid">Choose grid</string>
<string name="choose_filter">Choose filter</string>
</resources> </resources>