refactor: Use Date type for scheduled post date / times (#1032)
Previous code accepted the `scheduledAt` value as a String, and kept it as a String (including when serialising as part of a draft). Then it was converted to an actual Date for display. Refactor to keep it as a Date for as long as possible. Moshi decodes Dates correctly over the network, and the database is configured to serialise Dates as Longs. This necessitates two migration steps to preserve any existing `scheduledAt` values for drafts. The first step adds a new column to store the date as a Long and copies over existing data. The second step replaces the old column with the new column.
This commit is contained in:
parent
e68ab54f95
commit
0fe84f1611
@ -121,6 +121,7 @@ import com.mikepenz.iconics.utils.sizeDp
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
@ -292,8 +293,8 @@ class ComposeActivity :
|
|||||||
binding.composeEditField.setText(statusContent)
|
binding.composeEditField.setText(statusContent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!composeOptions?.scheduledAt.isNullOrEmpty()) {
|
composeOptions?.scheduledAt?.let {
|
||||||
binding.composeScheduleView.setDateTime(composeOptions?.scheduledAt)
|
binding.composeScheduleView.setDateTime(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
setupLanguageSpinner(getInitialLanguages(composeOptions?.language, activeAccount))
|
setupLanguageSpinner(getInitialLanguages(composeOptions?.language, activeAccount))
|
||||||
@ -314,7 +315,7 @@ class ComposeActivity :
|
|||||||
viewModel.showContentWarningChanged(this)
|
viewModel.showContentWarningChanged(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
it.getString(KEY_SCHEDULED_TIME)?.let { time ->
|
(it.getSerializable(KEY_SCHEDULED_TIME) as? Date)?.let { time ->
|
||||||
viewModel.updateScheduledAt(time)
|
viewModel.updateScheduledAt(time)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -717,7 +718,7 @@ class ComposeActivity :
|
|||||||
outState.putParcelable(KEY_PHOTO_UPLOAD_URI, photoUploadUri)
|
outState.putParcelable(KEY_PHOTO_UPLOAD_URI, photoUploadUri)
|
||||||
outState.putSerializable(KEY_VISIBILITY, viewModel.statusVisibility.value)
|
outState.putSerializable(KEY_VISIBILITY, viewModel.statusVisibility.value)
|
||||||
outState.putBoolean(KEY_CONTENT_WARNING_VISIBLE, viewModel.showContentWarning.value)
|
outState.putBoolean(KEY_CONTENT_WARNING_VISIBLE, viewModel.showContentWarning.value)
|
||||||
outState.putString(KEY_SCHEDULED_TIME, viewModel.scheduledAt.value)
|
outState.putSerializable(KEY_SCHEDULED_TIME, viewModel.scheduledAt.value)
|
||||||
super.onSaveInstanceState(outState)
|
super.onSaveInstanceState(outState)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,7 +784,7 @@ class ComposeActivity :
|
|||||||
// Can't reschedule a published status
|
// Can't reschedule a published status
|
||||||
enableButton(binding.composeScheduleButton, clickable = false, colorActive = false)
|
enableButton(binding.composeScheduleButton, clickable = false, colorActive = false)
|
||||||
} else {
|
} else {
|
||||||
val attr = if (binding.composeScheduleView.time == null) {
|
val attr = if (viewModel.scheduledAt.value == null) {
|
||||||
android.R.attr.colorControlNormal
|
android.R.attr.colorControlNormal
|
||||||
} else {
|
} else {
|
||||||
android.R.attr.colorPrimary
|
android.R.attr.colorPrimary
|
||||||
@ -970,7 +971,7 @@ class ComposeActivity :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun verifyScheduledTime(): Boolean {
|
private fun verifyScheduledTime(): Boolean {
|
||||||
return binding.composeScheduleView.verifyScheduledTime(binding.composeScheduleView.getDateTime(viewModel.scheduledAt.value))
|
return binding.composeScheduleView.verifyScheduledTime(viewModel.scheduledAt.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onSendClicked() = lifecycleScope.launch {
|
private fun onSendClicked() = lifecycleScope.launch {
|
||||||
@ -1410,7 +1411,7 @@ class ComposeActivity :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTimeSet(time: String?) {
|
override fun onTimeSet(time: Date?) {
|
||||||
viewModel.updateScheduledAt(time)
|
viewModel.updateScheduledAt(time)
|
||||||
if (verifyScheduledTime()) {
|
if (verifyScheduledTime()) {
|
||||||
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
|
||||||
|
@ -58,6 +58,7 @@ import com.github.michaelbull.result.mapBoth
|
|||||||
import com.github.michaelbull.result.mapError
|
import com.github.michaelbull.result.mapError
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import io.github.z4kn4fein.semver.constraints.toConstraint
|
import io.github.z4kn4fein.semver.constraints.toConstraint
|
||||||
|
import java.util.Date
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
@ -138,7 +139,7 @@ class ComposeViewModel @Inject constructor(
|
|||||||
val showContentWarning = _showContentWarning.asStateFlow()
|
val showContentWarning = _showContentWarning.asStateFlow()
|
||||||
private val _poll: MutableStateFlow<NewPoll?> = MutableStateFlow(null)
|
private val _poll: MutableStateFlow<NewPoll?> = MutableStateFlow(null)
|
||||||
val poll = _poll.asStateFlow()
|
val poll = _poll.asStateFlow()
|
||||||
private val _scheduledAt: MutableStateFlow<String?> = MutableStateFlow(null)
|
private val _scheduledAt: MutableStateFlow<Date?> = MutableStateFlow(null)
|
||||||
val scheduledAt = _scheduledAt.asStateFlow()
|
val scheduledAt = _scheduledAt.asStateFlow()
|
||||||
|
|
||||||
private val _media: MutableStateFlow<List<QueuedMedia>> = MutableStateFlow(emptyList())
|
private val _media: MutableStateFlow<List<QueuedMedia>> = MutableStateFlow(emptyList())
|
||||||
@ -637,7 +638,7 @@ class ComposeViewModel @Inject constructor(
|
|||||||
setupComplete = true
|
setupComplete = true
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateScheduledAt(newScheduledAt: String?) {
|
fun updateScheduledAt(newScheduledAt: Date?) {
|
||||||
if (newScheduledAt != scheduledAt.value) {
|
if (newScheduledAt != scheduledAt.value) {
|
||||||
scheduledTimeChanged = true
|
scheduledTimeChanged = true
|
||||||
}
|
}
|
||||||
|
@ -33,11 +33,9 @@ import com.google.android.material.datepicker.DateValidatorPointForward
|
|||||||
import com.google.android.material.datepicker.MaterialDatePicker
|
import com.google.android.material.datepicker.MaterialDatePicker
|
||||||
import com.google.android.material.timepicker.MaterialTimePicker
|
import com.google.android.material.timepicker.MaterialTimePicker
|
||||||
import com.google.android.material.timepicker.TimeFormat
|
import com.google.android.material.timepicker.TimeFormat
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
|
||||||
import java.util.TimeZone
|
import java.util.TimeZone
|
||||||
|
|
||||||
class ComposeScheduleView
|
class ComposeScheduleView
|
||||||
@ -47,7 +45,7 @@ class ComposeScheduleView
|
|||||||
defStyleAttr: Int = 0,
|
defStyleAttr: Int = 0,
|
||||||
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
) : ConstraintLayout(context, attrs, defStyleAttr) {
|
||||||
interface OnTimeSetListener {
|
interface OnTimeSetListener {
|
||||||
fun onTimeSet(time: String?)
|
fun onTimeSet(time: Date?)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var binding = ViewComposeScheduleBinding.inflate(
|
private var binding = ViewComposeScheduleBinding.inflate(
|
||||||
@ -57,12 +55,6 @@ class ComposeScheduleView
|
|||||||
private var listener: OnTimeSetListener? = null
|
private var listener: OnTimeSetListener? = null
|
||||||
private var dateFormat = SimpleDateFormat.getDateInstance()
|
private var dateFormat = SimpleDateFormat.getDateInstance()
|
||||||
private var timeFormat = SimpleDateFormat.getTimeInstance()
|
private var timeFormat = SimpleDateFormat.getTimeInstance()
|
||||||
private var iso8601 = SimpleDateFormat(
|
|
||||||
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
|
|
||||||
Locale.getDefault(),
|
|
||||||
).apply {
|
|
||||||
timeZone = TimeZone.getTimeZone("UTC")
|
|
||||||
}
|
|
||||||
|
|
||||||
/** The date/time the user has chosen to schedule the status, in UTC */
|
/** The date/time the user has chosen to schedule the status, in UTC */
|
||||||
private var scheduleDateTimeUtc: Calendar? = null
|
private var scheduleDateTimeUtc: Calendar? = null
|
||||||
@ -190,20 +182,9 @@ class ComposeScheduleView
|
|||||||
picker.show((context as AppCompatActivity).supportFragmentManager, "time_picker")
|
picker.show((context as AppCompatActivity).supportFragmentManager, "time_picker")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDateTime(scheduledAt: String?): Date? {
|
fun setDateTime(scheduledAt: Date) {
|
||||||
scheduledAt?.let {
|
|
||||||
try {
|
|
||||||
return iso8601.parse(it)
|
|
||||||
} catch (_: ParseException) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
fun setDateTime(scheduledAt: String?) {
|
|
||||||
val date = getDateTime(scheduledAt) ?: return
|
|
||||||
initializeSuggestedTime()
|
initializeSuggestedTime()
|
||||||
scheduleDateTimeUtc!!.time = date
|
scheduleDateTimeUtc!!.time = scheduledAt
|
||||||
updateScheduleUi()
|
updateScheduleUi()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,12 +219,9 @@ class ComposeScheduleView
|
|||||||
scheduleDateTimeUtc?.set(Calendar.HOUR_OF_DAY, hourOfDay)
|
scheduleDateTimeUtc?.set(Calendar.HOUR_OF_DAY, hourOfDay)
|
||||||
scheduleDateTimeUtc?.set(Calendar.MINUTE, minute)
|
scheduleDateTimeUtc?.set(Calendar.MINUTE, minute)
|
||||||
updateScheduleUi()
|
updateScheduleUi()
|
||||||
listener?.onTimeSet(time)
|
listener?.onTimeSet(scheduleDateTimeUtc?.time)
|
||||||
}
|
}
|
||||||
|
|
||||||
val time: String?
|
|
||||||
get() = scheduleDateTimeUtc?.time?.let { iso8601.format(it) }
|
|
||||||
|
|
||||||
private fun initializeSuggestedTime() {
|
private fun initializeSuggestedTime() {
|
||||||
if (scheduleDateTimeUtc == null) {
|
if (scheduleDateTimeUtc == null) {
|
||||||
scheduleDateTimeUtc = calendar().apply {
|
scheduleDateTimeUtc = calendar().apply {
|
||||||
|
@ -63,7 +63,7 @@ class DraftHelper @Inject constructor(
|
|||||||
poll: NewPoll?,
|
poll: NewPoll?,
|
||||||
failedToSend: Boolean,
|
failedToSend: Boolean,
|
||||||
failedToSendAlert: Boolean,
|
failedToSendAlert: Boolean,
|
||||||
scheduledAt: String?,
|
scheduledAt: Date?,
|
||||||
language: String?,
|
language: String?,
|
||||||
statusId: String?,
|
statusId: String?,
|
||||||
) = withContext(Dispatchers.IO) {
|
) = withContext(Dispatchers.IO) {
|
||||||
|
@ -40,6 +40,7 @@ import at.connyduck.calladapter.networkresult.fold
|
|||||||
import com.github.michaelbull.result.getOrElse
|
import com.github.michaelbull.result.getOrElse
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.Date
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -247,30 +248,33 @@ class SendStatusService : Service() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
sendResult.fold({ sentStatus ->
|
sendResult.fold(
|
||||||
statusesToSend.remove(statusId)
|
{ sentStatus ->
|
||||||
// If the status was loaded from a draft, delete the draft and associated media files.
|
statusesToSend.remove(statusId)
|
||||||
if (statusToSend.draftId != 0) {
|
// If the status was loaded from a draft, delete the draft and associated media files.
|
||||||
draftHelper.deleteDraftAndAttachments(statusToSend.draftId)
|
if (statusToSend.draftId != 0) {
|
||||||
}
|
draftHelper.deleteDraftAndAttachments(statusToSend.draftId)
|
||||||
|
}
|
||||||
|
|
||||||
mediaUploader.cancelUploadScope(*statusToSend.media.map { it.localId }.toIntArray())
|
mediaUploader.cancelUploadScope(*statusToSend.media.map { it.localId }.toIntArray())
|
||||||
|
|
||||||
val scheduled = !statusToSend.scheduledAt.isNullOrEmpty()
|
val scheduled = statusToSend.scheduledAt != null
|
||||||
|
|
||||||
if (scheduled) {
|
if (scheduled) {
|
||||||
eventHub.dispatch(StatusScheduledEvent)
|
eventHub.dispatch(StatusScheduledEvent)
|
||||||
} else if (!isNew) {
|
} else if (!isNew) {
|
||||||
eventHub.dispatch(StatusEditedEvent(statusToSend.statusId!!, sentStatus as Status))
|
eventHub.dispatch(StatusEditedEvent(statusToSend.statusId!!, sentStatus as Status))
|
||||||
} else {
|
} else {
|
||||||
eventHub.dispatch(StatusComposedEvent(sentStatus as Status))
|
eventHub.dispatch(StatusComposedEvent(sentStatus as Status))
|
||||||
}
|
}
|
||||||
|
|
||||||
notificationManager.cancel(statusId)
|
notificationManager.cancel(statusId)
|
||||||
}, { throwable ->
|
},
|
||||||
Timber.w(throwable, "failed sending status")
|
{ throwable ->
|
||||||
failOrRetry(throwable, statusId)
|
Timber.w(throwable, "failed sending status")
|
||||||
})
|
failOrRetry(throwable, statusId)
|
||||||
|
},
|
||||||
|
)
|
||||||
stopSelfWhenDone()
|
stopSelfWhenDone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -475,7 +479,7 @@ data class StatusToSend(
|
|||||||
val visibility: String,
|
val visibility: String,
|
||||||
val sensitive: Boolean,
|
val sensitive: Boolean,
|
||||||
val media: List<MediaToSend>,
|
val media: List<MediaToSend>,
|
||||||
val scheduledAt: String?,
|
val scheduledAt: Date?,
|
||||||
val inReplyToId: String?,
|
val inReplyToId: String?,
|
||||||
val poll: NewPoll?,
|
val poll: NewPoll?,
|
||||||
val replyingStatusContent: String?,
|
val replyingStatusContent: String?,
|
||||||
|
1203
core/database/schemas/app.pachli.core.database.AppDatabase/7.json
Normal file
1203
core/database/schemas/app.pachli.core.database.AppDatabase/7.json
Normal file
File diff suppressed because it is too large
Load Diff
1197
core/database/schemas/app.pachli.core.database.AppDatabase/8.json
Normal file
1197
core/database/schemas/app.pachli.core.database.AppDatabase/8.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,11 +17,17 @@
|
|||||||
|
|
||||||
package app.pachli.core.database
|
package app.pachli.core.database
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.content.ContentValues
|
||||||
|
import android.database.sqlite.SQLiteDatabase.CONFLICT_ABORT
|
||||||
|
import androidx.core.database.getStringOrNull
|
||||||
import androidx.room.AutoMigration
|
import androidx.room.AutoMigration
|
||||||
import androidx.room.Database
|
import androidx.room.Database
|
||||||
import androidx.room.DeleteColumn
|
import androidx.room.DeleteColumn
|
||||||
|
import androidx.room.RenameColumn
|
||||||
import androidx.room.RoomDatabase
|
import androidx.room.RoomDatabase
|
||||||
import androidx.room.migration.AutoMigrationSpec
|
import androidx.room.migration.AutoMigrationSpec
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
import app.pachli.core.database.dao.AccountDao
|
import app.pachli.core.database.dao.AccountDao
|
||||||
import app.pachli.core.database.dao.ConversationsDao
|
import app.pachli.core.database.dao.ConversationsDao
|
||||||
import app.pachli.core.database.dao.DraftDao
|
import app.pachli.core.database.dao.DraftDao
|
||||||
@ -40,6 +46,9 @@ import app.pachli.core.database.model.StatusViewDataEntity
|
|||||||
import app.pachli.core.database.model.TimelineAccountEntity
|
import app.pachli.core.database.model.TimelineAccountEntity
|
||||||
import app.pachli.core.database.model.TimelineStatusEntity
|
import app.pachli.core.database.model.TimelineStatusEntity
|
||||||
import app.pachli.core.database.model.TranslatedStatusEntity
|
import app.pachli.core.database.model.TranslatedStatusEntity
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
@Suppress("ClassName")
|
@Suppress("ClassName")
|
||||||
@Database(
|
@Database(
|
||||||
@ -55,13 +64,15 @@ import app.pachli.core.database.model.TranslatedStatusEntity
|
|||||||
TranslatedStatusEntity::class,
|
TranslatedStatusEntity::class,
|
||||||
LogEntryEntity::class,
|
LogEntryEntity::class,
|
||||||
],
|
],
|
||||||
version = 6,
|
version = 8,
|
||||||
autoMigrations = [
|
autoMigrations = [
|
||||||
AutoMigration(from = 1, to = 2, spec = AppDatabase.MIGRATE_1_2::class),
|
AutoMigration(from = 1, to = 2, spec = AppDatabase.MIGRATE_1_2::class),
|
||||||
AutoMigration(from = 2, to = 3),
|
AutoMigration(from = 2, to = 3),
|
||||||
AutoMigration(from = 3, to = 4),
|
AutoMigration(from = 3, to = 4),
|
||||||
AutoMigration(from = 4, to = 5),
|
AutoMigration(from = 4, to = 5),
|
||||||
AutoMigration(from = 5, to = 6),
|
AutoMigration(from = 5, to = 6),
|
||||||
|
AutoMigration(from = 6, to = 7, spec = AppDatabase.MIGRATE_6_7::class),
|
||||||
|
AutoMigration(from = 7, to = 8, spec = AppDatabase.MIGRATE_7_8::class),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
abstract class AppDatabase : RoomDatabase() {
|
abstract class AppDatabase : RoomDatabase() {
|
||||||
@ -78,4 +89,54 @@ abstract class AppDatabase : RoomDatabase() {
|
|||||||
@DeleteColumn("TimelineStatusEntity", "contentCollapsed")
|
@DeleteColumn("TimelineStatusEntity", "contentCollapsed")
|
||||||
@DeleteColumn("TimelineStatusEntity", "contentShowing")
|
@DeleteColumn("TimelineStatusEntity", "contentShowing")
|
||||||
class MIGRATE_1_2 : AutoMigrationSpec
|
class MIGRATE_1_2 : AutoMigrationSpec
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Part one of migrating [DraftEntity.scheduledAt] from String to Long.
|
||||||
|
*
|
||||||
|
* Copies existing data from `scheduledAt` into `scheduledAtLong`.
|
||||||
|
*/
|
||||||
|
class MIGRATE_6_7 : AutoMigrationSpec {
|
||||||
|
@SuppressLint("ConstantLocale")
|
||||||
|
private val iso8601 = SimpleDateFormat(
|
||||||
|
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'",
|
||||||
|
Locale.getDefault(),
|
||||||
|
).apply {
|
||||||
|
timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onPostMigrate(db: SupportSQLiteDatabase) {
|
||||||
|
db.beginTransaction()
|
||||||
|
|
||||||
|
val draftCursor = db.query("SELECT id, scheduledAt FROM DraftEntity")
|
||||||
|
with(draftCursor) {
|
||||||
|
while (moveToNext()) {
|
||||||
|
val scheduledAt = getStringOrNull(1) ?: continue
|
||||||
|
|
||||||
|
// Parse the string representation to a Date. Ignore errors, they
|
||||||
|
// shouldn't be possible.
|
||||||
|
val scheduledDate = runCatching { iso8601.parse(scheduledAt) }.getOrNull()
|
||||||
|
?: continue
|
||||||
|
|
||||||
|
// Dates are stored as Long, see Converters.dateToLong.
|
||||||
|
val values = ContentValues().apply {
|
||||||
|
put("scheduledAtLong", scheduledDate.time)
|
||||||
|
}
|
||||||
|
|
||||||
|
val draftId = getInt(0)
|
||||||
|
db.update("DraftEntity", CONFLICT_ABORT, values, "id = ?", arrayOf(draftId))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
db.setTransactionSuccessful()
|
||||||
|
db.endTransaction()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Completes the migration started in [MIGRATE_6_7]. SQLite on Android can't
|
||||||
|
* drop/rename columns, so use Room's annotations to generate the code to do this.
|
||||||
|
*/
|
||||||
|
@DeleteColumn("DraftEntity", "scheduledAt")
|
||||||
|
@RenameColumn("DraftEntity", "scheduledAtLong", "scheduledAt")
|
||||||
|
class MIGRATE_7_8 : AutoMigrationSpec
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import app.pachli.core.network.model.NewPoll
|
|||||||
import app.pachli.core.network.model.Status
|
import app.pachli.core.network.model.Status
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import java.util.Date
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -45,7 +46,7 @@ data class DraftEntity(
|
|||||||
val poll: NewPoll?,
|
val poll: NewPoll?,
|
||||||
val failedToSend: Boolean,
|
val failedToSend: Boolean,
|
||||||
val failedToSendNew: Boolean,
|
val failedToSendNew: Boolean,
|
||||||
val scheduledAt: String?,
|
val scheduledAt: Date?,
|
||||||
val language: String?,
|
val language: String?,
|
||||||
val statusId: String?,
|
val statusId: String?,
|
||||||
)
|
)
|
||||||
|
@ -38,6 +38,7 @@ import app.pachli.core.network.model.NewPoll
|
|||||||
import app.pachli.core.network.model.Notification
|
import app.pachli.core.network.model.Notification
|
||||||
import app.pachli.core.network.model.Status
|
import app.pachli.core.network.model.Status
|
||||||
import com.gaelmarhic.quadrant.QuadrantConstants
|
import com.gaelmarhic.quadrant.QuadrantConstants
|
||||||
|
import java.util.Date
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
private const val EXTRA_PACHLI_ACCOUNT_ID = "app.pachli.EXTRA_PACHLI_ACCOUNT_ID"
|
private const val EXTRA_PACHLI_ACCOUNT_ID = "app.pachli.EXTRA_PACHLI_ACCOUNT_ID"
|
||||||
@ -147,7 +148,7 @@ class ComposeActivityIntent(context: Context) : Intent() {
|
|||||||
val replyingStatusContent: String? = null,
|
val replyingStatusContent: String? = null,
|
||||||
val mediaAttachments: List<Attachment>? = null,
|
val mediaAttachments: List<Attachment>? = null,
|
||||||
val draftAttachments: List<DraftAttachment>? = null,
|
val draftAttachments: List<DraftAttachment>? = null,
|
||||||
val scheduledAt: String? = null,
|
val scheduledAt: Date? = null,
|
||||||
val sensitive: Boolean? = null,
|
val sensitive: Boolean? = null,
|
||||||
val poll: NewPoll? = null,
|
val poll: NewPoll? = null,
|
||||||
val modifiedInitialState: Boolean? = null,
|
val modifiedInitialState: Boolean? = null,
|
||||||
|
@ -19,6 +19,7 @@ package app.pachli.core.network.model
|
|||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import java.util.Date
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
@ -30,7 +31,7 @@ data class NewStatus(
|
|||||||
val sensitive: Boolean,
|
val sensitive: Boolean,
|
||||||
@Json(name = "media_ids") val mediaIds: List<String>?,
|
@Json(name = "media_ids") val mediaIds: List<String>?,
|
||||||
@Json(name = "media_attributes") val mediaAttributes: List<MediaAttribute>?,
|
@Json(name = "media_attributes") val mediaAttributes: List<MediaAttribute>?,
|
||||||
@Json(name = "scheduled_at") val scheduledAt: String?,
|
@Json(name = "scheduled_at") val scheduledAt: Date?,
|
||||||
val poll: NewPoll?,
|
val poll: NewPoll?,
|
||||||
val language: String?,
|
val language: String?,
|
||||||
)
|
)
|
||||||
|
@ -18,11 +18,12 @@ package app.pachli.core.network.model
|
|||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class ScheduledStatus(
|
data class ScheduledStatus(
|
||||||
val id: String,
|
val id: String,
|
||||||
@Json(name = "scheduled_at") val scheduledAt: String,
|
@Json(name = "scheduled_at") val scheduledAt: Date,
|
||||||
val params: StatusParams,
|
val params: StatusParams,
|
||||||
@Json(name = "media_attachments") val mediaAttachments: List<Attachment>,
|
@Json(name = "media_attachments") val mediaAttachments: List<Attachment>,
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user