mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-19 19:14:51 +00:00
Implemented delete comment support. Implemented Comments tab. Implemented replies overlay showing parent comment.
This commit is contained in:
parent
8a35cd0e82
commit
3bf73ed5e8
45 changed files with 1164 additions and 68 deletions
|
@ -32,7 +32,7 @@ import com.futo.platformplayer.models.Playlist
|
|||
import com.futo.platformplayer.models.Subscription
|
||||
import com.futo.platformplayer.parsers.HLS
|
||||
import com.futo.platformplayer.states.*
|
||||
import com.futo.platformplayer.views.Loader
|
||||
import com.futo.platformplayer.views.LoaderView
|
||||
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuGroup
|
||||
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuItem
|
||||
import com.futo.platformplayer.views.overlays.slideup.SlideUpMenuOverlay
|
||||
|
@ -137,7 +137,7 @@ class UISlideOverlays {
|
|||
}
|
||||
|
||||
fun showHlsPicker(video: IPlatformVideoDetails, source: Any, sourceUrl: String, container: ViewGroup): SlideUpMenuOverlay {
|
||||
val items = arrayListOf<View>(Loader(container.context))
|
||||
val items = arrayListOf<View>(LoaderView(container.context))
|
||||
val slideUpMenuOverlay = SlideUpMenuOverlay(container.context, container, container.context.getString(R.string.download_video), null, true, items)
|
||||
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
|
@ -501,7 +501,7 @@ class UISlideOverlays {
|
|||
val dp70 = 70.dp(container.context.resources);
|
||||
val dp15 = 15.dp(container.context.resources);
|
||||
val overlay = SlideUpMenuOverlay(container.context, container, text, null, true, listOf(
|
||||
Loader(container.context, true, dp70).apply {
|
||||
LoaderView(container.context, true, dp70).apply {
|
||||
this.setPadding(0, dp15, 0, dp15);
|
||||
}
|
||||
), true);
|
||||
|
|
|
@ -90,6 +90,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
lateinit var _fragMainPlaylistSearchResults: PlaylistSearchResultsFragment;
|
||||
lateinit var _fragMainSuggestions: SuggestionsFragment;
|
||||
lateinit var _fragMainSubscriptions: CreatorsFragment;
|
||||
lateinit var _fragMainComments: CommentsFragment;
|
||||
lateinit var _fragMainSubscriptionsFeed: SubscriptionsFeedFragment;
|
||||
lateinit var _fragMainChannel: ChannelFragment;
|
||||
lateinit var _fragMainSources: SourcesFragment;
|
||||
|
@ -205,6 +206,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
_fragMainCreatorSearchResults = CreatorSearchResultsFragment.newInstance();
|
||||
_fragMainPlaylistSearchResults = PlaylistSearchResultsFragment.newInstance();
|
||||
_fragMainSubscriptions = CreatorsFragment.newInstance();
|
||||
_fragMainComments = CommentsFragment.newInstance();
|
||||
_fragMainChannel = ChannelFragment.newInstance();
|
||||
_fragMainSubscriptionsFeed = SubscriptionsFeedFragment.newInstance();
|
||||
_fragMainSources = SourcesFragment.newInstance();
|
||||
|
@ -282,6 +284,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
//Set top bars
|
||||
_fragMainHome.topBar = _fragTopBarGeneral;
|
||||
_fragMainSubscriptions.topBar = _fragTopBarGeneral;
|
||||
_fragMainComments.topBar = _fragTopBarGeneral;
|
||||
_fragMainSuggestions.topBar = _fragTopBarSearch;
|
||||
_fragMainVideoSearchResults.topBar = _fragTopBarSearch;
|
||||
_fragMainCreatorSearchResults.topBar = _fragTopBarSearch;
|
||||
|
@ -916,6 +919,7 @@ class MainActivity : AppCompatActivity, IWithResultLauncher {
|
|||
GeneralTopBarFragment::class -> _fragTopBarGeneral as T;
|
||||
SearchTopBarFragment::class -> _fragTopBarSearch as T;
|
||||
CreatorsFragment::class -> _fragMainSubscriptions as T;
|
||||
CommentsFragment::class -> _fragMainComments as T;
|
||||
SubscriptionsFeedFragment::class -> _fragMainSubscriptionsFeed as T;
|
||||
PlaylistSearchResultsFragment::class -> _fragMainPlaylistSearchResults as T;
|
||||
ChannelFragment::class -> _fragMainChannel as T;
|
||||
|
|
|
@ -15,7 +15,7 @@ import androidx.lifecycle.lifecycleScope
|
|||
import com.futo.platformplayer.*
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.views.Loader
|
||||
import com.futo.platformplayer.views.LoaderView
|
||||
import com.futo.platformplayer.views.fields.FieldForm
|
||||
import com.futo.platformplayer.views.fields.ReadOnlyTextField
|
||||
import com.google.android.material.button.MaterialButton
|
||||
|
@ -23,7 +23,7 @@ import com.google.android.material.button.MaterialButton
|
|||
class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
||||
private lateinit var _form: FieldForm;
|
||||
private lateinit var _buttonBack: ImageButton;
|
||||
private lateinit var _loader: Loader;
|
||||
private lateinit var _loaderView: LoaderView;
|
||||
|
||||
private lateinit var _devSets: LinearLayout;
|
||||
private lateinit var _buttonDev: MaterialButton;
|
||||
|
@ -43,7 +43,7 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
|||
_buttonBack = findViewById(R.id.button_back);
|
||||
_buttonDev = findViewById(R.id.button_dev);
|
||||
_devSets = findViewById(R.id.dev_settings);
|
||||
_loader = findViewById(R.id.loader);
|
||||
_loaderView = findViewById(R.id.loader);
|
||||
|
||||
_form.onChanged.subscribe { field, value ->
|
||||
Logger.i("SettingsActivity", "Setting [${field.field?.name}] changed, saving");
|
||||
|
@ -70,9 +70,9 @@ class SettingsActivity : AppCompatActivity(), IWithResultLauncher {
|
|||
|
||||
fun reloadSettings() {
|
||||
_form.setSearchVisible(false);
|
||||
_loader.start();
|
||||
_loaderView.start();
|
||||
_form.fromObject(lifecycleScope, Settings.instance) {
|
||||
_loader.stop();
|
||||
_loaderView.stop();
|
||||
_form.setSearchVisible(true);
|
||||
|
||||
var devCounter = 0;
|
||||
|
|
|
@ -4,10 +4,7 @@ import com.futo.platformplayer.api.media.IPlatformClient
|
|||
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||
import com.futo.platformplayer.api.media.models.ratings.IRating
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.polycentric.PolycentricCache
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.polycentric.core.Pointer
|
||||
import com.futo.polycentric.core.SignedEvent
|
||||
import userpackage.Protocol.Reference
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
|
@ -20,16 +17,18 @@ class PolycentricPlatformComment : IPlatformComment {
|
|||
|
||||
override val replyCount: Int?;
|
||||
|
||||
val eventPointer: Pointer;
|
||||
val reference: Reference;
|
||||
|
||||
constructor(contextUrl: String, author: PlatformAuthorLink, msg: String, rating: IRating, date: OffsetDateTime, reference: Reference, replyCount: Int? = null) {
|
||||
constructor(contextUrl: String, author: PlatformAuthorLink, msg: String, rating: IRating, date: OffsetDateTime, eventPointer: Pointer, replyCount: Int? = null) {
|
||||
this.contextUrl = contextUrl;
|
||||
this.author = author;
|
||||
this.message = msg;
|
||||
this.rating = rating;
|
||||
this.date = date;
|
||||
this.replyCount = replyCount;
|
||||
this.reference = reference;
|
||||
this.eventPointer = eventPointer;
|
||||
this.reference = eventPointer.toReference();
|
||||
}
|
||||
|
||||
override fun getReplies(client: IPlatformClient): IPager<IPlatformComment> {
|
||||
|
@ -37,7 +36,7 @@ class PolycentricPlatformComment : IPlatformComment {
|
|||
}
|
||||
|
||||
fun cloneWithUpdatedReplyCount(replyCount: Int?): PolycentricPlatformComment {
|
||||
return PolycentricPlatformComment(contextUrl, author, message, rating, date, reference, replyCount);
|
||||
return PolycentricPlatformComment(contextUrl, author, message, rating, date, eventPointer, replyCount);
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -118,7 +118,7 @@ class CommentDialog(context: Context?, val contextUrl: String, val ref: Protocol
|
|||
msg = comment,
|
||||
rating = RatingLikeDislikes(0, 0),
|
||||
date = OffsetDateTime.now(),
|
||||
reference = eventPointer.toReference()
|
||||
eventPointer = eventPointer
|
||||
));
|
||||
|
||||
dismiss();
|
||||
|
|
|
@ -351,6 +351,7 @@ class MenuBottomBarFragment : MainActivityFragment() {
|
|||
ButtonDefinition(4, R.drawable.ic_playlist, R.drawable.ic_playlist_filled, R.string.playlists, canToggle = false, { it.currentMain is PlaylistsFragment }, { it.navigate<PlaylistsFragment>() }),
|
||||
ButtonDefinition(5, R.drawable.ic_history, R.drawable.ic_history, R.string.history, canToggle = false, { it.currentMain is HistoryFragment }, { it.navigate<HistoryFragment>() }),
|
||||
ButtonDefinition(6, R.drawable.ic_download, R.drawable.ic_download, R.string.downloads, canToggle = false, { it.currentMain is DownloadsFragment }, { it.navigate<DownloadsFragment>() }),
|
||||
ButtonDefinition(8, R.drawable.ic_chat, R.drawable.ic_chat_filled, R.string.comments, canToggle = true, { it.currentMain is CommentsFragment }, { it.navigate<CommentsFragment>() }),
|
||||
ButtonDefinition(7, R.drawable.ic_settings, R.drawable.ic_settings, R.string.settings, canToggle = false, { false }, {
|
||||
val c = it.context ?: return@ButtonDefinition;
|
||||
Logger.i(TAG, "settings preventPictureInPicture()");
|
||||
|
|
|
@ -35,6 +35,11 @@ class BuyFragment : MainFragment() {
|
|||
return view;
|
||||
}
|
||||
|
||||
override fun onDestroyMainView() {
|
||||
super.onDestroyMainView()
|
||||
_view = null
|
||||
}
|
||||
|
||||
class BuyView: LinearLayout {
|
||||
private val _fragment: BuyFragment;
|
||||
|
||||
|
|
|
@ -0,0 +1,306 @@
|
|||
package com.futo.platformplayer.fragment.mainactivity.main
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.view.ViewPropertyAnimator
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Spinner
|
||||
import android.widget.TextView
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.activities.PolycentricHomeActivity
|
||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||
import com.futo.platformplayer.constructs.TaskHandler
|
||||
import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StatePlatform
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.platformplayer.views.adapters.CommentWithReferenceViewHolder
|
||||
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
|
||||
import com.futo.platformplayer.views.overlays.RepliesOverlay
|
||||
import com.futo.polycentric.core.PublicKey
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.UnknownHostException
|
||||
|
||||
class CommentsFragment : MainFragment() {
|
||||
override val isMainView : Boolean = true
|
||||
override val isTab: Boolean = true
|
||||
override val hasBottomBar: Boolean get() = true
|
||||
|
||||
private var _view: CommentsView? = null
|
||||
|
||||
override fun onShownWithView(parameter: Any?, isBack: Boolean) {
|
||||
super.onShownWithView(parameter, isBack)
|
||||
_view?.onShown()
|
||||
}
|
||||
|
||||
override fun onCreateMainView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
|
||||
val view = CommentsView(this, inflater)
|
||||
_view = view
|
||||
return view
|
||||
}
|
||||
|
||||
override fun onDestroyMainView() {
|
||||
super.onDestroyMainView()
|
||||
_view = null
|
||||
}
|
||||
|
||||
override fun onBackPressed(): Boolean {
|
||||
return _view?.onBackPressed() ?: false
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
_view?.onShown()
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun newInstance() = CommentsFragment().apply {}
|
||||
private const val TAG = "CommentsFragment"
|
||||
}
|
||||
|
||||
class CommentsView : FrameLayout {
|
||||
private val _fragment: CommentsFragment
|
||||
private val _recyclerComments: RecyclerView;
|
||||
private val _adapterComments: InsertedViewAdapterWithLoader<CommentWithReferenceViewHolder>;
|
||||
private val _textCommentCount: TextView
|
||||
private val _comments: ArrayList<IPlatformComment> = arrayListOf();
|
||||
private val _llmReplies: LinearLayoutManager;
|
||||
private val _spinnerSortBy: Spinner;
|
||||
private val _layoutNotLoggedIn: LinearLayout;
|
||||
private val _buttonLogin: LinearLayout;
|
||||
private var _loading = false;
|
||||
private val _repliesOverlay: RepliesOverlay;
|
||||
private var _repliesAnimator: ViewPropertyAnimator? = null;
|
||||
|
||||
private val _taskLoadComments = if(!isInEditMode) TaskHandler<PublicKey, List<IPlatformComment>>(
|
||||
StateApp.instance.scopeGetter, { StatePolycentric.instance.getSystemComments(context, it) })
|
||||
.success { pager -> onCommentsLoaded(pager); }
|
||||
.exception<UnknownHostException> {
|
||||
UIDialogs.toast("Failed to load comments");
|
||||
setLoading(false);
|
||||
}
|
||||
.exception<Throwable> {
|
||||
Logger.e(TAG, "Failed to load comments.", it);
|
||||
UIDialogs.toast(context, context.getString(R.string.failed_to_load_comments) + "\n" + (it.message ?: ""));
|
||||
setLoading(false);
|
||||
} else TaskHandler(IPlatformVideoDetails::class.java, StateApp.instance.scopeGetter);
|
||||
|
||||
constructor(fragment: CommentsFragment, inflater: LayoutInflater) : super(inflater.context) {
|
||||
_fragment = fragment
|
||||
inflater.inflate(R.layout.fragment_comments, this)
|
||||
|
||||
val commentHeader = findViewById<LinearLayout>(R.id.layout_header)
|
||||
(commentHeader.parent as ViewGroup).removeView(commentHeader)
|
||||
_textCommentCount = commentHeader.findViewById(R.id.text_comment_count)
|
||||
|
||||
_recyclerComments = findViewById(R.id.recycler_comments)
|
||||
_adapterComments = InsertedViewAdapterWithLoader(context, arrayListOf(commentHeader), arrayListOf(),
|
||||
childCountGetter = { _comments.size },
|
||||
childViewHolderBinder = { viewHolder, position -> viewHolder.bind(_comments[position]); },
|
||||
childViewHolderFactory = { viewGroup, _ ->
|
||||
val holder = CommentWithReferenceViewHolder(viewGroup);
|
||||
holder.onDelete.subscribe(::onDelete);
|
||||
holder.onRepliesClick.subscribe(::onRepliesClick);
|
||||
return@InsertedViewAdapterWithLoader holder;
|
||||
}
|
||||
);
|
||||
|
||||
_spinnerSortBy = commentHeader.findViewById(R.id.spinner_sortby);
|
||||
_spinnerSortBy.adapter = ArrayAdapter(context, R.layout.spinner_item_simple, resources.getStringArray(R.array.comments_sortby_array)).also {
|
||||
it.setDropDownViewResource(R.layout.spinner_dropdownitem_simple);
|
||||
};
|
||||
_spinnerSortBy.setSelection(0);
|
||||
_spinnerSortBy.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>, view: View?, pos: Int, id: Long) {
|
||||
if (_spinnerSortBy.selectedItemPosition == 0) {
|
||||
_comments.sortByDescending { it.date!! }
|
||||
} else if (_spinnerSortBy.selectedItemPosition == 1) {
|
||||
_comments.sortBy { it.date!! }
|
||||
}
|
||||
|
||||
_adapterComments.notifyDataSetChanged()
|
||||
}
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) = Unit
|
||||
}
|
||||
|
||||
_llmReplies = LinearLayoutManager(context);
|
||||
_recyclerComments.layoutManager = _llmReplies;
|
||||
_recyclerComments.adapter = _adapterComments;
|
||||
updateCommentCountString();
|
||||
|
||||
_layoutNotLoggedIn = findViewById(R.id.layout_not_logged_in)
|
||||
_layoutNotLoggedIn.visibility = View.GONE
|
||||
|
||||
_buttonLogin = findViewById(R.id.button_login)
|
||||
_buttonLogin.setOnClickListener {
|
||||
context.startActivity(Intent(context, PolycentricHomeActivity::class.java));
|
||||
}
|
||||
|
||||
_repliesOverlay = findViewById(R.id.replies_overlay);
|
||||
_repliesOverlay.onClose.subscribe { setRepliesOverlayVisible(isVisible = false, animate = true); };
|
||||
}
|
||||
|
||||
private fun onDelete(comment: IPlatformComment) {
|
||||
val processHandle = StatePolycentric.instance.processHandle ?: return
|
||||
if (comment !is PolycentricPlatformComment) {
|
||||
return
|
||||
}
|
||||
|
||||
val index = _comments.indexOf(comment)
|
||||
if (index != -1) {
|
||||
_comments.removeAt(index)
|
||||
_adapterComments.notifyItemRemoved(_adapterComments.childToParentPosition(index))
|
||||
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
processHandle.delete(comment.eventPointer.process, comment.eventPointer.logicalClock)
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to delete event.", e);
|
||||
return@launch;
|
||||
}
|
||||
|
||||
try {
|
||||
Logger.i(TAG, "Started backfill");
|
||||
processHandle.fullyBackfillServersAnnounceExceptions();
|
||||
Logger.i(TAG, "Finished backfill");
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to fully backfill servers.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun onBackPressed(): Boolean {
|
||||
if (_repliesOverlay.visibility == View.VISIBLE) {
|
||||
setRepliesOverlayVisible(isVisible = false, animate = true);
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun onRepliesClick(c: IPlatformComment) {
|
||||
val replyCount = c.replyCount ?: 0;
|
||||
var metadata = "";
|
||||
if (replyCount > 0) {
|
||||
metadata += "$replyCount " + context.getString(R.string.replies);
|
||||
}
|
||||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
var parentComment: PolycentricPlatformComment = c;
|
||||
_repliesOverlay.load(false, metadata, c.contextUrl, c.reference, c,
|
||||
{ StatePolycentric.instance.getCommentPager(c.contextUrl, c.reference) },
|
||||
{
|
||||
val newComment = parentComment.cloneWithUpdatedReplyCount((parentComment.replyCount ?: 0) + 1);
|
||||
val index = _comments.indexOf(c);
|
||||
_comments[index] = newComment;
|
||||
_adapterComments.notifyItemChanged(_adapterComments.childToParentPosition(index));
|
||||
parentComment = newComment;
|
||||
});
|
||||
} else {
|
||||
_repliesOverlay.load(true, metadata, null, null, c, { StatePlatform.instance.getSubComments(c) });
|
||||
}
|
||||
|
||||
setRepliesOverlayVisible(isVisible = true, animate = true);
|
||||
}
|
||||
|
||||
private fun setRepliesOverlayVisible(isVisible: Boolean, animate: Boolean) {
|
||||
val desiredVisibility = if (isVisible) View.VISIBLE else View.GONE
|
||||
if (_repliesOverlay.visibility == desiredVisibility) {
|
||||
return;
|
||||
}
|
||||
|
||||
_repliesAnimator?.cancel();
|
||||
|
||||
if (isVisible) {
|
||||
_repliesOverlay.visibility = View.VISIBLE;
|
||||
|
||||
if (animate) {
|
||||
_repliesOverlay.translationY = _repliesOverlay.height.toFloat();
|
||||
|
||||
_repliesAnimator = _repliesOverlay.animate()
|
||||
.setDuration(300)
|
||||
.translationY(0f)
|
||||
.withEndAction {
|
||||
_repliesAnimator = null;
|
||||
}.apply { start() };
|
||||
}
|
||||
} else {
|
||||
if (animate) {
|
||||
_repliesOverlay.translationY = 0f;
|
||||
|
||||
_repliesAnimator = _repliesOverlay.animate()
|
||||
.setDuration(300)
|
||||
.translationY(_repliesOverlay.height.toFloat())
|
||||
.withEndAction {
|
||||
_repliesOverlay.visibility = GONE;
|
||||
_repliesAnimator = null;
|
||||
}.apply { start(); }
|
||||
} else {
|
||||
_repliesOverlay.visibility = View.GONE;
|
||||
_repliesOverlay.translationY = _repliesOverlay.height.toFloat();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateCommentCountString() {
|
||||
_textCommentCount.text = context.getString(R.string.these_are_all_commentcount_comments_you_have_made_in_grayjay).replace("{commentCount}", _comments.size.toString())
|
||||
}
|
||||
|
||||
private fun setLoading(loading: Boolean) {
|
||||
if (_loading == loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
_loading = loading;
|
||||
_adapterComments.setLoading(loading);
|
||||
}
|
||||
|
||||
private fun fetchComments() {
|
||||
val system = StatePolycentric.instance.processHandle?.system ?: return
|
||||
_comments.clear()
|
||||
_adapterComments.notifyDataSetChanged()
|
||||
setLoading(true)
|
||||
_taskLoadComments.run(system)
|
||||
}
|
||||
|
||||
private fun onCommentsLoaded(comments: List<IPlatformComment>) {
|
||||
setLoading(false)
|
||||
_comments.addAll(comments)
|
||||
|
||||
if (_spinnerSortBy.selectedItemPosition == 0) {
|
||||
_comments.sortByDescending { it.date!! }
|
||||
} else if (_spinnerSortBy.selectedItemPosition == 1) {
|
||||
_comments.sortBy { it.date!! }
|
||||
}
|
||||
|
||||
_adapterComments.notifyDataSetChanged()
|
||||
updateCommentCountString()
|
||||
}
|
||||
|
||||
fun onShown() {
|
||||
val processHandle = StatePolycentric.instance.processHandle
|
||||
if (processHandle != null) {
|
||||
_layoutNotLoggedIn.visibility = View.GONE
|
||||
_recyclerComments.visibility = View.VISIBLE
|
||||
fetchComments()
|
||||
} else {
|
||||
_layoutNotLoggedIn.visibility = View.VISIBLE
|
||||
_recyclerComments.visibility= View.GONE
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -224,7 +224,7 @@ class PostDetailFragment : MainFragment {
|
|||
updateCommentType(false);
|
||||
};
|
||||
|
||||
_commentsList.onClick.subscribe { c ->
|
||||
_commentsList.onRepliesClick.subscribe { c ->
|
||||
val replyCount = c.replyCount ?: 0;
|
||||
var metadata = "";
|
||||
if (replyCount > 0) {
|
||||
|
@ -233,7 +233,7 @@ class PostDetailFragment : MainFragment {
|
|||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
var parentComment: PolycentricPlatformComment = c;
|
||||
_repliesOverlay.load(_toggleCommentType.value, metadata, c.contextUrl, c.reference,
|
||||
_repliesOverlay.load(_toggleCommentType.value, metadata, c.contextUrl, c.reference, c,
|
||||
{ StatePolycentric.instance.getCommentPager(c.contextUrl, c.reference) },
|
||||
{
|
||||
val newComment = parentComment.cloneWithUpdatedReplyCount((parentComment.replyCount ?: 0) + 1);
|
||||
|
@ -241,7 +241,7 @@ class PostDetailFragment : MainFragment {
|
|||
parentComment = newComment;
|
||||
});
|
||||
} else {
|
||||
_repliesOverlay.load(_toggleCommentType.value, metadata, null, null, { StatePlatform.instance.getSubComments(c) });
|
||||
_repliesOverlay.load(_toggleCommentType.value, metadata, null, null, c, { StatePlatform.instance.getSubComments(c) });
|
||||
}
|
||||
|
||||
setRepliesOverlayVisible(isVisible = true, animate = true);
|
||||
|
|
|
@ -37,7 +37,6 @@ import com.futo.platformplayer.api.media.LiveChatManager
|
|||
import com.futo.platformplayer.api.media.PlatformID
|
||||
import com.futo.platformplayer.api.media.exceptions.ContentNotAvailableYetException
|
||||
import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException
|
||||
import com.futo.platformplayer.api.media.models.PlatformAuthorLink
|
||||
import com.futo.platformplayer.api.media.models.PlatformAuthorMembershipLink
|
||||
import com.futo.platformplayer.api.media.models.chapters.ChapterType
|
||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||
|
@ -52,7 +51,6 @@ import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource
|
|||
import com.futo.platformplayer.api.media.models.video.IPlatformVideo
|
||||
import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails
|
||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo
|
||||
import com.futo.platformplayer.api.media.platforms.js.models.IJSContentDetails
|
||||
import com.futo.platformplayer.api.media.platforms.js.models.JSVideoDetails
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.casting.CastConnectionState
|
||||
|
@ -60,7 +58,6 @@ import com.futo.platformplayer.casting.StateCasting
|
|||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.constructs.TaskHandler
|
||||
import com.futo.platformplayer.dialogs.AutoUpdateDialog
|
||||
import com.futo.platformplayer.downloads.VideoLocal
|
||||
import com.futo.platformplayer.engine.exceptions.ScriptAgeException
|
||||
import com.futo.platformplayer.engine.exceptions.ScriptException
|
||||
|
@ -109,7 +106,6 @@ import java.time.OffsetDateTime
|
|||
import kotlin.collections.ArrayList
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.roundToLong
|
||||
import kotlin.streams.toList
|
||||
|
||||
|
||||
class VideoDetailView : ConstraintLayout {
|
||||
|
@ -578,7 +574,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
|
||||
_container_content_current = _container_content_main;
|
||||
|
||||
_commentsList.onClick.subscribe { c ->
|
||||
_commentsList.onRepliesClick.subscribe { c ->
|
||||
val replyCount = c.replyCount ?: 0;
|
||||
var metadata = "";
|
||||
if (replyCount > 0) {
|
||||
|
@ -587,7 +583,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
var parentComment: PolycentricPlatformComment = c;
|
||||
_container_content_replies.load(_toggleCommentType.value, metadata, c.contextUrl, c.reference,
|
||||
_container_content_replies.load(_toggleCommentType.value, metadata, c.contextUrl, c.reference, c,
|
||||
{ StatePolycentric.instance.getCommentPager(c.contextUrl, c.reference) },
|
||||
{
|
||||
val newComment = parentComment.cloneWithUpdatedReplyCount((parentComment.replyCount ?: 0) + 1);
|
||||
|
@ -595,7 +591,7 @@ class VideoDetailView : ConstraintLayout {
|
|||
parentComment = newComment;
|
||||
});
|
||||
} else {
|
||||
_container_content_replies.load(_toggleCommentType.value, metadata, null, null, { StatePlatform.instance.getSubComments(c) });
|
||||
_container_content_replies.load(_toggleCommentType.value, metadata, null, null, c, { StatePlatform.instance.getSubComments(c) });
|
||||
}
|
||||
switchContentView(_container_content_replies);
|
||||
};
|
||||
|
|
|
@ -218,6 +218,59 @@ class StatePolycentric {
|
|||
}
|
||||
}
|
||||
|
||||
fun getSystemComments(context: Context, system: PublicKey): List<IPlatformComment> {
|
||||
val dp_25 = 25.dp(context.resources)
|
||||
val systemState = SystemState.fromStorageTypeSystemState(Store.instance.getSystemState(system))
|
||||
val author = system.systemToURLInfoSystemLinkUrl(systemState.servers.asIterable())
|
||||
val posts = arrayListOf<PolycentricPlatformComment>()
|
||||
Store.instance.enumerateSignedEvents(system, ContentType.POST) { se ->
|
||||
val ev = se.event
|
||||
val post = Protocol.Post.parseFrom(ev.content)
|
||||
|
||||
posts.add(PolycentricPlatformComment(
|
||||
contextUrl = author,
|
||||
author = PlatformAuthorLink(
|
||||
id = PlatformID("polycentric", author, null, ClaimType.POLYCENTRIC.value.toInt()),
|
||||
name = systemState.username,
|
||||
url = author,
|
||||
thumbnail = systemState.avatar?.selectBestImage(dp_25 * dp_25)?.let { img -> img.toURLInfoSystemLinkUrl(system.toProto(), img.process, listOf(PolycentricCache.SERVER)) },
|
||||
subscribers = null
|
||||
),
|
||||
msg = if (post.content.count() > PolycentricPlatformComment.MAX_COMMENT_SIZE) post.content.substring(0, PolycentricPlatformComment.MAX_COMMENT_SIZE) else post.content,
|
||||
rating = RatingLikeDislikes(0, 0),
|
||||
date = if (ev.unixMilliseconds != null) Instant.ofEpochMilli(ev.unixMilliseconds!!).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
|
||||
replyCount = 0,
|
||||
eventPointer = se.toPointer()
|
||||
))
|
||||
}
|
||||
|
||||
return posts
|
||||
}
|
||||
|
||||
suspend fun getLiveComment(contextUrl: String, reference: Protocol.Reference): PolycentricPlatformComment {
|
||||
val response = ApiMethods.getQueryReferences(PolycentricCache.SERVER, reference, null,
|
||||
Protocol.QueryReferencesRequestEvents.newBuilder()
|
||||
.setFromType(ContentType.POST.value)
|
||||
.addAllCountLwwElementReferences(arrayListOf(
|
||||
Protocol.QueryReferencesRequestCountLWWElementReferences.newBuilder()
|
||||
.setFromType(ContentType.OPINION.value)
|
||||
.setValue(ByteString.copyFrom(Opinion.like.data))
|
||||
.build(),
|
||||
Protocol.QueryReferencesRequestCountLWWElementReferences.newBuilder()
|
||||
.setFromType(ContentType.OPINION.value)
|
||||
.setValue(ByteString.copyFrom(Opinion.dislike.data))
|
||||
.build()
|
||||
))
|
||||
.addCountReferences(
|
||||
Protocol.QueryReferencesRequestCountReferences.newBuilder()
|
||||
.setFromType(ContentType.POST.value)
|
||||
.build())
|
||||
.build()
|
||||
)
|
||||
|
||||
return mapQueryReferences(contextUrl, response).first()
|
||||
}
|
||||
|
||||
suspend fun getCommentPager(contextUrl: String, reference: Protocol.Reference): IPager<IPlatformComment> {
|
||||
val response = ApiMethods.getQueryReferences(PolycentricCache.SERVER, reference, null,
|
||||
Protocol.QueryReferencesRequestEvents.newBuilder()
|
||||
|
@ -284,7 +337,7 @@ class StatePolycentric {
|
|||
};
|
||||
}
|
||||
|
||||
private suspend fun mapQueryReferences(contextUrl: String, response: Protocol.QueryReferencesResponse): List<IPlatformComment> {
|
||||
private suspend fun mapQueryReferences(contextUrl: String, response: Protocol.QueryReferencesResponse): List<PolycentricPlatformComment> {
|
||||
return response.itemsList.mapNotNull {
|
||||
val sev = SignedEvent.fromProto(it.event);
|
||||
val ev = sev.event;
|
||||
|
@ -338,7 +391,7 @@ class StatePolycentric {
|
|||
rating = RatingLikeDislikes(likes, dislikes),
|
||||
date = if (unixMilliseconds != null) Instant.ofEpochMilli(unixMilliseconds).atOffset(ZoneOffset.UTC) else OffsetDateTime.MIN,
|
||||
replyCount = replies.toInt(),
|
||||
reference = sev.toPointer().toReference()
|
||||
eventPointer = sev.toPointer()
|
||||
);
|
||||
} catch (e: Throwable) {
|
||||
return@mapNotNull null;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.futo.platformplayer.views
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.Animatable
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
|
@ -11,9 +12,10 @@ import android.widget.LinearLayout
|
|||
import androidx.core.view.updateLayoutParams
|
||||
import com.futo.platformplayer.R
|
||||
|
||||
class Loader : LinearLayout {
|
||||
class LoaderView : LinearLayout {
|
||||
private val _imageLoader: ImageView;
|
||||
private val _automatic: Boolean;
|
||||
private var _isWhite: Boolean;
|
||||
private val _animatable: Animatable;
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet? = null) : super(context, attrs) {
|
||||
|
@ -24,18 +26,25 @@ class Loader : LinearLayout {
|
|||
if (attrs != null) {
|
||||
val attrArr = context.obtainStyledAttributes(attrs, R.styleable.LoaderView, 0, 0);
|
||||
_automatic = attrArr.getBoolean(R.styleable.LoaderView_automatic, false);
|
||||
_isWhite = attrArr.getBoolean(R.styleable.LoaderView_isWhite, false);
|
||||
attrArr.recycle();
|
||||
} else {
|
||||
_automatic = false;
|
||||
_isWhite = false;
|
||||
}
|
||||
|
||||
visibility = View.GONE;
|
||||
|
||||
if (_isWhite) {
|
||||
_imageLoader.setColorFilter(Color.WHITE)
|
||||
}
|
||||
}
|
||||
constructor(context: Context, automatic: Boolean, height: Int = -1) : super(context) {
|
||||
constructor(context: Context, automatic: Boolean, height: Int = -1, isWhite: Boolean = false) : super(context) {
|
||||
inflate(context, R.layout.view_loader, this);
|
||||
_imageLoader = findViewById(R.id.image_loader);
|
||||
_animatable = _imageLoader.drawable as Animatable;
|
||||
_automatic = automatic;
|
||||
_isWhite = isWhite;
|
||||
|
||||
if(height > 0) {
|
||||
layoutParams = ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, height);
|
|
@ -41,7 +41,7 @@ class MonetizationView : LinearLayout {
|
|||
|
||||
private val _textMerchandise: TextView;
|
||||
private val _recyclerMerchandise: RecyclerView;
|
||||
private val _loaderMerchandise: Loader;
|
||||
private val _loaderViewMerchandise: LoaderView;
|
||||
private val _layoutMerchandise: FrameLayout;
|
||||
private var _merchandiseAdapterView: AnyAdapterView<StoreItem, StoreItemViewHolder>? = null;
|
||||
|
||||
|
@ -81,7 +81,7 @@ class MonetizationView : LinearLayout {
|
|||
|
||||
_textMerchandise = findViewById(R.id.text_merchandise);
|
||||
_recyclerMerchandise = findViewById(R.id.recycler_merchandise);
|
||||
_loaderMerchandise = findViewById(R.id.loader_merchandise);
|
||||
_loaderViewMerchandise = findViewById(R.id.loader_merchandise);
|
||||
_layoutMerchandise = findViewById(R.id.layout_merchandise);
|
||||
|
||||
_root = findViewById(R.id.root);
|
||||
|
@ -108,7 +108,7 @@ class MonetizationView : LinearLayout {
|
|||
}
|
||||
|
||||
private fun setMerchandise(items: List<StoreItem>?) {
|
||||
_loaderMerchandise.stop();
|
||||
_loaderViewMerchandise.stop();
|
||||
|
||||
if (items == null) {
|
||||
_textMerchandise.visibility = View.GONE;
|
||||
|
@ -147,7 +147,7 @@ class MonetizationView : LinearLayout {
|
|||
val uri = Uri.parse(storeData);
|
||||
if (uri.isAbsolute) {
|
||||
_taskLoadMerchandise.run(storeData);
|
||||
_loaderMerchandise.start();
|
||||
_loaderViewMerchandise.start();
|
||||
} else {
|
||||
Logger.i(TAG, "Merchandise not loaded, not URL nor JSON")
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.futo.platformplayer.views.adapters
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
|
@ -37,8 +38,10 @@ class CommentViewHolder : ViewHolder {
|
|||
private val _layoutRating: LinearLayout;
|
||||
private val _pillRatingLikesDislikes: PillRatingLikesDislikes;
|
||||
private val _layoutComment: ConstraintLayout;
|
||||
private val _buttonDelete: FrameLayout;
|
||||
|
||||
var onClick = Event1<IPlatformComment>();
|
||||
var onRepliesClick = Event1<IPlatformComment>();
|
||||
var onDelete = Event1<IPlatformComment>();
|
||||
var comment: IPlatformComment? = null
|
||||
private set;
|
||||
|
||||
|
@ -55,6 +58,7 @@ class CommentViewHolder : ViewHolder {
|
|||
_buttonReplies = itemView.findViewById(R.id.button_replies);
|
||||
_layoutRating = itemView.findViewById(R.id.layout_rating);
|
||||
_pillRatingLikesDislikes = itemView.findViewById(R.id.rating);
|
||||
_buttonDelete = itemView.findViewById(R.id.button_delete);
|
||||
|
||||
_pillRatingLikesDislikes.onLikeDislikeUpdated.subscribe { args ->
|
||||
val c = comment
|
||||
|
@ -87,7 +91,12 @@ class CommentViewHolder : ViewHolder {
|
|||
|
||||
_buttonReplies.onClick.subscribe {
|
||||
val c = comment ?: return@subscribe;
|
||||
onClick.emit(c);
|
||||
onRepliesClick.emit(c);
|
||||
}
|
||||
|
||||
_buttonDelete.setOnClickListener {
|
||||
val c = comment ?: return@setOnClickListener;
|
||||
onDelete.emit(c);
|
||||
}
|
||||
|
||||
_textBody.setPlatformPlayerLinkMovementMethod(viewGroup.context);
|
||||
|
@ -167,6 +176,13 @@ class CommentViewHolder : ViewHolder {
|
|||
_buttonReplies.visibility = View.GONE;
|
||||
}
|
||||
|
||||
val processHandle = StatePolycentric.instance.processHandle
|
||||
if (processHandle != null && comment is PolycentricPlatformComment && processHandle.system == comment.eventPointer.system) {
|
||||
_buttonDelete.visibility = View.VISIBLE
|
||||
} else {
|
||||
_buttonDelete.visibility = View.GONE
|
||||
}
|
||||
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
package com.futo.platformplayer.views.adapters
|
||||
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.recyclerview.widget.RecyclerView.ViewHolder
|
||||
import com.futo.platformplayer.*
|
||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.ratings.RatingLikeDislikes
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.constructs.TaskHandler
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.states.StateApp
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.platformplayer.views.others.CreatorThumbnail
|
||||
import com.futo.platformplayer.views.pills.PillButton
|
||||
import com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
||||
import com.futo.polycentric.core.Opinion
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class CommentWithReferenceViewHolder : ViewHolder {
|
||||
private val _creatorThumbnail: CreatorThumbnail;
|
||||
private val _textAuthor: TextView;
|
||||
private val _textMetadata: TextView;
|
||||
private val _textBody: TextView;
|
||||
private val _buttonReplies: PillButton;
|
||||
private val _pillRatingLikesDislikes: PillRatingLikesDislikes;
|
||||
private val _layoutComment: ConstraintLayout;
|
||||
private val _buttonDelete: FrameLayout;
|
||||
|
||||
private val _taskGetLiveComment = TaskHandler<PolycentricPlatformComment, PolycentricPlatformComment>(StateApp.instance.scopeGetter, { StatePolycentric.instance.getLiveComment(it.contextUrl, it.reference) })
|
||||
.success {
|
||||
bind(it, true);
|
||||
}
|
||||
.exception<Throwable> {
|
||||
Logger.w(TAG, "Failed to get live comment.", it);
|
||||
//TODO: Show error
|
||||
}
|
||||
|
||||
var onRepliesClick = Event1<IPlatformComment>();
|
||||
var onDelete = Event1<IPlatformComment>();
|
||||
var comment: IPlatformComment? = null
|
||||
private set;
|
||||
|
||||
constructor(viewGroup: ViewGroup) : super(LayoutInflater.from(viewGroup.context).inflate(R.layout.list_comment_with_reference, viewGroup, false)) {
|
||||
_layoutComment = itemView.findViewById(R.id.layout_comment);
|
||||
_creatorThumbnail = itemView.findViewById(R.id.image_thumbnail);
|
||||
_textAuthor = itemView.findViewById(R.id.text_author);
|
||||
_textMetadata = itemView.findViewById(R.id.text_metadata);
|
||||
_textBody = itemView.findViewById(R.id.text_body);
|
||||
_buttonReplies = itemView.findViewById(R.id.button_replies);
|
||||
_pillRatingLikesDislikes = itemView.findViewById(R.id.rating);
|
||||
_buttonDelete = itemView.findViewById(R.id.button_delete)
|
||||
|
||||
_pillRatingLikesDislikes.onLikeDislikeUpdated.subscribe { args ->
|
||||
val c = comment
|
||||
if (c !is PolycentricPlatformComment) {
|
||||
throw Exception("Not implemented for non polycentric comments")
|
||||
}
|
||||
|
||||
if (args.hasLiked) {
|
||||
args.processHandle.opinion(c.reference, Opinion.like);
|
||||
} else if (args.hasDisliked) {
|
||||
args.processHandle.opinion(c.reference, Opinion.dislike);
|
||||
} else {
|
||||
args.processHandle.opinion(c.reference, Opinion.neutral);
|
||||
}
|
||||
|
||||
_layoutComment.alpha = if (args.dislikes > 2 && args.dislikes.toFloat() / (args.likes + args.dislikes).toFloat() >= 0.7f) 0.5f else 1.0f;
|
||||
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
Logger.i(TAG, "Started backfill");
|
||||
args.processHandle.fullyBackfillServersAnnounceExceptions();
|
||||
Logger.i(TAG, "Finished backfill");
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to backfill servers.", e)
|
||||
}
|
||||
}
|
||||
|
||||
StatePolycentric.instance.updateLikeMap(c.reference, args.hasLiked, args.hasDisliked)
|
||||
};
|
||||
|
||||
_buttonReplies.onClick.subscribe {
|
||||
val c = comment ?: return@subscribe;
|
||||
onRepliesClick.emit(c);
|
||||
}
|
||||
|
||||
_buttonDelete.setOnClickListener {
|
||||
val c = comment ?: return@setOnClickListener;
|
||||
onDelete.emit(c);
|
||||
}
|
||||
|
||||
_textBody.setPlatformPlayerLinkMovementMethod(viewGroup.context);
|
||||
}
|
||||
|
||||
fun bind(comment: IPlatformComment, live: Boolean = false) {
|
||||
_taskGetLiveComment.cancel()
|
||||
|
||||
_creatorThumbnail.setThumbnail(comment.author.thumbnail, false);
|
||||
_creatorThumbnail.setHarborAvailable(comment is PolycentricPlatformComment,false);
|
||||
_textAuthor.text = comment.author.name;
|
||||
|
||||
val date = comment.date;
|
||||
if (date != null) {
|
||||
_textMetadata.visibility = View.VISIBLE;
|
||||
_textMetadata.text = " • ${date.toHumanNowDiffString()} ago";
|
||||
} else {
|
||||
_textMetadata.visibility = View.GONE;
|
||||
}
|
||||
|
||||
val rating = comment.rating;
|
||||
if (rating is RatingLikeDislikes) {
|
||||
_layoutComment.alpha = if (rating.dislikes > 2 && rating.dislikes.toFloat() / (rating.likes + rating.dislikes).toFloat() >= 0.7f) 0.5f else 1.0f;
|
||||
} else {
|
||||
_layoutComment.alpha = 1.0f;
|
||||
}
|
||||
|
||||
_textBody.text = comment.message.fixHtmlLinks();
|
||||
|
||||
if (comment is PolycentricPlatformComment) {
|
||||
if (live) {
|
||||
val hasLiked = StatePolycentric.instance.hasLiked(comment.reference);
|
||||
val hasDisliked = StatePolycentric.instance.hasDisliked(comment.reference);
|
||||
_pillRatingLikesDislikes.setRating(comment.rating, hasLiked, hasDisliked);
|
||||
} else {
|
||||
_pillRatingLikesDislikes.setLoading(true)
|
||||
}
|
||||
|
||||
if (live) {
|
||||
_buttonReplies.setLoading(false)
|
||||
|
||||
val replies = comment.replyCount ?: 0;
|
||||
if (replies > 0) {
|
||||
_buttonReplies.visibility = View.VISIBLE;
|
||||
_buttonReplies.text.text = "$replies " + itemView.context.getString(R.string.replies);
|
||||
} else {
|
||||
_buttonReplies.visibility = View.GONE;
|
||||
}
|
||||
} else {
|
||||
_buttonReplies.setLoading(true)
|
||||
}
|
||||
|
||||
if (false) {
|
||||
//Restore from cached
|
||||
} else {
|
||||
//_taskGetLiveComment.run(comment)
|
||||
}
|
||||
} else {
|
||||
_pillRatingLikesDislikes.visibility = View.GONE
|
||||
_buttonReplies.visibility = View.GONE
|
||||
}
|
||||
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "CommentWithReferenceViewHolder";
|
||||
}
|
||||
}
|
|
@ -17,8 +17,8 @@ class SubscriptionAdapter : RecyclerView.Adapter<SubscriptionViewHolder> {
|
|||
var onSettings = Event1<Subscription>();
|
||||
var sortBy: Int = 3
|
||||
set(value) {
|
||||
field = value;
|
||||
updateDataset();
|
||||
field = value
|
||||
updateDataset()
|
||||
}
|
||||
|
||||
constructor(inflater: LayoutInflater, confirmationMessage: String) : super() {
|
||||
|
|
|
@ -19,7 +19,7 @@ import com.futo.platformplayer.states.StateApp
|
|||
import com.futo.platformplayer.states.StatePlatform
|
||||
import com.futo.platformplayer.video.PlayerManager
|
||||
import com.futo.platformplayer.views.FeedStyle
|
||||
import com.futo.platformplayer.views.Loader
|
||||
import com.futo.platformplayer.views.LoaderView
|
||||
import com.futo.platformplayer.views.platform.PlatformIndicator
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
|
@ -28,7 +28,7 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||
|
||||
protected val _platformIndicatorNested: PlatformIndicator;
|
||||
protected val _containerLoader: LinearLayout;
|
||||
protected val _loader: Loader;
|
||||
protected val _loaderView: LoaderView;
|
||||
protected val _containerUnavailable: LinearLayout;
|
||||
protected val _textNestedUrl: TextView;
|
||||
|
||||
|
@ -42,7 +42,7 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||
constructor(context: Context, feedStyle: FeedStyle, exoPlayer: PlayerManager? = null): super(context, feedStyle, exoPlayer) {
|
||||
_platformIndicatorNested = findViewById(R.id.thumbnail_platform_nested);
|
||||
_containerLoader = findViewById(R.id.container_loader);
|
||||
_loader = findViewById(R.id.loader);
|
||||
_loaderView = findViewById(R.id.loader);
|
||||
_containerUnavailable = findViewById(R.id.container_unavailable);
|
||||
_textNestedUrl = findViewById(R.id.text_nested_url);
|
||||
|
||||
|
@ -116,7 +116,7 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||
if(!_contentSupported) {
|
||||
_containerUnavailable.visibility = View.VISIBLE;
|
||||
_containerLoader.visibility = View.GONE;
|
||||
_loader.stop();
|
||||
_loaderView.stop();
|
||||
}
|
||||
else {
|
||||
if(_feedStyle == FeedStyle.THUMBNAIL)
|
||||
|
@ -132,14 +132,14 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||
_contentSupported = false;
|
||||
_containerUnavailable.visibility = View.VISIBLE;
|
||||
_containerLoader.visibility = View.GONE;
|
||||
_loader.stop();
|
||||
_loaderView.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadNested(content: IPlatformNestedContent, onCompleted: ((IPlatformContentDetails)->Unit)? = null) {
|
||||
Logger.i(TAG, "Loading nested content [${content.contentUrl}]");
|
||||
_containerLoader.visibility = View.VISIBLE;
|
||||
_loader.start();
|
||||
_loaderView.start();
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
val def = StatePlatform.instance.getContentDetails(content.contentUrl);
|
||||
def.invokeOnCompletion {
|
||||
|
@ -150,13 +150,13 @@ class PreviewNestedVideoView : PreviewVideoView {
|
|||
if(_content == content) {
|
||||
_containerUnavailable.visibility = View.VISIBLE;
|
||||
_containerLoader.visibility = View.GONE;
|
||||
_loader.stop();
|
||||
_loaderView.stop();
|
||||
}
|
||||
//TODO: Handle exception
|
||||
}
|
||||
else if(_content == content) {
|
||||
_containerLoader.visibility = View.GONE;
|
||||
_loader.stop();
|
||||
_loaderView.stop();
|
||||
val nestedContent = def.getCompleted();
|
||||
_contentNested = nestedContent;
|
||||
if(nestedContent is IPlatformVideoDetails) {
|
||||
|
|
|
@ -4,15 +4,21 @@ import android.content.Context
|
|||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import com.futo.platformplayer.UIDialogs
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.api.media.models.comments.IPlatformComment
|
||||
import com.futo.platformplayer.api.media.models.comments.PolycentricPlatformComment
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.fixHtmlLinks
|
||||
import com.futo.platformplayer.states.StatePlatform
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.platformplayer.toHumanNowDiffString
|
||||
import com.futo.platformplayer.views.behavior.NonScrollingTextView
|
||||
import com.futo.platformplayer.views.comments.AddCommentView
|
||||
import com.futo.platformplayer.views.others.CreatorThumbnail
|
||||
import com.futo.platformplayer.views.segments.CommentsList
|
||||
import userpackage.Protocol
|
||||
|
||||
|
@ -22,6 +28,11 @@ class RepliesOverlay : LinearLayout {
|
|||
private val _topbar: OverlayTopbar;
|
||||
private val _commentsList: CommentsList;
|
||||
private val _addCommentView: AddCommentView;
|
||||
private val _textBody: NonScrollingTextView;
|
||||
private val _textAuthor: TextView;
|
||||
private val _textMetadata: TextView;
|
||||
private val _creatorThumbnail: CreatorThumbnail;
|
||||
private val _layoutParentComment: ConstraintLayout;
|
||||
private var _readonly = false;
|
||||
private var _onCommentAdded: ((comment: IPlatformComment) -> Unit)? = null;
|
||||
|
||||
|
@ -30,6 +41,11 @@ class RepliesOverlay : LinearLayout {
|
|||
_topbar = findViewById(R.id.topbar);
|
||||
_commentsList = findViewById(R.id.comments_list);
|
||||
_addCommentView = findViewById(R.id.add_comment_view);
|
||||
_textBody = findViewById(R.id.text_body)
|
||||
_textMetadata = findViewById(R.id.text_metadata)
|
||||
_textAuthor = findViewById(R.id.text_author)
|
||||
_creatorThumbnail = findViewById(R.id.image_thumbnail)
|
||||
_layoutParentComment = findViewById(R.id.layout_parent_comment)
|
||||
|
||||
_addCommentView.onCommentAdded.subscribe {
|
||||
_commentsList.addComment(it);
|
||||
|
@ -42,7 +58,7 @@ class RepliesOverlay : LinearLayout {
|
|||
}
|
||||
}
|
||||
|
||||
_commentsList.onClick.subscribe { c ->
|
||||
_commentsList.onRepliesClick.subscribe { c ->
|
||||
val replyCount = c.replyCount;
|
||||
var metadata = "";
|
||||
if (replyCount != null && replyCount > 0) {
|
||||
|
@ -50,9 +66,9 @@ class RepliesOverlay : LinearLayout {
|
|||
}
|
||||
|
||||
if (c is PolycentricPlatformComment) {
|
||||
load(false, metadata, c.contextUrl, c.reference, { StatePolycentric.instance.getCommentPager(c.contextUrl, c.reference) });
|
||||
load(false, metadata, c.contextUrl, c.reference, c, { StatePolycentric.instance.getCommentPager(c.contextUrl, c.reference) });
|
||||
} else {
|
||||
load(true, metadata, null, null, { StatePlatform.instance.getSubComments(c) });
|
||||
load(true, metadata, null, null, c, { StatePlatform.instance.getSubComments(c) });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -60,7 +76,7 @@ class RepliesOverlay : LinearLayout {
|
|||
_topbar.setInfo(context.getString(R.string.Replies), "");
|
||||
}
|
||||
|
||||
fun load(readonly: Boolean, metadata: String, contextUrl: String?, ref: Protocol.Reference?, loader: suspend () -> IPager<IPlatformComment>, onCommentAdded: ((comment: IPlatformComment) -> Unit)? = null) {
|
||||
fun load(readonly: Boolean, metadata: String, contextUrl: String?, ref: Protocol.Reference?, parentComment: IPlatformComment? = null, loader: suspend () -> IPager<IPlatformComment>, onCommentAdded: ((comment: IPlatformComment) -> Unit)? = null) {
|
||||
_readonly = readonly;
|
||||
if (readonly) {
|
||||
_addCommentView.visibility = View.GONE;
|
||||
|
@ -69,6 +85,26 @@ class RepliesOverlay : LinearLayout {
|
|||
_addCommentView.setContext(contextUrl, ref);
|
||||
}
|
||||
|
||||
if (parentComment == null) {
|
||||
_layoutParentComment.visibility = View.GONE
|
||||
} else {
|
||||
_layoutParentComment.visibility = View.VISIBLE
|
||||
|
||||
_textBody.text = parentComment.message.fixHtmlLinks()
|
||||
_textAuthor.text = parentComment.author.name
|
||||
|
||||
val date = parentComment.date
|
||||
if (date != null) {
|
||||
_textMetadata.visibility = View.VISIBLE
|
||||
_textMetadata.text = " • ${date.toHumanNowDiffString()} ago"
|
||||
} else {
|
||||
_textMetadata.visibility = View.GONE
|
||||
}
|
||||
|
||||
_creatorThumbnail.setThumbnail(parentComment.author.thumbnail, false);
|
||||
_creatorThumbnail.setHarborAvailable(parentComment is PolycentricPlatformComment,false);
|
||||
}
|
||||
|
||||
_topbar.setInfo(context.getString(R.string.Replies), metadata);
|
||||
_commentsList.load(readonly, loader);
|
||||
_onCommentAdded = onCommentAdded;
|
||||
|
|
|
@ -9,16 +9,20 @@ import android.widget.LinearLayout
|
|||
import android.widget.TextView
|
||||
import com.futo.platformplayer.R
|
||||
import com.futo.platformplayer.constructs.Event0
|
||||
import com.futo.platformplayer.views.LoaderView
|
||||
|
||||
class PillButton : LinearLayout {
|
||||
val icon: ImageView;
|
||||
val text: TextView;
|
||||
val loaderView: LoaderView;
|
||||
val onClick = Event0();
|
||||
private var _isLoading = false;
|
||||
|
||||
constructor(context : Context, attrs : AttributeSet) : super(context, attrs) {
|
||||
LayoutInflater.from(context).inflate(R.layout.pill_button, this, true);
|
||||
icon = findViewById(R.id.pill_icon);
|
||||
text = findViewById(R.id.pill_text);
|
||||
loaderView = findViewById(R.id.loader)
|
||||
|
||||
val attrArr = context.obtainStyledAttributes(attrs, R.styleable.PillButton, 0, 0);
|
||||
val attrIconRef = attrArr.getResourceId(R.styleable.PillButton_pillIcon, -1);
|
||||
|
@ -31,7 +35,29 @@ class PillButton : LinearLayout {
|
|||
text.text = attrText;
|
||||
|
||||
findViewById<LinearLayout>(R.id.root).setOnClickListener {
|
||||
if (_isLoading) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
||||
onClick.emit();
|
||||
};
|
||||
}
|
||||
|
||||
fun setLoading(loading: Boolean) {
|
||||
if (loading == _isLoading) {
|
||||
return
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
text.visibility = View.GONE
|
||||
loaderView.visibility = View.VISIBLE
|
||||
loaderView.start()
|
||||
} else {
|
||||
loaderView.stop()
|
||||
text.visibility = View.VISIBLE
|
||||
loaderView.visibility = View.GONE
|
||||
}
|
||||
|
||||
_isLoading = loading
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ import com.futo.platformplayer.constructs.Event1
|
|||
import com.futo.platformplayer.constructs.Event3
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.platformplayer.toHumanNumber
|
||||
import com.futo.platformplayer.views.LoaderView
|
||||
import com.futo.polycentric.core.ProcessHandle
|
||||
|
||||
data class OnLikeDislikeUpdatedArgs(
|
||||
|
@ -29,9 +30,12 @@ data class OnLikeDislikeUpdatedArgs(
|
|||
class PillRatingLikesDislikes : LinearLayout {
|
||||
private val _textLikes: TextView;
|
||||
private val _textDislikes: TextView;
|
||||
private val _loaderViewLikes: LoaderView;
|
||||
private val _loaderViewDislikes: LoaderView;
|
||||
private val _seperator: View;
|
||||
private val _iconLikes: ImageView;
|
||||
private val _iconDislikes: ImageView;
|
||||
private var _isLoading: Boolean = false;
|
||||
|
||||
private var _likes = 0L;
|
||||
private var _hasLiked = false;
|
||||
|
@ -47,14 +51,42 @@ class PillRatingLikesDislikes : LinearLayout {
|
|||
_seperator = findViewById(R.id.pill_seperator);
|
||||
_iconDislikes = findViewById(R.id.pill_dislike_icon);
|
||||
_iconLikes = findViewById(R.id.pill_like_icon);
|
||||
_loaderViewLikes = findViewById(R.id.loader_likes)
|
||||
_loaderViewDislikes = findViewById(R.id.loader_dislikes)
|
||||
|
||||
_iconLikes.setOnClickListener { StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_like)) { like(it) }; };
|
||||
_textLikes.setOnClickListener { StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_like)) { like(it) }; };
|
||||
_iconDislikes.setOnClickListener { StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_dislike)) { dislike(it) }; };
|
||||
_textDislikes.setOnClickListener { StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_dislike)) { dislike(it) }; };
|
||||
_iconLikes.setOnClickListener { if (!_isLoading) StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_like)) { like(it) }; };
|
||||
_textLikes.setOnClickListener { if (!_isLoading) StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_like)) { like(it) }; };
|
||||
_iconDislikes.setOnClickListener { if (!_isLoading) StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_dislike)) { dislike(it) }; };
|
||||
_textDislikes.setOnClickListener { if (!_isLoading) StatePolycentric.instance.requireLogin(context, context.getString(R.string.please_login_to_dislike)) { dislike(it) }; };
|
||||
}
|
||||
|
||||
fun setLoading(loading: Boolean) {
|
||||
if (_isLoading == loading) {
|
||||
return
|
||||
}
|
||||
|
||||
if (loading) {
|
||||
_textLikes.visibility = View.GONE
|
||||
_loaderViewLikes.visibility = View.VISIBLE
|
||||
_textDislikes.visibility = View.GONE
|
||||
_loaderViewDislikes.visibility = View.VISIBLE
|
||||
_loaderViewLikes.start()
|
||||
_loaderViewDislikes.start()
|
||||
} else {
|
||||
_loaderViewLikes.stop()
|
||||
_loaderViewDislikes.stop()
|
||||
_textLikes.visibility = View.VISIBLE
|
||||
_loaderViewLikes.visibility = View.GONE
|
||||
_textDislikes.visibility = View.VISIBLE
|
||||
_loaderViewDislikes.visibility = View.GONE
|
||||
}
|
||||
|
||||
_isLoading = loading
|
||||
}
|
||||
|
||||
fun setRating(rating: IRating, hasLiked: Boolean = false, hasDisliked: Boolean = false) {
|
||||
setLoading(false)
|
||||
|
||||
when (rating) {
|
||||
is RatingLikeDislikes -> {
|
||||
setRating(rating, hasLiked, hasDisliked);
|
||||
|
|
|
@ -19,9 +19,12 @@ import com.futo.platformplayer.api.media.structures.IAsyncPager
|
|||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.constructs.Event1
|
||||
import com.futo.platformplayer.constructs.TaskHandler
|
||||
import com.futo.platformplayer.fragment.mainactivity.main.ChannelFragment
|
||||
import com.futo.platformplayer.fullyBackfillServersAnnounceExceptions
|
||||
import com.futo.platformplayer.states.StatePolycentric
|
||||
import com.futo.platformplayer.views.adapters.CommentViewHolder
|
||||
import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import java.net.UnknownHostException
|
||||
|
||||
class CommentsList : ConstraintLayout {
|
||||
|
@ -69,7 +72,7 @@ class CommentsList : ConstraintLayout {
|
|||
private val _prependedView: FrameLayout;
|
||||
private var _readonly: Boolean = false;
|
||||
|
||||
var onClick = Event1<IPlatformComment>();
|
||||
var onRepliesClick = Event1<IPlatformComment>();
|
||||
var onCommentsLoaded = Event1<Int>();
|
||||
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
|
||||
|
@ -85,7 +88,8 @@ class CommentsList : ConstraintLayout {
|
|||
childViewHolderBinder = { viewHolder, position -> viewHolder.bind(_comments[position], _readonly); },
|
||||
childViewHolderFactory = { viewGroup, _ ->
|
||||
val holder = CommentViewHolder(viewGroup);
|
||||
holder.onClick.subscribe { c -> onClick.emit(c) };
|
||||
holder.onRepliesClick.subscribe { c -> onRepliesClick.emit(c) };
|
||||
holder.onDelete.subscribe(::onDelete);
|
||||
return@InsertedViewAdapterWithLoader holder;
|
||||
}
|
||||
);
|
||||
|
@ -106,6 +110,36 @@ class CommentsList : ConstraintLayout {
|
|||
_prependedView.addView(view);
|
||||
}
|
||||
|
||||
private fun onDelete(comment: IPlatformComment) {
|
||||
val processHandle = StatePolycentric.instance.processHandle ?: return
|
||||
if (comment !is PolycentricPlatformComment) {
|
||||
return
|
||||
}
|
||||
|
||||
val index = _comments.indexOf(comment)
|
||||
if (index != -1) {
|
||||
_comments.removeAt(index)
|
||||
_adapterComments.notifyItemRemoved(_adapterComments.childToParentPosition(index))
|
||||
|
||||
StateApp.instance.scopeOrNull?.launch(Dispatchers.IO) {
|
||||
try {
|
||||
processHandle.delete(comment.eventPointer.process, comment.eventPointer.logicalClock)
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to delete event.", e);
|
||||
return@launch;
|
||||
}
|
||||
|
||||
try {
|
||||
Logger.i(TAG, "Started backfill");
|
||||
processHandle.fullyBackfillServersAnnounceExceptions();
|
||||
Logger.i(TAG, "Finished backfill");
|
||||
} catch (e: Throwable) {
|
||||
Logger.e(TAG, "Failed to fully backfill servers.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun onScrolled() {
|
||||
val visibleItemCount = _recyclerComments.childCount;
|
||||
val firstVisibleItem = _llmReplies.findFirstVisibleItemPosition();
|
||||
|
|
6
app/src/main/res/drawable/background_comment.xml
Normal file
6
app/src/main/res/drawable/background_comment.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#1A1A1A" />
|
||||
<corners android:radius="4dp" />
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
</shape>
|
7
app/src/main/res/drawable/background_pill_pred.xml
Normal file
7
app/src/main/res/drawable/background_pill_pred.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="#A03D3D" />
|
||||
<corners android:radius="500dp" />
|
||||
<size android:height="20dp" />
|
||||
<padding android:left="0dp" android:top="0dp" android:right="0dp" android:bottom="0dp" />
|
||||
</shape>
|
9
app/src/main/res/drawable/ic_chat_filled.xml
Normal file
9
app/src/main/res/drawable/ic_chat_filled.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="M289.23,649.23q-13.08,0 -21.92,-8.85 -8.85,-8.85 -8.85,-21.92v-40h470l25.38,25.38L753.85,240h40q13.08,0 21.92,8.85 8.85,8.85 8.85,21.92v501.54L701.54,649.23L289.23,649.23ZM135.38,621.54v-470.77q0,-13.08 8.85,-21.92Q153.08,120 166.15,120h476.92q13.08,0 21.92,8.85 8.85,8.85 8.85,21.92v316.92q0,13.08 -8.85,21.92 -8.85,8.85 -21.92,8.85L258.46,498.46L135.38,621.54Z"/>
|
||||
</vector>
|
|
@ -52,7 +52,7 @@
|
|||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<com.futo.platformplayer.views.Loader
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader"
|
||||
android:layout_marginBottom="15dp"
|
||||
android:layout_marginTop="15dp"
|
||||
|
|
111
app/src/main/res/layout/fragment_comments.xml
Normal file
111
app/src/main/res/layout/fragment_comments.xml
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_header"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="24dp"
|
||||
android:text="@string/comments"
|
||||
android:fontFamily="@font/inter_extra_light"
|
||||
android:textColor="@color/white" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_comment_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="12dp"
|
||||
android:text="@string/these_are_all_commentcount_comments_you_have_made_in_grayjay"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textColor="#808080" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="14dp"
|
||||
android:textColor="@color/gray_ac"
|
||||
android:fontFamily="@font/inter_light"
|
||||
android:text="@string/sort_by" />
|
||||
|
||||
<Spinner
|
||||
android:id="@+id/spinner_sortby"
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="20dp"
|
||||
android:paddingEnd="12dp" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recycler_comments"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout android:id="@+id/layout_not_logged_in"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/black">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Login to view your comments"
|
||||
android:textSize="14dp"
|
||||
android:textColor="@color/white"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingStart="28dp"
|
||||
android:paddingEnd="28dp"
|
||||
android:layout_marginBottom="20dp"/>
|
||||
|
||||
<com.futo.platformplayer.views.overlays.RepliesOverlay
|
||||
android:id="@+id/replies_overlay"
|
||||
android:visibility="gone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_login"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_button_primary"
|
||||
android:clickable="true">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Login"
|
||||
android:textSize="14dp"
|
||||
android:textColor="@color/white"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:paddingTop="10dp"
|
||||
android:paddingBottom="10dp"
|
||||
android:paddingStart="28dp"
|
||||
android:paddingEnd="28dp"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_body"
|
||||
|
@ -136,6 +136,30 @@
|
|||
app:pillIcon="@drawable/ic_forum"
|
||||
app:pillText="55 Replies"
|
||||
android:layout_marginStart="15dp" />
|
||||
|
||||
<Space android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/button_delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_pill_pred"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
<TextView
|
||||
android:id="@+id/pill_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13dp"
|
||||
android:gravity="center_vertical"
|
||||
android:fontFamily="@font/inter_light"
|
||||
android:text="@string/delete" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
|
124
app/src/main/res/layout/list_comment_with_reference.xml
Normal file
124
app/src/main/res/layout/list_comment_with_reference.xml
Normal file
|
@ -0,0 +1,124 @@
|
|||
<?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/layout_comment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginStart="14dp"
|
||||
android:layout_marginEnd="14dp"
|
||||
android:orientation="vertical"
|
||||
android:background="@drawable/background_comment"
|
||||
android:padding="16dp">
|
||||
|
||||
<com.futo.platformplayer.views.others.CreatorThumbnail
|
||||
android:id="@+id/image_thumbnail"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:contentDescription="@string/channel_image"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/placeholder_channel_thumbnail" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_author"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||
app:layout_constraintTop_toTopOf="@id/image_thumbnail"
|
||||
tools:text="ShortCircuit" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_metadata"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textColor="@color/gray_ac"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/text_author"
|
||||
app:layout_constraintLeft_toRightOf="@id/text_author"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/text_author"
|
||||
tools:text=" • 3 years ago" />
|
||||
|
||||
<com.futo.platformplayer.views.behavior.NonScrollingTextView
|
||||
android:id="@+id/text_body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="@color/transparent"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:isScrollContainer="false"
|
||||
android:textColor="#CCCCCC"
|
||||
android:textSize="13sp"
|
||||
android:maxLines="100"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_metadata"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
tools:text="@string/lorem_ipsum" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_body"
|
||||
android:layout_marginTop="8dp"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<com.futo.platformplayer.views.pills.PillRatingLikesDislikes
|
||||
android:id="@+id/rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
android:layout_marginStart="10dp" />
|
||||
|
||||
<com.futo.platformplayer.views.pills.PillButton
|
||||
android:id="@+id/button_replies"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:pillIcon="@drawable/ic_forum"
|
||||
app:pillText="55 Replies"
|
||||
android:layout_marginStart="15dp" />
|
||||
|
||||
<Space android:layout_width="0dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/button_delete"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_pill_pred"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp">
|
||||
<TextView
|
||||
android:id="@+id/pill_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="13dp"
|
||||
android:gravity="center_vertical"
|
||||
android:fontFamily="@font/inter_light"
|
||||
android:text="@string/delete" />
|
||||
</FrameLayout>
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -127,7 +127,7 @@
|
|||
android:visibility="gone"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
<com.futo.platformplayer.views.Loader
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp" />
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:background="@color/black"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
|
@ -15,6 +16,78 @@
|
|||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/layout_parent_comment"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/topbar"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:padding="12dp"
|
||||
android:background="@drawable/background_16_round_4dp">
|
||||
|
||||
<com.futo.platformplayer.views.others.CreatorThumbnail
|
||||
android:id="@+id/image_thumbnail"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="25dp"
|
||||
android:contentDescription="@string/channel_image"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/placeholder_channel_thumbnail" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_author"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||
app:layout_constraintTop_toTopOf="@id/image_thumbnail"
|
||||
android:text="ShortCircuit" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text_metadata"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:textColor="@color/gray_ac"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/text_author"
|
||||
app:layout_constraintLeft_toRightOf="@id/text_author"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/text_author"
|
||||
android:text=" • 3 years ago" />
|
||||
|
||||
<com.futo.platformplayer.views.behavior.NonScrollingTextView
|
||||
android:id="@+id/text_body"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginStart="10dp"
|
||||
android:background="@color/transparent"
|
||||
android:fontFamily="@font/inter_regular"
|
||||
android:isScrollContainer="false"
|
||||
android:textColor="#CCCCCC"
|
||||
android:textSize="13sp"
|
||||
android:maxLines="3"
|
||||
android:ellipsize="end"
|
||||
app:layout_constraintTop_toBottomOf="@id/text_metadata"
|
||||
app:layout_constraintLeft_toRightOf="@id/image_thumbnail"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
android:text="@string/lorem_ipsum" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<com.futo.platformplayer.views.comments.AddCommentView
|
||||
android:id="@+id/add_comment_view"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -22,8 +95,7 @@
|
|||
android:layout_marginTop="12dp"
|
||||
android:layout_marginStart="12dp"
|
||||
android:layout_marginEnd="12dp"
|
||||
android:paddingBottom="12dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/topbar"
|
||||
app:layout_constraintTop_toBottomOf="@id/layout_parent_comment"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent" />
|
||||
|
||||
|
@ -32,6 +104,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/add_comment_view"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
android:layout_marginTop="12dp" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -9,12 +9,13 @@
|
|||
android:paddingStart="7dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:background="@drawable/background_pill"
|
||||
android:id="@+id/root">
|
||||
android:id="@+id/root"
|
||||
android:gravity="center_vertical">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/pill_icon"
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_width="18dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginRight="5dp"
|
||||
android:layout_marginLeft="5dp"
|
||||
android:layout_marginTop="0dp"
|
||||
|
@ -31,4 +32,10 @@
|
|||
android:fontFamily="@font/inter_light"
|
||||
tools:text="500K" />
|
||||
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
app:isWhite="true" />
|
||||
|
||||
</LinearLayout>
|
|
@ -8,7 +8,8 @@
|
|||
android:paddingBottom="7dp"
|
||||
android:paddingLeft="7dp"
|
||||
android:paddingRight="12dp"
|
||||
android:background="@drawable/background_pill">
|
||||
android:background="@drawable/background_pill"
|
||||
android:gravity="center_vertical">
|
||||
<ImageView
|
||||
android:id="@+id/pill_like_icon"
|
||||
android:layout_width="30dp"
|
||||
|
@ -22,6 +23,11 @@
|
|||
android:textSize="13dp"
|
||||
android:gravity="center_vertical"
|
||||
tools:text="500K" />
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader_likes"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
app:isWhite="true" />
|
||||
|
||||
<View
|
||||
android:id="@+id/pill_seperator"
|
||||
|
@ -44,5 +50,10 @@
|
|||
android:gravity="center_vertical"
|
||||
android:textSize="13dp"
|
||||
tools:text="500K" />
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader_dislikes"
|
||||
android:layout_width="14dp"
|
||||
android:layout_height="14dp"
|
||||
app:isWhite="true" />
|
||||
|
||||
</LinearLayout>
|
|
@ -120,7 +120,7 @@
|
|||
android:orientation="horizontal"
|
||||
android:layout_gravity="center" />
|
||||
|
||||
<com.futo.platformplayer.views.Loader
|
||||
<com.futo.platformplayer.views.LoaderView
|
||||
android:id="@+id/loader_merchandise"
|
||||
android:layout_width="64dp"
|
||||
android:layout_height="64dp"
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>معلومات</item>
|
||||
<item>تفصيلي</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>Information</item>
|
||||
<item>Ausführlich</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -738,4 +738,8 @@
|
|||
<item>Información</item>
|
||||
<item>Detallado</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>Information</item>
|
||||
<item>Verbeux</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>情報</item>
|
||||
<item>詳細</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>정보</item>
|
||||
<item>상세</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>Informação</item>
|
||||
<item>Detalhado</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
|
@ -722,4 +722,8 @@
|
|||
<item>Информация</item>
|
||||
<item>Подробно</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -722,4 +722,8 @@
|
|||
<item>信息</item>
|
||||
<item>详细</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -2,5 +2,6 @@
|
|||
<resources>
|
||||
<declare-styleable name="LoaderView">
|
||||
<attr name="automatic" format="boolean" />
|
||||
<attr name="isWhite" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
|
@ -687,6 +687,7 @@
|
|||
<string name="allow_grayjay_to_handle_specific_urls_please_set_it_as_default_in_the_app_settings">When you click \'Yes\', the Grayjay app settings will open.\n\nThere, navigate to:\n1. "Open by default" or "Set as default" section.\nYou might find this option directly or under \'Advanced\' settings, depending on your device.\n\n2. Choose \'Open supported links\' for Grayjay.\n\n(some devices have this listed under \'Default Apps\' in the main settings followed by selecting Grayjay for relevant categories)</string>
|
||||
<string name="failed_to_show_settings">Failed to show settings</string>
|
||||
<string name="play_store_version_does_not_support_default_url_handling">Play store version does not support default URL handling.</string>
|
||||
<string name="these_are_all_commentcount_comments_you_have_made_in_grayjay">These are all {commentCount} comments you have made in Grayjay.</string>
|
||||
<string-array name="home_screen_array">
|
||||
<item>Recommendations</item>
|
||||
<item>Subscriptions</item>
|
||||
|
@ -774,6 +775,10 @@
|
|||
<item>Disabled</item>
|
||||
<item>Enabled</item>
|
||||
</string-array>
|
||||
<string-array name="comments_sortby_array">
|
||||
<item>Newest</item>
|
||||
<item>Oldest</item>
|
||||
</string-array>
|
||||
<string-array name="subscriptions_sortby_array">
|
||||
<item>Name Ascending</item>
|
||||
<item>Name Descending</item>
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 839e4c4a4f5ed6cb6f68047f88b26c5831e6e703
|
||||
Subproject commit faaa7a6d8efb3f92fc239e7d77ec2f9a46c3a958
|
Loading…
Add table
Reference in a new issue