mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
Merge branch 'master' of gitlab.futo.org:videostreaming/grayjay
This commit is contained in:
commit
7cdded8fd7
11 changed files with 259 additions and 115 deletions
|
@ -52,7 +52,7 @@
|
|||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
|
||||
android:exported="true"
|
||||
android:theme="@style/Theme.FutoVideo.NoActionBar"
|
||||
android:launchMode="singleTask"
|
||||
android:launchMode="singleInstance"
|
||||
android:resizeableActivity="true"
|
||||
android:supportsPictureInPicture="true">
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.graphics.Color
|
|||
import android.os.Bundle
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
||||
import android.view.KeyEvent
|
||||
import android.view.LayoutInflater
|
||||
import android.view.WindowManager
|
||||
import android.view.inputmethod.InputMethodManager
|
||||
|
@ -57,11 +58,21 @@ class CommentDialog(context: Context?, val contextUrl: String, val ref: Protocol
|
|||
_editComment = findViewById(R.id.edit_comment);
|
||||
_textCharacterCount = findViewById(R.id.character_count);
|
||||
_textCharacterCountMax = findViewById(R.id.character_count_max);
|
||||
setCanceledOnTouchOutside(false)
|
||||
setOnKeyListener { _, keyCode, event ->
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK && event.action == KeyEvent.ACTION_UP) {
|
||||
handleCloseAttempt()
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
_editComment.addTextChangedListener(object : TextWatcher {
|
||||
override fun afterTextChanged(s: Editable?) = Unit
|
||||
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
|
||||
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, c: Int) {
|
||||
val count = s?.length ?: 0;
|
||||
_textCharacterCount.text = count.toString();
|
||||
|
||||
if (count > PolycentricPlatformComment.MAX_COMMENT_SIZE) {
|
||||
|
@ -79,10 +90,13 @@ class CommentDialog(context: Context?, val contextUrl: String, val ref: Protocol
|
|||
_inputMethodManager = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
|
||||
|
||||
_buttonCancel.setOnClickListener {
|
||||
clearFocus();
|
||||
dismiss();
|
||||
handleCloseAttempt()
|
||||
};
|
||||
|
||||
setOnCancelListener {
|
||||
handleCloseAttempt()
|
||||
}
|
||||
|
||||
_buttonCreate.setOnClickListener {
|
||||
clearFocus();
|
||||
|
||||
|
@ -134,6 +148,22 @@ class CommentDialog(context: Context?, val contextUrl: String, val ref: Protocol
|
|||
focus();
|
||||
}
|
||||
|
||||
private fun handleCloseAttempt() {
|
||||
if (_editComment.text.isEmpty()) {
|
||||
clearFocus()
|
||||
dismiss()
|
||||
} else {
|
||||
UIDialogs.showConfirmationDialog(
|
||||
context,
|
||||
context.resources.getString(R.string.not_empty_close),
|
||||
action = {
|
||||
clearFocus()
|
||||
dismiss()
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun focus() {
|
||||
_editComment.requestFocus();
|
||||
window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
|
||||
|
|
|
@ -8,6 +8,7 @@ import android.widget.AdapterView
|
|||
import android.widget.ArrayAdapter
|
||||
import android.widget.EditText
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageButton
|
||||
import android.widget.Spinner
|
||||
import androidx.core.widget.addTextChangedListener
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
|
@ -25,11 +26,20 @@ class CreatorsFragment : MainFragment() {
|
|||
private var _overlayContainer: FrameLayout? = null;
|
||||
private var _containerSearch: FrameLayout? = null;
|
||||
private var _editSearch: EditText? = null;
|
||||
private var _buttonClearSearch: ImageButton? = null
|
||||
|
||||
override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val view = inflater.inflate(R.layout.fragment_creators, container, false);
|
||||
_containerSearch = view.findViewById(R.id.container_search);
|
||||
_editSearch = view.findViewById(R.id.edit_search);
|
||||
val editSearch: EditText = view.findViewById(R.id.edit_search);
|
||||
val buttonClearSearch: ImageButton = view.findViewById(R.id.button_clear_search)
|
||||
_editSearch = editSearch
|
||||
_buttonClearSearch = buttonClearSearch
|
||||
buttonClearSearch.setOnClickListener {
|
||||
editSearch.text.clear()
|
||||
editSearch.requestFocus()
|
||||
_buttonClearSearch?.visibility = View.INVISIBLE;
|
||||
}
|
||||
|
||||
val adapter = SubscriptionAdapter(inflater, getString(R.string.confirm_delete_subscription));
|
||||
adapter.onClick.subscribe { platformUser -> navigate<ChannelFragment>(platformUser) };
|
||||
|
@ -51,7 +61,12 @@ class CreatorsFragment : MainFragment() {
|
|||
_spinnerSortBy = spinnerSortBy;
|
||||
|
||||
_editSearch?.addTextChangedListener {
|
||||
adapter.query = it.toString();
|
||||
adapter.query = it.toString()
|
||||
if (it?.isEmpty() == true) {
|
||||
_buttonClearSearch?.visibility = View.INVISIBLE
|
||||
} else {
|
||||
_buttonClearSearch?.visibility = View.VISIBLE
|
||||
}
|
||||
}
|
||||
|
||||
val recyclerView = view.findViewById<RecyclerView>(R.id.recycler_subscriptions);
|
||||
|
|
|
@ -1799,8 +1799,13 @@ class VideoDetailView : ConstraintLayout {
|
|||
private fun onSourceChanged(videoSource: IVideoSource?, audioSource: IAudioSource?, resume: Boolean){
|
||||
Logger.i(TAG, "onSourceChanged(videoSource=$videoSource, audioSource=$audioSource, resume=$resume)")
|
||||
|
||||
if((videoSource == null || videoSource is LocalVideoSource) && (audioSource == null || audioSource is LocalAudioSource))
|
||||
UIDialogs.toast(context, context.getString(R.string.offline_playback), false);
|
||||
if((videoSource == null || videoSource is LocalVideoSource) && (audioSource == null || audioSource is LocalAudioSource)) {
|
||||
Logger.i(TAG, "Time since last offline playback toast: " + (System.currentTimeMillis() - _lastOfflinePlaybackToastTime).toString())
|
||||
if (System.currentTimeMillis() - _lastOfflinePlaybackToastTime > 5000) {
|
||||
UIDialogs.toast(context, context.getString(R.string.offline_playback), false);
|
||||
_lastOfflinePlaybackToastTime = System.currentTimeMillis()
|
||||
}
|
||||
}
|
||||
//If LiveStream, set to end
|
||||
if(videoSource is IDashManifestSource || videoSource is IHLSManifestSource) {
|
||||
if (video?.isLive == true) {
|
||||
|
@ -2379,8 +2384,8 @@ class VideoDetailView : ConstraintLayout {
|
|||
}
|
||||
|
||||
fun isLandscapeVideo(): Boolean? {
|
||||
var videoSourceWidth = _player.exoPlayer?.player?.videoSize?.width
|
||||
var videoSourceHeight = _player.exoPlayer?.player?.videoSize?.height
|
||||
val videoSourceWidth = _player.exoPlayer?.player?.videoSize?.width
|
||||
val videoSourceHeight = _player.exoPlayer?.player?.videoSize?.height
|
||||
|
||||
return if (videoSourceWidth == null || videoSourceHeight == null || videoSourceWidth == 0 || videoSourceHeight == 0){
|
||||
null
|
||||
|
@ -3030,8 +3035,6 @@ class VideoDetailView : ConstraintLayout {
|
|||
const val TAG_MORE = "MORE";
|
||||
|
||||
private val _buttonPinStore = FragmentedStorage.get<StringArrayStorage>("videoPinnedButtons");
|
||||
|
||||
|
||||
|
||||
private var _lastOfflinePlaybackToastTime: Long = 0
|
||||
}
|
||||
}
|
|
@ -12,70 +12,109 @@ import com.futo.platformplayer.activities.MainActivity
|
|||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.receivers.MediaControlReceiver
|
||||
import com.futo.platformplayer.timestampRegex
|
||||
import com.futo.platformplayer.views.behavior.NonScrollingTextView
|
||||
import com.futo.platformplayer.views.behavior.NonScrollingTextView.Companion
|
||||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class PlatformLinkMovementMethod : LinkMovementMethod {
|
||||
private val _context: Context;
|
||||
class PlatformLinkMovementMethod(private val _context: Context) : LinkMovementMethod() {
|
||||
|
||||
constructor(context: Context) : super() {
|
||||
_context = context;
|
||||
}
|
||||
private var pressedLinks: Array<URLSpan>? = null
|
||||
private var linkPressed = false
|
||||
private var downX = 0f
|
||||
private var downY = 0f
|
||||
private val touchSlop = 20
|
||||
|
||||
override fun onTouchEvent(widget: TextView, buffer: Spannable, event: MotionEvent): Boolean {
|
||||
val action = event.action;
|
||||
Logger.i(TAG, "onTouchEvent (action = $action)")
|
||||
if (action == MotionEvent.ACTION_UP) {
|
||||
val x = event.x.toInt() - widget.totalPaddingLeft + widget.scrollX;
|
||||
val y = event.y.toInt() - widget.totalPaddingTop + widget.scrollY;
|
||||
val action = event.actionMasked
|
||||
|
||||
val layout = widget.layout;
|
||||
val line = layout.getLineForVertical(y);
|
||||
val off = layout.getOffsetForHorizontal(line, x.toFloat());
|
||||
val links = buffer.getSpans(off, off, URLSpan::class.java);
|
||||
when (action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
val links = findLinksAtTouchPosition(widget, buffer, event)
|
||||
if (links.isNotEmpty()) {
|
||||
pressedLinks = links
|
||||
linkPressed = true
|
||||
downX = event.x
|
||||
downY = event.y
|
||||
widget.parent?.requestDisallowInterceptTouchEvent(true)
|
||||
return true
|
||||
} else {
|
||||
linkPressed = false
|
||||
pressedLinks = null
|
||||
}
|
||||
}
|
||||
|
||||
if (links.isNotEmpty()) {
|
||||
runBlocking {
|
||||
for (link in links) {
|
||||
Logger.i(TAG) { "Link clicked '${link.url}'." };
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (linkPressed) {
|
||||
val dx = event.x - downX
|
||||
val dy = event.y - downY
|
||||
if (Math.abs(dx) > touchSlop || Math.abs(dy) > touchSlop) {
|
||||
linkPressed = false
|
||||
pressedLinks = null
|
||||
widget.parent?.requestDisallowInterceptTouchEvent(false)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if (_context is MainActivity) {
|
||||
if (_context.handleUrl(link.url)) {
|
||||
continue;
|
||||
}
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (linkPressed && pressedLinks != null) {
|
||||
val dx = event.x - downX
|
||||
val dy = event.y - downY
|
||||
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) {
|
||||
runBlocking {
|
||||
for (link in pressedLinks!!) {
|
||||
Logger.i(TAG) { "Link clicked '${link.url}'." }
|
||||
|
||||
if (timestampRegex.matches(link.url)) {
|
||||
val tokens = link.url.split(':');
|
||||
if (_context is MainActivity) {
|
||||
if (_context.handleUrl(link.url)) continue
|
||||
if (timestampRegex.matches(link.url)) {
|
||||
val tokens = link.url.split(':')
|
||||
var time_s = -1L
|
||||
when (tokens.size) {
|
||||
2 -> time_s = tokens[0].toLong() * 60 + tokens[1].toLong()
|
||||
3 -> time_s = tokens[0].toLong() * 3600 +
|
||||
tokens[1].toLong() * 60 +
|
||||
tokens[2].toLong()
|
||||
}
|
||||
|
||||
var time_s = -1L;
|
||||
if (tokens.size == 2) {
|
||||
time_s = tokens[0].toLong() * 60 + tokens[1].toLong();
|
||||
} else if (tokens.size == 3) {
|
||||
time_s =
|
||||
tokens[0].toLong() * 60 * 60 + tokens[1].toLong() * 60 + tokens[2].toLong();
|
||||
}
|
||||
|
||||
if (time_s != -1L) {
|
||||
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000);
|
||||
continue;
|
||||
if (time_s != -1L) {
|
||||
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
_context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)));
|
||||
pressedLinks = null
|
||||
linkPressed = false
|
||||
return true
|
||||
} else {
|
||||
pressedLinks = null
|
||||
linkPressed = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
linkPressed = false
|
||||
pressedLinks = null
|
||||
}
|
||||
}
|
||||
|
||||
return super.onTouchEvent(widget, buffer, event);
|
||||
return super.onTouchEvent(widget, buffer, event)
|
||||
}
|
||||
|
||||
private fun findLinksAtTouchPosition(widget: TextView, buffer: Spannable, event: MotionEvent): Array<URLSpan> {
|
||||
val x = (event.x - widget.totalPaddingLeft + widget.scrollX).toInt()
|
||||
val y = (event.y - widget.totalPaddingTop + widget.scrollY).toInt()
|
||||
|
||||
val layout = widget.layout ?: return emptyArray()
|
||||
val line = layout.getLineForVertical(y)
|
||||
val off = layout.getOffsetForHorizontal(line, x.toFloat())
|
||||
return buffer.getSpans(off, off, URLSpan::class.java)
|
||||
}
|
||||
|
||||
companion object {
|
||||
val TAG = "PlatformLinkMovementMethod";
|
||||
const val TAG = "PlatformLinkMovementMethod"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,18 +112,23 @@ class StateSync {
|
|||
Logger.i(TAG, "Sync key pair initialized (public key = ${publicKey})")
|
||||
|
||||
_thread = Thread {
|
||||
val serverSocket = ServerSocket(PORT)
|
||||
_serverSocket = serverSocket
|
||||
try {
|
||||
val serverSocket = ServerSocket(PORT)
|
||||
_serverSocket = serverSocket
|
||||
|
||||
Log.i(TAG, "Running on port ${PORT} (TCP)")
|
||||
Log.i(TAG, "Running on port ${PORT} (TCP)")
|
||||
|
||||
while (_started) {
|
||||
val socket = serverSocket.accept()
|
||||
val session = createSocketSession(socket, true) { session, socketSession ->
|
||||
while (_started) {
|
||||
val socket = serverSocket.accept()
|
||||
val session = createSocketSession(socket, true) { session, socketSession ->
|
||||
|
||||
}
|
||||
|
||||
session.startAsResponder()
|
||||
}
|
||||
|
||||
session.startAsResponder()
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to bind server socket to port ${PORT}", e)
|
||||
UIDialogs.toast("Failed to start sync, port in use")
|
||||
}
|
||||
}.apply { start() }
|
||||
|
||||
|
|
|
@ -16,73 +16,113 @@ import com.futo.platformplayer.timestampRegex
|
|||
import kotlinx.coroutines.runBlocking
|
||||
|
||||
class NonScrollingTextView : androidx.appcompat.widget.AppCompatTextView {
|
||||
private var _lastTouchedLinks: Array<URLSpan>? = null
|
||||
private var downX = 0f
|
||||
private var downY = 0f
|
||||
private var linkPressed = false
|
||||
private val touchSlop = 20
|
||||
|
||||
constructor(context: Context) : super(context) {}
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
|
||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {}
|
||||
|
||||
override fun scrollTo(x: Int, y: Int) {
|
||||
//do nothing
|
||||
// do nothing
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
val action = event?.action
|
||||
Logger.i(TAG, "onTouchEvent (action = $action)");
|
||||
val action = event?.actionMasked
|
||||
if (event == null) return super.onTouchEvent(event)
|
||||
|
||||
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
|
||||
val x = event.x.toInt()
|
||||
val y = event.y.toInt()
|
||||
when (action) {
|
||||
MotionEvent.ACTION_DOWN -> {
|
||||
val x = event.x.toInt()
|
||||
val y = event.y.toInt()
|
||||
|
||||
val layout: Layout? = this.layout
|
||||
if (layout != null) {
|
||||
val line = layout.getLineForVertical(y)
|
||||
val offset = layout.getOffsetForHorizontal(line, x.toFloat())
|
||||
|
||||
val text = this.text
|
||||
if (text is Spannable) {
|
||||
val layout: Layout? = this.layout
|
||||
if (layout != null && this.text is Spannable) {
|
||||
val offset = layout.getOffsetForHorizontal(layout.getLineForVertical(y), x.toFloat())
|
||||
val text = this.text as Spannable
|
||||
val links = text.getSpans(offset, offset, URLSpan::class.java)
|
||||
if (links.isNotEmpty()) {
|
||||
runBlocking {
|
||||
for (link in links) {
|
||||
Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." };
|
||||
|
||||
val c = context;
|
||||
if (c is MainActivity) {
|
||||
if (c.handleUrl(link.url)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (timestampRegex.matches(link.url)) {
|
||||
val tokens = link.url.split(':');
|
||||
|
||||
var time_s = -1L;
|
||||
if (tokens.size == 2) {
|
||||
time_s = tokens[0].toLong() * 60 + tokens[1].toLong();
|
||||
} else if (tokens.size == 3) {
|
||||
time_s = tokens[0].toLong() * 60 * 60 + tokens[1].toLong() * 60 + tokens[2].toLong();
|
||||
}
|
||||
|
||||
if (time_s != -1L) {
|
||||
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent?.requestDisallowInterceptTouchEvent(true)
|
||||
_lastTouchedLinks = links
|
||||
downX = event.x
|
||||
downY = event.y
|
||||
linkPressed = true
|
||||
return true
|
||||
} else {
|
||||
linkPressed = false
|
||||
_lastTouchedLinks = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_MOVE -> {
|
||||
if (linkPressed) {
|
||||
val dx = event.x - downX
|
||||
val dy = event.y - downY
|
||||
if (Math.abs(dx) > touchSlop || Math.abs(dy) > touchSlop) {
|
||||
linkPressed = false
|
||||
_lastTouchedLinks = null
|
||||
parent?.requestDisallowInterceptTouchEvent(false)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_UP -> {
|
||||
if (linkPressed && _lastTouchedLinks != null) {
|
||||
val dx = event.x - downX
|
||||
val dy = event.y - downY
|
||||
if (Math.abs(dx) <= touchSlop && Math.abs(dy) <= touchSlop) {
|
||||
runBlocking {
|
||||
for (link in _lastTouchedLinks!!) {
|
||||
Logger.i(PlatformLinkMovementMethod.TAG) { "Link clicked '${link.url}'." }
|
||||
val c = context
|
||||
if (c is MainActivity) {
|
||||
if (c.handleUrl(link.url)) continue
|
||||
if (timestampRegex.matches(link.url)) {
|
||||
val tokens = link.url.split(':')
|
||||
var time_s = -1L
|
||||
when (tokens.size) {
|
||||
2 -> time_s = tokens[0].toLong() * 60 + tokens[1].toLong()
|
||||
3 -> time_s = tokens[0].toLong() * 3600 +
|
||||
tokens[1].toLong() * 60 +
|
||||
tokens[2].toLong()
|
||||
}
|
||||
if (time_s != -1L) {
|
||||
MediaControlReceiver.onSeekToReceived.emit(time_s * 1000)
|
||||
continue
|
||||
}
|
||||
}
|
||||
c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)))
|
||||
} else {
|
||||
c.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(link.url)))
|
||||
}
|
||||
}
|
||||
}
|
||||
_lastTouchedLinks = null
|
||||
linkPressed = false
|
||||
return true
|
||||
} else {
|
||||
linkPressed = false
|
||||
_lastTouchedLinks = null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MotionEvent.ACTION_CANCEL -> {
|
||||
linkPressed = false
|
||||
_lastTouchedLinks = null
|
||||
}
|
||||
}
|
||||
|
||||
super.onTouchEvent(event)
|
||||
return false
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "NonScrollingTextView"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView
|
|||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.comments.LazyComment
|
||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||
import com.futo.platformplayer.api.media.structures.IAsyncPager
|
||||
|
@ -267,9 +268,13 @@ class CommentsList : ConstraintLayout {
|
|||
}
|
||||
|
||||
fun replaceComment(c: PolycentricPlatformComment, newComment: PolycentricPlatformComment) {
|
||||
val index = _comments.indexOf(c);
|
||||
_comments[index] = newComment;
|
||||
_adapterComments.notifyItemChanged(_adapterComments.childToParentPosition(index));
|
||||
val index = _comments.indexOfFirst { it == c || (it is LazyComment && it.getUnderlyingComment() == c) };
|
||||
if (index >= 0) {
|
||||
_comments[index] = newComment;
|
||||
_adapterComments.notifyItemChanged(_adapterComments.childToParentPosition(index));
|
||||
} else {
|
||||
Logger.w(TAG, "Parent comment not found")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -592,6 +592,11 @@ class FutoVideoPlayer : FutoVideoPlayerBase {
|
|||
|
||||
@OptIn(UnstableApi::class)
|
||||
fun setFullScreen(fullScreen: Boolean) {
|
||||
// prevent fullscreen before the video has loaded to make sure we know whether it's a vertical or horizontal video
|
||||
if(exoPlayer?.player?.videoSize?.height ?: 0 == 0 && fullScreen){
|
||||
return
|
||||
}
|
||||
|
||||
updateRotateLock()
|
||||
|
||||
if (isFullScreen == fullScreen) {
|
||||
|
|
|
@ -199,6 +199,7 @@
|
|||
<string name="previous">Previous</string>
|
||||
<string name="next">Next</string>
|
||||
<string name="comment">Comment</string>
|
||||
<string name="not_empty_close">Comment is not empty, close anyway?</string>
|
||||
<string name="str_import">Import</string>
|
||||
<string name="my_playlist_name">My Playlist Name</string>
|
||||
<string name="do_you_want_to_import_this_store">Do you want to import this store?</string>
|
||||
|
|
|
@ -15,6 +15,7 @@ touch $DOCUMENT_ROOT/maintenance.file
|
|||
|
||||
# Swap over the content
|
||||
echo "Deploying content..."
|
||||
cp ./app/build/outputs/bundle/playstoreRelease/app-playstore-release.aab $DOCUMENT_ROOT/app-playstore-release.aab
|
||||
aws s3 cp ./app/build/outputs/bundle/playstoreRelease/app-playstore-release.aab s3://artifacts-grayjay-app/app-playstore-release.aab
|
||||
|
||||
# Notify Cloudflare to wipe the CDN cache
|
||||
|
|
Loading…
Add table
Reference in a new issue