This commit is contained in:
Erik Cavazos 2023-08-27 23:03:40 -06:00
parent 633b366baf
commit ca17fe1e22
14 changed files with 171 additions and 43 deletions

View File

@ -308,7 +308,7 @@
<PersistentState>
<option name="values">
<map>
<entry key="url" value="jar:file:/C:/Program%20Files/Android/Android%20Studio/plugins/android/lib/android.jar!/images/material/icons/materialicons/info/baseline_info_24.xml" />
<entry key="url" value="file:/$USER_HOME$/AppData/Local/Android/Sdk/icons/material/materialicons/download/baseline_download_24.xml" />
</map>
</option>
</PersistentState>
@ -318,7 +318,7 @@
</option>
<option name="values">
<map>
<entry key="outputName" value="baseline_info_24" />
<entry key="outputName" value="baseline_download_24" />
<entry key="sourceFile" value="C:\Users\erike\Downloads\isolaatti.svg" />
</map>
</option>

View File

@ -7,11 +7,11 @@
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="C:\Users\erike\.android\avd\Pixel_3a_API_34_extension_level_7_x86_64.avd" />
<value value="C:\Users\erike\.android\avd\Pixel_5_API_33.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-08-19T23:37:01.462209700Z" />
<timeTargetWasSelectedWithDropDown value="2023-08-21T02:45:21.143691700Z" />
</component>
</project>

View File

