Skip to content

Commit 9e29a49

Browse files
committed
add camera screen styles + color filters
1 parent c4fa0ed commit 9e29a49

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1194
-34
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<activity
2222
android:name="com.banuba.sdk.ve.flow.VideoCreationActivity"
2323
android:screenOrientation="portrait"
24-
android:theme="@style/VideoCreationTheme"
24+
android:theme="@style/CustomIntegrationAppTheme"
2525
android:windowSoftInputMode="adjustResize"
2626
tools:replace="android:theme" />
2727
</application>
11 KB
Loading
220 KB
Loading
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package com.banuba.example.integrationapp.videoeditor.custom
2+
3+
import android.content.Context
4+
import android.view.ViewGroup
5+
import com.banuba.example.integrationapp.R
6+
import com.banuba.example.integrationapp.videoeditor.custom.widget.CustomRecordingButtonView
7+
import com.banuba.sdk.cameraui.data.CameraRecordingAnimationProvider
8+
import com.banuba.sdk.core.ui.ext.dimenPx
9+
10+
class CustomRecordingAnimationProvider (context: Context) : CameraRecordingAnimationProvider {
11+
12+
private val animationView = CustomRecordingButtonView(context).apply {
13+
val defaultButtonSize = context.dimenPx(R.dimen.record_button_size)
14+
layoutParams = ViewGroup.LayoutParams(defaultButtonSize, defaultButtonSize)
15+
isFocusable = true
16+
isClickable = true
17+
}
18+
19+
private var onEndTakenPictureAnimationCallback: () -> Unit = {}
20+
private var onStartRecordingAnimationCallback: () -> Unit = {}
21+
private var onEndRecordingAnimationCallback: () -> Unit = {}
22+
23+
override fun provideView() = animationView
24+
25+
override fun setOnStartRecordingAnimationCallback(callback: () -> Unit) {
26+
onStartRecordingAnimationCallback = callback
27+
}
28+
29+
override fun setOnEndRecordingAnimationCallback(callback: () -> Unit) {
30+
onEndRecordingAnimationCallback = callback
31+
}
32+
33+
override fun setOnEndTakenPictureAnimationCallback(callback: () -> Unit) {
34+
onEndTakenPictureAnimationCallback = callback
35+
}
36+
37+
override fun animatePauseRecording() {
38+
animationView.pauseAnimation()
39+
}
40+
41+
override fun animateResumeRecording() {
42+
animationView.resumeAnimation()
43+
}
44+
45+
override fun setRecordingPhotoState(state: CameraRecordingAnimationProvider.PhotoState) {
46+
when (state) {
47+
CameraRecordingAnimationProvider.PhotoState.Idle -> animationView.reset()
48+
CameraRecordingAnimationProvider.PhotoState.Capture -> animationView.animateTakePhoto {
49+
onEndTakenPictureAnimationCallback()
50+
}
51+
}
52+
}
53+
54+
override fun setRecordingVideoState(state: CameraRecordingAnimationProvider.VideoState) {
55+
when (state) {
56+
is CameraRecordingAnimationProvider.VideoState.Idle -> animationView.reset()
57+
is CameraRecordingAnimationProvider.VideoState.StartRecord -> {
58+
if (state.availableDurationMs <= 0) return
59+
animationView.animateStartVideoRecord(
60+
availableDurationMs = state.availableDurationMs,
61+
maxDurationMs = state.maxDurationMs
62+
) {
63+
onStartRecordingAnimationCallback()
64+
}
65+
}
66+
is CameraRecordingAnimationProvider.VideoState.StopRecord -> {
67+
animationView.animateStopVideoRecord {
68+
onEndRecordingAnimationCallback()
69+
}
70+
}
71+
}
72+
}
73+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.banuba.example.integrationapp.videoeditor.content
1+
package com.banuba.example.integrationapp.videoeditor.custom
22

33
import android.app.Activity
44
import android.content.Context
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package com.banuba.example.integrationapp.videoeditor.custom.widget
2+
3+
import android.animation.ValueAnimator
4+
import android.content.Context
5+
import android.graphics.*
6+
import android.util.AttributeSet
7+
import android.view.View
8+
import android.view.animation.LinearInterpolator
9+
import com.banuba.example.integrationapp.R
10+
import com.banuba.sdk.core.ui.ext.dimen
11+
12+
class CustomRecordingButtonOuterView @JvmOverloads constructor(
13+
context: Context,
14+
attr: AttributeSet? = null,
15+
defStyle: Int = 0
16+
) : View(context, attr, defStyle) {
17+
18+
companion object {
19+
private const val ANGLE_END = 360F
20+
private const val ANGLE_START = 0F
21+
private const val INIT_VIEW_ROTATION = -90F
22+
}
23+
24+
private var circleWidth = context.dimen(R.dimen.record_button_circle_idle_width)
25+
set(value) {
26+
field = value
27+
gradientPaint.strokeWidth = value
28+
whitePaint.strokeWidth = value
29+
isDrawAreaMeasured = false
30+
}
31+
private val circleColors = context.resources.getIntArray(R.array.progress_gradient_colors)
32+
private var circleDrawArea = RectF()
33+
34+
private var isDrawAreaMeasured = false
35+
36+
private val gradientPaint by lazy(LazyThreadSafetyMode.NONE) {
37+
Paint().apply {
38+
isAntiAlias = true
39+
style = Paint.Style.STROKE
40+
strokeWidth = circleWidth
41+
shader = SweepGradient(
42+
measuredWidth.toFloat() / 2,
43+
measuredHeight.toFloat() / 2,
44+
circleColors,
45+
null
46+
)
47+
}
48+
}
49+
private val whitePaint by lazy(LazyThreadSafetyMode.NONE) {
50+
Paint().apply {
51+
color = Color.WHITE
52+
isAntiAlias = true
53+
style = Paint.Style.STROKE
54+
strokeWidth = circleWidth
55+
}
56+
}
57+
58+
private var gradientSweepAngle = 0F
59+
60+
private val animator = ValueAnimator().apply {
61+
repeatCount = 0
62+
setFloatValues(ANGLE_START, ANGLE_END)
63+
interpolator = LinearInterpolator()
64+
addUpdateListener {
65+
gradientSweepAngle = it.animatedValue as Float
66+
invalidate()
67+
}
68+
}
69+
70+
init {
71+
// Because 0 degrees angle correspond to 3 o'clock on a watch
72+
rotation = INIT_VIEW_ROTATION
73+
}
74+
75+
override fun onDraw(canvas: Canvas) {
76+
if (!isDrawAreaMeasured) {
77+
isDrawAreaMeasured = true
78+
circleDrawArea = RectF(
79+
0f + circleWidth,
80+
0f + circleWidth,
81+
measuredWidth.toFloat() - circleWidth,
82+
measuredHeight.toFloat() - circleWidth
83+
)
84+
}
85+
with(canvas) {
86+
save()
87+
rotate(gradientSweepAngle, measuredWidth.toFloat() / 2, measuredHeight.toFloat() / 2)
88+
drawArc(circleDrawArea, ANGLE_START, ANGLE_END, false, gradientPaint)
89+
restore()
90+
drawArc(
91+
circleDrawArea,
92+
gradientSweepAngle,
93+
ANGLE_END - gradientSweepAngle,
94+
false,
95+
whitePaint
96+
)
97+
}
98+
}
99+
100+
fun startAnimation(
101+
availableDurationMs: Long,
102+
maxDurationMs: Long
103+
) {
104+
circleWidth = context.dimen(R.dimen.record_button_circle_progress_width)
105+
animator.duration = maxDurationMs
106+
animator.cancel()
107+
animator.currentPlayTime = maxDurationMs - availableDurationMs
108+
}
109+
110+
fun stopAnimation() {
111+
circleWidth = context.dimen(R.dimen.record_button_circle_idle_width)
112+
animator.cancel()
113+
gradientSweepAngle = 0F
114+
invalidate()
115+
}
116+
117+
fun pauseAnimation() {
118+
animator.pause()
119+
}
120+
121+
fun resumeAnimation() {
122+
animator.start()
123+
}
124+
}

0 commit comments

Comments
 (0)