Merge pull request #342 from KryptKode/feat/camera-x
CameraX: Fix capture/preview resolution
@ -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,7 +374,11 @@ class MainActivity : SimpleActivity(), PhotoProcessor.MediaSavedListener, Camera
|
||||
|
||||
private fun toggleFlash() {
|
||||
if (checkCameraAvailable()) {
|
||||
mPreview?.toggleFlashlight()
|
||||
if (mIsInPhotoMode) {
|
||||
showFlashOptions(mIsInPhotoMode)
|
||||
} else {
|
||||
mPreview?.toggleFlashlight()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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()
|
||||
}
|
||||
val intent = Intent(applicationContext, SettingsActivity::class.java)
|
||||
startActivity(intent)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -47,7 +47,12 @@ class ChangeResolutionDialogX(
|
||||
val items = photoResolutions.mapIndexed { index, resolution ->
|
||||
val megapixels = resolution.megaPixels
|
||||
val aspectRatio = resolution.getAspectRatio(activity)
|
||||
RadioItem(index, "${resolution.width} x ${resolution.height} ($megapixels MP, $aspectRatio)")
|
||||
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)
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
@ -20,21 +20,20 @@ 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 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()
|
||||
imageQualities.add(CameraSelectorImageQualities(cameraSelector, imageSizes))
|
||||
}
|
||||
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 = 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)
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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?) {}
|
||||
}
|
@ -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 }
|
||||
}
|
||||
|
||||
|
@ -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(
|
||||
activity,
|
||||
cameraSelector,
|
||||
preview,
|
||||
captureUseCase,
|
||||
)
|
||||
|
||||
preview?.setSurfaceProvider(previewView.surfaceProvider)
|
||||
cameraProvider.unbindAll()
|
||||
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,
|
||||
useCaseGroup,
|
||||
)
|
||||
} else {
|
||||
cameraProvider.bindToLifecycle(
|
||||
activity,
|
||||
cameraSelector,
|
||||
previewUseCase,
|
||||
captureUseCase,
|
||||
)
|
||||
}
|
||||
|
||||
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()
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -2,18 +2,21 @@ 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
|
||||
|
||||
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / ONE_MEGA_PIXEL)
|
||||
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / ONE_MEGA_PIXEL)
|
||||
|
||||
fun isSixteenToNine() = ratio == 16 / 9f
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
@ -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,
|
||||
)
|
@ -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) {
|
||||
@ -11,7 +13,7 @@ enum class VideoQuality(val width: Int, val height: Int) {
|
||||
|
||||
val pixels: Int = width * height
|
||||
|
||||
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / VideoQuality.ONE_MEGA_PIXEL)
|
||||
val megaPixels: String = String.format("%.1f", (width * height.toFloat()) / VideoQuality.ONE_MEGA_PIXEL)
|
||||
|
||||
val ratio = width / height.toFloat()
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
7
app/src/main/res/color/camera_option_color.xml
Normal 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>
|
5
app/src/main/res/color/tab_color.xml
Normal 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>
|
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 5.3 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 4.1 KiB |
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
31
app/src/main/res/drawable/ic_photo_16x9.xml
Normal 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>
|
22
app/src/main/res/drawable/ic_photo_1x1.xml
Normal 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>
|
26
app/src/main/res/drawable/ic_photo_4x3.xml
Normal 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>
|
21
app/src/main/res/drawable/ic_photo_full.xml
Normal 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>
|
19
app/src/main/res/drawable/ic_shutter.xml
Normal 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>
|
24
app/src/main/res/drawable/ic_shutter_animated.xml
Normal 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>
|
@ -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>
|
19
app/src/main/res/drawable/ic_video_fhd.xml
Normal 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>
|
17
app/src/main/res/drawable/ic_video_hd.xml
Normal 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>
|
30
app/src/main/res/drawable/ic_video_rec.xml
Normal 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>
|
41
app/src/main/res/drawable/ic_video_rec_animated.xml
Normal 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>
|
17
app/src/main/res/drawable/ic_video_sd.xml
Normal 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>
|
20
app/src/main/res/drawable/ic_video_uhd.xml
Normal 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>
|
26
app/src/main/res/drawable/shutter_pressed_to_unpressed.xml
Normal 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>
|
26
app/src/main/res/drawable/shutter_unpressed_to_pressed.xml
Normal 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>
|
14
app/src/main/res/drawable/tab_indicator.xml
Normal 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>
|
||||
|
27
app/src/main/res/drawable/video_rec_idle_to_record.xml
Normal 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>
|
26
app/src/main/res/drawable/video_rec_pressed_to_unpressed.xml
Normal 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>
|
27
app/src/main/res/drawable/video_rec_record_to_idle.xml
Normal 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>
|
26
app/src/main/res/drawable/video_rec_unpressed_to_pressed.xml
Normal 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>
|
@ -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" />
|
||||
|
||||
<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>
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/settings"
|
||||
android:id="@+id/toggle_camera"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:contentDescription="@string/settings"
|
||||
android:contentDescription="@string/toggle_camera"
|
||||
android:padding="@dimen/normal_margin"
|
||||
android:src="@drawable/ic_settings_cog_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/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" />
|
||||
android:id="@+id/shutter"
|
||||
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_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/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" />
|
||||
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
|
||||
android:id="@+id/btn_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
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" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/shutter"
|
||||
android:layout_width="@dimen/icon_size"
|
||||
android:layout_height="@dimen/icon_size"
|
||||
android:layout_weight="1"
|
||||
android:contentDescription="@string/shutter"
|
||||
android:src="@drawable/ic_shutter_vector" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/toggle_flash"
|
||||
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" />
|
||||
|
||||
</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>
|
||||
|
@ -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
|
||||
|
8
app/src/main/res/layout/layout_button.xml
Normal 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" />
|
||||
|
36
app/src/main/res/layout/layout_flash.xml
Normal 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>
|
8
app/src/main/res/layout/layout_media_size.xml
Normal 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" />
|
53
app/src/main/res/layout/layout_top.xml
Normal 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>
|
@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<color name="overlay_color">#2e000000</color>
|
||||
</resources>
|
||||
|
@ -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>
|
||||
|
11
app/src/main/res/values/ids.xml
Normal 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>
|
4
app/src/main/res/values/integers.xml
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<integer name="icon_anim_duration">200</integer>
|
||||
</resources>
|
@ -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>
|
||||
|