@ -30,6 +30,7 @@ import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.posting.posts.presentation.CreatePostContract
import com.isolaatti.posting.posts.presentation.EditPostContract
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
@ -80,26 +81,26 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
// region observers
val optionsObserver: Observer<OptionClicked?> = Observer { optionClicked ->
private val optionsObserver: Observer<OptionClicked?> = Observer { optionClicked ->
if(optionClicked?.callerId == CALLER_ID) {
// post id should come as payload
val postId = optionClicked.payload as? Long ?: return@Observer
val post = optionClicked.payload as? Post ?: return@Observer
when(optionClicked.optionId) {
Options.Option.OPTION_DELETE -> {
Dialogs.buildDeletePostDialog(requireContext()) { delete ->
optionsViewModel.handle()
if(delete) {
viewModel.deletePost(postId)
viewModel.deletePost(post.id)
}
}.show()
}
Options.Option.OPTION_EDIT -> {
optionsViewModel.handle()
editDiscussion.launch(postId)
editDiscussion.launch(post.id)
}
Options.Option.OPTION_REPORT -> {
optionsViewModel.handle()
}
}
}

View File

@ -33,11 +33,12 @@ class FeedViewModel @Inject constructor(
postsRepository.getFeed(getLastId()).onEach { listResource ->
when (listResource) {
is Resource.Success -> {
val eventType = if((postsList?.size ?: 0) > 0) UpdateEvent.UpdateType.PAGE_ADDED else UpdateEvent.UpdateType.REFRESH
loadingPosts.postValue(false)
posts.postValue(Pair(postsList?.apply {
addAll(listResource.data ?: listOf())
} ?: listResource.data,
UpdateEvent(UpdateEvent.UpdateType.PAGE_ADDED, null)))
UpdateEvent(eventType, null)))
noMoreContent.postValue(listResource.data?.size == 0)
}
@ -50,6 +51,7 @@ class FeedViewModel @Inject constructor(
is Resource.Error -> {
//errorLoading.postValue(feedDtoResource.errorType)
}
}
isLoadingFromScrolling = false
}.flowOn(Dispatchers.IO).launchIn(this)

View File

@ -11,13 +11,17 @@ import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import com.isolaatti.common.Dialogs
import com.isolaatti.databinding.BottomSheetPostCommentsBinding
import com.isolaatti.home.FeedFragment
import com.isolaatti.posting.comments.domain.model.Comment
import com.isolaatti.posting.common.domain.OnUserInteractedCallback
import com.isolaatti.posting.common.domain.Ownable
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.profile.ui.ProfileActivity
import com.isolaatti.utils.PicassoImagesPluginDef
import dagger.hilt.android.AndroidEntryPoint
@ -36,9 +40,27 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
val optionsObserver: Observer<OptionClicked?> = Observer {
if(it?.callerId == CALLER_ID) {
optionsViewModel.optionClicked(-1)
val optionsObserver: Observer<OptionClicked?> = Observer { optionClicked ->
if(optionClicked?.callerId == BottomSheetPostComments.CALLER_ID) {
val comment = optionClicked.payload as? Comment ?: return@Observer
when(optionClicked.optionId) {
Options.Option.OPTION_DELETE -> {
Dialogs.buildDeletePostDialog(requireContext()) { delete ->
optionsViewModel.handle()
if(delete) {
// remove comment
}
}.show()
}
Options.Option.OPTION_EDIT -> {
optionsViewModel.handle()
//editDiscussion.launch(post.id)
}
Options.Option.OPTION_REPORT -> {
optionsViewModel.handle()
}
}
}
}
@ -95,7 +117,6 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
}
optionsViewModel.optionClicked(-1)
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
}

View File

@ -17,31 +17,61 @@ data class Options(
const val OPTION_DELETE = 1
const val OPTION_EDIT = 2
const val OPTION_REPORT = 3
const val OPTION_SAVE = 4
const val OPTION_SNAPSHOT = 5
}
}
companion object {
const val POST_OPTIONS = 1
const val COMMENT_OPTIONS = 2
val noOptions = Options(0, listOf())
val myPostOptions = Options(R.string.post_options_title, listOf(
fun getPostsOptions(userOwned: Boolean, savable: Boolean, snapshotAble: Boolean): Options {
val list = mutableListOf(
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
)
if(userOwned) {
list.addAll(listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT))
)
}
val postOptions = Options(R.string.post_options_title, listOf(
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
if(savable) {
list.add(Option(R.string.save, R.drawable.baseline_save_24, Option.OPTION_SAVE))
}
val myCommentOptions = Options(R.string.post_options_title, listOf(
if(snapshotAble) {
list.add(Option(R.string.save_snapshot, R.drawable.baseline_download_24, Option.OPTION_SNAPSHOT))
}
return Options(R.string.post_options_title, list)
}
fun getCommentOptions(userOwned: Boolean, savable: Boolean, snapshotAble: Boolean): Options {
val list = mutableListOf(
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
)
if(userOwned) {
list.addAll(listOf(
Option(R.string.delete, R.drawable.baseline_delete_24, Option.OPTION_DELETE),
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT),
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
Option(R.string.edit, R.drawable.baseline_edit_24, Option.OPTION_EDIT))
)
}
val commentOptions = Options(R.string.post_options_title, listOf(
Option(R.string.report, R.drawable.baseline_report_24, Option.OPTION_REPORT)
))
if(savable) {
list.add(Option(R.string.save, R.drawable.baseline_save_24, Option.OPTION_SAVE))
}
if(snapshotAble) {
list.add(Option(R.string.save_snapshot, R.drawable.baseline_download_24, Option.OPTION_SNAPSHOT))
}
return Options(R.string.comment_options, list)
}
}
}

View File

@ -7,6 +7,7 @@ import androidx.lifecycle.viewModelScope
import com.isolaatti.posting.common.domain.Ownable
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options.Companion.COMMENT_OPTIONS
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options.Companion.POST_OPTIONS
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.settings.domain.UserIdSetting
@ -38,27 +39,33 @@ class BottomSheetPostOptionsViewModel @Inject constructor(private val userIdSett
when(options) {
POST_OPTIONS -> {
userIdSetting.getUserId()?.let { userId ->
if(userId == payload?.userId) {
_options.postValue(Options.myPostOptions)
} else {
_options.postValue(Options.postOptions)
}
_options.postValue(Options.getPostsOptions(
userOwned = userId == payload?.userId,
savable = false,
snapshotAble = false)
)
_callerId = callerId
_payload = payload
}
}
COMMENT_OPTIONS -> {
userIdSetting.getUserId()?.let { userId ->
_options.postValue(Options.getCommentOptions(
userOwned = userId == payload?.userId,
savable = false,
snapshotAble = false)
)
_callerId = callerId
_payload = payload
}
}
}
}
}
}
fun optionClicked(optionId: Int) {
_optionClicked.postValue(OptionClicked(optionId, _callerId, _payload))
}
}

View File

@ -55,6 +55,7 @@ class BottomSheetPostOptionsFragment : BottomSheetDialogFragment(), OptionsRecyc
private fun renderOptions(options: Options) {
viewBinding.title.text = requireContext().getText(options.title)
viewBinding.recyclerOptions.adapter = OptionsRecyclerAdapter(options.items, this)
viewBinding.recyclerOptions.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.VERTICAL, false)
}

View File

