WIP visor de discusiones

This commit is contained in:
Erik Cavazos 2023-09-10 16:37:21 -06:00
parent 003ab3ea5d
commit 5cf9fcb426
19 changed files with 403 additions and 80 deletions

View File

@ -31,7 +31,7 @@
android:parentActivityName=".MainActivity"/>
<activity android:name=".settings.ui.SettingsActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".posting.posts.ui.CreatePostActivity" android:theme="@style/Theme.Isolaatti" android:windowSoftInputMode="adjustResize"/>
<activity android:name=".posting.PostViewerActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".posting.posts.viewer.ui.PostViewerActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".drafts.ui.DraftsActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".about.AboutActivity" android:theme="@style/Theme.Isolaatti"/>
<activity android:name=".picture_viewer.ui.PictureViewerActivity" android:theme="@style/Theme.Isolaatti"/>

View File

@ -25,7 +25,7 @@ import com.isolaatti.databinding.FragmentFeedBinding
import com.isolaatti.drafts.ui.DraftsActivity
import com.isolaatti.home.presentation.FeedViewModel
import com.isolaatti.picture_viewer.ui.PictureViewerActivity
import com.isolaatti.posting.PostViewerActivity
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
import com.isolaatti.posting.common.domain.OnUserInteractedWithPostCallback
import com.isolaatti.posting.common.domain.Ownable

View File

@ -1,32 +0,0 @@
package com.isolaatti.posting
import android.content.Context
import android.content.Intent
import android.os.Bundle
import com.isolaatti.common.IsolaattiBaseActivity
import com.isolaatti.databinding.ActivityCreatePostBinding
import com.isolaatti.databinding.ActivityPostViewerBinding
class PostViewerActivity : IsolaattiBaseActivity() {
companion object {
const val POST_ID = "postId"
fun startActivity(context: Context, postId: Long) {
context.startActivity(Intent(context, PostViewerActivity::class.java).apply {
putExtra(POST_ID, postId)
})
}
}
private lateinit var binding: ActivityPostViewerBinding
private var postId: Long? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityPostViewerBinding.inflate(layoutInflater)
setContentView(binding.root)
}
}

View File

