WIP
This commit is contained in:
parent
7f042917e2
commit
1e02f0bc6f
@ -1,8 +1,7 @@
|
||||
package com.isolaatti.auth
|
||||
|
||||
import android.content.Context
|
||||
import com.isolaatti.auth.data.AuthRepositoryImpl
|
||||
import com.isolaatti.auth.data.local.KeyValueDao
|
||||
import com.isolaatti.settings.data.KeyValueDao
|
||||
import com.isolaatti.auth.data.local.TokenStorage
|
||||
import com.isolaatti.auth.data.remote.AuthApi
|
||||
import com.isolaatti.auth.domain.AuthRepository
|
||||
@ -11,7 +10,6 @@ import com.isolaatti.database.AppDatabase
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@ -21,10 +19,6 @@ class Module {
|
||||
fun provideAuthApi(retrofitClient: RetrofitClient): AuthApi {
|
||||
return retrofitClient.client.create(AuthApi::class.java)
|
||||
}
|
||||
@Provides
|
||||
fun provideKeyValueDao(database: AppDatabase): KeyValueDao {
|
||||
return database.keyValueDao()
|
||||
}
|
||||
|
||||
@Provides
|
||||
fun provideAuthRepository(tokenStorage: TokenStorage, authApi: AuthApi, keyValueDao: KeyValueDao): AuthRepository {
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
package com.isolaatti.auth.data
|
||||
|
||||
import com.isolaatti.auth.data.local.KeyValueDao
|
||||
import com.isolaatti.auth.data.local.KeyValueEntity
|
||||
import com.isolaatti.settings.data.KeyValueDao
|
||||
import com.isolaatti.settings.data.KeyValueEntity
|
||||
import com.isolaatti.auth.data.remote.AuthTokenDto
|
||||
import com.isolaatti.auth.data.local.TokenStorage
|
||||
import com.isolaatti.auth.data.remote.AuthApi
|
||||
|
||||
15
app/src/main/java/com/isolaatti/common/Dialogs.kt
Normal file
15
app/src/main/java/com/isolaatti/common/Dialogs.kt
Normal file
@ -0,0 +1,15 @@
|
||||
package com.isolaatti.common
|
||||
|
||||
import android.content.Context
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.isolaatti.R
|
||||
|
||||
object Dialogs {
|
||||
fun buildDeletePostDialog(context: Context, onContinue: (delete: Boolean) -> Unit, ): MaterialAlertDialogBuilder {
|
||||
return MaterialAlertDialogBuilder(context)
|
||||
.setTitle(R.string.delete)
|
||||
.setMessage(R.string.post_will_dropped)
|
||||
.setPositiveButton(R.string.yes_continue) {_, _ -> onContinue(true)}
|
||||
.setNegativeButton(R.string.cancel) { _, _ -> onContinue(false)}
|
||||
}
|
||||
}
|
||||
@ -2,8 +2,8 @@ package com.isolaatti.database
|
||||
|
||||
import androidx.room.Database
|
||||
import androidx.room.RoomDatabase
|
||||
import com.isolaatti.auth.data.local.KeyValueDao
|
||||
import com.isolaatti.auth.data.local.KeyValueEntity
|
||||
import com.isolaatti.settings.data.KeyValueDao
|
||||
import com.isolaatti.settings.data.KeyValueEntity
|
||||
|
||||
@Database(entities = [KeyValueEntity::class], version = 1)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
|
||||
@ -15,10 +15,10 @@ import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.fragment.app.activityViewModels
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.isolaatti.BuildConfig
|
||||
import com.isolaatti.R
|
||||
import com.isolaatti.about.AboutActivity
|
||||
import com.isolaatti.common.Dialogs
|
||||
import com.isolaatti.common.ErrorMessageViewModel
|
||||
import com.isolaatti.databinding.FragmentFeedBinding
|
||||
import com.isolaatti.drafts.ui.DraftsActivity
|
||||
@ -68,14 +68,23 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
||||
}
|
||||
}
|
||||
|
||||
val optionsObserver: Observer<OptionClicked> = Observer {
|
||||
if(it.callerId == CALLER_ID) {
|
||||
when(it.optionId) {
|
||||
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
|
||||
when(optionClicked.optionId) {
|
||||
Options.Option.OPTION_DELETE -> {
|
||||
Dialogs.buildDeletePostDialog(requireContext()) { delete ->
|
||||
optionsViewModel.handle()
|
||||
if(delete) {
|
||||
viewModel.deletePost(postId)
|
||||
}
|
||||
}.show()
|
||||
|
||||
}
|
||||
Options.Option.OPTION_EDIT -> {
|
||||
|
||||
optionsViewModel.handle()
|
||||
CreatePostActivity.startActivityEditMode(requireContext(), postId)
|
||||
}
|
||||
Options.Option.OPTION_REPORT -> {
|
||||
|
||||
@ -197,15 +206,12 @@ class FeedFragment : Fragment(), OnUserInteractedWithPostCallback {
|
||||
optionsViewModel.optionClicked.observe(viewLifecycleOwner, optionsObserver)
|
||||
}
|
||||
|
||||
fun onNewMenuItemClicked(v: View) {
|
||||
|
||||
}
|
||||
override fun onLiked(postId: Long) = viewModel.likePost(postId)
|
||||
|
||||
override fun onUnLiked(postId: Long) = viewModel.unLikePost(postId)
|
||||
|
||||
override fun onOptions(postId: Long) {
|
||||
optionsViewModel.setOptions(Options.myPostOptions, CALLER_ID)
|
||||
optionsViewModel.setOptions(Options.myPostOptions, CALLER_ID, postId)
|
||||
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||
}
|
||||
|
||||
@ -35,8 +35,8 @@ class BottomSheetPostComments() : BottomSheetDialogFragment(), OnUserInteractedC
|
||||
|
||||
val optionsViewModel: BottomSheetPostOptionsViewModel by activityViewModels()
|
||||
|
||||
val optionsObserver: Observer<OptionClicked> = Observer {
|
||||
if(it.callerId == CALLER_ID) {
|
||||
val optionsObserver: Observer<OptionClicked?> = Observer {
|
||||
if(it?.callerId == CALLER_ID) {
|
||||
optionsViewModel.optionClicked(-1)
|
||||
}
|
||||
|
||||
|
||||
@ -1,3 +1,8 @@
|
||||
package com.isolaatti.posting.common.options_bottom_sheet.domain
|
||||
|
||||
data class OptionClicked(val optionId: Int, val callerId: Int)
|
||||
/**
|
||||
* @param optionId Identify action
|
||||
* @param callerId Identify who started dialog
|
||||
* @param payload Data to identify on what item perform action
|
||||
*/
|
||||
data class OptionClicked(val optionId: Int, val callerId: Int, val payload: Any? = null)
|
||||
@ -21,6 +21,7 @@ data class Options(
|
||||
}
|
||||
|
||||
companion object {
|
||||
val noOptions = Options(0, listOf())
|
||||
val myPostOptions = Options(R.string.post_options_title, 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),
|
||||
|
||||
@ -12,16 +12,24 @@ class BottomSheetPostOptionsViewModel : ViewModel() {
|
||||
|
||||
private var _callerId: Int = 0
|
||||
|
||||
private val _optionClicked: MutableLiveData<OptionClicked> = MutableLiveData()
|
||||
val optionClicked: LiveData<OptionClicked> get() = _optionClicked
|
||||
private val _optionClicked: MutableLiveData<OptionClicked?> = MutableLiveData()
|
||||
val optionClicked: LiveData<OptionClicked?> get() = _optionClicked
|
||||
|
||||
fun setOptions(options: Options, callerId: Int) {
|
||||
private var _payload: Any? = null
|
||||
|
||||
fun handle() {
|
||||
_optionClicked.postValue(null)
|
||||
}
|
||||
|
||||
fun setOptions(options: Options, callerId: Int, payload: Any? = null) {
|
||||
_options.postValue(options)
|
||||
_callerId = callerId
|
||||
_payload = payload
|
||||
|
||||
}
|
||||
|
||||
fun optionClicked(optionId: Int) {
|
||||
_optionClicked.postValue(OptionClicked(optionId, _callerId))
|
||||
_optionClicked.postValue(OptionClicked(optionId, _callerId, _payload))
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package com.isolaatti.posting.common.options_bottom_sheet.ui
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
@ -39,14 +40,16 @@ class BottomSheetPostOptionsFragment : BottomSheetDialogFragment(), OptionsRecyc
|
||||
|
||||
|
||||
viewModel.options.observe(viewLifecycleOwner) {
|
||||
Log.d("BottomSheetPostOptionsFragment", "entra")
|
||||
renderOptions(it)
|
||||
}
|
||||
|
||||
viewModel.optionClicked.observe(viewLifecycleOwner) {
|
||||
if(it.optionId > -1) {
|
||||
if(it != null) {
|
||||
(dialog as BottomSheetDialog).dismiss()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -12,6 +12,6 @@ interface PostApi {
|
||||
fun editPost(@Body editedPost: EditPostDto): Call<FeedDto.PostDto>
|
||||
|
||||
@POST("Posting/Delete")
|
||||
fun deletePost(@Body postToDelete: DeletePostDto): Call<Any>
|
||||
fun deletePost(@Body postToDelete: DeletePostDto): Call<PostDeletedDto>
|
||||
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
package com.isolaatti.posting.posts.data.remote
|
||||
|
||||
data class PostDeletedDto(val operationTime: String, val postId: Long, val success: Boolean)
|
||||
@ -2,11 +2,13 @@ package com.isolaatti.posting.posts.data.repository
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.isolaatti.posting.posts.data.remote.CreatePostDto
|
||||
import com.isolaatti.posting.posts.data.remote.DeletePostDto
|
||||
import com.isolaatti.posting.posts.data.remote.EditPostDto
|
||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||
import com.isolaatti.posting.posts.data.remote.FeedFilterDto
|
||||
import com.isolaatti.posting.posts.data.remote.FeedsApi
|
||||
import com.isolaatti.posting.posts.data.remote.PostApi
|
||||
import com.isolaatti.posting.posts.data.remote.PostDeletedDto
|
||||
import com.isolaatti.posting.posts.domain.PostsRepository
|
||||
import com.isolaatti.utils.Resource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
@ -90,4 +92,23 @@ class PostsRepositoryImpl @Inject constructor(private val feedsApi: FeedsApi, pr
|
||||
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
|
||||
}
|
||||
}
|
||||
|
||||
override fun deletePost(postId: Long): Flow<Resource<PostDeletedDto>> = flow {
|
||||
emit(Resource.Loading())
|
||||
try {
|
||||
val result = postApi.deletePost(DeletePostDto(postId)).execute()
|
||||
if(result.isSuccessful) {
|
||||
emit(Resource.Success(result.body()))
|
||||
return@flow
|
||||
}
|
||||
when(result.code()) {
|
||||
401 -> emit(Resource.Error(Resource.Error.ErrorType.AuthError))
|
||||
404 -> emit(Resource.Error(Resource.Error.ErrorType.NotFoundError))
|
||||
500 -> emit(Resource.Error(Resource.Error.ErrorType.ServerError))
|
||||
else -> emit(Resource.Error(Resource.Error.ErrorType.OtherError))
|
||||
}
|
||||
} catch(_: Exception) {
|
||||
emit(Resource.Error(Resource.Error.ErrorType.NetworkError))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4,6 +4,7 @@ import com.isolaatti.posting.posts.data.remote.CreatePostDto
|
||||
import com.isolaatti.posting.posts.data.remote.EditPostDto
|
||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||
import com.isolaatti.posting.posts.data.remote.FeedFilterDto
|
||||
import com.isolaatti.posting.posts.data.remote.PostDeletedDto
|
||||
import com.isolaatti.utils.Resource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@ -15,4 +16,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>>
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
package com.isolaatti.posting.posts.domain.use_case
|
||||
|
||||
import com.isolaatti.posting.posts.data.remote.PostDeletedDto
|
||||
import com.isolaatti.posting.posts.domain.PostsRepository
|
||||
import com.isolaatti.utils.Resource
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import javax.inject.Inject
|
||||
|
||||
class DeletePost @Inject constructor(private val postsRepository: PostsRepository) {
|
||||
operator fun invoke(postId: Long): Flow<Resource<PostDeletedDto>> {
|
||||
return postsRepository.deletePost(postId)
|
||||
}
|
||||
}
|
||||
@ -4,9 +4,9 @@ import android.util.Log
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.isolaatti.posting.likes.data.remote.LikeDto
|
||||
import com.isolaatti.posting.likes.domain.repository.LikesRepository
|
||||
import com.isolaatti.posting.posts.data.remote.FeedDto
|
||||
import com.isolaatti.posting.posts.domain.use_case.DeletePost
|
||||
import com.isolaatti.profile.domain.use_case.GetProfilePosts
|
||||
import com.isolaatti.utils.Resource
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
@ -21,9 +21,12 @@ abstract class PostListingViewModelBase : ViewModel() {
|
||||
lateinit var likesRepository: LikesRepository
|
||||
@Inject
|
||||
lateinit var getProfilePosts: GetProfilePosts
|
||||
@Inject
|
||||
lateinit var deletePostUseCase: DeletePost
|
||||
|
||||
val posts: MutableLiveData<Pair<FeedDto?, UpdateEvent>?> = MutableLiveData()
|
||||
|
||||
|
||||
val loadingPosts = MutableLiveData(false)
|
||||
|
||||
val noMoreContent = MutableLiveData(false)
|
||||
@ -50,7 +53,7 @@ abstract class PostListingViewModelBase : ViewModel() {
|
||||
|
||||
})
|
||||
}
|
||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, likedPost?.post?.id)))
|
||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
|
||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||
}
|
||||
}
|
||||
@ -66,7 +69,27 @@ abstract class PostListingViewModelBase : ViewModel() {
|
||||
numberOfLikes = likeDto.likesCount
|
||||
})
|
||||
}
|
||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, likedPost?.post?.id)))
|
||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_LIKED, index)))
|
||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||
}
|
||||
}
|
||||
|
||||
fun deletePost(postId: Long) {
|
||||
viewModelScope.launch {
|
||||
deletePostUseCase(postId).onEach { res ->
|
||||
when(res) {
|
||||
is Resource.Success -> {
|
||||
val postDeleted = posts.value?.first?.data?.find { postDto -> postDto.post.id == postId }
|
||||
?: return@onEach
|
||||
val index = posts.value?.first?.data?.indexOf(postDeleted)
|
||||
|
||||
posts.value?.first?.data?.removeAt(index!!)
|
||||
posts.postValue(posts.value?.copy(second = UpdateEvent(UpdateEvent.UpdateType.POST_REMOVED, index)))
|
||||
}
|
||||
is Resource.Loading -> {}
|
||||
is Resource.Error -> {}
|
||||
}
|
||||
|
||||
}.flowOn(Dispatchers.IO).launchIn(this)
|
||||
}
|
||||
}
|
||||
|
||||
@ -136,8 +136,8 @@ class PostsRecyclerViewAdapter (private val markwon: Markwon, private val callba
|
||||
notifyDataSetChanged()
|
||||
return
|
||||
}
|
||||
val postUpdated = feedDto?.data?.find { p -> p.post.id == updateEvent.affectedId }
|
||||
val position = feedDto?.data?.indexOf(postUpdated)
|
||||
val postUpdated = updateEvent.affectedPosition?.let { feedDto?.data?.get(it) }
|
||||
val position = updateEvent.affectedPosition
|
||||
|
||||
previousSize = itemCount
|
||||
feedDto = updatedFeed
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
package com.isolaatti.posting.posts.presentation
|
||||
|
||||
data class UpdateEvent(val updateType: UpdateType, val affectedId: Long?) {
|
||||
data class UpdateEvent(val updateType: UpdateType, val affectedPosition: Int?) {
|
||||
enum class UpdateType {
|
||||
POST_LIKED,
|
||||
POST_COMMENTED,
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.isolaatti.posting.posts.ui
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.os.PersistableBundle
|
||||
@ -31,6 +32,14 @@ class CreatePostActivity : IsolaattiBaseActivity() {
|
||||
const val EXTRA_KEY_POST_ID = "postId"
|
||||
|
||||
const val EXTRA_KEY_POST_POSTED = "post"
|
||||
|
||||
fun startActivityEditMode(context: Context, postId: Long) {
|
||||
val intent = Intent(context, CreatePostActivity::class.java).apply {
|
||||
putExtra(EXTRA_KEY_MODE, EXTRA_MODE_EDIT)
|
||||
putExtra(EXTRA_KEY_POST_ID, postId)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
lateinit var binding: ActivityCreatePostBinding
|
||||
|
||||
@ -211,7 +211,7 @@ class ProfileMainFragment : Fragment() {
|
||||
}
|
||||
|
||||
override fun onOptions(postId: Long) {
|
||||
optionsViewModel.setOptions(Options.myPostOptions, FeedFragment.CALLER_ID)
|
||||
optionsViewModel.setOptions(Options.myPostOptions, FeedFragment.CALLER_ID, postId)
|
||||
val modalBottomSheet = BottomSheetPostOptionsFragment()
|
||||
modalBottomSheet.show(requireActivity().supportFragmentManager, BottomSheetPostOptionsFragment.TAG)
|
||||
}
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
package com.isolaatti.reports.ui
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
|
||||
class ReportsActivity : AppCompatActivity() {
|
||||
}
|
||||
17
app/src/main/java/com/isolaatti/settings/Module.kt
Normal file
17
app/src/main/java/com/isolaatti/settings/Module.kt
Normal file
@ -0,0 +1,17 @@
|
||||
package com.isolaatti.settings
|
||||
|
||||
import com.isolaatti.database.AppDatabase
|
||||
import com.isolaatti.settings.data.KeyValueDao
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
|
||||
@Module
|
||||
@InstallIn(SingletonComponent::class)
|
||||
class Module {
|
||||
@Provides
|
||||
fun provideKeyValueDao(database: AppDatabase): KeyValueDao {
|
||||
return database.keyValueDao()
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package com.isolaatti.auth.data.local
|
||||
package com.isolaatti.settings.data
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
@ -1,4 +1,4 @@
|
||||
package com.isolaatti.auth.data.local
|
||||
package com.isolaatti.settings.data
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
@ -65,4 +65,7 @@
|
||||
<string name="million_suffix">M</string>
|
||||
<string name="people">People</string>
|
||||
<string name="about">About</string>
|
||||
<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>
|
||||
</resources>
|
||||
Loading…
x
Reference in New Issue
Block a user