Comment draft in EditCommentActivity.

This commit is contained in:
Docile-Alligator 2025-07-08 15:24:27 -04:00
parent 8a55adeff0
commit af132eefee
10 changed files with 183 additions and 35 deletions

View File

@ -0,0 +1,16 @@
package ml.docilealligator.infinityforreddit
import androidx.room.TypeConverter
import ml.docilealligator.infinityforreddit.comment.DraftType
class Converters {
@TypeConverter
fun fromDraftType(value: DraftType): String {
return value.name
}
@TypeConverter
fun toDraftType(value: String): DraftType {
return DraftType.valueOf(value)
}
}

View File

@ -8,6 +8,7 @@ import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.room.TypeConverters;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
@ -46,6 +47,7 @@ import ml.docilealligator.infinityforreddit.user.UserData;
SubscribedUserData.class, MultiReddit.class, CustomTheme.class, RecentSearchQuery.class,
ReadPost.class, PostFilter.class, PostFilterUsage.class, AnonymousMultiredditSubreddit.class,
CommentFilter.class, CommentFilterUsage.class, CommentDraft.class}, version = 29, exportSchema = false)
@TypeConverters(Converters.class)
public abstract class RedditDataRoomDatabase extends RoomDatabase {
public static RedditDataRoomDatabase create(final Context context) {
@ -447,9 +449,11 @@ public abstract class RedditDataRoomDatabase extends RoomDatabase {
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE accounts ADD COLUMN is_mod INTEGER DEFAULT 0 NOT NULL");
database.execSQL("CREATE TABLE comment_draft(" +
"parent_full_name TEXT NOT NULL PRIMARY KEY, " +
"full_name TEXT NOT NULL, " +
"content TEXT NOT NULL, " +
"last_updated INTEGER NOT NULL)");
"last_updated INTEGER NOT NULL," +
"draft_type TEXT NOT NULL," +
"PRIMARY KEY (full_name, draft_type))");
}
};
}

View File

@ -588,7 +588,11 @@ public class CommentActivity extends BaseActivity implements UploadImageEnabledA
finish();
}
})
.setNegativeButton(R.string.no, (dialog, which) -> finish())
.setNegativeButton(R.string.no, (dialog, which) -> {
if (canSaveDraft) {
finish();
}
})
.setNeutralButton(R.string.cancel, null)
.show();
}

View File

