mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-08-03 14:50:49 +00:00
Loop support, Improve add to queue behavior, home retry, fix history search pager, defaults progressbar
This commit is contained in:
parent
58da91eae8
commit
b284176072
13 changed files with 123 additions and 7 deletions
|
@ -181,7 +181,7 @@ class Settings : FragmentedStorageFileJson() {
|
||||||
|
|
||||||
|
|
||||||
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
||||||
var progressBar: Boolean = false;
|
var progressBar: Boolean = true;
|
||||||
|
|
||||||
|
|
||||||
@FormField(R.string.clear_hidden, FieldForm.BUTTON, R.string.clear_hidden_description, 8)
|
@FormField(R.string.clear_hidden, FieldForm.BUTTON, R.string.clear_hidden_description, 8)
|
||||||
|
@ -212,7 +212,7 @@ class Settings : FragmentedStorageFileJson() {
|
||||||
var previewFeedItems: Boolean = true;
|
var previewFeedItems: Boolean = true;
|
||||||
|
|
||||||
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
||||||
var progressBar: Boolean = false;
|
var progressBar: Boolean = true;
|
||||||
|
|
||||||
|
|
||||||
fun getSearchFeedStyle(): FeedStyle {
|
fun getSearchFeedStyle(): FeedStyle {
|
||||||
|
@ -230,7 +230,7 @@ class Settings : FragmentedStorageFileJson() {
|
||||||
class ChannelSettings {
|
class ChannelSettings {
|
||||||
|
|
||||||
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
||||||
var progressBar: Boolean = false;
|
var progressBar: Boolean = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@FormField(R.string.subscriptions, "group", R.string.configure_how_your_subscriptions_works_and_feels, 4)
|
@FormField(R.string.subscriptions, "group", R.string.configure_how_your_subscriptions_works_and_feels, 4)
|
||||||
|
@ -252,7 +252,7 @@ class Settings : FragmentedStorageFileJson() {
|
||||||
var previewFeedItems: Boolean = true;
|
var previewFeedItems: Boolean = true;
|
||||||
|
|
||||||
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
@FormField(R.string.progress_bar, FieldForm.TOGGLE, R.string.progress_bar_description, 6)
|
||||||
var progressBar: Boolean = false;
|
var progressBar: Boolean = true;
|
||||||
|
|
||||||
@FormField(R.string.fetch_on_app_boot, FieldForm.TOGGLE, R.string.shortly_after_opening_the_app_start_fetching_subscriptions, 7)
|
@FormField(R.string.fetch_on_app_boot, FieldForm.TOGGLE, R.string.shortly_after_opening_the_app_start_fetching_subscriptions, 7)
|
||||||
@Serializable(with = FlexibleBooleanSerializer::class)
|
@Serializable(with = FlexibleBooleanSerializer::class)
|
||||||
|
|
|
@ -168,7 +168,7 @@ abstract class ContentFeedView<TFragment> : FeedView<TFragment, IPlatformContent
|
||||||
protected open fun onContentClicked(content: IPlatformContent, time: Long) {
|
protected open fun onContentClicked(content: IPlatformContent, time: Long) {
|
||||||
if(content is IPlatformVideo) {
|
if(content is IPlatformVideo) {
|
||||||
if (StatePlayer.instance.hasQueue) {
|
if (StatePlayer.instance.hasQueue) {
|
||||||
StatePlayer.instance.addToQueue(content)
|
StatePlayer.instance.insertToQueue(content, true);
|
||||||
} else {
|
} else {
|
||||||
if (Settings.instance.playback.shouldResumePreview(time))
|
if (Settings.instance.playback.shouldResumePreview(time))
|
||||||
fragment.navigate<VideoDetailFragment>(content.withTimestamp(time)).maximizeVideoDetail();
|
fragment.navigate<VideoDetailFragment>(content.withTimestamp(time)).maximizeVideoDetail();
|
||||||
|
|
|
@ -18,6 +18,7 @@ import com.futo.platformplayer.*
|
||||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||||
import com.futo.platformplayer.api.media.structures.IAsyncPager
|
import com.futo.platformplayer.api.media.structures.IAsyncPager
|
||||||
import com.futo.platformplayer.api.media.structures.IPager
|
import com.futo.platformplayer.api.media.structures.IPager
|
||||||
|
import com.futo.platformplayer.api.media.structures.PlatformContentPager
|
||||||
import com.futo.platformplayer.constructs.TaskHandler
|
import com.futo.platformplayer.constructs.TaskHandler
|
||||||
import com.futo.platformplayer.logging.Logger
|
import com.futo.platformplayer.logging.Logger
|
||||||
import com.futo.platformplayer.models.HistoryVideo
|
import com.futo.platformplayer.models.HistoryVideo
|
||||||
|
@ -181,6 +182,7 @@ class HistoryFragment : MainFragment() {
|
||||||
val query = _editSearch.text.toString();
|
val query = _editSearch.text.toString();
|
||||||
if (_editSearch.text.isNotEmpty()) {
|
if (_editSearch.text.isNotEmpty()) {
|
||||||
setPager(StateHistory.instance.getHistorySearchPager(query));
|
setPager(StateHistory.instance.getHistorySearchPager(query));
|
||||||
|
//setPager(StateHistory.instance.getHistorySearchPager(query));
|
||||||
} else {
|
} else {
|
||||||
setPager(StateHistory.instance.getHistoryPager());
|
setPager(StateHistory.instance.getHistoryPager());
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ class StateHistory {
|
||||||
return _historyDBStore.getObjectPager();
|
return _historyDBStore.getObjectPager();
|
||||||
}
|
}
|
||||||
fun getHistorySearchPager(query: String): IPager<HistoryVideo> {
|
fun getHistorySearchPager(query: String): IPager<HistoryVideo> {
|
||||||
return _historyDBStore.queryLikeObjectPager(DBHistory.Index::url, "%${query}%", 10);
|
return _historyDBStore.queryLikeObjectPager(DBHistory.Index::name, "%${query}%", 10);
|
||||||
}
|
}
|
||||||
fun getHistoryIndexByUrl(url: String): DBHistory.Index? {
|
fun getHistoryIndexByUrl(url: String): DBHistory.Index? {
|
||||||
return historyIndex[url];
|
return historyIndex[url];
|
||||||
|
|
|
@ -40,6 +40,7 @@ import com.futo.platformplayer.models.ImageVariable
|
||||||
import com.futo.platformplayer.stores.*
|
import com.futo.platformplayer.stores.*
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import okhttp3.internal.concat
|
import okhttp3.internal.concat
|
||||||
|
import java.lang.Thread.sleep
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap.PlatformMutabilityMapping
|
import kotlin.reflect.jvm.internal.impl.builtins.jvm.JavaToKotlinClassMap.PlatformMutabilityMapping
|
||||||
import kotlin.streams.asSequence
|
import kotlin.streams.asSequence
|
||||||
|
@ -405,7 +406,12 @@ class StatePlatform {
|
||||||
val deferred: List<Pair<IPlatformClient, Deferred<IPager<IPlatformContent>?>>> = clients.map {
|
val deferred: List<Pair<IPlatformClient, Deferred<IPager<IPlatformContent>?>>> = clients.map {
|
||||||
return@map Pair(it, scope.async(Dispatchers.IO) {
|
return@map Pair(it, scope.async(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val searchResult = it.fromPool(_pagerClientPool).getHome();
|
var searchResult = it.fromPool(_pagerClientPool).getHome();
|
||||||
|
if(searchResult.getResults().size == 0) {
|
||||||
|
Logger.i(TAG, "No home results, retrying");
|
||||||
|
sleep(500);
|
||||||
|
searchResult = it.fromPool(_pagerClientPool).getHome();
|
||||||
|
}
|
||||||
return@async searchResult;
|
return@async searchResult;
|
||||||
} catch(ex: Throwable) {
|
} catch(ex: Throwable) {
|
||||||
Logger.e(TAG, "getHomeRefresh", ex);
|
Logger.e(TAG, "getHomeRefresh", ex);
|
||||||
|
|
|
@ -37,6 +37,7 @@ class StatePlayer {
|
||||||
|
|
||||||
//Video Status
|
//Video Status
|
||||||
var rotationLock : Boolean = false;
|
var rotationLock : Boolean = false;
|
||||||
|
var loopVideo : Boolean = false;
|
||||||
|
|
||||||
val isPlaying: Boolean get() = _exoplayer?.player?.playWhenReady ?: false;
|
val isPlaying: Boolean get() = _exoplayer?.player?.playWhenReady ?: false;
|
||||||
|
|
||||||
|
@ -286,6 +287,31 @@ class StatePlayer {
|
||||||
}
|
}
|
||||||
onQueueChanged.emit(true);
|
onQueueChanged.emit(true);
|
||||||
}
|
}
|
||||||
|
fun insertToQueue(video: IPlatformVideo, playNow: Boolean = false) {
|
||||||
|
synchronized(_queue) {
|
||||||
|
if(_queue.isEmpty()) {
|
||||||
|
setQueueType(TYPE_QUEUE);
|
||||||
|
currentVideo?.let {
|
||||||
|
_queue.add(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(_queue.isEmpty())
|
||||||
|
_queue.add(video);
|
||||||
|
else
|
||||||
|
_queue.add(_queuePosition.coerceAtLeast(0).coerceAtMost(_queue.size - 1), video);
|
||||||
|
|
||||||
|
if (queueShuffle) {
|
||||||
|
addToShuffledQueue(video);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_queuePosition < 0) {
|
||||||
|
_queuePosition = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onQueueChanged.emit(true);
|
||||||
|
if(playNow)
|
||||||
|
setQueuePosition(video);
|
||||||
|
}
|
||||||
fun setQueuePosition(video: IPlatformVideo) {
|
fun setQueuePosition(video: IPlatformVideo) {
|
||||||
synchronized(_queue) {
|
synchronized(_queue) {
|
||||||
if (getCurrentQueueItem() == video) {
|
if (getCurrentQueueItem() == video) {
|
||||||
|
@ -348,6 +374,8 @@ class StatePlayer {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNextQueueItem() : IPlatformVideo? {
|
fun getNextQueueItem() : IPlatformVideo? {
|
||||||
|
if(loopVideo)
|
||||||
|
return currentVideo;
|
||||||
synchronized(_queue) {
|
synchronized(_queue) {
|
||||||
val shuffledQueue = _queueShuffled;
|
val shuffledQueue = _queueShuffled;
|
||||||
val queue = if (queueShuffle && shuffledQueue != null) {
|
val queue = if (queueShuffle && shuffledQueue != null) {
|
||||||
|
@ -375,6 +403,8 @@ class StatePlayer {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
fun nextQueueItem(withoutRemoval: Boolean = false) : IPlatformVideo? {
|
fun nextQueueItem(withoutRemoval: Boolean = false) : IPlatformVideo? {
|
||||||
|
if(loopVideo)
|
||||||
|
return currentVideo;
|
||||||
synchronized(_queue) {
|
synchronized(_queue) {
|
||||||
if (_queue.isEmpty())
|
if (_queue.isEmpty())
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -26,6 +26,7 @@ class CastView : ConstraintLayout {
|
||||||
private val _thumbnail: ImageView;
|
private val _thumbnail: ImageView;
|
||||||
private val _buttonMinimize: ImageButton;
|
private val _buttonMinimize: ImageButton;
|
||||||
private val _buttonSettings: ImageButton;
|
private val _buttonSettings: ImageButton;
|
||||||
|
private val _buttonLoop: ImageButton;
|
||||||
private val _buttonPlay: ImageButton;
|
private val _buttonPlay: ImageButton;
|
||||||
private val _buttonPause: ImageButton;
|
private val _buttonPause: ImageButton;
|
||||||
private val _buttonCast: CastButton;
|
private val _buttonCast: CastButton;
|
||||||
|
@ -49,6 +50,7 @@ class CastView : ConstraintLayout {
|
||||||
_thumbnail = findViewById(R.id.image_thumbnail);
|
_thumbnail = findViewById(R.id.image_thumbnail);
|
||||||
_buttonMinimize = findViewById(R.id.button_minimize);
|
_buttonMinimize = findViewById(R.id.button_minimize);
|
||||||
_buttonSettings = findViewById(R.id.button_settings);
|
_buttonSettings = findViewById(R.id.button_settings);
|
||||||
|
_buttonLoop = findViewById(R.id.button_loop);
|
||||||
_buttonPlay = findViewById(R.id.button_play);
|
_buttonPlay = findViewById(R.id.button_play);
|
||||||
_buttonPause = findViewById(R.id.button_pause);
|
_buttonPause = findViewById(R.id.button_pause);
|
||||||
_buttonCast = findViewById(R.id.button_cast);
|
_buttonCast = findViewById(R.id.button_cast);
|
||||||
|
@ -65,6 +67,12 @@ class CastView : ConstraintLayout {
|
||||||
StateCasting.instance.videoSeekTo(d.expectedCurrentTime + it / 1000);
|
StateCasting.instance.videoSeekTo(d.expectedCurrentTime + it / 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_buttonLoop.setOnClickListener {
|
||||||
|
StatePlayer.instance.loopVideo = !StatePlayer.instance.loopVideo;
|
||||||
|
_buttonLoop.setImageResource(if(StatePlayer.instance.loopVideo) R.drawable.ic_loop_active else R.drawable.ic_loop);
|
||||||
|
}
|
||||||
|
_buttonLoop.setImageResource(if(StatePlayer.instance.loopVideo) R.drawable.ic_loop_active else R.drawable.ic_loop);
|
||||||
|
|
||||||
_timeBar.addListener(object : OnScrubListener {
|
_timeBar.addListener(object : OnScrubListener {
|
||||||
override fun onScrubStart(timeBar: TimeBar, position: Long) {
|
override fun onScrubStart(timeBar: TimeBar, position: Long) {
|
||||||
StateCasting.instance.videoSeekTo(position.toDouble());
|
StateCasting.instance.videoSeekTo(position.toDouble());
|
||||||
|
|
|
@ -68,6 +68,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
private val _control_videosettings: ImageButton;
|
private val _control_videosettings: ImageButton;
|
||||||
private val _control_minimize: ImageButton;
|
private val _control_minimize: ImageButton;
|
||||||
private val _control_rotate_lock: ImageButton;
|
private val _control_rotate_lock: ImageButton;
|
||||||
|
private val _control_loop: ImageButton;
|
||||||
private val _control_cast: ImageButton;
|
private val _control_cast: ImageButton;
|
||||||
private val _control_play: ImageButton;
|
private val _control_play: ImageButton;
|
||||||
private val _control_chapter: TextView;
|
private val _control_chapter: TextView;
|
||||||
|
@ -77,6 +78,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
private val _control_videosettings_fullscreen: ImageButton;
|
private val _control_videosettings_fullscreen: ImageButton;
|
||||||
private val _control_minimize_fullscreen: ImageButton;
|
private val _control_minimize_fullscreen: ImageButton;
|
||||||
private val _control_rotate_lock_fullscreen: ImageButton;
|
private val _control_rotate_lock_fullscreen: ImageButton;
|
||||||
|
private val _control_loop_fullscreen: ImageButton;
|
||||||
private val _control_cast_fullscreen: ImageButton;
|
private val _control_cast_fullscreen: ImageButton;
|
||||||
private val _control_play_fullscreen: ImageButton;
|
private val _control_play_fullscreen: ImageButton;
|
||||||
private val _time_bar_fullscreen: TimeBar;
|
private val _time_bar_fullscreen: TimeBar;
|
||||||
|
@ -128,6 +130,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
_control_videosettings = videoControls.findViewById(R.id.exo_settings);
|
_control_videosettings = videoControls.findViewById(R.id.exo_settings);
|
||||||
_control_minimize = videoControls.findViewById(R.id.exo_minimize);
|
_control_minimize = videoControls.findViewById(R.id.exo_minimize);
|
||||||
_control_rotate_lock = videoControls.findViewById(R.id.exo_rotate_lock);
|
_control_rotate_lock = videoControls.findViewById(R.id.exo_rotate_lock);
|
||||||
|
_control_loop = videoControls.findViewById(R.id.exo_loop);
|
||||||
_control_cast = videoControls.findViewById(R.id.exo_cast);
|
_control_cast = videoControls.findViewById(R.id.exo_cast);
|
||||||
_control_play = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
_control_play = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
||||||
_time_bar = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
|
_time_bar = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_progress);
|
||||||
|
@ -138,6 +141,7 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
_control_minimize_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_minimize);
|
_control_minimize_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_minimize);
|
||||||
_control_videosettings_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_settings);
|
_control_videosettings_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_settings);
|
||||||
_control_rotate_lock_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_rotate_lock);
|
_control_rotate_lock_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_rotate_lock);
|
||||||
|
_control_loop_fullscreen = videoControls.findViewById(R.id.exo_loop);
|
||||||
_control_cast_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_cast);
|
_control_cast_fullscreen = _videoControls_fullscreen.findViewById(R.id.exo_cast);
|
||||||
_control_play_fullscreen = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
_control_play_fullscreen = videoControls.findViewById(com.google.android.exoplayer2.ui.R.id.exo_play);
|
||||||
_control_chapter_fullscreen = _videoControls_fullscreen.findViewById(R.id.text_chapter_current);
|
_control_chapter_fullscreen = _videoControls_fullscreen.findViewById(R.id.text_chapter_current);
|
||||||
|
@ -244,6 +248,16 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
UIDialogs.showCastingDialog(context);
|
UIDialogs.showCastingDialog(context);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
_control_loop.setOnClickListener {
|
||||||
|
StatePlayer.instance.loopVideo = !StatePlayer.instance.loopVideo;
|
||||||
|
updateLoopVideoUI();
|
||||||
|
}
|
||||||
|
_control_loop_fullscreen.setOnClickListener {
|
||||||
|
StatePlayer.instance.loopVideo = !StatePlayer.instance.loopVideo;
|
||||||
|
updateLoopVideoUI();
|
||||||
|
}
|
||||||
|
|
||||||
_control_minimize_fullscreen.setOnClickListener {
|
_control_minimize_fullscreen.setOnClickListener {
|
||||||
onMinimize.emit(this);
|
onMinimize.emit(this);
|
||||||
};
|
};
|
||||||
|
@ -273,6 +287,8 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateLoopVideoUI();
|
||||||
|
|
||||||
if(!isInEditMode) {
|
if(!isInEditMode) {
|
||||||
gestureControl.hideControls();
|
gestureControl.hideControls();
|
||||||
}
|
}
|
||||||
|
@ -555,6 +571,17 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
||||||
_control_rotate_lock.setImageResource(R.drawable.ic_screen_lock_rotation);
|
_control_rotate_lock.setImageResource(R.drawable.ic_screen_lock_rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fun updateLoopVideoUI() {
|
||||||
|
if(StatePlayer.instance.loopVideo) {
|
||||||
|
_control_loop.setImageResource(R.drawable.ic_loop_active);
|
||||||
|
_control_loop_fullscreen.setImageResource(R.drawable.ic_loop_active);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_control_loop.setImageResource(R.drawable.ic_loop);
|
||||||
|
_control_loop_fullscreen.setImageResource(R.drawable.ic_loop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
fun setGestureSoundFactor(soundFactor: Float) {
|
fun setGestureSoundFactor(soundFactor: Float) {
|
||||||
gestureControl.setSoundFactor(soundFactor);
|
gestureControl.setSoundFactor(soundFactor);
|
||||||
|
|
9
app/src/main/res/drawable/ic_loop.xml
Normal file
9
app/src/main/res/drawable/ic_loop.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M292.31,840L160,707.69L292.31,575.39L320.61,604.15L237.08,687.69L692.31,687.69L692.31,527.69L732.31,527.69L732.31,727.69L237.08,727.69L320.61,811.23L292.31,840ZM227.69,432.31L227.69,232.31L722.92,232.31L639.39,148.77L667.69,120L800,252.31L667.69,384.61L639.39,355.85L722.92,272.31L267.69,272.31L267.69,432.31L227.69,432.31Z"/>
|
||||||
|
</vector>
|
9
app/src/main/res/drawable/ic_loop_active.xml
Normal file
9
app/src/main/res/drawable/ic_loop_active.xml
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="960"
|
||||||
|
android:viewportHeight="960">
|
||||||
|
<path
|
||||||
|
android:fillColor="@color/colorPrimary"
|
||||||
|
android:pathData="M292.31,840L160,707.69L292.31,575.39L320.61,604.15L237.08,687.69L692.31,687.69L692.31,527.69L732.31,527.69L732.31,727.69L237.08,727.69L320.61,811.23L292.31,840ZM227.69,432.31L227.69,232.31L722.92,232.31L639.39,148.77L667.69,120L800,252.31L667.69,384.61L639.39,355.85L722.92,272.31L267.69,272.31L267.69,432.31L227.69,432.31Z"/>
|
||||||
|
</vector>
|
|
@ -45,6 +45,14 @@
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
app:srcCompat="@drawable/ic_screen_lock_rotation" />
|
app:srcCompat="@drawable/ic_screen_lock_rotation" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_loop"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:srcCompat="@drawable/ic_loop" />
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/exo_settings"
|
android:id="@+id/exo_settings"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
|
|
|
@ -73,6 +73,14 @@
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
app:srcCompat="@drawable/ic_screen_lock_rotation" />
|
app:srcCompat="@drawable/ic_screen_lock_rotation" />
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/exo_loop"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:srcCompat="@drawable/ic_loop" />
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/exo_settings"
|
android:id="@+id/exo_settings"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
|
|
|
@ -54,6 +54,15 @@
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:padding="12dp"
|
android:padding="12dp"
|
||||||
app:srcCompat="@drawable/ic_cast" />
|
app:srcCompat="@drawable/ic_cast" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/button_loop"
|
||||||
|
android:layout_width="50dp"
|
||||||
|
android:layout_height="50dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:clickable="true"
|
||||||
|
android:padding="12dp"
|
||||||
|
app:srcCompat="@drawable/ic_loop" />
|
||||||
<ImageButton
|
<ImageButton
|
||||||
android:id="@+id/button_settings"
|
android:id="@+id/button_settings"
|
||||||
android:layout_width="50dp"
|
android:layout_width="50dp"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue