diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java index 0e2e4957..d8b2b422 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/adapters/PostDetailRecyclerViewAdapter.java @@ -1125,12 +1125,15 @@ public class PostDetailRecyclerViewAdapter extends RecyclerView.Adapter { + mPost = moderationEvent.getPost(); + if (mPostAdapter != null) { + mPostAdapter.updatePost(mPost); + } + EventBus.getDefault().post(new PostUpdateEventToPostList(moderationEvent.getPost(), moderationEvent.getPosition())); + Toast.makeText(activity, moderationEvent.getToastMessageResId(), Toast.LENGTH_SHORT).show(); + }); } public void fetchCommentsAfterCommentFilterAvailable() { @@ -1613,7 +1631,9 @@ public class ViewPostDetailFragment extends Fragment implements FragmentCommunic public void fetchPostSuccess(Post post) { if (isAdded()) { mPost = post; - mPostAdapter.updatePost(mPost); + if (mPostAdapter != null) { + mPostAdapter.updatePost(mPost); + } EventBus.getDefault().post(new PostUpdateEventToPostList(mPost, postListPosition)); setupMenu(); binding.swipeRefreshLayoutViewPostDetailFragment.setRefreshing(false); @@ -2031,4 +2051,39 @@ public class ViewPostDetailFragment extends Fragment implements FragmentCommunic mPostAdapter.setCanPlayVideo(hasWindowsFocus); } } + + @Override + public void approvePost(@NonNull Post post, int position) { + viewPostDetailFragmentViewModel.approvePost(post, position); + } + + @Override + public void removePost(@NonNull Post post, int position, boolean isSpam) { + viewPostDetailFragmentViewModel.removePost(post, position, isSpam); + } + + @Override + public void toggleSticky(@NonNull Post post, int position) { + viewPostDetailFragmentViewModel.toggleSticky(post, position); + } + + @Override + public void toggleLock(@NonNull Post post, int position) { + viewPostDetailFragmentViewModel.toggleLock(post, position); + } + + @Override + public void toggleNSFW(@NonNull Post post, int position) { + viewPostDetailFragmentViewModel.toggleNSFW(post, position); + } + + @Override + public void toggleSpoiler(@NonNull Post post, int position) { + viewPostDetailFragmentViewModel.toggleSpoiler(post, position); + } + + @Override + public void toggleMod(@NonNull Post post, int position) { + viewPostDetailFragmentViewModel.toggleMod(post, position); + } } diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java index 64ca9140..593af126 100644 --- a/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/post/PostViewModel.java @@ -535,7 +535,7 @@ public class PostViewModel extends ViewModel { }); } - public void toggleStickyPost(@NonNull Post post, int position) { + public void toggleSticky(@NonNull Post post, int position) { Map params = new HashMap<>(); params.put(APIUtils.ID_KEY, post.getFullName()); params.put(APIUtils.STATE_KEY, Boolean.toString(!post.isStickied())); @@ -558,7 +558,7 @@ public class PostViewModel extends ViewModel { }); } - public void toggleLockPost(@NonNull Post post, int position) { + public void toggleLock(@NonNull Post post, int position) { Map params = new HashMap<>(); params.put(APIUtils.ID_KEY, post.getFullName()); Call call = post.isLocked() ? retrofit.create(RedditAPI.class).unLockThing(APIUtils.getOAuthHeader(accessToken), params) : retrofit.create(RedditAPI.class).lockThing(APIUtils.getOAuthHeader(accessToken), params); diff --git a/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/ViewPostDetailFragmentViewModel.kt b/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/ViewPostDetailFragmentViewModel.kt new file mode 100644 index 00000000..e610bc75 --- /dev/null +++ b/app/src/main/java/ml/docilealligator/infinityforreddit/viewmodels/ViewPostDetailFragmentViewModel.kt @@ -0,0 +1,313 @@ +package ml.docilealligator.infinityforreddit.viewmodels + +import androidx.lifecycle.ViewModel +import androidx.lifecycle.ViewModelProvider +import androidx.lifecycle.viewmodel.CreationExtras +import ml.docilealligator.infinityforreddit.SingleLiveEvent +import ml.docilealligator.infinityforreddit.apis.RedditAPI +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.ApproveFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.Approved +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.DistinguishAsModFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.DistinguishedAsMod +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.LockFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.Locked +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.MarkAsSpamFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.MarkNSFWFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.MarkSpoilerFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.MarkedAsSpam +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.MarkedNSFW +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.MarkedSpoiler +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.RemoveFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.SetStickyPost +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.SetStickyPostFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UndistinguishAsModFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UndistinguishedAsMod +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnlockFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.Unlocked +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnmarkNSFWFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnmarkSpoilerFailed +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnmarkedNSFW +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnmarkedSpoiler +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnsetStickyPost +import ml.docilealligator.infinityforreddit.moderation.ModerationEvent.UnsetStickyPostFailed +import ml.docilealligator.infinityforreddit.post.Post +import ml.docilealligator.infinityforreddit.utils.APIUtils +import retrofit2.Call +import retrofit2.Callback +import retrofit2.Response +import retrofit2.Retrofit + +class ViewPostDetailFragmentViewModel( + private val oauthRetrofit: Retrofit, + private val accessToken: String? +) : ViewModel() { + val moderationEventLiveData: SingleLiveEvent = SingleLiveEvent() + + fun approvePost(post: Post, position: Int) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + oauthRetrofit.create(RedditAPI::class.java) + .approveThing(APIUtils.getOAuthHeader(accessToken), params) + .enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + moderationEventLiveData.postValue(Approved(post, position)) + } else { + moderationEventLiveData.postValue(ApproveFailed(post, position)) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue(ApproveFailed(post, position)) + } + }) + } + + fun removePost(post: Post, position: Int, isSpam: Boolean) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + params[APIUtils.SPAM_KEY] = isSpam.toString() + oauthRetrofit.create(RedditAPI::class.java) + .removeThing(APIUtils.getOAuthHeader(accessToken), params) + .enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + moderationEventLiveData.postValue( + if (isSpam) MarkedAsSpam( + post, + position + ) else ModerationEvent.Removed(post, position) + ) + } else { + moderationEventLiveData.postValue( + if (isSpam) MarkAsSpamFailed( + post, + position + ) else RemoveFailed(post, position) + ) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue( + if (isSpam) MarkAsSpamFailed( + post, + position + ) else RemoveFailed(post, position) + ) + } + }) + } + + fun toggleSticky(post: Post, position: Int) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + params[APIUtils.STATE_KEY] = (!post.isStickied).toString() + params[APIUtils.API_TYPE_KEY] = APIUtils.API_TYPE_JSON + oauthRetrofit.create(RedditAPI::class.java) + .toggleStickyPost(APIUtils.getOAuthHeader(accessToken), params) + .enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + post.setIsStickied(!post.isStickied) + moderationEventLiveData.postValue( + if (post.isStickied) SetStickyPost( + post, + position + ) else UnsetStickyPost(post, position) + ) + } else { + moderationEventLiveData.postValue( + if (post.isStickied) UnsetStickyPostFailed( + post, + position + ) else SetStickyPostFailed(post, position) + ) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue( + if (post.isStickied) UnsetStickyPostFailed( + post, + position + ) else SetStickyPostFailed(post, position) + ) + } + }) + } + + fun toggleLock(post: Post, position: Int) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + val call: Call = if (post.isLocked) oauthRetrofit.create( + RedditAPI::class.java + ).unLockThing(APIUtils.getOAuthHeader(accessToken), params) else oauthRetrofit.create( + RedditAPI::class.java + ).lockThing(APIUtils.getOAuthHeader(accessToken), params) + call.enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + post.setIsLocked(!post.isLocked) + moderationEventLiveData.postValue( + if (post.isLocked) Locked( + post, + position + ) else Unlocked(post, position) + ) + } else { + moderationEventLiveData.postValue( + if (post.isLocked) UnlockFailed( + post, + position + ) else LockFailed(post, position) + ) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue( + if (post.isLocked) UnlockFailed( + post, + position + ) else LockFailed(post, position) + ) + } + }) + } + + fun toggleNSFW(post: Post, position: Int) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + val call: Call = if (post.isNSFW) oauthRetrofit.create( + RedditAPI::class.java + ).unmarkNSFW(APIUtils.getOAuthHeader(accessToken), params) else oauthRetrofit.create( + RedditAPI::class.java + ).markNSFW(APIUtils.getOAuthHeader(accessToken), params) + call.enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + post.isNSFW = !post.isNSFW + moderationEventLiveData.postValue( + if (post.isNSFW) MarkedNSFW( + post, + position + ) else UnmarkedNSFW(post, position) + ) + } else { + moderationEventLiveData.postValue( + if (post.isNSFW) UnmarkNSFWFailed( + post, + position + ) else MarkNSFWFailed(post, position) + ) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue( + if (post.isNSFW) UnmarkNSFWFailed( + post, + position + ) else MarkNSFWFailed(post, position) + ) + } + }) + } + + fun toggleSpoiler(post: Post, position: Int) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + val call: Call = if (post.isSpoiler) oauthRetrofit.create( + RedditAPI::class.java + ).unmarkSpoiler( + APIUtils.getOAuthHeader(accessToken), + params + ) else oauthRetrofit.create( + RedditAPI::class.java + ).markSpoiler(APIUtils.getOAuthHeader(accessToken), params) + call.enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + post.isSpoiler = !post.isSpoiler + moderationEventLiveData.postValue( + if (post.isSpoiler) MarkedSpoiler( + post, + position + ) else UnmarkedSpoiler(post, position) + ) + } else { + moderationEventLiveData.postValue( + if (post.isSpoiler) UnmarkSpoilerFailed( + post, + position + ) else MarkSpoilerFailed(post, position) + ) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue( + if (post.isSpoiler) UnmarkSpoilerFailed( + post, + position + ) else MarkSpoilerFailed(post, position) + ) + } + }) + } + + fun toggleMod(post: Post, position: Int) { + val params: MutableMap = HashMap() + params[APIUtils.ID_KEY] = post.fullName + params[APIUtils.HOW_KEY] = if (post.isModerator) APIUtils.HOW_NO else APIUtils.HOW_YES + oauthRetrofit.create(RedditAPI::class.java) + .toggleDistinguishedThing(APIUtils.getOAuthHeader(accessToken), params) + .enqueue(object : Callback { + override fun onResponse(call: Call, response: Response) { + if (response.isSuccessful) { + post.setIsModerator(!post.isModerator) + moderationEventLiveData.postValue( + if (post.isModerator) DistinguishedAsMod( + post, + position + ) else UndistinguishedAsMod(post, position) + ) + } else { + moderationEventLiveData.postValue( + if (post.isModerator) UndistinguishAsModFailed( + post, + position + ) else DistinguishAsModFailed(post, position) + ) + } + } + + override fun onFailure(call: Call, throwable: Throwable) { + moderationEventLiveData.postValue( + if (post.isModerator) UndistinguishAsModFailed( + post, + position + ) else DistinguishAsModFailed(post, position) + ) + } + }) + } + + companion object { + fun provideFactory(oauthRetrofit: Retrofit, accessToken: String?) : ViewModelProvider.Factory { + return object: ViewModelProvider.Factory { + @Suppress("UNCHECKED_CAST") + override fun create( + modelClass: Class, + extras: CreationExtras + ): T { + return ViewPostDetailFragmentViewModel( + oauthRetrofit, accessToken + ) as T + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_moderation_action_bottom_sheet.xml b/app/src/main/res/layout/fragment_moderation_action_bottom_sheet.xml index c65c5cfd..255c94ab 100644 --- a/app/src/main/res/layout/fragment_moderation_action_bottom_sheet.xml +++ b/app/src/main/res/layout/fragment_moderation_action_bottom_sheet.xml @@ -85,7 +85,6 @@ android:paddingTop="16dp" android:paddingEnd="32dp" android:paddingBottom="16dp" - android:text="@string/mark_as_spam" android:textColor="?attr/primaryTextColor" android:textSize="?attr/font_default" app:drawableTint="?attr/primaryTextColor" />