@ -5,24 +5,36 @@ import com.isolaatti.posting.likes.data.remote.LikeDto
import com.isolaatti.posting.likes.data.remote.LikesApi
import com.isolaatti.posting.likes.domain.repository.LikesRepository
import com.isolaatti.utils.LongIdentificationWrapper
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import retrofit2.Response
import retrofit2.awaitResponse
class LikesRepositoryImpl(private val likesApi: LikesApi) : LikesRepository {
override fun likePost(postId: Long): Flow<LikeDto> = flow {
val response = likesApi.likePost(LongIdentificationWrapper(postId)).awaitResponse()
Log.d("likes_repo", response.toString())
if(response.isSuccessful) {
response.body()?.let { emit(it) }
override fun likePost(postId: Long): Flow<Resource<LikeDto>> = flow {
try {
val response = likesApi.likePost(LongIdentificationWrapper(postId)).awaitResponse()
if(response.isSuccessful) {
response.body()?.let { emit(Resource.Success(it)) }
} else {
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
}
} catch(_: Exception) {
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
}
}
override fun unLikePost(postId: Long): Flow<LikeDto> = flow {
val response = likesApi.unLikePost(LongIdentificationWrapper(postId)).awaitResponse()
Log.d("likes_repo", response.toString())
if(response.isSuccessful) {
response.body()?.let { emit(it) }
override fun unLikePost(postId: Long): Flow<Resource<LikeDto>> = flow {
try {
val response = likesApi.unLikePost(LongIdentificationWrapper(postId)).awaitResponse()
if(response.isSuccessful) {
response.body()?.let { emit(Resource.Success(it)) }
} else {
emit(Resource.Error(Resource.Error.mapErrorCode(response.code())))
}
} catch(_: Exception) {
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
}
}
}

View File

@ -1,9 +1,10 @@
package com.isolaatti.posting.likes.domain.repository
import com.isolaatti.posting.likes.data.remote.LikeDto
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
interface LikesRepository {
fun likePost(postId: Long): Flow<LikeDto>
fun unLikePost(postId: Long): Flow<LikeDto>
fun likePost(postId: Long): Flow<Resource<LikeDto>>
fun unLikePost(postId: Long): Flow<Resource<LikeDto>>
}

View File

@ -94,13 +94,16 @@ class PostsRepositoryImpl @Inject constructor(private val feedsApi: FeedsApi, pr
}
}
override fun loadPost(postId: Long): Flow<Resource<FeedDto.PostDto>> = flow {
override fun loadPost(postId: Long): Flow<Resource<Post>> = flow {
emit(Resource.Loading())
try {
val result = postApi.getPost(postId).execute()
if(result.isSuccessful) {
emit(Resource.Success(result.body()))
return@flow
val dto = result.body()
if(dto != null) {
emit(Resource.Success(Post.fromPostDto(dto)))
return@flow
}
}
emit(Resource.Error(Resource.Error.mapErrorCode(result.code())))
} catch(_: Exception) {

View File

@ -18,5 +18,5 @@ interface PostsRepository {
fun makePost(createPostDto: CreatePostDto): Flow<Resource<FeedDto.PostDto>>
fun editPost(editPostDto: EditPostDto): Flow<Resource<FeedDto.PostDto>>
fun deletePost(postId: Long): Flow<Resource<PostDeletedDto>>
fun loadPost(postId: Long): Flow<Resource<FeedDto.PostDto>>
fun loadPost(postId: Long): Flow<Resource<Post>>
}

View File

@ -36,5 +36,22 @@ data class Post(
)
}.toMutableList()
}
fun fromPostDto(postDto: FeedDto.PostDto): Post {
return Post(
id = postDto.post.id,
userId = postDto.post.userId,
textContent = postDto.post.textContent,
privacy = postDto.post.privacy,
date = postDto.post.date,
audioId = postDto.post.audioId,
squadId = postDto.post.squadId,
numberOfComments = postDto.numberOfComments,
numberOfLikes = postDto.numberOfLikes,
userName = postDto.userName,
squadName = postDto.squadName,
liked = postDto.liked
)
}
}
}

View File

@ -1,13 +1,13 @@
package com.isolaatti.posting.posts.domain.use_case
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.domain.PostsRepository
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.utils.Resource
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject
class LoadSinglePost @Inject constructor(private val postsRepository: PostsRepository) {
operator fun invoke(postId: Long): Flow<Resource<FeedDto.PostDto>> {
operator fun invoke(postId: Long): Flow<Resource<Post>> {
return postsRepository.loadPost(postId)
}
}

View File

@ -72,7 +72,7 @@ class CreatePostViewModel @Inject constructor(private val makePost: MakePost, pr
loadPost(postId).onEach { postRes ->
if(postRes is Resource.Success) {
postRes.data?.let {
postToEdit.postValue(EditPostDto(PRIVACY_ISOLAATTI, content = it.post.textContent, postId = it.post.id))
postToEdit.postValue(EditPostDto(PRIVACY_ISOLAATTI, content = it.textContent, postId = it.id))
}
}
}.flowOn(Dispatchers.IO).launchIn(this)

View File

@ -43,36 +43,54 @@ abstract class PostListingViewModelBase : ViewModel() {
fun likePost(postId: Long) {
viewModelScope.launch {
likesRepository.likePost(postId).onEach {likeDto ->
val likedPost = posts.value?.first?.find { post -> post.id == likeDto.postId }
val index = posts.value?.first?.indexOf(likedPost)
if(index != null){
val temp = posts.value?.first?.toMutableList()
Log.d("***", temp.toString())
temp?.set(index, likedPost!!.apply {
liked = true
numberOfLikes = likeDto.likesCount
likesRepository.likePost(postId).onEach {like ->
})
when(like) {
is Resource.Error -> {}
is Resource.Loading -> {}
is Resource.Success -> {
val likedPost = posts.value?.first?.find { post -> post.id == like.data?.postId }
val index = posts.value?.first?.indexOf(likedPost)
if(index != null){
val temp = posts.value?.first?.toMutableList()
Log.d("***", temp.toString())
temp?.set(index, likedPost!!.apply {
liked = true
numberOfLikes = like.data?.likesCount ?: 0
})
}
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
}
}
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
fun unLikePost(postId: Long) {
viewModelScope.launch {
likesRepository.unLikePost(postId).onEach {likeDto ->
val likedPost = posts.value?.first?.find { post -> post.id == likeDto.postId }
val index = posts.value?.first?.indexOf(likedPost)
if(index != null){
val temp = posts.value?.first?.toMutableList()
temp?.set(index, likedPost!!.apply {
liked = false
numberOfLikes = likeDto.likesCount
})
likesRepository.unLikePost(postId).onEach {like ->
when(like) {
is Resource.Error -> TODO()
is Resource.Loading -> TODO()
is Resource.Success -> {
val likedPost = posts.value?.first?.find { post -> post.id == like.data?.postId }
val index = posts.value?.first?.indexOf(likedPost)
if(index != null){
val temp = posts.value?.first?.toMutableList()
temp?.set(index, likedPost!!.apply {
liked = false
numberOfLikes = like.data?.likesCount ?: 0
})
}
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
}
}
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
}.flowOn(Dispatchers.IO).launchIn(this)
}
}

View File

@ -0,0 +1,97 @@
package com.isolaatti.posting.posts.viewer.presentation
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.isolaatti.posting.comments.domain.use_case.GetComments
import com.isolaatti.posting.likes.domain.repository.LikesRepository
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.posting.posts.domain.use_case.LoadSinglePost
import com.isolaatti.utils.Resource
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
@HiltViewModel
class PostViewerViewModel @Inject constructor(private val loadSinglePost: LoadSinglePost, private val likesRepository: LikesRepository) : ViewModel() {
val error: MutableLiveData<Resource.Error.ErrorType?> = MutableLiveData()
val post: MutableLiveData<Post> = MutableLiveData()
var postId: Long = 0
private val toRetry: MutableList<Runnable> = mutableListOf()
val postLiked: MutableLiveData<Boolean> = MutableLiveData()
// runs the lists of "Runnable" one by one and clears list. After this is executed,
// caller should report as handled
fun retry() {
toRetry.forEach {
it.run()
}
toRetry.clear()
}
fun getPost() {
viewModelScope.launch {
loadSinglePost(postId).onEach {
when(it) {
is Resource.Error -> {
error.postValue(it.errorType)
toRetry.add {
getPost()
}
}
is Resource.Loading -> {}
is Resource.Success -> {
if(it.data != null) {
post.postValue(it.data)
postLiked.postValue(it.data.liked)
}
}
}
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
private fun updateLikesCount(likesCount: Int) {
val updatedPost = post.value?.copy(numberOfLikes = likesCount)
if(updatedPost != null) {
post.postValue(updatedPost)
}
}
fun likeDislikePost() {
viewModelScope.launch {
if(postLiked.value == true) {
likesRepository.unLikePost(postId).onEach {
when(it) {
is Resource.Error -> TODO()
is Resource.Loading -> TODO()
is Resource.Success -> {
updateLikesCount(it.data?.likesCount ?: 0)
postLiked.postValue(false)
}
}
}.flowOn(Dispatchers.IO).launchIn(this)
} else {
likesRepository.likePost(postId).onEach {
when(it) {
is Resource.Error -> TODO()
is Resource.Loading -> TODO()
is Resource.Success -> {
updateLikesCount(it.data?.likesCount ?: 0)
postLiked.postValue(true)
}
}
}.flowOn(Dispatchers.IO).launchIn(this)
}
}
}
}

View File

@ -0,0 +1,133 @@
package com.isolaatti.posting.posts.viewer.ui
import android.content.Context
import android.content.Intent
import android.content.res.ColorStateList
import android.os.Bundle
import androidx.activity.viewModels
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.core.content.res.ResourcesCompat
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.common.ErrorMessageViewModel
import com.isolaatti.common.IsolaattiBaseActivity
import com.isolaatti.databinding.ActivityPostViewerBinding
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
import com.isolaatti.posting.posts.viewer.presentation.PostViewerViewModel
import com.isolaatti.profile.ui.ProfileActivity
import com.isolaatti.utils.PicassoImagesPluginDef
import com.isolaatti.utils.UrlGen
import com.squareup.picasso.Picasso
import io.noties.markwon.AbstractMarkwonPlugin
import io.noties.markwon.Markwon
import io.noties.markwon.MarkwonConfiguration
import io.noties.markwon.image.destination.ImageDestinationProcessorRelativeToAbsolute
import io.noties.markwon.linkify.LinkifyPlugin
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
class PostViewerActivity : IsolaattiBaseActivity() {
companion object {
const val POST_ID = "postId"
fun startActivity(context: Context, postId: Long) {
context.startActivity(Intent(context, PostViewerActivity::class.java).apply {
putExtra(POST_ID, postId)
})
}
}
private lateinit var binding: ActivityPostViewerBinding
private val viewModel: PostViewerViewModel by viewModels()
private var postId: Long = 0
private lateinit var markwon: Markwon
private fun openComments() {
val modalBottomSheet = BottomSheetPostComments.getInstance(postId)
modalBottomSheet.show(supportFragmentManager, BottomSheetPostComments.TAG)
}
private fun setObservers() {
viewModel.error.observe(this) {
errorViewModel.error.postValue(it)
CoroutineScope(Dispatchers.Default).launch {
errorViewModel.retry.collect {
viewModel.retry()
errorViewModel.handleRetry()
}
}
}
viewModel.post.observe(this) {
markwon.setMarkdown(binding.markwonContainer, it.textContent)
binding.author.text = it.userName
Picasso.get().load(UrlGen.userProfileImage(it.userId)).into(binding.profileImageView)
binding.commentsInfo.text = getString(R.string.comments_info, it.numberOfComments)
binding.likesInfo.text = getString(R.string.likes_info, it.numberOfLikes)
binding.author.setOnClickListener {_ ->
ProfileActivity.startActivity(this@PostViewerActivity, it.userId)
}
}
viewModel.postLiked.observe(this) {
val color = if(it) R.color.purple_lighter else R.color.on_surface
val menuItem = binding.toolbar.menu.findItem(R.id.like)
menuItem.isEnabled = true
menuItem.icon?.setTint(ResourcesCompat.getColor(resources, color, null))
}
}
private fun setListeners() {
binding.toolbar.setOnMenuItemClickListener {
when(it.itemId) {
R.id.like -> {
viewModel.likeDislikePost()
true
}
R.id.comments -> {
openComments()
true
}
else -> false
}
}
binding.commentsInfo.setOnClickListener {
openComments()
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
postId = intent.getLongExtra(POST_ID, 0)
binding = ActivityPostViewerBinding.inflate(layoutInflater)
markwon = Markwon.builder(this)
.usePlugin(object: AbstractMarkwonPlugin() {
override fun configureConfiguration(builder: MarkwonConfiguration.Builder) {
builder
.imageDestinationProcessor(
ImageDestinationProcessorRelativeToAbsolute
.create(BuildConfig.backend))
}
})
.usePlugin(PicassoImagesPluginDef.picassoImagePlugin)
.usePlugin(LinkifyPlugin.create())
.build()
setContentView(binding.root)
if(postId!! > 0) {
viewModel.postId = postId
setObservers()
setListeners()
viewModel.getPost()
}
}
}

View File

@ -22,7 +22,7 @@ import com.isolaatti.common.ErrorMessageViewModel
import com.isolaatti.databinding.FragmentDiscussionsBinding
import com.isolaatti.followers.domain.FollowingState
import com.isolaatti.home.FeedFragment
import com.isolaatti.posting.PostViewerActivity
import com.isolaatti.posting.posts.viewer.ui.PostViewerActivity
import com.isolaatti.posting.comments.ui.BottomSheetPostComments
import com.isolaatti.posting.common.domain.Ownable
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked

View File

@ -4,6 +4,6 @@
android:viewportWidth="640"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:fillColor="@color/on_surface"
android:pathData="M208,352c114.9,0 208,-78.8 208,-176S322.9,0 208,0S0,78.8 0,176c0,38.6 14.7,74.3 39.6,103.4c-3.5,9.4 -8.7,17.7 -14.2,24.7c-4.8,6.2 -9.7,11 -13.3,14.3c-1.8,1.6 -3.3,2.9 -4.3,3.7c-0.5,0.4 -0.9,0.7 -1.1,0.8l-0.2,0.2 0,0 0,0C1,327.2 -1.4,334.4 0.8,340.9S9.1,352 16,352c21.8,0 43.8,-5.6 62.1,-12.5c9.2,-3.5 17.8,-7.4 25.3,-11.4C134.1,343.3 169.8,352 208,352zM448,176c0,112.3 -99.1,196.9 -216.5,207C255.8,457.4 336.4,512 432,512c38.2,0 73.9,-8.7 104.7,-23.9c7.5,4 16,7.9 25.2,11.4c18.3,6.9 40.3,12.5 62.1,12.5c6.9,0 13.1,-4.5 15.2,-11.1c2.1,-6.6 -0.2,-13.8 -5.8,-17.9l0,0 0,0 -0.2,-0.2c-0.2,-0.2 -0.6,-0.4 -1.1,-0.8c-1,-0.8 -2.5,-2 -4.3,-3.7c-3.6,-3.3 -8.5,-8.1 -13.3,-14.3c-5.5,-7 -10.7,-15.4 -14.2,-24.7c24.9,-29 39.6,-64.7 39.6,-103.4c0,-92.8 -84.9,-168.9 -192.6,-175.5c0.4,5.1 0.6,10.3 0.6,15.5z"/>
</vector>

View File

@ -4,6 +4,6 @@
android:viewportWidth="512"
android:viewportHeight="512">
<path
android:fillColor="#FF000000"
android:fillColor="@color/on_surface"
android:pathData="M336,16L336,80c0,8.8 -7.2,16 -16,16s-16,-7.2 -16,-16L304,16c0,-8.8 7.2,-16 16,-16s16,7.2 16,16zM237.3,23.1l32,48c4.9,7.4 2.9,17.3 -4.4,22.2s-17.3,2.9 -22.2,-4.4l-32,-48c-4.9,-7.4 -2.9,-17.3 4.4,-22.2s17.3,-2.9 22.2,4.4zM135,119c9.4,-9.4 24.6,-9.4 33.9,0L292.7,242.7c10.1,10.1 27.3,2.9 27.3,-11.3L320,192c0,-17.7 14.3,-32 32,-32s32,14.3 32,32L384,345.6c0,57.1 -30,110 -78.9,139.4c-64,38.4 -145.8,28.3 -198.5,-24.4L7,361c-9.4,-9.4 -9.4,-24.6 0,-33.9s24.6,-9.4 33.9,0l53,53c6.1,6.1 16,6.1 22.1,0s6.1,-16 0,-22.1L23,265c-9.4,-9.4 -9.4,-24.6 0,-33.9s24.6,-9.4 33.9,0l93,93c6.1,6.1 16,6.1 22.1,0s6.1,-16 0,-22.1L55,185c-9.4,-9.4 -9.4,-24.6 0,-33.9s24.6,-9.4 33.9,0l117,117c6.1,6.1 16,6.1 22.1,0s6.1,-16 0,-22.1l-93,-93c-9.4,-9.4 -9.4,-24.6 0,-33.9zM433.1,484.9c-24.2,14.5 -50.9,22.1 -77.7,23.1c48.1,-39.6 76.6,-99 76.6,-162.4l0,-98.1c8.2,-0.1 16,-6.4 16,-16L448,192c0,-17.7 14.3,-32 32,-32s32,14.3 32,32L512,345.6c0,57.1 -30,110 -78.9,139.4zM424.9,18.7c7.4,4.9 9.3,14.8 4.4,22.2l-32,48c-4.9,7.4 -14.8,9.3 -22.2,4.4s-9.3,-14.8 -4.4,-22.2l32,-48c4.9,-7.4 14.8,-9.3 22.2,-4.4z"/>
</vector>

View File

@ -1,21 +1,71 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.google.android.material.appbar.AppBarLayout
android:id="@+id/appBarLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<com.google.android.material.appbar.MaterialToolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Theme.Isolaatti"
app:navigationIcon="@drawable/baseline_arrow_back_24"
app:navigationIconTint="@color/on_surface"
/>
app:title="@string/discussion"
app:menu="@menu/post_viewer_menu"/>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/profile_image_view"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="16dp"
app:shapeAppearance="@style/ShapeAppearanceOverlay.Avatar"
tools:srcCompat="@tools:sample/avatars"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="username"
android:textAlignment="center"
android:textStyle="bold"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="8dp"
style="@style/Widget.Material3.Button.TextButton"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_horizontal">
<com.google.android.material.button.MaterialButton
android:id="@+id/comments_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.TextButton"
android:layout_marginEnd="4dp"/>
<com.google.android.material.button.MaterialButton
android:id="@+id/likes_info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Widget.Material3.Button.TextButton"/>
</LinearLayout>
<TextView
android:id="@+id/markwon_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/comments"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:title="@string/comments"
android:icon="@drawable/comments_solid"
app:showAsAction="always"/>
<item
android:id="@+id/like"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:title="@string/clap"
android:icon="@drawable/hands_clapping_solid"
android:enabled="false"
app:showAsAction="always"/>
</menu>

View File

@ -80,4 +80,8 @@
<string name="retry">Retry</string>
<string name="not_found">The resource you are trying to load could not be found</string>
<string name="unknown_error">An unkwnow error occurred</string>
<string name="clap">Clap</string>
<string name="comments">Comments</string>
<string name="likes_info">Claps: %d</string>
<string name="comments_info">Comments: %d</string>
</resources>