@ -5,6 +5,7 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
@ -13,17 +14,21 @@ import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.isolaatti.BuildConfig
import com.isolaatti.R
import com.isolaatti.common.Dialogs
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.comments.presentation.BottomSheetPostComments
import com.isolaatti.posting.common.domain.Ownable
import com.isolaatti.posting.common.options_bottom_sheet.domain.OptionClicked
import com.isolaatti.posting.common.options_bottom_sheet.domain.Options
import com.isolaatti.posting.common.options_bottom_sheet.presentation.BottomSheetPostOptionsViewModel
import com.isolaatti.posting.common.options_bottom_sheet.ui.BottomSheetPostOptionsFragment
import com.isolaatti.posting.posts.data.remote.FeedDto
import com.isolaatti.posting.posts.domain.entity.Post
import com.isolaatti.posting.posts.presentation.CreatePostContract
import com.isolaatti.posting.posts.presentation.EditPostContract
import com.isolaatti.posting.posts.presentation.PostListingRecyclerViewAdapterWiring
import com.isolaatti.posting.posts.presentation.PostsRecyclerViewAdapter
import com.isolaatti.posting.posts.presentation.UpdateEvent
@ -53,6 +58,18 @@ class ProfileMainFragment : Fragment() {
private var scrollRange = -1
private var isShow = false
private val createDiscussion = registerForActivityResult(CreatePostContract()) {
if(it != null) {
Toast.makeText(requireContext(), R.string.posted_successfully, Toast.LENGTH_SHORT).show()
}
}
private val editDiscussion = registerForActivityResult(EditPostContract()) {
if(it != null) {
viewModel.onPostUpdate(it)
}
}
private val profileObserver = Observer<UserProfileDto> { profile ->
Picasso.get()
.load(UrlGen.userProfileImage(profile.id))
@ -102,6 +119,31 @@ class ProfileMainFragment : Fragment() {
}
}
private val optionsObserver: Observer<OptionClicked?> = Observer { optionClicked ->
if(optionClicked?.callerId == FeedFragment.CALLER_ID) {
// post id should come as payload
val post = optionClicked.payload as? Post ?: return@Observer
when(optionClicked.optionId) {
Options.Option.OPTION_DELETE -> {
Dialogs.buildDeletePostDialog(requireContext()) { delete ->
optionsViewModel.handle()
if(delete) {
viewModel.deletePost(post.id)
}
}.show()
}
Options.Option.OPTION_EDIT -> {
optionsViewModel.handle()
editDiscussion.launch(post.id)
}
Options.Option.OPTION_REPORT -> {
optionsViewModel.handle()
}
}
}
}
private lateinit var postListingRecyclerViewAdapterWiring: PostListingRecyclerViewAdapterWiring
@ -159,6 +201,7 @@ class ProfileMainFragment : Fragment() {
viewModel.profile.observe(viewLifecycleOwner, profileObserver)
viewModel.posts.observe(viewLifecycleOwner, postsObserver)
viewModel.followingState.observe(viewLifecycleOwner, followingStateObserver)
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
viewModel.loadingPosts.observe(viewLifecycleOwner) {
viewBinding.loadingIndicator.visibility = if(it) View.VISIBLE else View.GONE
if(!it) {

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M5,20h14v-2H5V20zM19,9h-4V3H9v6H5l7,7L19,9z"/>
</vector>

View File

@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17,3L5,3c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2L21,7l-4,-4zM12,19c-1.66,0 -3,-1.34 -3,-3s1.34,-3 3,-3 3,1.34 3,3 -1.34,3 -3,3zM15,9L5,9L5,5h10v4z"/>
</vector>

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:layout_width="match_parent"
<LinearLayout xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
@ -9,6 +10,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAlignment="center"
android:textSize="20sp"
android:textStyle="bold"
tools:text="Title" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_options"
android:layout_width="match_parent"

View File

@ -32,6 +32,7 @@
<string name="home">Home</string>
<string name="notifications">Notifications</string>
<string name="search">Search</string>
<string name="comment_options">Comment options</string>
<!-- Audio recorder -->
<string name="audio_recorder">Record audio</string>
@ -68,4 +69,6 @@
<string name="post_will_dropped">This discussion and all related content will be dropped. Continue?</string>
<string name="yes_continue">Yes, delete</string>
<string name="cancel">Cancel</string>
<string name="save">Save</string>
<string name="save_snapshot">Save snapshot</string>
</resources>

View File

@ -12,8 +12,8 @@ buildscript {
}
}
plugins {
id 'com.android.application' version '8.1.0' apply false
id 'com.android.library' version '8.1.0' apply false
id 'com.android.application' version '8.1.1' apply false
id 'com.android.library' version '8.1.1' apply false
id 'org.jetbrains.kotlin.android' version '1.8.0' apply false
id 'com.google.dagger.hilt.android' version '2.47' apply false
}