feat: reviews in info page
This commit is contained in:
parent
91f728150c
commit
d12ddc9c0d
10 changed files with 97 additions and 50 deletions
|
@ -75,7 +75,7 @@ class AnilistQueries {
|
||||||
media.cameFromContinue = false
|
media.cameFromContinue = false
|
||||||
|
|
||||||
val query =
|
val query =
|
||||||
"""{Media(id:${media.id}){id favourites popularity episodes chapters mediaListEntry{id status score(format:POINT_100)progress private notes repeat customLists updatedAt startedAt{year month day}completedAt{year month day}}isFavourite siteUrl idMal nextAiringEpisode{episode airingAt}source countryOfOrigin format duration season seasonYear startDate{year month day}endDate{year month day}genres studios(isMain:true){nodes{id name siteUrl}}description trailer{site id}synonyms tags{name rank isMediaSpoiler}characters(sort:[ROLE,FAVOURITES_DESC],perPage:25,page:1){edges{role voiceActors { id name { first middle last full native userPreferred } image { large medium } languageV2 } node{id image{medium}name{userPreferred}isFavourite}}}relations{edges{relationType(version:2)node{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}popularity meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}staffPreview:staff(perPage:8,sort:[RELEVANCE,ID]){edges{role node{id image{large medium}name{userPreferred}}}}recommendations(sort:RATING_DESC){nodes{mediaRecommendation{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}externalLinks{url site}}Page(page:1){pageInfo{total perPage currentPage lastPage hasNextPage}mediaList(isFollowing:true,sort:[STATUS],mediaId:${media.id}){id status score(format: POINT_100) progress progressVolumes user{id name avatar{large medium}}}}}"""
|
"""{Media(id:${media.id}){id favourites popularity episodes chapters mediaListEntry{id status score(format:POINT_100)progress private notes repeat customLists updatedAt startedAt{year month day}completedAt{year month day}}reviews(perPage:3, sort:SCORE_DESC){nodes{id mediaId mediaType summary body(asHtml:true) rating ratingAmount userRating score private siteUrl createdAt updatedAt user{id name bannerImage avatar{medium large}}}}isFavourite siteUrl idMal nextAiringEpisode{episode airingAt}source countryOfOrigin format duration season seasonYear startDate{year month day}endDate{year month day}genres studios(isMain:true){nodes{id name siteUrl}}description trailer{site id}synonyms tags{name rank isMediaSpoiler}characters(sort:[ROLE,FAVOURITES_DESC],perPage:25,page:1){edges{role voiceActors { id name { first middle last full native userPreferred } image { large medium } languageV2 } node{id image{medium}name{userPreferred}isFavourite}}}relations{edges{relationType(version:2)node{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}popularity meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}staffPreview:staff(perPage:8,sort:[RELEVANCE,ID]){edges{role node{id image{large medium}name{userPreferred}}}}recommendations(sort:RATING_DESC){nodes{mediaRecommendation{id idMal mediaListEntry{progress private score(format:POINT_100)status}episodes chapters nextAiringEpisode{episode}meanScore isAdult isFavourite format title{english romaji userPreferred}type status(version:2)bannerImage coverImage{large}}}}externalLinks{url site}}Page(page:1){pageInfo{total perPage currentPage lastPage hasNextPage}mediaList(isFollowing:true,sort:[STATUS],mediaId:${media.id}){id status score(format: POINT_100) progress progressVolumes user{id name avatar{large medium}}}}}"""
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val anilist = async {
|
val anilist = async {
|
||||||
var response = executeQuery<Query.Media>(query, force = true)
|
var response = executeQuery<Query.Media>(query, force = true)
|
||||||
|
@ -211,6 +211,9 @@ class AnilistQueries {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fetchedMedia.reviews?.nodes != null){
|
||||||
|
media.review = fetchedMedia.reviews!!.nodes as ArrayList<Query.Review>
|
||||||
|
}
|
||||||
if (user?.mediaList?.isNotEmpty() == true) {
|
if (user?.mediaList?.isNotEmpty() == true) {
|
||||||
media.users = user.mediaList?.mapNotNull {
|
media.users = user.mediaList?.mapNotNull {
|
||||||
it.user?.let { user ->
|
it.user?.let { user ->
|
||||||
|
@ -1505,7 +1508,7 @@ Page(page:$page,perPage:50) {
|
||||||
return author
|
return author
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getReviews(mediaId: Int, page: Int = 1, sort: String = "CREATED_AT_DESC"): Query.ReviewsResponse? {
|
suspend fun getReviews(mediaId: Int, page: Int = 1, sort: String = "SCORE_DESC"): Query.ReviewsResponse? {
|
||||||
return executeQuery<Query.ReviewsResponse>(
|
return executeQuery<Query.ReviewsResponse>(
|
||||||
"""{Page(page:$page,perPage:10){pageInfo{currentPage,hasNextPage,total}reviews(mediaId:$mediaId,sort:$sort){id,mediaId,mediaType,summary,body(asHtml:true)rating,ratingAmount,userRating,score,private,siteUrl,createdAt,updatedAt,user{id,name,bannerImage avatar{medium,large}}}}}""",
|
"""{Page(page:$page,perPage:10){pageInfo{currentPage,hasNextPage,total}reviews(mediaId:$mediaId,sort:$sort){id,mediaId,mediaType,summary,body(asHtml:true)rating,ratingAmount,userRating,score,private,siteUrl,createdAt,updatedAt,user{id,name,bannerImage avatar{medium,large}}}}}""",
|
||||||
force = true
|
force = true
|
||||||
|
|
|
@ -152,7 +152,7 @@ data class Media(
|
||||||
@SerialName("mediaListEntry") var mediaListEntry: MediaList?,
|
@SerialName("mediaListEntry") var mediaListEntry: MediaList?,
|
||||||
|
|
||||||
// User reviews of the media
|
// User reviews of the media
|
||||||
// @SerialName("reviews") var reviews: ReviewConnection?,
|
@SerialName("reviews") var reviews: ReviewConnection?,
|
||||||
|
|
||||||
// User recommendations for similar media
|
// User recommendations for similar media
|
||||||
@SerialName("recommendations") var recommendations: RecommendationConnection?,
|
@SerialName("recommendations") var recommendations: RecommendationConnection?,
|
||||||
|
@ -538,3 +538,8 @@ data class MediaListGroup(
|
||||||
|
|
||||||
@SerialName("status") var status: MediaListStatus?,
|
@SerialName("status") var status: MediaListStatus?,
|
||||||
) : java.io.Serializable
|
) : java.io.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ReviewConnection(
|
||||||
|
@SerialName("nodes") var nodes: List<Query.Review>?,
|
||||||
|
)
|
|
@ -5,6 +5,7 @@ import ani.dantotsu.connections.anilist.api.FuzzyDate
|
||||||
import ani.dantotsu.connections.anilist.api.MediaEdge
|
import ani.dantotsu.connections.anilist.api.MediaEdge
|
||||||
import ani.dantotsu.connections.anilist.api.MediaList
|
import ani.dantotsu.connections.anilist.api.MediaList
|
||||||
import ani.dantotsu.connections.anilist.api.MediaType
|
import ani.dantotsu.connections.anilist.api.MediaType
|
||||||
|
import ani.dantotsu.connections.anilist.api.Query
|
||||||
import ani.dantotsu.media.anime.Anime
|
import ani.dantotsu.media.anime.Anime
|
||||||
import ani.dantotsu.media.manga.Manga
|
import ani.dantotsu.media.manga.Manga
|
||||||
import ani.dantotsu.profile.User
|
import ani.dantotsu.profile.User
|
||||||
|
@ -62,6 +63,7 @@ data class Media(
|
||||||
var timeUntilAiring: Long? = null,
|
var timeUntilAiring: Long? = null,
|
||||||
|
|
||||||
var characters: ArrayList<Character>? = null,
|
var characters: ArrayList<Character>? = null,
|
||||||
|
var review: ArrayList<Query.Review>? = null,
|
||||||
var staff: ArrayList<Author>? = null,
|
var staff: ArrayList<Author>? = null,
|
||||||
var prequel: Media? = null,
|
var prequel: Media? = null,
|
||||||
var sequel: Media? = null,
|
var sequel: Media? = null,
|
||||||
|
|
|
@ -34,7 +34,6 @@ import ani.dantotsu.databinding.ItemChipBinding
|
||||||
import ani.dantotsu.databinding.ItemQuelsBinding
|
import ani.dantotsu.databinding.ItemQuelsBinding
|
||||||
import ani.dantotsu.databinding.ItemTitleChipgroupBinding
|
import ani.dantotsu.databinding.ItemTitleChipgroupBinding
|
||||||
import ani.dantotsu.databinding.ItemTitleRecyclerBinding
|
import ani.dantotsu.databinding.ItemTitleRecyclerBinding
|
||||||
import ani.dantotsu.databinding.ItemTitleSearchBinding
|
|
||||||
import ani.dantotsu.databinding.ItemTitleTextBinding
|
import ani.dantotsu.databinding.ItemTitleTextBinding
|
||||||
import ani.dantotsu.databinding.ItemTitleTrailerBinding
|
import ani.dantotsu.databinding.ItemTitleTrailerBinding
|
||||||
import ani.dantotsu.displayTimer
|
import ani.dantotsu.displayTimer
|
||||||
|
@ -46,6 +45,7 @@ import ani.dantotsu.px
|
||||||
import ani.dantotsu.setSafeOnClickListener
|
import ani.dantotsu.setSafeOnClickListener
|
||||||
import ani.dantotsu.settings.saving.PrefManager
|
import ani.dantotsu.settings.saving.PrefManager
|
||||||
import ani.dantotsu.settings.saving.PrefName
|
import ani.dantotsu.settings.saving.PrefName
|
||||||
|
import com.xwray.groupie.GroupieAdapter
|
||||||
import io.noties.markwon.Markwon
|
import io.noties.markwon.Markwon
|
||||||
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
import io.noties.markwon.SoftBreakAddsNewLinePlugin
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -81,7 +81,8 @@ class MediaInfoFragment : Fragment() {
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
val model: MediaDetailsViewModel by activityViewModels()
|
val model: MediaDetailsViewModel by activityViewModels()
|
||||||
val offline: Boolean = PrefManager.getVal(PrefName.OfflineMode) || !isOnline(requireContext())
|
val offline: Boolean =
|
||||||
|
PrefManager.getVal(PrefName.OfflineMode) || !isOnline(requireContext())
|
||||||
binding.mediaInfoProgressBar.isGone = loaded
|
binding.mediaInfoProgressBar.isGone = loaded
|
||||||
binding.mediaInfoContainer.isVisible = loaded
|
binding.mediaInfoContainer.isVisible = loaded
|
||||||
binding.mediaInfoContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += 128f.px + navBarHeight }
|
binding.mediaInfoContainer.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin += 128f.px + navBarHeight }
|
||||||
|
@ -254,7 +255,8 @@ class MediaInfoFragment : Fragment() {
|
||||||
if (!media.users.isNullOrEmpty() && !offline) {
|
if (!media.users.isNullOrEmpty() && !offline) {
|
||||||
val users: ArrayList<User> = media.users ?: arrayListOf()
|
val users: ArrayList<User> = media.users ?: arrayListOf()
|
||||||
if (Anilist.token != null && media.userStatus != null) {
|
if (Anilist.token != null && media.userStatus != null) {
|
||||||
users.add(0,
|
users.add(
|
||||||
|
0,
|
||||||
User(
|
User(
|
||||||
id = Anilist.userid!!,
|
id = Anilist.userid!!,
|
||||||
name = getString(R.string.you),
|
name = getString(R.string.you),
|
||||||
|
@ -263,7 +265,8 @@ class MediaInfoFragment : Fragment() {
|
||||||
status = media.userStatus,
|
status = media.userStatus,
|
||||||
score = media.userScore.toFloat(),
|
score = media.userScore.toFloat(),
|
||||||
progress = media.userProgress,
|
progress = media.userProgress,
|
||||||
totalEpisodes = media.anime?.totalEpisodes ?: media.manga?.totalChapters,
|
totalEpisodes = media.anime?.totalEpisodes
|
||||||
|
?: media.manga?.totalChapters,
|
||||||
nextAiringEpisode = media.anime?.nextAiringEpisode
|
nextAiringEpisode = media.anime?.nextAiringEpisode
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -519,22 +522,41 @@ class MediaInfoFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemTitleSearchBinding.inflate(
|
if (!media.review.isNullOrEmpty()) {
|
||||||
LayoutInflater.from(context),
|
ItemTitleRecyclerBinding.inflate(
|
||||||
parent,
|
LayoutInflater.from(context),
|
||||||
false
|
parent,
|
||||||
).apply {
|
false
|
||||||
|
).apply {
|
||||||
titleSearchImage.loadImage(media.banner ?: media.cover)
|
fun onUserClick(userId: Int) {
|
||||||
titleSearchText.text =
|
val review = media.review!!.find { i -> i.id == userId }
|
||||||
getString(R.string.reviews)
|
if (review != null) {
|
||||||
titleSearchCard.setSafeOnClickListener {
|
startActivity(
|
||||||
val query = Intent(requireContext(), ReviewActivity::class.java)
|
Intent(requireContext(), ReviewViewActivity::class.java)
|
||||||
.putExtra("mediaId", media.id)
|
.putExtra("review", review)
|
||||||
ContextCompat.startActivity(requireContext(), query, null)
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val adapter = GroupieAdapter()
|
||||||
|
media.review!!.forEach {
|
||||||
|
adapter.add(ReviewAdapter(it, ::onUserClick))
|
||||||
|
}
|
||||||
|
itemTitle.setText(R.string.reviews)
|
||||||
|
itemRecycler.adapter = adapter
|
||||||
|
itemRecycler.layoutManager = LinearLayoutManager(
|
||||||
|
requireContext(),
|
||||||
|
LinearLayoutManager.VERTICAL,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
itemMore.visibility = View.VISIBLE
|
||||||
|
itemMore.setSafeOnClickListener {
|
||||||
|
startActivity(
|
||||||
|
Intent(requireContext(), ReviewActivity::class.java)
|
||||||
|
.putExtra("mediaId", media.id)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
parent.addView(root)
|
||||||
}
|
}
|
||||||
|
|
||||||
parent.addView(root)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ItemTitleRecyclerBinding.inflate(
|
ItemTitleRecyclerBinding.inflate(
|
||||||
|
|
|
@ -125,7 +125,6 @@ class ReviewActivity : AppCompatActivity() {
|
||||||
adapter.add(
|
adapter.add(
|
||||||
ReviewAdapter(
|
ReviewAdapter(
|
||||||
it,
|
it,
|
||||||
this,
|
|
||||||
this::onUserClick
|
this::onUserClick
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,30 +1,24 @@
|
||||||
package ani.dantotsu.media
|
package ani.dantotsu.media
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.text.SpannableString
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.lifecycle.lifecycleScope
|
|
||||||
import ani.dantotsu.R
|
import ani.dantotsu.R
|
||||||
import ani.dantotsu.blurImage
|
|
||||||
import ani.dantotsu.connections.anilist.Anilist
|
import ani.dantotsu.connections.anilist.Anilist
|
||||||
import ani.dantotsu.connections.anilist.api.Query
|
import ani.dantotsu.connections.anilist.api.Query
|
||||||
import ani.dantotsu.databinding.ItemFollowerBinding
|
|
||||||
import ani.dantotsu.databinding.ItemReviewsBinding
|
import ani.dantotsu.databinding.ItemReviewsBinding
|
||||||
import ani.dantotsu.getThemeColor
|
|
||||||
import ani.dantotsu.loadImage
|
import ani.dantotsu.loadImage
|
||||||
import ani.dantotsu.profile.activity.ActivityItemBuilder
|
import ani.dantotsu.profile.activity.ActivityItemBuilder
|
||||||
import ani.dantotsu.toast
|
import ani.dantotsu.toast
|
||||||
import com.xwray.groupie.viewbinding.BindableItem
|
import com.xwray.groupie.viewbinding.BindableItem
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
|
||||||
class ReviewAdapter(
|
class ReviewAdapter(
|
||||||
private var review: Query.Review,
|
private var review: Query.Review,
|
||||||
val context: ReviewActivity,
|
|
||||||
val clickCallback: (Int) -> Unit
|
val clickCallback: (Int) -> Unit
|
||||||
|
|
||||||
) : BindableItem<ItemReviewsBinding>() {
|
) : BindableItem<ItemReviewsBinding>() {
|
||||||
private lateinit var binding: ItemReviewsBinding
|
private lateinit var binding: ItemReviewsBinding
|
||||||
|
|
||||||
|
@ -34,7 +28,8 @@ class ReviewAdapter(
|
||||||
binding.reviewUserAvatar.loadImage(review.user?.avatar?.medium)
|
binding.reviewUserAvatar.loadImage(review.user?.avatar?.medium)
|
||||||
binding.reviewText.text = review.summary
|
binding.reviewText.text = review.summary
|
||||||
binding.reviewPostTime.text = ActivityItemBuilder.getDateTime(review.createdAt)
|
binding.reviewPostTime.text = ActivityItemBuilder.getDateTime(review.createdAt)
|
||||||
binding.reviewTag.text = "[${review.score}]"
|
val text = "[${review.score/ 10.0f}]"
|
||||||
|
binding.reviewTag.text = text
|
||||||
binding.root.setOnClickListener { clickCallback(review.id) }
|
binding.root.setOnClickListener { clickCallback(review.id) }
|
||||||
userVote(review.userRating)
|
userVote(review.userRating)
|
||||||
enableVote()
|
enableVote()
|
||||||
|
@ -75,7 +70,8 @@ class ReviewAdapter(
|
||||||
|
|
||||||
private fun rateReview(rating: String) {
|
private fun rateReview(rating: String) {
|
||||||
disableVote()
|
disableVote()
|
||||||
context.lifecycleScope.launch {
|
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
|
||||||
|
scope.launch {
|
||||||
val result = Anilist.mutation.rateReview(review.id, rating)
|
val result = Anilist.mutation.rateReview(review.id, rating)
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
@ -91,7 +87,7 @@ class ReviewAdapter(
|
||||||
} else {
|
} else {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
toast(
|
toast(
|
||||||
context.getString(R.string.error_message, "response is null")
|
binding.root.context.getString(R.string.error_message, "response is null")
|
||||||
)
|
)
|
||||||
enableVote()
|
enableVote()
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
android:id="@+id/activityUserAvatar"
|
android:id="@+id/activityUserAvatar"
|
||||||
android:layout_width="42dp"
|
android:layout_width="42dp"
|
||||||
android:layout_height="42dp"
|
android:layout_height="42dp"
|
||||||
android:layout_gravity="center"
|
|
||||||
app:srcCompat="@drawable/ic_round_add_circle_24"
|
app:srcCompat="@drawable/ic_round_add_circle_24"
|
||||||
tools:ignore="ContentDescription,ImageContrastCheck"
|
tools:ignore="ContentDescription,ImageContrastCheck"
|
||||||
tools:tint="@color/transparent" />
|
tools:tint="@color/transparent" />
|
||||||
|
|
|
@ -12,14 +12,16 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:backgroundTint="@color/bg_white"
|
android:backgroundTint="@color/transparent"
|
||||||
|
app:strokeColor="@color/transparent"
|
||||||
app:cardCornerRadius="124dp">
|
app:cardCornerRadius="124dp">
|
||||||
|
|
||||||
<ImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/profileUserAvatar"
|
android:id="@+id/profileUserAvatar"
|
||||||
android:layout_width="100dp"
|
android:layout_width="92dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="92dp"
|
||||||
tools:ignore="ContentDescription,ImageContrastCheck"
|
app:srcCompat="@drawable/ic_round_add_circle_24"
|
||||||
|
tools:ignore="ContentDescription"
|
||||||
tools:tint="@color/transparent" />
|
tools:tint="@color/transparent" />
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:layout_marginTop="12dp"
|
|
||||||
android:backgroundTint="@color/transparent"
|
android:backgroundTint="@color/transparent"
|
||||||
app:cardCornerRadius="64dp"
|
app:cardCornerRadius="64dp"
|
||||||
app:strokeColor="@color/transparent">
|
app:strokeColor="@color/transparent">
|
||||||
|
|
|
@ -5,16 +5,35 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:orientation="vertical">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/itemTitle"
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="32dp"
|
android:orientation="horizontal"
|
||||||
android:layout_marginTop="8dp"
|
tools:ignore="UseCompoundDrawables">
|
||||||
android:layout_marginEnd="32dp"
|
|
||||||
android:fontFamily="@font/poppins_bold"
|
<TextView
|
||||||
android:text="@string/relations"
|
android:id="@+id/itemTitle"
|
||||||
android:textSize="16sp" />
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="24dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:text="@string/relations"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/itemMore"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:fontFamily="@font/poppins_bold"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:src="@drawable/arrow_mark"
|
||||||
|
android:textSize="16sp"
|
||||||
|
tools:ignore="ContentDescription" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
<ani.dantotsu.FadingEdgeRecyclerView
|
<ani.dantotsu.FadingEdgeRecyclerView
|
||||||
android:id="@+id/itemRecycler"
|
android:id="@+id/itemRecycler"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue