mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Added monetization tutorial and added tutorial descriptions.
This commit is contained in:
parent
788c54bf8f
commit
689766a6ac
9 changed files with 186 additions and 54 deletions
|
@ -67,7 +67,7 @@ class TutorialFragment : MainFragment() {
|
|||
|
||||
addView(createHeader("Initial setup"))
|
||||
initialSetupVideos.forEach {
|
||||
addView(createTutorialPill(R.drawable.ic_movie, it.name).apply {
|
||||
addView(createTutorialPill(R.drawable.ic_movie, it.name, it.description).apply {
|
||||
onClick.subscribe {
|
||||
fragment.navigate<VideoDetailFragment>(it)
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class TutorialFragment : MainFragment() {
|
|||
|
||||
addView(createHeader("Features"))
|
||||
featuresVideos.forEach {
|
||||
addView(createTutorialPill(R.drawable.ic_movie, it.name).apply {
|
||||
addView(createTutorialPill(R.drawable.ic_movie, it.name, it.description).apply {
|
||||
onClick.subscribe {
|
||||
fragment.navigate<VideoDetailFragment>(it)
|
||||
}
|
||||
|
@ -95,10 +95,11 @@ class TutorialFragment : MainFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
private fun createTutorialPill(iconPrefix: Int, t: String): WidePillButton {
|
||||
private fun createTutorialPill(iconPrefix: Int, t: String, d: String): WidePillButton {
|
||||
return WidePillButton(context).apply {
|
||||
setIconPrefix(iconPrefix)
|
||||
setText(t)
|
||||
setDescription(d)
|
||||
setIconSuffix(R.drawable.ic_play_notif)
|
||||
layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT).apply {
|
||||
setMargins(15.dp(resources), 0, 15.dp(resources), 12.dp(resources))
|
||||
|
@ -163,7 +164,7 @@ class TutorialFragment : MainFragment() {
|
|||
TutorialVideo(
|
||||
uuid = "3b99ebfe-2640-4643-bfe0-a0cf04261fc5",
|
||||
name = "Getting started",
|
||||
description = "Learn how to get started with Grayjay.",
|
||||
description = "Learn how to get started with Grayjay. How do you install plugins?",
|
||||
thumbnailUrl = "https://releases.grayjay.app/tutorials/getting-started.jpg",
|
||||
videoUrl = "https://releases.grayjay.app/tutorials/getting-started.mp4",
|
||||
duration = 50
|
||||
|
@ -171,7 +172,7 @@ class TutorialFragment : MainFragment() {
|
|||
TutorialVideo(
|
||||
uuid = "793aa009-516c-4581-b82f-a8efdfef4c27",
|
||||
name = "Is Grayjay free?",
|
||||
description = "Learn how Grayjay is monetized.",
|
||||
description = "Learn how Grayjay is monetized. How do we make money?",
|
||||
thumbnailUrl = "https://releases.grayjay.app/tutorials/pay.jpg",
|
||||
videoUrl = "https://releases.grayjay.app/tutorials/pay.mp4",
|
||||
duration = 52
|
||||
|
@ -182,7 +183,7 @@ class TutorialFragment : MainFragment() {
|
|||
TutorialVideo(
|
||||
uuid = "d2238d88-4252-4a91-a12d-b90c049bb7cf",
|
||||
name = "Searching",
|
||||
description = "Learn about searching in Grayjay.",
|
||||
description = "Learn about searching in Grayjay. How can I find channels, videos or playlists?",
|
||||
thumbnailUrl = "https://releases.grayjay.app/tutorials/search.jpg",
|
||||
videoUrl = "https://releases.grayjay.app/tutorials/search.mp4",
|
||||
duration = 39
|
||||
|
@ -198,10 +199,18 @@ class TutorialFragment : MainFragment() {
|
|||
TutorialVideo(
|
||||
uuid = "94d36959-e3fc-4c24-a988-89147067a179",
|
||||
name = "Casting",
|
||||
description = "Learn about casting in Grayjay.",
|
||||
description = "Learn about casting in Grayjay. How do I show video on my TV?",
|
||||
thumbnailUrl = "https://releases.grayjay.app/tutorials/how-to-cast.jpg",
|
||||
videoUrl = "https://releases.grayjay.app/tutorials/how-to-cast.mp4",
|
||||
duration = 79
|
||||
),
|
||||
TutorialVideo(
|
||||
uuid = "5128c2e3-852b-4281-869b-efea2ec82a0e",
|
||||
name = "Monetization",
|
||||
description = "How can I monetize as a creator?",
|
||||
thumbnailUrl = "https://releases.grayjay.app/tutorials/monetization.jpg",
|
||||
videoUrl = "https://releases.grayjay.app/tutorials/monetization.mp4",
|
||||
duration = 47
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import android.util.AttributeSet
|
|||
import android.view.GestureDetector
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MotionEvent
|
||||
import android.view.ScaleGestureDetector
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
|
@ -24,6 +25,7 @@ import com.futo.platformplayer.R
|
|||
import com.futo.platformplayer.Settings
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.constructs.Event2
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.views.others.CircularProgressBar
|
||||
import kotlinx.coroutines.CancellationException
|
||||
|
@ -74,10 +76,19 @@ class GestureControlView : LinearLayout {
|
|||
private var _fullScreenFactorUp = 1.0f;
|
||||
private var _fullScreenFactorDown = 1.0f;
|
||||
|
||||
private var _scaleGestureDetector: ScaleGestureDetector
|
||||
private var _scaleFactor = 1.0f
|
||||
private var _translationX = 0.0f
|
||||
private var _translationY = 0.0f
|
||||
private val _layoutControlsZoom: FrameLayout
|
||||
private val _textZoom: TextView
|
||||
|
||||
private val _gestureController: GestureDetectorCompat;
|
||||
|
||||
val onSeek = Event1<Long>();
|
||||
val onBrightnessAdjusted = Event1<Float>();
|
||||
val onPan = Event2<Float, Float>();
|
||||
val onZoom = Event1<Float>();
|
||||
val onSoundAdjusted = Event1<Float>();
|
||||
val onToggleFullscreen = Event0();
|
||||
|
||||
|
@ -95,9 +106,27 @@ class GestureControlView : LinearLayout {
|
|||
_layoutControlsSound = findViewById(R.id.layout_controls_sound);
|
||||
_progressSound = findViewById(R.id.progress_sound);
|
||||
_layoutControlsBrightness = findViewById(R.id.layout_controls_brightness);
|
||||
_layoutControlsZoom = findViewById(R.id.layout_controls_zoom)
|
||||
_textZoom = findViewById(R.id.text_zoom)
|
||||
_progressBrightness = findViewById(R.id.progress_brightness);
|
||||
_layoutControlsFullscreen = findViewById(R.id.layout_controls_fullscreen);
|
||||
|
||||
_scaleGestureDetector = ScaleGestureDetector(context, object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||
override fun onScale(detector: ScaleGestureDetector): Boolean {
|
||||
Logger.i(TAG, "onScale _scaleFactor $_scaleFactor sf " + detector.scaleFactor.toString())
|
||||
_scaleFactor = (_scaleFactor + detector.scaleFactor - 1.0f).coerceAtLeast(1.0f).coerceAtMost(5.0f)
|
||||
onZoom.emit(_scaleFactor)
|
||||
|
||||
_translationX = _translationX.coerceAtLeast(-height / _scaleFactor)
|
||||
_translationY = _translationY.coerceAtLeast(-width / _scaleFactor)
|
||||
onPan.emit(_translationX, _translationY)
|
||||
|
||||
_layoutControlsZoom.visibility = View.VISIBLE
|
||||
_textZoom.text = "${String.format("%.1f", _scaleFactor)}x"
|
||||
return true
|
||||
}
|
||||
})
|
||||
|
||||
_gestureController = GestureDetectorCompat(context, object : GestureDetector.OnGestureListener {
|
||||
override fun onDown(p0: MotionEvent): Boolean { return false; }
|
||||
override fun onShowPress(p0: MotionEvent) = Unit;
|
||||
|
@ -107,41 +136,53 @@ class GestureControlView : LinearLayout {
|
|||
if(p0 == null)
|
||||
return false;
|
||||
|
||||
val minDistance = Math.min(width, height)
|
||||
if (_isFullScreen && _adjustingBrightness) {
|
||||
val adjustAmount = (distanceY * 2) / minDistance;
|
||||
_brightnessFactor = (_brightnessFactor + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_progressBrightness.progress = _brightnessFactor;
|
||||
onBrightnessAdjusted.emit(_brightnessFactor);
|
||||
} else if (_isFullScreen && _adjustingSound) {
|
||||
val adjustAmount = (distanceY * 2) / minDistance;
|
||||
_soundFactor = (_soundFactor + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_progressSound.progress = _soundFactor;
|
||||
onSoundAdjusted.emit(_soundFactor);
|
||||
} else if (_adjustingFullscreenUp) {
|
||||
val adjustAmount = (distanceY * 2) / minDistance;
|
||||
_fullScreenFactorUp = (_fullScreenFactorUp + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_layoutControlsFullscreen.alpha = _fullScreenFactorUp;
|
||||
} else if (_adjustingFullscreenDown) {
|
||||
val adjustAmount = (-distanceY * 2) / minDistance;
|
||||
_fullScreenFactorDown = (_fullScreenFactorDown + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_layoutControlsFullscreen.alpha = _fullScreenFactorDown;
|
||||
} else {
|
||||
val rx = (p0.x + p1.x) / (2 * width);
|
||||
val ry = (p0.y + p1.y) / (2 * height);
|
||||
if (ry > 0.1 && ry < 0.9) {
|
||||
if (Settings.instance.gestureControls.brightnessSlider && _isFullScreen && rx < 0.2) {
|
||||
startAdjustingBrightness();
|
||||
} else if (Settings.instance.gestureControls.volumeSlider && _isFullScreen && rx > 0.8) {
|
||||
startAdjustingSound();
|
||||
} else if (Settings.instance.gestureControls.toggleFullscreen && fullScreenGestureEnabled && rx in 0.3..0.7) {
|
||||
if (_isFullScreen) {
|
||||
startAdjustingFullscreenDown();
|
||||
} else {
|
||||
startAdjustingFullscreenUp();
|
||||
Logger.i(TAG, "p0.pointerCount: " + p0.pointerCount)
|
||||
|
||||
if (p1.pointerCount == 1) {
|
||||
val minDistance = Math.min(width, height)
|
||||
if (_isFullScreen && _adjustingBrightness) {
|
||||
val adjustAmount = (distanceY * 2) / minDistance;
|
||||
_brightnessFactor = (_brightnessFactor + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_progressBrightness.progress = _brightnessFactor;
|
||||
onBrightnessAdjusted.emit(_brightnessFactor);
|
||||
} else if (_isFullScreen && _adjustingSound) {
|
||||
val adjustAmount = (distanceY * 2) / minDistance;
|
||||
_soundFactor = (_soundFactor + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_progressSound.progress = _soundFactor;
|
||||
onSoundAdjusted.emit(_soundFactor);
|
||||
} else if (_adjustingFullscreenUp) {
|
||||
val adjustAmount = (distanceY * 2) / minDistance;
|
||||
_fullScreenFactorUp = (_fullScreenFactorUp + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_layoutControlsFullscreen.alpha = _fullScreenFactorUp;
|
||||
} else if (_adjustingFullscreenDown) {
|
||||
val adjustAmount = (-distanceY * 2) / minDistance;
|
||||
_fullScreenFactorDown = (_fullScreenFactorDown + adjustAmount).coerceAtLeast(0.0f).coerceAtMost(1.0f);
|
||||
_layoutControlsFullscreen.alpha = _fullScreenFactorDown;
|
||||
} else if (p0.pointerCount == 1) {
|
||||
val rx = (p0.x + p1.x) / (2 * width);
|
||||
val ry = (p0.y + p1.y) / (2 * height);
|
||||
if (ry > 0.1 && ry < 0.9) {
|
||||
if (Settings.instance.gestureControls.brightnessSlider && _isFullScreen && rx < 0.2) {
|
||||
startAdjustingBrightness();
|
||||
} else if (Settings.instance.gestureControls.volumeSlider && _isFullScreen && rx > 0.8) {
|
||||
startAdjustingSound();
|
||||
} else if (Settings.instance.gestureControls.toggleFullscreen && fullScreenGestureEnabled && rx in 0.3..0.7) {
|
||||
if (_isFullScreen) {
|
||||
startAdjustingFullscreenDown();
|
||||
} else {
|
||||
startAdjustingFullscreenUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_isFullScreen) {
|
||||
stopAllGestures()
|
||||
|
||||
_translationX = (_translationX - distanceX).coerceAtLeast(-height / _scaleFactor)
|
||||
_translationY = (_translationY - distanceY).coerceAtLeast(-width / _scaleFactor)
|
||||
|
||||
Logger.i(TAG, "onPan " + _translationX.toString() + ", " + _translationY.toString())
|
||||
onPan.emit(_translationX, _translationY)
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -227,9 +268,14 @@ class GestureControlView : LinearLayout {
|
|||
stopAdjustingFullscreenDown();
|
||||
}
|
||||
|
||||
if (_layoutControlsZoom.visibility == View.VISIBLE && ev.action == MotionEvent.ACTION_UP) {
|
||||
_layoutControlsZoom.visibility = View.GONE
|
||||
}
|
||||
|
||||
startHideJobIfNecessary();
|
||||
|
||||
_gestureController.onTouchEvent(ev)
|
||||
_scaleGestureDetector.onTouchEvent(ev)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -562,6 +608,12 @@ class GestureControlView : LinearLayout {
|
|||
}
|
||||
|
||||
fun setFullscreen(isFullScreen: Boolean) {
|
||||
_scaleFactor = 1.0f
|
||||
onZoom.emit(_scaleFactor)
|
||||
_translationX = 0f
|
||||
_translationY = 0f
|
||||
onPan.emit(_translationX, _translationY)
|
||||
|
||||
if (isFullScreen) {
|
||||
val c = context
|
||||
if (c is Activity && Settings.instance.gestureControls.useSystemBrightness) {
|
||||
|
|
|
@ -14,6 +14,7 @@ class WidePillButton : LinearLayout {
|
|||
private val _iconPrefix: ImageView
|
||||
private val _iconSuffix: ImageView
|
||||
private val _text: TextView
|
||||
private val _textDescription: TextView
|
||||
val onClick = Event0()
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) {
|
||||
|
@ -21,11 +22,13 @@ class WidePillButton : LinearLayout {
|
|||
_iconPrefix = findViewById(R.id.image_prefix)
|
||||
_iconSuffix = findViewById(R.id.image_suffix)
|
||||
_text = findViewById(R.id.text)
|
||||
_textDescription = findViewById(R.id.text_description)
|
||||
|
||||
val attrArr = context.obtainStyledAttributes(attrs, R.styleable.WidePillButton, 0, 0)
|
||||
setIconPrefix(attrArr.getResourceId(R.styleable.WidePillButton_widePillIconPrefix, -1))
|
||||
setIconSuffix(attrArr.getResourceId(R.styleable.WidePillButton_widePillIconSuffix, -1))
|
||||
setText(attrArr.getText(R.styleable.PillButton_pillText) ?: "")
|
||||
setText(attrArr.getText(R.styleable.WidePillButton_widePillText) ?: "")
|
||||
setDescription(attrArr.getText(R.styleable.WidePillButton_widePillDescription))
|
||||
attrArr.recycle()
|
||||
|
||||
findViewById<LinearLayout>(R.id.root).setOnClickListener {
|
||||
|
@ -54,4 +57,13 @@ class WidePillButton : LinearLayout {
|
|||
fun setText(t: CharSequence) {
|
||||
_text.text = t
|
||||
}
|
||||
|
||||
fun setDescription(t: CharSequence?) {
|
||||
if (!t.isNullOrEmpty()) {
|
||||
_textDescription.visibility = View.VISIBLE
|
||||
_textDescription.text = t
|
||||
} else {
|
||||
_textDescription.visibility= View.GONE
|
||||
}
|
||||
}
|
||||
}
|
|
@ -263,6 +263,14 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
}
|
||||
}
|
||||
};
|
||||
gestureControl.onPan.subscribe { x, y ->
|
||||
_videoView.translationX = x
|
||||
_videoView.translationY = y
|
||||
}
|
||||
gestureControl.onZoom.subscribe {
|
||||
_videoView.scaleX = it
|
||||
_videoView.scaleY = it
|
||||
}
|
||||
|
||||
if(!isInEditMode) {
|
||||
_videoView.resizeMode = AspectRatioFrameLayout.RESIZE_MODE_ZOOM;
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#2A2A2A" />
|
||||
<corners android:radius="25dp" />
|
||||
<size android:height="20dp" />
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
</shape>
|
|
@ -152,4 +152,29 @@
|
|||
android:textSize="16dp"/>
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/layout_controls_zoom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
android:background="@drawable/background_gesture_controls"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_zoom"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
tools:text="@string/zoom"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16dp"/>
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -3,7 +3,7 @@
|
|||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="50dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="7dp"
|
||||
android:paddingStart="7dp"
|
||||
|
@ -21,19 +21,36 @@
|
|||
android:scaleType="fitCenter"
|
||||
app:srcCompat="@drawable/ic_thumb_up" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:gravity="center_vertical"
|
||||
android:fontFamily="@font/inter_light"
|
||||
tools:text="500K" />
|
||||
|
||||
<Space android:layout_height="match_parent"
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1" />
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="16sp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:fontFamily="@font/inter_light"
|
||||
tools:text="500K" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="#848484"
|
||||
android:textSize="16sp"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:fontFamily="@font/inter_light"
|
||||
tools:text="500K" />
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/image_suffix"
|
||||
|
|
|
@ -739,6 +739,7 @@
|
|||
<string name="do_you_want_to_see_the_tutorials_you_can_find_them_at_any_time_through_the_more_button">Do you want to see the tutorials? You can find them at any time through the more button.</string>
|
||||
<string name="add_creator">Add Creators</string>
|
||||
<string name="select">Select</string>
|
||||
<string name="zoom">Zoom</string>
|
||||
<string-array name="home_screen_array">
|
||||
<item>Recommendations</item>
|
||||
<item>Subscriptions</item>
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
<resources>
|
||||
<declare-styleable name="WidePillButton">
|
||||
<attr name="widePillIconPrefix" format="reference" />
|
||||
<attr name="widePilllText" format="string" />
|
||||
<attr name="widePillText" format="string" />
|
||||
<attr name="widePillDescription" format="string" />
|
||||
<attr name="widePillIconSuffix" format="reference" />
|
||||
</declare-styleable>
|
||||
</resources>
|
Loading…
Add table
Reference in a new issue