@ -21,6 +21,7 @@ import androidx.core.graphics.Insets;
import androidx.core.view.OnApplyWindowInsetsListener;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.giphy.sdk.core.models.Media;
@ -45,8 +46,10 @@ import java.util.concurrent.Executor;
import javax.inject.Inject;
import javax.inject.Named;
import kotlin.Unit;
import ml.docilealligator.infinityforreddit.Infinity;
import ml.docilealligator.infinityforreddit.R;
import ml.docilealligator.infinityforreddit.RedditDataRoomDatabase;
import ml.docilealligator.infinityforreddit.adapters.MarkdownBottomBarRecyclerViewAdapter;
import ml.docilealligator.infinityforreddit.apis.RedditAPI;
import ml.docilealligator.infinityforreddit.bottomsheetfragments.UploadedImagesBottomSheetFragment;
@ -57,12 +60,14 @@ import ml.docilealligator.infinityforreddit.customviews.LinearLayoutManagerBugFi
import ml.docilealligator.infinityforreddit.databinding.ActivityEditCommentBinding;
import ml.docilealligator.infinityforreddit.events.SwitchAccountEvent;
import ml.docilealligator.infinityforreddit.markdown.RichTextJSONConverter;
import ml.docilealligator.infinityforreddit.repositories.EditCommentActivityRepository;
import ml.docilealligator.infinityforreddit.thing.GiphyGif;
import ml.docilealligator.infinityforreddit.thing.MediaMetadata;
import ml.docilealligator.infinityforreddit.thing.UploadedImage;
import ml.docilealligator.infinityforreddit.utils.APIUtils;
import ml.docilealligator.infinityforreddit.utils.SharedPreferencesUtils;
import ml.docilealligator.infinityforreddit.utils.Utils;
import ml.docilealligator.infinityforreddit.viewmodels.EditCommentActivityViewModel;
import retrofit2.Response;
import retrofit2.Retrofit;
@ -91,6 +96,8 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
@Named("upload_media")
Retrofit mUploadMediaRetrofit;
@Inject
RedditDataRoomDatabase mRedditDataRoomDatabase;
@Inject
@Named("default")
SharedPreferences mSharedPreferences;
@Inject
@ -108,6 +115,7 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
private ArrayList<UploadedImage> uploadedImages = new ArrayList<>();
private GiphyGif giphyGif;
private ActivityEditCommentBinding binding;
public EditCommentActivityViewModel editCommentActivityViewModel;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -222,17 +230,34 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
Giphy.INSTANCE.configure(this, APIUtils.GIPHY_GIF_API_KEY);
editCommentActivityViewModel = new ViewModelProvider(
this,
EditCommentActivityViewModel.Companion.provideFactory(new EditCommentActivityRepository(mRedditDataRoomDatabase.commentDraftDao()))
).get(EditCommentActivityViewModel.class);
if (savedInstanceState == null) {
editCommentActivityViewModel.getCommentDraft(mFullName).observe(this, commentDraft -> {
if (commentDraft != null && !commentDraft.getContent().isEmpty()) {
binding.commentEditTextEditCommentActivity.setText(commentDraft.getContent());
}
});
}
getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
if (isSubmitting) {
promptAlertDialog(R.string.exit_when_submit, R.string.exit_when_edit_comment_detail);
promptAlertDialog(R.string.exit_when_submit, R.string.exit_when_edit_comment_detail, false);
} else {
if (binding.commentEditTextEditCommentActivity.getText().toString().equals(mCommentContent)) {
setEnabled(false);
triggerBackPress();
String content = binding.commentEditTextEditCommentActivity.getText().toString();
if (content.isEmpty() || content.equals(mCommentContent)) {
editCommentActivityViewModel.deleteCommentDraft(mFullName, () -> {
setEnabled(false);
triggerBackPress();
return Unit.INSTANCE;
});
} else {
promptAlertDialog(R.string.discard, R.string.discard_detail);
promptAlertDialog(R.string.save_comment_draft, R.string.save_comment_draft_detail, true);
}
}
}
@ -334,7 +359,10 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
returnIntent.putExtra(RETURN_EXTRA_EDITED_COMMENT_POSITION, getIntent().getExtras().getInt(EXTRA_POSITION));
setResult(RESULT_OK, returnIntent);
finish();
editCommentActivityViewModel.deleteCommentDraft(mFullName, () -> {
finish();
return Unit.INSTANCE;
});
});
} else {
handler.post(() -> {
@ -359,20 +387,37 @@ public class EditCommentActivity extends BaseActivity implements UploadImageEnab
returnIntent.putExtra(RETURN_EXTRA_EDITED_COMMENT_POSITION, getIntent().getExtras().getInt(EXTRA_POSITION));
setResult(RESULT_OK, returnIntent);
finish();
editCommentActivityViewModel.deleteCommentDraft(mFullName, () -> {
finish();
return Unit.INSTANCE;
});
});
}
});
}
}
private void promptAlertDialog(int titleResId, int messageResId) {
private void promptAlertDialog(int titleResId, int messageResId, boolean canSaveDraft) {
new MaterialAlertDialogBuilder(this, R.style.MaterialAlertDialogTheme)
.setTitle(titleResId)
.setMessage(messageResId)
.setPositiveButton(R.string.discard_dialog_button, (dialogInterface, i)
-> finish())
.setNegativeButton(R.string.no, null)
.setPositiveButton(R.string.yes, (dialogInterface, i)
-> {
if (canSaveDraft) {
editCommentActivityViewModel.saveCommentDraft(mFullName, binding.commentEditTextEditCommentActivity.getText().toString(), () -> {
finish();
return Unit.INSTANCE;
});
} else {
finish();
}
})
.setNegativeButton(R.string.no, (dialog, which) -> {
if (canSaveDraft) {
finish();
}
})
.setNeutralButton(R.string.cancel, null)
.show();
}

View File

@ -1,17 +1,23 @@
package ml.docilealligator.infinityforreddit.comment
import androidx.annotation.NonNull
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity(tableName = "comment_draft")
@Entity(
tableName = "comment_draft",
primaryKeys = ["full_name", "draft_type"]
)
data class CommentDraft(
@PrimaryKey
@ColumnInfo(name = "parent_full_name")
@ColumnInfo(name = "full_name")
var parentFullName: String,
var content: String,
@ColumnInfo(name = "last_updated")
var lastUpdated: Long
) {
var lastUpdated: Long,
@ColumnInfo(name = "draft_type")
var draftType: DraftType
)
enum class DraftType {
REPLY,
EDIT
}

View File

@ -15,6 +15,6 @@ interface CommentDraftDao {
@Delete
suspend fun delete(commentDraft: CommentDraft)
@Query("SELECT * FROM comment_draft WHERE parent_full_name = :parentFullName")
fun getCommentDraftLiveData(parentFullName: String): LiveData<CommentDraft>
@Query("SELECT * FROM comment_draft WHERE full_name = :fullName AND draft_type = :draftType")
fun getCommentDraftLiveData(fullName: String, draftType: DraftType): LiveData<CommentDraft>
}

View File

@ -3,19 +3,20 @@ package ml.docilealligator.infinityforreddit.repositories
import androidx.lifecycle.LiveData
import ml.docilealligator.infinityforreddit.comment.CommentDraft
import ml.docilealligator.infinityforreddit.comment.CommentDraftDao
import ml.docilealligator.infinityforreddit.comment.DraftType
class CommentActivityRepository(
private val commentDraftDao: CommentDraftDao
) {
fun getCommentDraft(parentFullname: String): LiveData<CommentDraft> {
return commentDraftDao.getCommentDraftLiveData(parentFullname)
fun getCommentDraft(fullname: String): LiveData<CommentDraft> {
return commentDraftDao.getCommentDraftLiveData(fullname, DraftType.REPLY)
}
suspend fun saveCommentDraft(parentFullname: String, content: String) {
commentDraftDao.insert(CommentDraft(parentFullname, content, System.currentTimeMillis()))
suspend fun saveCommentDraft(fullname: String, content: String) {
commentDraftDao.insert(CommentDraft(fullname, content, System.currentTimeMillis(), DraftType.REPLY))
}
suspend fun deleteCommentDraft(parentFullname: String) {
commentDraftDao.delete(CommentDraft(parentFullname, "", 0))
suspend fun deleteCommentDraft(fullname: String) {
commentDraftDao.delete(CommentDraft(fullname, "", 0, DraftType.REPLY))
}
}

View File

@ -0,0 +1,22 @@
package ml.docilealligator.infinityforreddit.repositories
import androidx.lifecycle.LiveData
import ml.docilealligator.infinityforreddit.comment.CommentDraft
import ml.docilealligator.infinityforreddit.comment.CommentDraftDao
import ml.docilealligator.infinityforreddit.comment.DraftType
class EditCommentActivityRepository(
private val commentDraftDao: CommentDraftDao
) {
fun getCommentDraft(fullname: String): LiveData<CommentDraft> {
return commentDraftDao.getCommentDraftLiveData(fullname, DraftType.EDIT)
}
suspend fun saveCommentDraft(fullname: String, content: String) {
commentDraftDao.insert(CommentDraft(fullname, content, System.currentTimeMillis(), DraftType.EDIT))
}
suspend fun deleteCommentDraft(fullname: String) {
commentDraftDao.delete(CommentDraft(fullname, "", 0, DraftType.EDIT))
}
}

View File

@ -7,25 +7,26 @@ import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import kotlinx.coroutines.launch
import ml.docilealligator.infinityforreddit.comment.CommentDraft
import ml.docilealligator.infinityforreddit.comment.DraftType
import ml.docilealligator.infinityforreddit.repositories.CommentActivityRepository
class CommentActivityViewModel(
private val commentActivityRepository: CommentActivityRepository
): ViewModel() {
fun getCommentDraft(parentFullname: String): LiveData<CommentDraft> {
return commentActivityRepository.getCommentDraft(parentFullname)
fun getCommentDraft(fullname: String): LiveData<CommentDraft> {
return commentActivityRepository.getCommentDraft(fullname)
}
fun saveCommentDraft(parentFullname: String, content: String, onSaved: () -> Unit) {
fun saveCommentDraft(fullname: String, content: String, onSaved: () -> Unit) {
viewModelScope.launch {
commentActivityRepository.saveCommentDraft(parentFullname, content)
commentActivityRepository.saveCommentDraft(fullname, content)
onSaved()
}
}
fun deleteCommentDraft(parentFullname: String, onDeleted: () -> Unit) {
fun deleteCommentDraft(fullname: String, onDeleted: () -> Unit) {
viewModelScope.launch {
commentActivityRepository.deleteCommentDraft(parentFullname)
commentActivityRepository.deleteCommentDraft(fullname)
onDeleted()
}
}

View File

@ -0,0 +1,49 @@
package ml.docilealligator.infinityforreddit.viewmodels
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import androidx.lifecycle.viewmodel.CreationExtras
import kotlinx.coroutines.launch
import ml.docilealligator.infinityforreddit.comment.CommentDraft
import ml.docilealligator.infinityforreddit.comment.DraftType
import ml.docilealligator.infinityforreddit.repositories.EditCommentActivityRepository
class EditCommentActivityViewModel(
private val editCommentActivityRepository: EditCommentActivityRepository
): ViewModel() {
fun getCommentDraft(fullname: String): LiveData<CommentDraft> {
return editCommentActivityRepository.getCommentDraft(fullname)
}
fun saveCommentDraft(fullname: String, content: String, onSaved: () -> Unit) {
viewModelScope.launch {
editCommentActivityRepository.saveCommentDraft(fullname, content)
onSaved()
}
}
fun deleteCommentDraft(fullname: String, onDeleted: () -> Unit) {
viewModelScope.launch {
editCommentActivityRepository.deleteCommentDraft(fullname)
onDeleted()
}
}
companion object {
fun provideFactory(editCommentActivityRepository: EditCommentActivityRepository) : ViewModelProvider.Factory {
return object: ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
return EditCommentActivityViewModel(
editCommentActivityRepository,
) as T
}
}
}
}
}