Merge pull request #342 from KryptKode/feat/camera-x

CameraX: Fix capture/preview resolution
This commit is contained in:
Tibor Kaputa 2022-09-21 12:28:46 +02:00 committed by GitHub
commit 48bbb827bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 1359 additions and 305 deletions

View File

@ -2,6 +2,7 @@ package com.simplemobiletools.camera.activities
import android.app.Activity
import android.content.Intent
import android.content.res.ColorStateList
import android.graphics.Bitmap
import android.hardware.SensorManager
import android.net.Uri
@ -10,38 +11,59 @@ import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import android.view.*
import android.widget.RelativeLayout
import android.view.animation.OvershootInterpolator
import android.widget.LinearLayout
import androidx.appcompat.content.res.AppCompatResources
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import androidx.core.view.*
import androidx.transition.*
import com.bumptech.glide.Glide
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.load.resource.drawable.DrawableTransitionOptions
import com.bumptech.glide.request.RequestOptions
import com.google.android.material.button.MaterialButton
import com.google.android.material.tabs.TabLayout
import com.simplemobiletools.camera.BuildConfig
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.extensions.config
import com.simplemobiletools.camera.extensions.toFlashModeId
import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.implementations.CameraXInitializer
import com.simplemobiletools.camera.implementations.CameraXPreviewListener
import com.simplemobiletools.camera.implementations.MyCameraImpl
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.ResolutionOption
import com.simplemobiletools.camera.views.FocusCircleView
import com.simplemobiletools.commons.extensions.*
import com.simplemobiletools.commons.helpers.*
import com.simplemobiletools.commons.models.Release
import java.util.concurrent.TimeUnit
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.layout_flash.flash_auto
import kotlinx.android.synthetic.main.layout_flash.flash_off
import kotlinx.android.synthetic.main.layout_flash.flash_on
import kotlinx.android.synthetic.main.layout_flash.flash_toggle_group
import kotlinx.android.synthetic.main.layout_media_size.media_size_toggle_group
import kotlinx.android.synthetic.main.layout_top.change_resolution
import kotlinx.android.synthetic.main.layout_top.default_icons
import kotlinx.android.synthetic.main.layout_top.settings
import kotlinx.android.synthetic.main.layout_top.toggle_flash
class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, CameraXPreviewListener {
companion object {
private const val FADE_DELAY = 5000L
private const val CAPTURE_ANIMATION_DURATION = 100L
private companion object {
const val CAPTURE_ANIMATION_DURATION = 500L
const val PHOTO_MODE_INDEX = 1
const val VIDEO_MODE_INDEX = 0
}
lateinit var mTimerHandler: Handler
private lateinit var defaultScene: Scene
private lateinit var mediaSizeScene: Scene
private lateinit var flashModeScene: Scene
private lateinit var mOrientationEventListener: OrientationEventListener
private lateinit var mFocusCircleView: FocusCircleView
private lateinit var mFadeHandler: Handler
private lateinit var mCameraImpl: MyCameraImpl
private var mPreview: MyPreview? = null
private var mPreviewUri: Uri? = null
private var mIsInPhotoMode = true
@ -50,23 +72,65 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
private var mCurrVideoRecTimer = 0
var mLastHandledOrientation = 0
private val tabSelectedListener = object : TabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab) {
handleTogglePhotoVideo()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
useDynamicTheme = false
super.onCreate(savedInstanceState)
appLaunched(BuildConfig.APPLICATION_ID)
requestWindowFeature(Window.FEATURE_NO_TITLE)
WindowCompat.setDecorFitsSystemWindows(window, false)
initVariables()
tryInitCamera()
supportActionBar?.hide()
checkWhatsNewDialog()
setupOrientationEventListener()
val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView)
windowInsetsController?.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController?.hide(WindowInsetsCompat.Type.statusBars())
if (isOreoMr1Plus()) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
window.addFlags(
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON or
WindowManager.LayoutParams.FLAG_FULLSCREEN
)
}
}
private fun selectPhotoTab(triggerListener: Boolean = false) {
if (!triggerListener) {
removeTabListener()
}
camera_mode_tab.getTabAt(PHOTO_MODE_INDEX)?.select()
setTabListener()
}
private fun selectVideoTab(triggerListener: Boolean = false) {
if (!triggerListener) {
removeTabListener()
}
camera_mode_tab.getTabAt(VIDEO_MODE_INDEX)?.select()
setTabListener()
}
private fun setTabListener() {
camera_mode_tab.addOnTabSelectedListener(tabSelectedListener)
}
private fun removeTabListener() {
camera_mode_tab.removeOnTabSelectedListener(tabSelectedListener)
}
override fun onResume() {
@ -74,7 +138,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
if (hasStorageAndCameraPermissions()) {
resumeCameraItems()
setupPreviewImage(mIsInPhotoMode)
scheduleFadeOut()
mFocusCircleView.setStrokeColor(getProperPrimaryColor())
if (isVideoCaptureIntent() && mIsInPhotoMode) {
@ -82,11 +145,14 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
checkButtons()
}
toggleBottomButtons(false)
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
if (hasStorageAndCameraPermissions()) {
mOrientationEventListener.enable()
}
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
ensureTransparentNavigationBar()
}
private fun ensureTransparentNavigationBar() {
window.navigationBarColor = ContextCompat.getColor(this, android.R.color.transparent)
}
override fun onPause() {
@ -96,8 +162,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
return
}
mFadeHandler.removeCallbacksAndMessages(null)
hideTimer()
mOrientationEventListener.disable()
}
@ -107,6 +171,12 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
mPreview = null
}
override fun onBackPressed() {
if (!closeOptions()) {
super.onBackPressed()
}
}
private fun initVariables() {
mIsInPhotoMode = if (isVideoCaptureIntent()) {
false
@ -145,9 +215,9 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun hideIntentButtons() {
toggle_photo_video.beGone()
camera_mode_tab.beGone()
settings.beGone()
last_photo_video_preview.beGone()
last_photo_video_preview.beInvisible()
}
private fun tryInitCamera() {
@ -180,6 +250,8 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
}
private fun is3rdPartyIntent() = isVideoCaptureIntent() || isImageCaptureIntent()
private fun isImageCaptureIntent(): Boolean = intent?.action == MediaStore.ACTION_IMAGE_CAPTURE || intent?.action == MediaStore.ACTION_IMAGE_CAPTURE_SECURE
private fun isVideoCaptureIntent(): Boolean = intent?.action == MediaStore.ACTION_VIDEO_CAPTURE
@ -195,7 +267,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun checkVideoCaptureIntent() {
if (intent?.action == MediaStore.ACTION_VIDEO_CAPTURE) {
if (isVideoCaptureIntent()) {
mIsInPhotoMode = false
hideIntentButtons()
shutter.setImageResource(R.drawable.ic_video_rec)
@ -206,16 +278,37 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
setContentView(R.layout.activity_main)
initButtons()
(btn_holder.layoutParams as RelativeLayout.LayoutParams).setMargins(
0,
0,
0,
(navigationBarHeight + resources.getDimension(R.dimen.activity_margin)).toInt()
)
defaultScene = Scene(top_options, default_icons)
mediaSizeScene = Scene(top_options, media_size_toggle_group)
flashModeScene = Scene(top_options, flash_toggle_group)
ViewCompat.setOnApplyWindowInsetsListener(view_holder) { _, windowInsets ->
val safeInsetBottom = windowInsets.displayCutout?.safeInsetBottom ?: 0
val safeInsetTop = windowInsets.displayCutout?.safeInsetTop ?: 0
top_options.updateLayoutParams<ViewGroup.MarginLayoutParams> {
topMargin = safeInsetTop
}
val marginBottom = safeInsetBottom + navigationBarHeight + resources.getDimensionPixelSize(R.dimen.bigger_margin)
(shutter.layoutParams as ConstraintLayout.LayoutParams).goneBottomMargin = marginBottom
video_rec_curr_timer.updateLayoutParams<ViewGroup.MarginLayoutParams> {
bottomMargin = marginBottom
}
WindowInsetsCompat.CONSUMED
}
checkVideoCaptureIntent()
if (mIsInPhotoMode) {
selectPhotoTab()
} else {
selectVideoTab()
}
val outputUri = intent.extras?.get(MediaStore.EXTRA_OUTPUT) as? Uri
val is3rdPartyIntent = isVideoCaptureIntent() || isImageCaptureIntent()
val is3rdPartyIntent = is3rdPartyIntent()
mPreview = CameraXInitializer(this).createCameraXPreview(
preview_view,
listener = this,
@ -234,12 +327,19 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
view_holder.addView(mFocusCircleView)
mTimerHandler = Handler(Looper.getMainLooper())
mFadeHandler = Handler(Looper.getMainLooper())
setupPreviewImage(true)
val initialFlashlightState = FLASH_OFF
mPreview!!.setFlashlightState(initialFlashlightState)
updateFlashlightState(initialFlashlightState)
initFlashModeTransitionNames()
}
private fun initFlashModeTransitionNames() {
val baseName = getString(R.string.toggle_flash)
flash_auto.transitionName = "$baseName$FLASH_AUTO"
flash_off.transitionName = "$baseName$FLASH_OFF"
flash_on.transitionName = "$baseName$FLASH_ON"
}
private fun initButtons() {
@ -248,8 +348,15 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
toggle_flash.setOnClickListener { toggleFlash() }
shutter.setOnClickListener { shutterPressed() }
settings.setOnClickListener { launchSettings() }
toggle_photo_video.setOnClickListener { handleTogglePhotoVideo() }
change_resolution.setOnClickListener { mPreview?.showChangeResolutionDialog() }
change_resolution.setOnClickListener { mPreview?.showChangeResolution() }
flash_on.setOnClickListener { selectFlashMode(FLASH_ON) }
flash_off.setOnClickListener { selectFlashMode(FLASH_OFF) }
flash_auto.setOnClickListener { selectFlashMode(FLASH_AUTO) }
}
private fun selectFlashMode(flashMode: Int) {
closeOptions()
mPreview?.setFlashlightState(flashMode)
}
private fun toggleCamera() {
@ -267,9 +374,13 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
private fun toggleFlash() {
if (checkCameraAvailable()) {
if (mIsInPhotoMode) {
showFlashOptions(mIsInPhotoMode)
} else {
mPreview?.toggleFlashlight()
}
}
}
fun updateFlashlightState(state: Int) {
config.flashlightState = state
@ -279,6 +390,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
else -> R.drawable.ic_flash_auto_vector
}
toggle_flash.setImageResource(flashDrawable)
toggle_flash.transitionName = "${getString(R.string.toggle_flash)}$state"
}
private fun shutterPressed() {
@ -290,22 +402,18 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
private fun handleShutter() {
if (mIsInPhotoMode) {
toggleBottomButtons(true)
change_resolution.isEnabled = true
mPreview?.tryTakePicture()
capture_black_screen.animate().alpha(0.8f).setDuration(CAPTURE_ANIMATION_DURATION).withEndAction {
capture_black_screen.animate().alpha(0f).setDuration(CAPTURE_ANIMATION_DURATION).start()
}.start()
shutter_animation.alpha = 1.0f
shutter_animation.animate().alpha(0f).setDuration(CAPTURE_ANIMATION_DURATION).start()
} else {
mPreview?.toggleRecording()
}
}
private fun launchSettings() {
if (settings.alpha == 1f) {
val intent = Intent(applicationContext, SettingsActivity::class.java)
startActivity(intent)
} else {
fadeInButtons()
}
}
private fun handleTogglePhotoVideo() {
@ -314,6 +422,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
togglePhotoVideo()
} else {
toast(R.string.no_audio_permissions)
selectPhotoTab()
if (isVideoCaptureIntent()) {
finish()
}
@ -351,10 +460,10 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun initPhotoMode() {
toggle_photo_video.setImageResource(R.drawable.ic_video_vector)
shutter.setImageResource(R.drawable.ic_shutter_vector)
shutter.setImageResource(R.drawable.ic_shutter_animated)
mPreview?.initPhotoMode()
setupPreviewImage(true)
selectPhotoTab()
}
private fun tryInitVideoMode() {
@ -369,10 +478,10 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun initVideoButtons() {
toggle_photo_video.setImageResource(R.drawable.ic_camera_vector)
shutter.setImageResource(R.drawable.ic_video_rec)
shutter.setImageResource(R.drawable.ic_video_rec_animated)
setupPreviewImage(false)
mPreview?.checkFlashlight()
selectVideoTab()
}
private fun setupPreviewImage(isPhoto: Boolean) {
@ -405,43 +514,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
}
private fun scheduleFadeOut() {
if (!config.keepSettingsVisible) {
mFadeHandler.postDelayed({
fadeOutButtons()
}, FADE_DELAY)
}
}
private fun fadeOutButtons() {
fadeAnim(settings, .5f)
fadeAnim(toggle_photo_video, .0f)
fadeAnim(change_resolution, .0f)
fadeAnim(last_photo_video_preview, .0f)
}
private fun fadeInButtons() {
fadeAnim(settings, 1f)
fadeAnim(toggle_photo_video, 1f)
fadeAnim(change_resolution, 1f)
fadeAnim(last_photo_video_preview, 1f)
scheduleFadeOut()
}
private fun fadeAnim(view: View, value: Float) {
view.animate().alpha(value).start()
view.isClickable = value != .0f
}
@Suppress("DEPRECATION")
private fun hideNavigationBarIcons() {
if (isRPlus()) {
window.insetsController?.hide(WindowInsets.Type.systemBars())
} else {
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LOW_PROFILE
}
}
private fun showTimer() {
video_rec_curr_timer.beVisible()
setupTimer()
@ -464,8 +536,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun resumeCameraItems() {
hideNavigationBarIcons()
if (!mIsInPhotoMode) {
initVideoButtons()
}
@ -508,7 +578,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
private fun animateViews(degrees: Int) {
val views = arrayOf<View>(toggle_camera, toggle_flash, toggle_photo_video, change_resolution, shutter, settings, last_photo_video_preview)
val views = arrayOf<View>(toggle_camera, toggle_flash, change_resolution, shutter, settings, last_photo_video_preview)
for (view in views) {
rotate(view, degrees)
}
@ -547,11 +617,6 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
override fun toggleBottomButtons(hide: Boolean) {
runOnUiThread {
val alpha = if (hide) 0f else 1f
shutter.animate().alpha(alpha).start()
toggle_camera.animate().alpha(alpha).start()
toggle_flash.animate().alpha(alpha).start()
shutter.isClickable = !hide
toggle_camera.isClickable = !hide
toggle_flash.isClickable = !hide
@ -559,6 +624,7 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
override fun onMediaSaved(uri: Uri) {
change_resolution.isEnabled = true
loadLastTakenMedia(uri)
if (isImageCaptureIntent()) {
Intent().apply {
@ -592,15 +658,19 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
}
override fun onVideoRecordingStarted() {
shutter.setImageResource(R.drawable.ic_video_stop)
camera_mode_tab.beInvisible()
shutter.isSelected = true
toggle_camera.beInvisible()
change_resolution.isEnabled = false
video_rec_curr_timer.beVisible()
}
override fun onVideoRecordingStopped() {
shutter.setImageResource(R.drawable.ic_video_rec)
camera_mode_tab.beVisible()
shutter.isSelected = false
video_rec_curr_timer.text = 0.getFormattedDuration()
video_rec_curr_timer.beGone()
change_resolution.isEnabled = true
toggle_camera.beVisible()
}
@ -613,14 +683,127 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
mFocusCircleView.drawFocusCircle(xPos, yPos)
}
override fun onSwipeLeft() {
if (!is3rdPartyIntent() && camera_mode_tab.isVisible()) {
selectPhotoTab(triggerListener = true)
}
}
override fun onSwipeRight() {
if (!is3rdPartyIntent() && camera_mode_tab.isVisible()) {
selectVideoTab(triggerListener = true)
}
}
override fun onTouchPreview() {
closeOptions()
}
private fun closeOptions(): Boolean {
if (media_size_toggle_group.isVisible() ||
flash_toggle_group.isVisible()
) {
val transitionSet = createTransition(isClosing = true)
TransitionManager.go(defaultScene, transitionSet)
return true
}
return false
}
override fun displaySelectedResolution(resolutionOption: ResolutionOption) {
val imageRes = resolutionOption.imageDrawableResId
change_resolution.setImageResource(imageRes)
change_resolution.transitionName = "${resolutionOption.buttonViewId}"
}
override fun showImageSizes(
selectedResolution: ResolutionOption,
resolutions: List<ResolutionOption>,
isPhotoCapture: Boolean,
isFrontCamera: Boolean,
onSelect: (index: Int, changed: Boolean) -> Unit
) {
media_size_toggle_group.removeAllViews()
media_size_toggle_group.clearChecked()
val onItemClick = { clickedViewId: Int ->
closeOptions()
val index = resolutions.indexOfFirst { it.buttonViewId == clickedViewId }
onSelect.invoke(index, selectedResolution.buttonViewId != clickedViewId)
}
resolutions.map {
createButton(it, onItemClick)
}.forEach { button ->
media_size_toggle_group.addView(button)
}
media_size_toggle_group.check(selectedResolution.buttonViewId)
showResolutionOptions()
}
private fun createButton(resolutionOption: ResolutionOption, onClick: (clickedViewId: Int) -> Unit): MaterialButton {
val params = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT).apply {
weight = 1f
}
return (layoutInflater.inflate(R.layout.layout_button, null) as MaterialButton).apply {
layoutParams = params
icon = AppCompatResources.getDrawable(context, resolutionOption.imageDrawableResId)
id = resolutionOption.buttonViewId
transitionName = "${resolutionOption.buttonViewId}"
setOnClickListener {
onClick.invoke(id)
}
}
}
private fun showResolutionOptions() {
val transitionSet = createTransition()
TransitionManager.go(mediaSizeScene, transitionSet)
media_size_toggle_group.children.map { it as MaterialButton }.forEach(::setButtonColors)
}
private fun createTransition(isClosing: Boolean = false): Transition {
val fadeTransition = Fade()
val changeBounds = ChangeBounds().apply {
interpolator = OvershootInterpolator()
}
return TransitionSet().apply {
if (!isClosing) {
addTransition(changeBounds)
}
addTransition(fadeTransition)
this.duration = resources.getInteger(R.integer.icon_anim_duration).toLong()
}
}
override fun showFlashOptions(photoCapture: Boolean) {
val transitionSet = createTransition()
TransitionManager.go(flashModeScene, transitionSet)
flash_auto.beVisibleIf(photoCapture)
flash_toggle_group.check(config.flashlightState.toFlashModeId())
flash_toggle_group.beVisible()
flash_toggle_group.children.map { it as MaterialButton }.forEach(::setButtonColors)
}
private fun setButtonColors(button: MaterialButton) {
val primaryColor = getProperPrimaryColor()
val states = arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked))
val iconColors = intArrayOf(ContextCompat.getColor(this, R.color.md_grey_white), primaryColor)
button.iconTint = ColorStateList(states, iconColors)
}
fun setRecordingState(isRecording: Boolean) {
runOnUiThread {
if (isRecording) {
shutter.setImageResource(R.drawable.ic_video_stop)
shutter.isSelected = true
toggle_camera.beInvisible()
showTimer()
} else {
shutter.setImageResource(R.drawable.ic_video_rec)
shutter.isSelected = false
hideTimer()
}
}

View File

@ -34,7 +34,6 @@ class SettingsActivity : SimpleActivity() {
setupSound()
setupVolumeButtonsAsShutter()
setupFlipPhotos()
setupKeepSettingsVisible()
setupSavePhotoMetadata()
setupSavePhotosFolder()
setupPhotoQuality()
@ -94,9 +93,8 @@ class SettingsActivity : SimpleActivity() {
settings_use_english_holder.beVisibleIf(config.wasUseEnglishToggled || Locale.getDefault().language != "en")
settings_use_english.isChecked = config.useEnglish
if (settings_use_english_holder.isGone() && settings_purchase_thank_you_holder.isGone()) {
settings_keep_settings_visible_holder.background = ResourcesCompat.getDrawable(resources, R.drawable.ripple_all_corners, theme)
}
settings_general_settings_holder.beGoneIf(settings_use_english_holder.isGone() && settings_purchase_thank_you_holder.isGone())
settings_general_settings_label.beGoneIf(settings_use_english_holder.isGone() && settings_purchase_thank_you_holder.isGone())
settings_use_english_holder.setOnClickListener {
settings_use_english.toggle()
@ -149,14 +147,6 @@ class SettingsActivity : SimpleActivity() {
}
}
private fun setupKeepSettingsVisible() {
settings_keep_settings_visible.isChecked = config.keepSettingsVisible
settings_keep_settings_visible_holder.setOnClickListener {
settings_keep_settings_visible.toggle()
config.keepSettingsVisible = settings_keep_settings_visible.isChecked
}
}
private fun setupSavePhotoMetadata() {
settings_save_photo_metadata.isChecked = config.savePhotoMetadata
settings_save_photo_metadata_holder.setOnClickListener {

View File

@ -47,8 +47,13 @@ class ChangeResolutionDialogX(
val items = photoResolutions.mapIndexed { index, resolution ->
val megapixels = resolution.megaPixels
val aspectRatio = resolution.getAspectRatio(activity)
if (resolution.isFullScreen) {
//TODO: Extract to string resource
RadioItem(index, "Full")
} else {
RadioItem(index, "${resolution.width} x ${resolution.height} ($megapixels MP, $aspectRatio)")
}
}
var selectionIndex = if (isFrontCamera) config.frontPhotoResIndex else config.backPhotoResIndex
selectionIndex = selectionIndex.coerceAtLeast(0)

View File

@ -2,10 +2,10 @@ package com.simplemobiletools.camera.extensions
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.helpers.FLASH_AUTO
import com.simplemobiletools.camera.helpers.FLASH_OFF
import com.simplemobiletools.camera.helpers.FLASH_ON
import java.lang.IllegalArgumentException
fun Int.toCameraXFlashMode(): Int {
return when (this) {
@ -25,6 +25,24 @@ fun Int.toAppFlashMode(): Int {
}
}
fun Int.toFlashModeId(): Int {
return when (this) {
FLASH_ON -> R.id.flash_on
FLASH_OFF -> R.id.flash_off
FLASH_AUTO -> R.id.flash_auto
else -> throw IllegalArgumentException("Unknown mode: $this")
}
}
fun Int.idToAppFlashMode(): Int {
return when (this) {
R.id.flash_on -> FLASH_ON
R.id.flash_off -> FLASH_OFF
R.id.flash_auto -> FLASH_AUTO
else -> throw IllegalArgumentException("Unknown mode: $this")
}
}
fun Int.toCameraSelector(): CameraSelector {
return if (this == CameraSelector.LENS_FACING_FRONT) {
CameraSelector.DEFAULT_FRONT_CAMERA

View File

@ -66,10 +66,6 @@ class Config(context: Context) : BaseConfig(context) {
get() = prefs.getInt(FRONT_VIDEO_RESOLUTION_INDEX, 0)
set(frontVideoResIndex) = prefs.edit().putInt(FRONT_VIDEO_RESOLUTION_INDEX, frontVideoResIndex).apply()
var keepSettingsVisible: Boolean
get() = prefs.getBoolean(KEEP_SETTINGS_VISIBLE, false)
set(keepSettingsVisible) = prefs.edit().putBoolean(KEEP_SETTINGS_VISIBLE, keepSettingsVisible).apply()
var savePhotoMetadata: Boolean
get() = prefs.getBoolean(SAVE_PHOTO_METADATA, true)
set(savePhotoMetadata) = prefs.edit().putBoolean(SAVE_PHOTO_METADATA, savePhotoMetadata).apply()

View File

@ -20,22 +20,21 @@ class ImageQualityManager(
}
private val cameraManager = activity.getSystemService(Context.CAMERA_SERVICE) as CameraManager
private val config = activity.config
private val imageQualities = mutableListOf<CameraSelectorImageQualities>()
private val mediaSizeStore = MediaSizeStore(activity.config)
fun initSupportedQualities() {
if (imageQualities.isEmpty()) {
for (cameraId in cameraManager.cameraIdList) {
try {
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
for (lens in CAMERA_LENS) {
if (characteristics.get(CameraCharacteristics.LENS_FACING) == lens) {
val lensFacing = characteristics.get(CameraCharacteristics.LENS_FACING) ?: continue
if (lensFacing in CAMERA_LENS) {
val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP) ?: continue
val imageSizes = configMap.getOutputSizes(ImageFormat.JPEG).map { MySize(it.width, it.height) }
val cameraSelector = lens.toCameraSelector()
val cameraSelector = lensFacing.toCameraSelector()
imageQualities.add(CameraSelectorImageQualities(cameraSelector, imageSizes))
}
}
} catch (e: Exception) {
activity.showErrorToast(e)
}
@ -52,19 +51,27 @@ class ImageQualityManager(
}
fun getUserSelectedResolution(cameraSelector: CameraSelector): MySize {
val index = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontPhotoResIndex else config.backPhotoResIndex
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedWith(compareByDescending<MySize> { it.ratio }.thenByDescending { it.pixels })
.distinctBy { it.pixels }
.filter { it.megaPixels != "0.0" }[index]
val resolutions = getSupportedResolutions(cameraSelector)
val isFrontCamera = cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA
var index = mediaSizeStore.getCurrentSizeIndex(isPhotoCapture = true, isFrontCamera = isFrontCamera)
index = index.coerceAtMost(resolutions.lastIndex).coerceAtLeast(0)
return resolutions[index]
}
fun getSupportedResolutions(cameraSelector: CameraSelector): List<MySize> {
val fullScreenSize = getFullScreenResolution(cameraSelector)
return listOf(fullScreenSize) + imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedByDescending { it.pixels }
.distinctBy { it.getAspectRatio(activity) }
.filter { it.isSupported(fullScreenSize.isSixteenToNine()) }
}
private fun getFullScreenResolution(cameraSelector: CameraSelector): MySize {
return imageQualities.filter { it.camSelector == cameraSelector }
.flatMap { it.qualities }
.sortedWith(compareByDescending<MySize> { it.ratio }.thenByDescending { it.pixels })
.distinctBy { it.pixels }
.filter { it.megaPixels != "0.0" }
.sortedByDescending { it.width }
.first { it.isSupported(false) }
.copy(isFullScreen = true)
}
}

View File

@ -0,0 +1,38 @@
package com.simplemobiletools.camera.helpers
class MediaSizeStore(
private val config: Config,
) {
fun storeSize(isPhotoCapture: Boolean, isFrontCamera: Boolean, currentIndex: Int) {
if (isPhotoCapture) {
if (isFrontCamera) {
config.frontPhotoResIndex = currentIndex
} else {
config.backPhotoResIndex = currentIndex
}
} else {
if (isFrontCamera) {
config.frontVideoResIndex = currentIndex
} else {
config.backVideoResIndex = currentIndex
}
}
}
fun getCurrentSizeIndex(isPhotoCapture: Boolean, isFrontCamera: Boolean): Int {
return if (isPhotoCapture) {
if (isFrontCamera) {
config.frontPhotoResIndex
} else {
config.backPhotoResIndex
}
} else {
if (isFrontCamera) {
config.frontVideoResIndex
} else {
config.backVideoResIndex
}
}
}
}

View File

@ -0,0 +1,9 @@
package com.simplemobiletools.camera.helpers
import com.google.android.material.tabs.TabLayout
interface TabSelectedListener : TabLayout.OnTabSelectedListener {
override fun onTabReselected(tab: TabLayout.Tab?){}
override fun onTabUnselected(tab: TabLayout.Tab?) {}
}

View File

@ -20,8 +20,8 @@ class VideoQualityManager(
private val CAMERA_SELECTORS = arrayOf(CameraSelector.DEFAULT_BACK_CAMERA, CameraSelector.DEFAULT_FRONT_CAMERA)
}
private val config = activity.config
private val videoQualities = mutableListOf<CameraSelectorVideoQualities>()
private val mediaSizeStore = MediaSizeStore(activity.config)
fun initSupportedQualities(cameraProvider: ProcessCameraProvider) {
if (videoQualities.isEmpty()) {
@ -45,8 +45,8 @@ class VideoQualityManager(
}
fun getUserSelectedQuality(cameraSelector: CameraSelector): VideoQuality {
var selectionIndex = if (cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA) config.frontVideoResIndex else config.backVideoResIndex
selectionIndex = selectionIndex.coerceAtLeast(0)
val isFrontCamera = cameraSelector == CameraSelector.DEFAULT_FRONT_CAMERA
val selectionIndex = mediaSizeStore.getCurrentSizeIndex(isPhotoCapture = false, isFrontCamera = isFrontCamera).coerceAtLeast(0)
return getSupportedQualities(cameraSelector).getOrElse(selectionIndex) { VideoQuality.HD }
}

View File

@ -4,6 +4,7 @@ import android.annotation.SuppressLint
import android.content.Context
import android.hardware.SensorManager
import android.hardware.display.DisplayManager
import android.util.Rational
import android.util.Size
import android.view.*
import android.view.GestureDetector.SimpleOnGestureListener
@ -14,10 +15,12 @@ import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.video.*
import androidx.camera.video.VideoCapture
import androidx.camera.view.PreviewView
import androidx.camera.view.PreviewView.ScaleType
import androidx.core.content.ContextCompat
import androidx.core.view.doOnLayout
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.window.layout.WindowMetricsCalculator
import com.bumptech.glide.load.ImageHeaderParser.UNKNOWN_ORIENTATION
import com.simplemobiletools.camera.R
import com.simplemobiletools.camera.dialogs.ChangeResolutionDialogX
@ -26,8 +29,10 @@ import com.simplemobiletools.camera.helpers.*
import com.simplemobiletools.camera.interfaces.MyPreview
import com.simplemobiletools.camera.models.MediaOutput
import com.simplemobiletools.camera.models.MySize
import com.simplemobiletools.camera.models.ResolutionOption
import com.simplemobiletools.commons.extensions.toast
import com.simplemobiletools.commons.helpers.ensureBackgroundThread
import kotlin.math.abs
class CameraXPreview(
private val activity: AppCompatActivity,
@ -42,6 +47,7 @@ class CameraXPreview(
// Auto focus is 1/6 of the area.
private const val AF_SIZE = 1.0f / 6.0f
private const val AE_SIZE = AF_SIZE * 1.5f
private const val MIN_SWIPE_DISTANCE_X = 100
}
private val config = activity.config
@ -49,9 +55,11 @@ class CameraXPreview(
private val mainExecutor = ContextCompat.getMainExecutor(activity)
private val displayManager = activity.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
private val mediaSoundHelper = MediaSoundHelper()
private val windowMetricsCalculator = WindowMetricsCalculator.getOrCreate()
private val videoQualityManager = VideoQualityManager(activity)
private val imageQualityManager = ImageQualityManager(activity)
private val exifRemover = ExifRemover(contentResolver)
private val mediaSizeStore = MediaSizeStore(config)
private val orientationEventListener = object : OrientationEventListener(activity, SensorManager.SENSOR_DELAY_NORMAL) {
@SuppressLint("RestrictedApi")
@ -120,30 +128,110 @@ class CameraXPreview(
private fun bindCameraUseCases() {
val cameraProvider = cameraProvider ?: throw IllegalStateException("Camera initialization failed.")
val rotation = previewView.display.rotation
val resolution = if (isPhotoCapture) {
imageQualityManager.getUserSelectedResolution(cameraSelector)
imageQualityManager.getUserSelectedResolution(cameraSelector).also {
displaySelectedResolution(it.toResolutionOption())
}
} else {
val selectedQuality = videoQualityManager.getUserSelectedQuality(cameraSelector)
val selectedQuality = videoQualityManager.getUserSelectedQuality(cameraSelector).also {
displaySelectedResolution(it.toResolutionOption())
}
MySize(selectedQuality.width, selectedQuality.height)
}
val isFullSize = resolution.isFullScreen
previewView.scaleType = if (isFullSize) ScaleType.FILL_CENTER else ScaleType.FIT_CENTER
val rotation = previewView.display.rotation
val rotatedResolution = getRotatedResolution(resolution, rotation)
preview = buildPreview(rotatedResolution, rotation)
val previewUseCase = buildPreview(rotatedResolution, rotation)
val captureUseCase = getCaptureUseCase(rotatedResolution, rotation)
cameraProvider.unbindAll()
camera = cameraProvider.bindToLifecycle(
camera = if (isFullSize) {
val metrics = windowMetricsCalculator.computeCurrentWindowMetrics(activity).bounds
val screenWidth = metrics.width()
val screenHeight = metrics.height()
val viewPort = ViewPort.Builder(Rational(screenWidth, screenHeight), rotation).build()
val useCaseGroup = UseCaseGroup.Builder()
.addUseCase(previewUseCase)
.addUseCase(captureUseCase)
.setViewPort(viewPort)
.build()
cameraProvider.bindToLifecycle(
activity,
cameraSelector,
preview,
useCaseGroup,
)
} else {
cameraProvider.bindToLifecycle(
activity,
cameraSelector,
previewUseCase,
captureUseCase,
)
}
preview?.setSurfaceProvider(previewView.surfaceProvider)
previewUseCase.setSurfaceProvider(previewView.surfaceProvider)
preview = previewUseCase
setupZoomAndFocus()
}
private fun displaySelectedResolution(resolutionOption: ResolutionOption) {
listener.displaySelectedResolution(resolutionOption)
}
private fun getRotatedResolution(resolution: MySize, rotationDegrees: Int): Size {
return if (rotationDegrees == Surface.ROTATION_0 || rotationDegrees == Surface.ROTATION_180) {
Size(resolution.height, resolution.width)
} else {
Size(resolution.width, resolution.height)
}
}
private fun buildPreview(resolution: Size, rotation: Int): Preview {
return Preview.Builder()
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun getCaptureUseCase(resolution: Size, rotation: Int): UseCase {
return if (isPhotoCapture) {
buildImageCapture(resolution, rotation).also {
imageCapture = it
}
} else {
buildVideoCapture().also {
videoCapture = it
}
}
}
private fun buildImageCapture(resolution: Size, rotation: Int): ImageCapture {
return Builder()
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
.setFlashMode(flashMode)
.setJpegQuality(config.photoQuality)
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun buildVideoCapture(): VideoCapture<Recorder> {
val qualitySelector = QualitySelector.from(
videoQualityManager.getUserSelectedQuality(cameraSelector).toCameraXQuality(),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD),
)
val recorder = Recorder.Builder()
.setQualitySelector(qualitySelector)
.build()
return VideoCapture.withOutput(recorder)
}
private fun setupCameraObservers() {
listener.setFlashAvailable(camera?.cameraInfo?.hasFlashUnit() ?: false)
listener.onChangeCamera(isFrontCameraInUse())
@ -166,56 +254,6 @@ class CameraXPreview(
}
}
private fun getCaptureUseCase(resolution: Size, rotation: Int): UseCase {
return if (isPhotoCapture) {
cameraProvider?.unbind(videoCapture)
buildImageCapture(resolution, rotation).also {
imageCapture = it
}
} else {
cameraProvider?.unbind(imageCapture)
buildVideoCapture().also {
videoCapture = it
}
}
}
private fun buildImageCapture(resolution: Size, rotation: Int): ImageCapture {
return Builder()
.setCaptureMode(CAPTURE_MODE_MAXIMIZE_QUALITY)
.setFlashMode(flashMode)
.setJpegQuality(config.photoQuality)
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun getRotatedResolution(resolution: MySize, rotationDegrees: Int): Size {
return if (rotationDegrees == Surface.ROTATION_0 || rotationDegrees == Surface.ROTATION_180) {
Size(resolution.height, resolution.width)
} else {
Size(resolution.width, resolution.height)
}
}
private fun buildPreview(resolution: Size, rotation: Int): Preview {
return Preview.Builder()
.setTargetRotation(rotation)
.setTargetResolution(resolution)
.build()
}
private fun buildVideoCapture(): VideoCapture<Recorder> {
val qualitySelector = QualitySelector.from(
videoQualityManager.getUserSelectedQuality(cameraSelector).toCameraXQuality(),
FallbackStrategy.higherQualityOrLowerThan(Quality.SD),
)
val recorder = Recorder.Builder()
.setQualitySelector(qualitySelector)
.build()
return VideoCapture.withOutput(recorder)
}
private fun hasBackCamera(): Boolean {
return cameraProvider?.hasCamera(CameraSelector.DEFAULT_BACK_CAMERA) ?: false
}
@ -233,6 +271,11 @@ class CameraXPreview(
private fun setupZoomAndFocus() {
val scaleGesture = camera?.let { ScaleGestureDetector(activity, PinchToZoomOnScaleGestureListener(it.cameraInfo, it.cameraControl)) }
val gestureDetector = GestureDetector(activity, object : SimpleOnGestureListener() {
override fun onDown(e: MotionEvent?): Boolean {
listener.onTouchPreview()
return super.onDown(e)
}
override fun onSingleTapConfirmed(event: MotionEvent): Boolean {
return camera?.cameraInfo?.let {
val display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)
@ -252,11 +295,26 @@ class CameraXPreview(
true
} ?: false
}
override fun onFling(event1: MotionEvent, event2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
val deltaX = event1.x - event2.x
val deltaXAbs = abs(deltaX)
if (deltaXAbs >= MIN_SWIPE_DISTANCE_X) {
if (deltaX > 0) {
listener.onSwipeLeft()
} else {
listener.onSwipeRight()
}
}
return true
}
})
previewView.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(event)
scaleGesture?.onTouchEvent(event)
true
val handledGesture = gestureDetector.onTouchEvent(event)
val handledScaleGesture = scaleGesture?.onTouchEvent(event)
handledGesture || handledScaleGesture ?: false
}
}
@ -283,6 +341,52 @@ class CameraXPreview(
}
}
override fun showChangeResolution() {
val selectedResolution = if (isPhotoCapture) {
imageQualityManager.getUserSelectedResolution(cameraSelector).toResolutionOption()
} else {
videoQualityManager.getUserSelectedQuality(cameraSelector).toResolutionOption()
}
val resolutions = if (isPhotoCapture) {
imageQualityManager.getSupportedResolutions(cameraSelector).map { it.toResolutionOption() }
} else {
videoQualityManager.getSupportedQualities(cameraSelector).map { it.toResolutionOption() }
}
if (resolutions.size > 2) {
listener.showImageSizes(
selectedResolution = selectedResolution,
resolutions = resolutions,
isPhotoCapture = isPhotoCapture,
isFrontCamera = isFrontCameraInUse()
) { index, changed ->
mediaSizeStore.storeSize(isPhotoCapture, isFrontCameraInUse(), index)
if (changed) {
currentRecording?.stop()
startCamera()
}
}
} else {
toggleResolutions(resolutions)
}
}
private fun toggleResolutions(resolutions: List<ResolutionOption>) {
val currentIndex = mediaSizeStore.getCurrentSizeIndex(isPhotoCapture, isFrontCameraInUse())
val nextIndex = if (currentIndex >= resolutions.lastIndex) {
0
} else {
currentIndex + 1
}
mediaSizeStore.storeSize(isPhotoCapture, isFrontCameraInUse(), nextIndex)
currentRecording?.stop()
startCamera()
}
override fun toggleFrontBackCamera() {
val newCameraSelector = if (isFrontCameraInUse()) {
CameraSelector.DEFAULT_BACK_CAMERA
@ -307,10 +411,16 @@ class CameraXPreview(
FLASH_MODE_OFF -> FLASH_MODE_ON
FLASH_MODE_ON -> FLASH_MODE_OFF
else -> throw IllegalArgumentException("Unknown mode: $flashMode")
}.also {
camera?.cameraControl?.enableTorch(it == FLASH_MODE_ON)
}
}
setFlashlightState(newFlashMode.toAppFlashMode())
}
override fun setFlashlightState(state: Int) {
val newFlashMode = state.toCameraXFlashMode()
if (!isPhotoCapture) {
camera?.cameraControl?.enableTorch(newFlashMode == FLASH_MODE_ON)
}
flashMode = newFlashMode
imageCapture?.flashMode = newFlashMode
val appFlashMode = flashMode.toAppFlashMode()

View File

@ -2,13 +2,14 @@ package com.simplemobiletools.camera.implementations
import android.graphics.Bitmap
import android.net.Uri
import com.simplemobiletools.camera.models.ResolutionOption
interface CameraXPreviewListener {
fun setCameraAvailable(available: Boolean)
fun setHasFrontAndBackCamera(hasFrontAndBack:Boolean)
fun setHasFrontAndBackCamera(hasFrontAndBack: Boolean)
fun setFlashAvailable(available: Boolean)
fun onChangeCamera(frontCamera: Boolean)
fun toggleBottomButtons(hide:Boolean)
fun toggleBottomButtons(hide: Boolean)
fun onMediaSaved(uri: Uri)
fun onImageCaptured(bitmap: Bitmap)
fun onChangeFlashMode(flashMode: Int)
@ -16,4 +17,17 @@ interface CameraXPreviewListener {
fun onVideoRecordingStopped()
fun onVideoDurationChanged(durationNanos: Long)
fun onFocusCamera(xPos: Float, yPos: Float)
fun onSwipeLeft()
fun onSwipeRight()
fun onTouchPreview()
fun displaySelectedResolution(resolutionOption: ResolutionOption)
fun showImageSizes(
selectedResolution: ResolutionOption,
resolutions: List<ResolutionOption>,
isPhotoCapture: Boolean,
isFrontCamera: Boolean,
onSelect: (index: Int, changed: Boolean) -> Unit,
)
fun showFlashOptions(photoCapture: Boolean)
}

View File

@ -20,7 +20,7 @@ interface MyPreview {
fun toggleFrontBackCamera()
fun toggleFlashlight()
fun toggleFlashlight() = Unit
fun tryTakePicture()
@ -31,4 +31,6 @@ interface MyPreview {
fun initVideoMode()
fun checkFlashlight() = Unit
fun showChangeResolution() = Unit
}

View File

@ -2,14 +2,17 @@ package com.simplemobiletools.camera.models
import android.content.Context
import android.util.Size
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import com.simplemobiletools.camera.R
data class MySize(val width: Int, val height: Int) {
data class MySize(val width: Int, val height: Int, val isFullScreen: Boolean = false) {
companion object {
private const val ONE_MEGA_PIXEL = 1000000
private const val ZERO_MEGA_PIXEL = "0.0"
}
val ratio = width / height.toFloat()
private val ratio = width / height.toFloat()
val pixels: Int = width * height
@ -37,6 +40,14 @@ data class MySize(val width: Int, val height: Int) {
private fun isSquare() = width == height
fun isSupported(isFullScreenSize16x9: Boolean): Boolean {
return if (isFullScreenSize16x9) {
isFourToThree() || isSquare()
} else {
isFourToThree() || isSixteenToNine() || isSquare()
} && megaPixels != ZERO_MEGA_PIXEL
}
fun getAspectRatio(context: Context) = when {
isSixteenToNine() -> "16:9"
isFiveToThree() -> "5:3"
@ -52,5 +63,27 @@ data class MySize(val width: Int, val height: Int) {
else -> context.resources.getString(R.string.other)
}
@DrawableRes
fun getImageResId(): Int = when {
isFullScreen -> R.drawable.ic_photo_full
isSixteenToNine() -> R.drawable.ic_photo_16x9
isFourToThree() -> R.drawable.ic_photo_4x3
isSquare() -> R.drawable.ic_photo_1x1
else -> throw UnsupportedOperationException("This size $this is not supported")
}
@IdRes
fun getButtonId(): Int = when {
isFullScreen -> R.id.photo_full
isSixteenToNine() -> R.id.photo_16x9
isFourToThree() -> R.id.photo_4x3
isSquare() -> R.id.photo_1x1
else -> throw UnsupportedOperationException("This size $this is not supported")
}
fun toResolutionOption(): ResolutionOption {
return ResolutionOption(buttonViewId = getButtonId(), imageDrawableResId = getImageResId())
}
fun toSize() = Size(width, height)
}

View File

@ -0,0 +1,9 @@
package com.simplemobiletools.camera.models
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
data class ResolutionOption(
@IdRes val buttonViewId: Int,
@DrawableRes val imageDrawableResId: Int,
)

View File

@ -1,6 +1,8 @@
package com.simplemobiletools.camera.models
import android.content.Context
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import com.simplemobiletools.camera.R
enum class VideoQuality(val width: Int, val height: Int) {
@ -52,6 +54,26 @@ enum class VideoQuality(val width: Int, val height: Int) {
else -> context.resources.getString(R.string.other)
}
@DrawableRes
fun getImageResId(): Int = when (this) {
UHD -> R.drawable.ic_video_uhd
FHD -> R.drawable.ic_video_fhd
HD -> R.drawable.ic_video_hd
SD -> R.drawable.ic_video_sd
}
@IdRes
fun getButtonId(): Int = when (this) {
UHD -> R.id.video_uhd
FHD -> R.id.video_fhd
HD -> R.id.video_hd
SD -> R.id.video_sd
}
fun toResolutionOption(): ResolutionOption {
return ResolutionOption(buttonViewId = getButtonId(), imageDrawableResId = getImageResId())
}
companion object {
private const val ONE_MEGA_PIXEL = 1000000
}

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/color_accent" android:state_selected="true" />
<item android:color="@color/color_accent" android:state_checked="true" />
<item android:color="@color/radiobutton_disabled" android:state_enabled="false" />
<item android:color="@color/md_grey_white" />
</selector>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/md_grey_white" android:state_selected="true" />
<item android:color="@android:color/transparent" />
</selector>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:fillColor="@color/camera_option_color"
android:pathData="M3,2v12h3v9l7,-12L9,11l4,-9L3,2zM19,2h-2l-3.2,9h1.9l0.7,-2h3.2l0.7,2h1.9L19,2zM16.85,7.65L18,4l1.15,3.65h-2.3z"/>
</vector>

View File

@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:fillColor="@color/camera_option_color"
android:pathData="M3.27,3L2,4.27l5,5V13h3v9l3.58,-6.14L17.73,20 19,18.73 3.27,3zM17,10h-4l4,-8H7v2.18l8.46,8.46L17,10z"/>
</vector>

View File

@ -4,6 +4,6 @@
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:fillColor="@color/camera_option_color"
android:pathData="M7,2v11h3v9l7,-12h-4l4,-8z"/>
</vector>

View File

@ -0,0 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26dp"
android:height="24dp"
android:viewportWidth="26"
android:viewportHeight="24">
<group>
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M6.934,18.011V21.072C6.934,21.099 6.946,21.125 6.966,21.144C6.986,21.164 7.013,21.174 7.042,21.174H19.958C19.987,21.174 20.014,21.164 20.034,21.144C20.054,21.125 20.066,21.099 20.066,21.072V18.011H22V21.072C22,21.587 21.785,22.08 21.402,22.443C21.019,22.807 20.5,23.011 19.958,23.011H7.042C6.5,23.011 5.981,22.807 5.598,22.443C5.215,22.08 5,21.587 5,21.072V18.011H6.934Z" />
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M20.063,6.02L20.067,2.958C20.067,2.931 20.055,2.905 20.035,2.886C20.015,2.867 19.988,2.856 19.959,2.856L7.043,2.839C7.014,2.839 6.987,2.85 6.967,2.869C6.946,2.888 6.935,2.914 6.935,2.941L6.931,6.003L4.997,6L5.001,2.939C5.001,2.425 5.217,1.932 5.601,1.569C5.984,1.206 6.503,1.002 7.045,1.003L19.962,1.019C20.503,1.02 21.022,1.225 21.404,1.589C21.787,1.953 22.001,2.447 22.001,2.961L21.997,6.022L20.063,6.02Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M14.5,10C15.328,10 16,9.328 16,8.5C16,7.672 15.328,7 14.5,7C13.672,7 13,7.672 13,8.5C13,9.328 13.672,10 14.5,10Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M14.5,16C15.328,16 16,15.328 16,14.5C16,13.672 15.328,13 14.5,13C13.672,13 13,13.672 13,14.5C13,15.328 13.672,16 14.5,16Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M24,10.993C24,11.386 23.969,11.775 23.908,12.161C23.85,12.547 23.746,12.911 23.598,13.253C23.449,13.593 23.241,13.895 22.973,14.159C22.705,14.421 22.364,14.626 21.951,14.776C21.537,14.925 21.037,15 20.449,15C20.31,15 20.147,14.994 19.959,14.981C19.772,14.972 19.617,14.956 19.494,14.935V13.776C19.623,13.808 19.761,13.833 19.906,13.851C20.051,13.867 20.198,13.875 20.347,13.875C20.938,13.875 21.393,13.784 21.713,13.604C22.036,13.423 22.262,13.173 22.392,12.852C22.524,12.531 22.6,12.161 22.619,11.741H22.561C22.467,11.89 22.356,12.025 22.227,12.147C22.101,12.265 21.939,12.36 21.742,12.432C21.545,12.5 21.295,12.534 20.991,12.534C20.587,12.534 20.236,12.45 19.935,12.282C19.638,12.111 19.407,11.865 19.242,11.544C19.081,11.221 19,10.83 19,10.372C19,9.877 19.097,9.454 19.291,9.102C19.488,8.747 19.767,8.475 20.129,8.285C20.491,8.095 20.917,8 21.408,8C21.77,8 22.107,8.061 22.42,8.182C22.734,8.3 23.008,8.483 23.244,8.728C23.483,8.974 23.669,9.286 23.801,9.662C23.934,10.039 24,10.483 24,10.993ZM21.437,9.158C21.146,9.158 20.909,9.255 20.725,9.448C20.541,9.641 20.449,9.943 20.449,10.354C20.449,10.684 20.528,10.945 20.686,11.138C20.844,11.331 21.085,11.428 21.408,11.428C21.631,11.428 21.825,11.381 21.989,11.288C22.154,11.191 22.282,11.071 22.372,10.928C22.466,10.782 22.513,10.632 22.513,10.48C22.513,10.321 22.49,10.164 22.445,10.008C22.399,9.852 22.332,9.711 22.241,9.583C22.151,9.455 22.038,9.353 21.902,9.275C21.77,9.197 21.615,9.158 21.437,9.158Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M4,15H2.721V10.949C2.721,10.838 2.723,10.7 2.726,10.538C2.728,10.372 2.732,10.203 2.738,10.03C2.743,9.855 2.749,9.697 2.754,9.556C2.724,9.598 2.662,9.669 2.568,9.772C2.477,9.87 2.392,9.96 2.312,10.04L1.617,10.686L1,9.795L2.949,8H4V15Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M5,12.007C5,11.614 5.029,11.227 5.087,10.844C5.149,10.458 5.254,10.095 5.402,9.756C5.551,9.413 5.759,9.111 6.027,8.85C6.295,8.585 6.636,8.378 7.049,8.229C7.463,8.076 7.964,8 8.551,8C8.69,8 8.852,8.006 9.036,8.019C9.223,8.028 9.378,8.045 9.501,8.07V9.223C9.372,9.195 9.233,9.174 9.084,9.158C8.939,9.139 8.794,9.13 8.648,9.13C8.06,9.13 7.605,9.22 7.282,9.401C6.962,9.582 6.736,9.832 6.604,10.153C6.474,10.47 6.399,10.841 6.376,11.264H6.439C6.529,11.112 6.642,10.976 6.778,10.858C6.917,10.74 7.085,10.646 7.282,10.578C7.479,10.506 7.71,10.47 7.975,10.47C8.388,10.47 8.747,10.556 9.05,10.727C9.354,10.895 9.588,11.14 9.753,11.46C9.918,11.781 10,12.172 10,12.632C10,13.124 9.901,13.548 9.704,13.903C9.507,14.257 9.228,14.53 8.866,14.72C8.508,14.907 8.081,15 7.587,15C7.225,15 6.888,14.941 6.575,14.823C6.261,14.701 5.987,14.517 5.751,14.271C5.515,14.026 5.331,13.716 5.199,13.342C5.066,12.965 5,12.52 5,12.007ZM7.558,13.847C7.852,13.847 8.091,13.75 8.275,13.557C8.459,13.364 8.551,13.062 8.551,12.651C8.551,12.318 8.471,12.057 8.309,11.867C8.151,11.674 7.91,11.577 7.587,11.577C7.368,11.577 7.174,11.625 7.006,11.722C6.841,11.815 6.714,11.935 6.623,12.081C6.533,12.225 6.487,12.373 6.487,12.525C6.487,12.684 6.51,12.841 6.555,12.997C6.6,13.152 6.668,13.294 6.759,13.422C6.849,13.549 6.961,13.652 7.093,13.73C7.229,13.808 7.384,13.847 7.558,13.847Z" />
</group>
</vector>

View File

@ -0,0 +1,22 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="18"
android:viewportHeight="18">
<path
android:fillColor="@color/camera_option_color"
android:pathData="M9,7m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M9,11m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0" />
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M2,0C0.895,0 0,0.895 0,2V5H2V2L16,2V5H18V2C18,0.895 17.105,0 16,0H2ZM18,13H16V16H2V13H0V16C0,17.105 0.895,18 2,18H16C17.105,18 18,17.105 18,16V13Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M15,12H13.13V9.033C13.13,8.978 13.13,8.878 13.13,8.733C13.13,8.585 13.132,8.423 13.135,8.245C13.141,8.067 13.149,7.907 13.158,7.765C13.078,7.85 13.002,7.922 12.93,7.982C12.862,8.042 12.795,8.099 12.73,8.15L11.956,8.713L11,7.679L13.34,6H15V12Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M6,12H4.131V9.033C4.131,8.978 4.131,8.878 4.131,8.733C4.131,8.585 4.132,8.423 4.135,8.245C4.141,8.067 4.149,7.907 4.159,7.765C4.078,7.85 4.002,7.922 3.93,7.982C3.862,8.042 3.795,8.099 3.73,8.15L2.956,8.713L2,7.679L4.34,6H6V12Z" />
</vector>

View File

@ -0,0 +1,26 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M6.436,18.011V21.072C6.436,21.099 6.446,21.125 6.465,21.144C6.484,21.164 6.51,21.174 6.537,21.174H18.694C18.721,21.174 18.746,21.164 18.765,21.144C18.784,21.125 18.795,21.099 18.795,21.072V18.011H20.615V21.072C20.615,21.587 20.413,22.08 20.053,22.443C19.692,22.807 19.203,23.011 18.694,23.011H6.537C6.027,23.011 5.539,22.807 5.178,22.443C4.818,22.08 4.615,21.587 4.615,21.072V18.011H6.436Z" />
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M18.484,6.02L18.488,2.958C18.488,2.931 18.477,2.905 18.458,2.886C18.439,2.867 18.414,2.856 18.387,2.856L6.23,2.839C6.203,2.839 6.178,2.85 6.159,2.869C6.14,2.888 6.129,2.914 6.129,2.941L6.125,6.002L4.305,6L4.308,2.938C4.309,2.424 4.512,1.931 4.873,1.568C5.234,1.205 5.723,1.002 6.232,1.002L18.389,1.019C18.899,1.02 19.387,1.225 19.747,1.589C20.107,1.953 20.309,2.447 20.308,2.961L20.305,6.022L18.484,6.02Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M12.577,11C13.405,11 14.077,10.328 14.077,9.5C14.077,8.672 13.405,8 12.577,8C11.748,8 11.077,8.672 11.077,9.5C11.077,10.328 11.748,11 12.577,11Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M12.577,16C13.405,16 14.077,15.328 14.077,14.5C14.077,13.672 13.405,13 12.577,13C11.748,13 11.077,13.672 11.077,14.5C11.077,15.328 11.748,16 12.577,16Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M8,14.342H7.042V16H5.397V14.342H2V13.165L5.49,8H7.042V13.029H8V14.342ZM5.397,13.029V11.672C5.397,11.544 5.399,11.393 5.403,11.217C5.41,11.042 5.417,10.867 5.425,10.692C5.432,10.517 5.439,10.362 5.446,10.227C5.457,10.089 5.465,9.992 5.468,9.937H5.425C5.356,10.087 5.283,10.233 5.207,10.375C5.131,10.514 5.042,10.659 4.94,10.813L3.481,13.029H5.397Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M21.745,9.852C21.745,10.211 21.662,10.521 21.496,10.784C21.33,11.046 21.105,11.261 20.82,11.428C20.539,11.595 20.223,11.717 19.872,11.795V11.827C20.567,11.905 21.095,12.097 21.455,12.402C21.818,12.707 22,13.115 22,13.626C22,14.08 21.875,14.487 21.626,14.845C21.381,15.203 21.002,15.486 20.488,15.691C19.974,15.897 19.312,16 18.502,16C18.024,16 17.577,15.965 17.162,15.894C16.751,15.826 16.364,15.721 16,15.58V14.18C16.372,14.35 16.761,14.479 17.168,14.568C17.575,14.653 17.955,14.696 18.306,14.696C18.962,14.696 19.421,14.595 19.682,14.392C19.947,14.187 20.079,13.899 20.079,13.53C20.079,13.314 20.018,13.131 19.895,12.982C19.773,12.833 19.559,12.719 19.255,12.641C18.955,12.563 18.534,12.524 17.992,12.524H17.334V11.263H18.004C18.538,11.263 18.943,11.219 19.219,11.13C19.5,11.038 19.69,10.913 19.788,10.757C19.891,10.597 19.943,10.417 19.943,10.214C19.943,9.937 19.848,9.721 19.658,9.565C19.468,9.409 19.152,9.331 18.709,9.331C18.433,9.331 18.18,9.363 17.951,9.426C17.725,9.487 17.522,9.561 17.34,9.65C17.158,9.735 16.998,9.819 16.86,9.9L16.012,8.766C16.352,8.546 16.749,8.364 17.204,8.218C17.662,8.073 18.208,8 18.84,8C19.733,8 20.441,8.161 20.962,8.484C21.484,8.807 21.745,9.263 21.745,9.852Z" />
</vector>

View File

@ -0,0 +1,21 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="@color/camera_option_color"
android:pathData="M0,0v512h512V0H0zM477.87,477.87H34.13V34.13h443.73V477.87z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M126.53,102.4l72.58,0l0,-34.13l-130.84,0l0,130.84l34.13,0l0,-72.57l96.02,96.02l24.13,-24.13z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M222.56,313.58l-24.14,-24.14l-96.02,96.02l0,-72.58l-34.13,0l0,130.84l130.84,0l0,-34.13l-72.57,0z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M409.6,312.89l0,72.58l-96.02,-96.02l-24.13,24.13l96.02,96.02l-72.57,0l0,34.13l130.84,0l0,-130.84z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M312.89,68.27l0,34.13l72.58,0l-96.02,96.02l24.13,24.13l96.02,-96.02l0,72.57l34.13,0l0,-130.84z" />
</vector>

View File

@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/icon_size"
android:height="@dimen/icon_size"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#ffffff"
android:fillType="evenOdd"
android:pathData="M256,485C382.47,485 485,382.47 485,256C485,129.53 382.47,27 256,27C129.53,27 27,129.53 27,256C27,382.47 129.53,485 256,485ZM256,465C370.32,465 463,371.43 463,256C463,140.57 370.32,47 256,47C141.68,47 49,140.57 49,256C49,371.43 141.68,465 256,465Z" />
<group
android:name="inner"
android:pivotX="256"
android:pivotY="256">
<path
android:fillColor="#ffffff"
android:pathData="M255.5,255.5m-170.5,0a170.5,170.5 0,1 1,341 0a170.5,170.5 0,1 1,-341 0" />
</group>
</vector>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/icon_size"
android:height="@dimen/icon_size"
android:viewportWidth="168"
android:viewportHeight="168">
<item
android:id="@+id/pressed"
android:drawable="@drawable/ic_shutter"
android:state_pressed="true" />
<item
android:id="@+id/unpressed"
android:drawable="@drawable/ic_shutter" />
<transition
android:drawable="@drawable/shutter_pressed_to_unpressed"
android:fromId="@id/pressed"
android:toId="@id/unpressed" />
<transition
android:drawable="@drawable/shutter_unpressed_to_pressed"
android:fromId="@id/unpressed"
android:toId="@id/pressed" />
</animated-selector>

View File

@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M9.4,10.5l4.77,-8.26C13.47,2.09 12.75,2 12,2c-2.4,0 -4.6,0.85 -6.32,2.25l3.66,6.35 0.06,-0.1zM21.54,9c-0.92,-2.92 -3.15,-5.26 -6,-6.34L11.88,9h9.66zM21.8,10h-7.49l0.29,0.5 4.76,8.25C21,16.97 22,14.61 22,12c0,-0.69 -0.07,-1.35 -0.2,-2zM8.54,12l-3.9,-6.75C3.01,7.03 2,9.39 2,12c0,0.69 0.07,1.35 0.2,2h7.49l-1.15,-2zM2.46,15c0.92,2.92 3.15,5.26 6,6.34L12.12,15L2.46,15zM13.73,15l-3.9,6.76c0.7,0.15 1.42,0.24 2.17,0.24 2.4,0 4.6,-0.85 6.32,-2.25l-3.66,-6.35 -0.93,1.6z"/>
</vector>

View File

@ -0,0 +1,19 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="26"
android:viewportHeight="24">
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M5.206,2C3.374,2 1.889,3.485 1.889,5.317V18.583C1.889,20.415 3.374,21.9 5.206,21.9H20.683C22.515,21.9 24,20.415 24,18.583V5.317C24,3.485 22.515,2 20.683,2H5.206ZM5.979,3.106C4.331,3.106 2.994,4.425 2.994,6.054V17.846C2.994,19.475 4.331,20.794 5.979,20.794H19.909C21.558,20.794 22.894,19.475 22.894,17.846V6.054C22.894,4.425 21.558,3.106 19.909,3.106H5.979Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M6.25,16H5V8H8.434V9.39H6.25V11.453H8.282V12.837H6.25V16Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M14.514,16H13.248V12.547H10.875V16H9.605V8H10.875V11.135H13.248V8H14.514V16Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M21,11.923C21,12.824 20.87,13.578 20.611,14.183C20.354,14.785 19.981,15.239 19.492,15.546C19.003,15.849 18.415,16 17.726,16H16.03V8H17.911C18.539,8 19.084,8.15 19.545,8.449C20.007,8.744 20.365,9.184 20.619,9.767C20.873,10.347 21,11.066 21,11.923ZM19.681,11.967C19.681,11.376 19.615,10.891 19.484,10.512C19.356,10.129 19.164,9.846 18.91,9.663C18.659,9.481 18.348,9.39 17.976,9.39H17.3V14.599H17.845C18.465,14.599 18.925,14.378 19.226,13.937C19.529,13.496 19.681,12.839 19.681,11.967Z" />
</vector>

View File

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="26"
android:viewportHeight="24">
<path
android:fillColor="@color/camera_option_color"
android:pathData="M12.6,16H11.156V12.547H8.449V16H7V8H8.449V11.135H11.156V8H12.6V16Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M20,11.923C20,12.824 19.852,13.578 19.556,14.183C19.263,14.785 18.838,15.239 18.28,15.546C17.722,15.849 17.05,16 16.265,16H14.33V8H16.475C17.192,8 17.814,8.15 18.34,8.449C18.867,8.744 19.275,9.184 19.565,9.767C19.855,10.347 20,11.066 20,11.923ZM18.495,11.967C18.495,11.376 18.42,10.891 18.27,10.512C18.124,10.129 17.906,9.846 17.616,9.663C17.329,9.481 16.974,9.39 16.55,9.39H15.779V14.599H16.401C17.108,14.599 17.633,14.378 17.976,13.937C18.322,13.496 18.495,12.839 18.495,11.967Z" />
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M5.317,2C3.485,2 2,3.485 2,5.317V18.583C2,20.415 3.485,21.9 5.317,21.9H20.794C22.626,21.9 24.111,20.415 24.111,18.583V5.317C24.111,3.485 22.626,2 20.794,2H5.317ZM6.091,3.106C4.442,3.106 3.106,4.425 3.106,6.054V17.846C3.106,19.475 4.442,20.794 6.091,20.794H20.021C21.669,20.794 23.006,19.475 23.006,17.846V6.054C23.006,4.425 21.669,3.106 20.021,3.106H6.091Z" />
</vector>

View File

@ -0,0 +1,30 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/large_icon_size"
android:height="@dimen/large_icon_size"
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="@android:color/white"
android:fillType="evenOdd"
android:pathData="M256,485C382.47,485 485,382.47 485,256C485,129.53 382.47,27 256,27C129.53,27 27,129.53 27,256C27,382.47 129.53,485 256,485ZM256,465C370.32,465 463,371.43 463,256C463,140.57 370.32,47 256,47C141.68,47 49,140.57 49,256C49,371.43 141.68,465 256,465Z" />
<group
android:name="inner_big"
android:pivotX="256"
android:pivotY="256">
<path
android:fillColor="@color/md_red"
android:pathData="M255.5,255.5m-170.5,0a170.5,170.5 0,1 1,341 0a170.5,170.5 0,1 1,-341 0" />
</group>
<group
android:name="inner_small"
android:pivotX="256"
android:pivotY="256">
<path
android:fillColor="@color/md_red"
android:pathData="M221,138L292,138A82,82 0,0 1,374 220L374,291A82,82 0,0 1,292 373L221,373A82,82 0,0 1,139 291L139,220A82,82 0,0 1,221 138z" />
</group>
</vector>

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="@dimen/large_icon_size"
android:height="@dimen/large_icon_size"
android:viewportWidth="168"
android:viewportHeight="168">
<item
android:id="@+id/selected"
android:drawable="@drawable/ic_video_rec"
android:state_selected="true" />
<item
android:id="@+id/pressed"
android:drawable="@drawable/ic_video_rec"
android:state_pressed="true" />
<item
android:id="@+id/default_state"
android:drawable="@drawable/ic_video_rec" />
<transition
android:drawable="@drawable/video_rec_record_to_idle"
android:fromId="@id/selected"
android:toId="@id/default_state" />
<transition
android:drawable="@drawable/video_rec_idle_to_record"
android:fromId="@id/default_state"
android:toId="@id/selected" />
<transition
android:drawable="@drawable/video_rec_pressed_to_unpressed"
android:fromId="@id/pressed"
android:toId="@id/default_state" />
<transition
android:drawable="@drawable/video_rec_unpressed_to_pressed"
android:fromId="@id/default_state"
android:toId="@id/pressed" />
</animated-selector>

View File

@ -0,0 +1,17 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="26"
android:viewportHeight="24">
<path
android:fillColor="@color/camera_option_color"
android:pathData="M12.096,13.733C12.096,14.194 11.984,14.595 11.759,14.936C11.535,15.276 11.207,15.539 10.775,15.723C10.348,15.908 9.827,16 9.214,16C8.943,16 8.677,15.982 8.417,15.947C8.16,15.911 7.913,15.86 7.674,15.792C7.438,15.721 7.214,15.634 7,15.532V13.999C7.371,14.162 7.756,14.309 8.155,14.441C8.554,14.572 8.95,14.637 9.342,14.637C9.613,14.637 9.831,14.602 9.995,14.531C10.162,14.46 10.283,14.362 10.358,14.238C10.433,14.114 10.471,13.972 10.471,13.812C10.471,13.617 10.405,13.45 10.273,13.312C10.141,13.174 9.959,13.044 9.727,12.924C9.499,12.803 9.241,12.673 8.952,12.535C8.77,12.45 8.572,12.347 8.358,12.226C8.144,12.102 7.941,11.951 7.749,11.774C7.556,11.596 7.398,11.382 7.273,11.13C7.152,10.874 7.091,10.569 7.091,10.214C7.091,9.749 7.198,9.352 7.412,9.022C7.626,8.692 7.93,8.44 8.326,8.266C8.725,8.089 9.196,8 9.738,8C10.144,8 10.531,8.048 10.898,8.144C11.269,8.236 11.656,8.371 12.059,8.548L11.524,9.831C11.164,9.686 10.841,9.574 10.556,9.496C10.271,9.414 9.98,9.373 9.684,9.373C9.478,9.373 9.301,9.407 9.155,9.474C9.009,9.538 8.898,9.631 8.824,9.751C8.749,9.868 8.711,10.005 8.711,10.161C8.711,10.345 8.765,10.502 8.872,10.629C8.982,10.754 9.146,10.874 9.364,10.991C9.585,11.108 9.859,11.245 10.187,11.401C10.587,11.589 10.927,11.786 11.209,11.992C11.494,12.194 11.713,12.434 11.866,12.711C12.02,12.984 12.096,13.325 12.096,13.733Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M20,11.928C20,12.805 19.831,13.537 19.492,14.126C19.157,14.712 18.67,15.154 18.032,15.452C17.394,15.746 16.626,15.894 15.727,15.894H13.513V8.112H15.968C16.788,8.112 17.499,8.257 18.102,8.548C18.704,8.836 19.171,9.263 19.503,9.831C19.834,10.395 20,11.094 20,11.928ZM18.278,11.971C18.278,11.396 18.192,10.924 18.021,10.555C17.854,10.182 17.604,9.907 17.273,9.73C16.945,9.552 16.538,9.464 16.053,9.464H15.171V14.531H15.882C16.692,14.531 17.292,14.316 17.684,13.887C18.08,13.458 18.278,12.819 18.278,11.971Z" />
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M5.317,2C3.485,2 2,3.485 2,5.317V18.583C2,20.415 3.485,21.9 5.317,21.9H20.794C22.626,21.9 24.111,20.415 24.111,18.583V5.317C24.111,3.485 22.626,2 20.794,2H5.317ZM6.091,3.106C4.442,3.106 3.106,4.425 3.106,6.054V17.846C3.106,19.475 4.442,20.794 6.091,20.794H20.021C21.669,20.794 23.006,19.475 23.006,17.846V6.054C23.006,4.425 21.669,3.106 20.021,3.106H6.091Z" />
</vector>

View File

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="26"
android:viewportHeight="24">
<path
android:fillColor="@color/camera_option_color"
android:pathData="M9.425,8V13.107C9.425,13.65 9.343,14.141 9.178,14.58C9.016,15.016 8.769,15.361 8.437,15.617C8.107,15.872 7.692,16 7.19,16C6.477,16 5.934,15.734 5.561,15.201C5.187,14.668 5,13.963 5,13.085V8H6.139V12.831C6.139,13.483 6.23,13.94 6.412,14.202C6.594,14.465 6.863,14.597 7.22,14.597C7.471,14.597 7.673,14.533 7.828,14.408C7.986,14.282 8.101,14.087 8.175,13.825C8.249,13.562 8.286,13.227 8.286,12.821V8H9.425Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M15.163,15.892H14.023V12.486H11.888V15.892H10.745V8H11.888V11.093H14.023V8H15.163V15.892Z" />
<path
android:fillColor="@color/camera_option_color"
android:pathData="M21,11.87C21,12.759 20.883,13.502 20.65,14.1C20.419,14.694 20.083,15.142 19.643,15.444C19.203,15.743 18.673,15.892 18.054,15.892H16.527V8H18.22C18.785,8 19.275,8.148 19.691,8.443C20.106,8.734 20.428,9.168 20.657,9.744C20.886,10.316 21,11.025 21,11.87ZM19.813,11.914C19.813,11.331 19.754,10.852 19.636,10.478C19.52,10.1 19.348,9.821 19.119,9.641C18.893,9.461 18.613,9.371 18.279,9.371H17.67V14.51H18.161C18.719,14.51 19.133,14.292 19.403,13.857C19.676,13.422 19.813,12.774 19.813,11.914Z" />
<path
android:fillColor="@color/camera_option_color"
android:fillType="evenOdd"
android:pathData="M5.317,2C3.485,2 2,3.485 2,5.317V18.583C2,20.415 3.485,21.9 5.317,21.9H20.794C22.626,21.9 24.111,20.415 24.111,18.583V5.317C24.111,3.485 22.626,2 20.794,2H5.317ZM6.091,3.106C4.442,3.106 3.106,4.425 3.106,6.054V17.846C3.106,19.475 4.442,20.794 6.091,20.794H20.021C21.669,20.794 23.006,19.475 23.006,17.846V6.054C23.006,4.425 21.669,3.106 20.021,3.106H6.091Z" />
</vector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_shutter">
<target android:name="inner">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleX"
android:valueFrom="0.9"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleY"
android:valueFrom="0.9"
android:valueTo="1"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_shutter">
<target android:name="inner">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.9"
android:valueType="floatType" />
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.9"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:bottom="@dimen/tab_indicator_margin"
android:end="@dimen/tab_indicator_margin"
android:start="@dimen/tab_indicator_margin"
android:top="@dimen/tab_indicator_margin">
<shape>
<corners android:radius="@dimen/tab_indicator_margin" />
<solid android:color="@color/tab_color" />
</shape>
</item>
</layer-list>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_video_rec">
<target android:name="inner_big">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_video_rec">
<target android:name="inner_big">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="800"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleX"
android:valueFrom="0.9"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:duration="800"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleY"
android:valueFrom="0.9"
android:valueTo="1"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_video_rec">
<target android:name="inner_big">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleX"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleY"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_video_rec">
<target android:name="inner_big">
<aapt:attr name="android:animation">
<set>
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.9"
android:valueType="floatType" />
<objectAnimator
android:duration="@integer/icon_anim_duration"
android:interpolator="@android:anim/accelerate_interpolator"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.9"
android:valueType="floatType" />
</set>
</aapt:attr>
</target>
</animated-vector>

View File

@ -1,107 +1,138 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/view_holder"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/black">
android:animateLayoutChanges="true"
android:background="@android:color/black"
android:fitsSystemWindows="true">
<androidx.camera.view.PreviewView
android:id="@+id/preview_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:scaleType="fitStart" />
android:layout_height="match_parent" />
<View
android:id="@+id/capture_black_screen"
android:id="@+id/shutter_animation"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:alpha="0"
android:background="@color/md_grey_black" />
android:background="@android:color/black" />
<ImageView
android:id="@+id/settings"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_alignParentEnd="true"
android:contentDescription="@string/settings"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_settings_cog_vector" />
<ImageView
android:id="@+id/toggle_photo_video"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_below="@+id/settings"
android:layout_alignParentEnd="true"
android:contentDescription="@string/toggle_photo_video"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_video_vector" />
<ImageView
android:id="@+id/change_resolution"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_below="@+id/toggle_photo_video"
android:layout_alignParentEnd="true"
android:contentDescription="@string/resolution"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_resolution_vector" />
<ImageView
android:id="@+id/last_photo_video_preview"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_below="@+id/change_resolution"
android:layout_alignParentEnd="true"
android:contentDescription="@string/view_last_media"
android:padding="@dimen/medium_margin" />
<LinearLayout
android:id="@+id/btn_holder"
<FrameLayout
android:id="@+id/top_options"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<include layout="@layout/layout_top" />
<include layout="@layout/layout_media_size" />
<include
layout="@layout/layout_flash"
android:visibility="gone" />
</FrameLayout>
<View
android:id="@+id/bottom_overlay"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@color/overlay_color"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/camera_mode_tab" />
<com.google.android.material.tabs.TabLayout
android:id="@+id/camera_mode_tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/big_margin"
android:background="@android:color/transparent"
app:layout_constraintBottom_toTopOf="@id/shutter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:tabBackground="@drawable/tab_indicator"
app:tabIndicator="@null"
app:tabMode="auto"
app:tabRippleColor="@null"
app:tabSelectedTextColor="@color/md_grey_600_dark"
app:tabTextColor="@color/md_grey_white">
<com.google.android.material.tabs.TabItem
android:id="@+id/camera_mode_tab_video"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/video" />
<com.google.android.material.tabs.TabItem
android:id="@+id/camera_mode_tab_photo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/photo" />
</com.google.android.material.tabs.TabLayout>
android:layout_alignParentBottom="true"
android:gravity="center_horizontal|bottom">
<ImageView
android:id="@+id/toggle_camera"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:contentDescription="@string/toggle_camera"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_camera_front_vector" />
android:src="@drawable/ic_camera_front_vector"
app:layout_constraintBottom_toBottomOf="@id/shutter"
app:layout_constraintEnd_toStartOf="@id/shutter"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@id/shutter" />
<ImageView
android:id="@+id/shutter"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:layout_width="@dimen/large_icon_size"
android:layout_height="@dimen/large_icon_size"
android:layout_marginBottom="@dimen/small_margin"
android:contentDescription="@string/shutter"
android:src="@drawable/ic_shutter_vector" />
android:src="@drawable/ic_shutter_animated"
app:layout_constraintBottom_toTopOf="@id/video_rec_curr_timer"
app:layout_constraintEnd_toStartOf="@id/last_photo_video_preview"
app:layout_constraintStart_toEndOf="@id/toggle_camera"
app:layout_constraintVertical_bias="1"
app:layout_goneMarginBottom="@dimen/big_margin" />
<ImageView
android:id="@+id/toggle_flash"
android:id="@+id/last_photo_video_preview"
android:layout_width="@dimen/icon_size"
android:layout_height="@dimen/icon_size"
android:layout_weight="1"
android:contentDescription="@string/toggle_flash"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flash_off_vector" />
android:contentDescription="@string/view_last_media"
android:padding="@dimen/medium_margin"
app:layout_constraintBottom_toBottomOf="@id/shutter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/shutter"
app:layout_constraintTop_toTopOf="@id/shutter"
tools:src="@tools:sample/backgrounds/scenic" />
</LinearLayout>
<TextView
android:id="@+id/video_rec_curr_timer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/btn_holder"
android:layout_centerHorizontal="true"
android:layout_marginTop="@dimen/small_margin"
android:layout_marginBottom="@dimen/big_margin"
android:textColor="@android:color/white"
android:visibility="gone"
tools:text="00:00" />
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:text="00:00"
tools:visibility="gone" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -116,21 +116,6 @@
</RelativeLayout>
<RelativeLayout
android:id="@+id/settings_keep_settings_visible_holder"
style="@style/SettingsHolderCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/ripple_bottom_corners">
<com.simplemobiletools.commons.views.MyAppCompatCheckbox
android:id="@+id/settings_keep_settings_visible"
style="@style/SettingsCheckboxStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/keep_settings_visible" />
</RelativeLayout>
</LinearLayout>
<TextView

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
style="@style/Widget.App.Button.OutlineButton.IconOnly"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:icon="@drawable/ic_photo_1x1" />

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.button.MaterialButtonToggleGroup xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/flash_toggle_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:selectionRequired="true"
app:singleSelection="true">
<Button
android:id="@+id/flash_off"
style="@style/Widget.App.Button.OutlineButton.IconOnly"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:icon="@drawable/ic_flash_off_vector" />
<Button
android:id="@+id/flash_auto"
style="@style/Widget.App.Button.OutlineButton.IconOnly"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:icon="@drawable/ic_flash_auto_vector" />
<Button
android:id="@+id/flash_on"
style="@style/Widget.App.Button.OutlineButton.IconOnly"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
app:icon="@drawable/ic_flash_on_vector" />
</com.google.android.material.button.MaterialButtonToggleGroup>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.button.MaterialButtonToggleGroup xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/media_size_toggle_group"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:selectionRequired="true"
app:singleSelection="true" />

View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/default_icons"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/toggle_flash"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:layout_weight="1"
android:contentDescription="@string/toggle_flash"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_flash_off_vector"
app:layout_constraintEnd_toStartOf="@id/change_resolution"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/change_resolution"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_alignParentEnd="true"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:contentDescription="@string/resolution"
android:padding="@dimen/normal_margin"
android:transitionName="one_by_one"
app:layout_constraintEnd_toStartOf="@id/settings"
app:layout_constraintStart_toEndOf="@id/toggle_flash"
app:layout_constraintTop_toTopOf="@id/toggle_flash"
tools:src="@drawable/ic_photo_4x3" />
<ImageView
android:id="@+id/settings"
android:layout_width="@dimen/top_icon_size"
android:layout_height="@dimen/top_icon_size"
android:layout_marginStart="@dimen/normal_margin"
android:layout_marginEnd="@dimen/normal_margin"
android:contentDescription="@string/settings"
android:padding="@dimen/normal_margin"
android:src="@drawable/ic_settings_cog_vector"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/change_resolution"
app:layout_constraintTop_toTopOf="@id/toggle_flash" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="overlay_color">#2e000000</color>
</resources>

View File

@ -1,4 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<dimen name="icon_size">56dp</dimen>
<dimen name="large_icon_size">72dp</dimen>
<dimen name="top_icon_size">48dp</dimen>
<dimen name="toggle_icon_size">24dp</dimen>
<dimen name="tab_indicator_margin">10dp</dimen>
</resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<item name="photo_full" type="id" />
<item name="photo_16x9" type="id" />
<item name="photo_4x3" type="id" />
<item name="photo_1x1" type="id" />
<item name="video_sd" type="id" />
<item name="video_hd" type="id" />
<item name="video_fhd" type="id" />
<item name="video_uhd" type="id" />
</resources>

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<integer name="icon_anim_duration">200</integer>
</resources>

View File

@ -1,11 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="AppTheme" parent="AppTheme.Base"/>
<style name="AppTheme" parent="AppTheme.Base" />
<style name="FullScreenTheme" parent="AppTheme">
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowTranslucentNavigation">true</item>
<item name="android:windowActionBar">false</item>
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
<item name="android:enforceNavigationBarContrast">false</item>
</style>
<style name="Widget.App.Button.OutlineButton.IconOnly" parent="Widget.MaterialComponents.Button.TextButton">
<item name="iconTint">@null</item>
<item name="iconPadding">0dp</item>
<item name="iconGravity">textStart</item>
<item name="cornerRadius">0dp</item>
<item name="iconSize">@dimen/toggle_icon_size</item>
<item name="backgroundTint">@android:color/transparent</item>
<item name="android:backgroundTint">@android:color/transparent</item>
<item name="android:insetTop">0dp</item>
<item name="android:insetBottom">0dp</item>
<item name="android:minWidth">@dimen/icon_size</item>
<item name="android:minHeight">@dimen/icon_size</item>
</style>
</resources>