Use OffsetDateTime instead of Date in database

This commit is contained in:
Matthieu 2021-08-19 14:24:37 +02:00
parent 42491ff6e2
commit 87d5341fea
16 changed files with 108 additions and 39 deletions

View File

@ -16,6 +16,7 @@ android {
compileSdkVersion 30
buildToolsVersion '30.0.3'
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -100,6 +101,8 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
/**
* AndroidX dependencies:
*/

View File

@ -27,6 +27,7 @@ import org.junit.*
import org.junit.rules.Timeout
import org.junit.runner.RunWith
import java.text.SimpleDateFormat
import java.time.OffsetDateTime
@RunWith(AndroidJUnit4::class)
@ -66,7 +67,8 @@ class PostTest {
username = "SQDFSQDF",
url = "$INSTANCE_URI/pixeldroid",
),
media_attachments = listOf(attachment)
media_attachments = listOf(attachment),
created_at = OffsetDateTime.now().minusHours(1)
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
@ -102,7 +104,8 @@ class PostTest {
username = "douze",
url = "$INSTANCE_URI/pixeldroid",
),
media_attachments = listOf(attachment1, attachment2)
media_attachments = listOf(attachment1, attachment2),
created_at = OffsetDateTime.now().minusHours(1)
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
@ -134,7 +137,8 @@ class PostTest {
username = "douze",
url = "$INSTANCE_URI/pixeldroid",
),
media_attachments = listOf(attachment)
media_attachments = listOf(attachment),
created_at = OffsetDateTime.now().minusHours(1)
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
@ -165,7 +169,8 @@ class PostTest {
username = "douze",
url = "$INSTANCE_URI/pixeldroid",
),
media_attachments = listOf(attachment1, attachment2)
media_attachments = listOf(attachment1, attachment2),
created_at = OffsetDateTime.now().minusHours(1)
)
val intent = Intent(context, PostActivity::class.java)
intent.putExtra(Status.POST_TAG, post)
@ -181,7 +186,7 @@ class PostTest {
@Test
fun getNLikesReturnsCorrectFormat() {
val status = Status(id="140364967936397312", uri="https://pixelfed.de/p/Miike/140364967936397312",
created_at= SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.hhmmss'Z'").parse("2020-03-03T08:00:16.000000Z"),
created_at= OffsetDateTime.parse("2020-03-03T08:00:16+00:00"),
account= Account(id="115114166443970560", username="Miike", acct="Miike",
url="https://pixelfed.de/Miike", display_name="Miike Duart", note="",
avatar="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",
@ -208,7 +213,7 @@ class PostTest {
@Test
fun getNSharesReturnsCorrectFormat() {
val status = Status(id="140364967936397312", uri="https://pixelfed.de/p/Miike/140364967936397312",
created_at= SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.hhmmss'Z'").parse("2020-03-03T08:00:16.000000Z"),
created_at= OffsetDateTime.parse("2020-03-03T08:00:16+00:00"),
account= Account(id="115114166443970560", username="Miike", acct="Miike",
url="https://pixelfed.de/Miike", display_name="Miike Duart", note="",
avatar="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",

View File

@ -10,7 +10,6 @@ import android.text.style.URLSpan
import android.util.Log
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.core.text.toSpanned
import androidx.lifecycle.LifecycleCoroutineScope
import org.pixeldroid.app.R
@ -22,6 +21,9 @@ import org.pixeldroid.app.utils.di.PixelfedAPIHolder
import java.net.URI
import java.net.URISyntaxException
import java.text.ParseException
import java.time.Instant
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.util.*
fun fromHtml(html: String): Spanned {
@ -128,18 +130,18 @@ fun parseHTMLText(
}
fun setTextViewFromISO8601(date: Date, textView: TextView, absoluteTime: Boolean, context: Context) {
val now = Date().time
fun setTextViewFromISO8601(date: OffsetDateTime, textView: TextView, absoluteTime: Boolean, context: Context) {
val now = Date.from(OffsetDateTime.ofInstant(Instant.now(), ZoneOffset.UTC).toInstant()).time
try {
val then = date.time
val formattedDate = android.text.format.DateUtils
.getRelativeTimeSpanString(then, now,
android.text.format.DateUtils.SECOND_IN_MILLIS,
android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE)
val then = Date.from(date.toInstant()).time
val formattedDate: String = android.text.format.DateUtils
.getRelativeTimeSpanString(then, now,
android.text.format.DateUtils.SECOND_IN_MILLIS,
android.text.format.DateUtils.FORMAT_ABBREV_RELATIVE).toString()
textView.text = if(absoluteTime) context.getString(R.string.posted_on).format(date)
else "$formattedDate"
else formattedDate
} catch (e: ParseException) {
e.printStackTrace()

View File

@ -24,10 +24,44 @@ interface PixelfedAPI {
fun createFromUrl(baseUrl: String): PixelfedAPI {
return Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gSonInstance))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build().create(PixelfedAPI::class.java)
}
private var gSonInstance: Gson = GsonBuilder()
.registerTypeAdapter(
OffsetDateTime::class.java,
JsonDeserializer { json: JsonElement, _, _ ->
OffsetDateTime.parse(
json.asString
)
} as JsonDeserializer<OffsetDateTime>)
.create()
private val intermediate: Retrofit.Builder = Retrofit.Builder()
.addConverterFactory(GsonConverterFactory.create(gSonInstance))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
fun apiForUser(
user: UserDatabaseEntity,
db: AppDatabase,
pixelfedAPIHolder: PixelfedAPIHolder
): PixelfedAPI =
intermediate
.baseUrl(user.instance_uri)
.client(
OkHttpClient().newBuilder().authenticator(TokenAuthenticator(user, db, pixelfedAPIHolder))
.addInterceptor {
it.request().newBuilder().run {
header("Accept", "application/json")
header("Authorization", "Bearer ${user.accessToken}")
it.proceed(build())
}
}.build()
)
.build().create(PixelfedAPI::class.java)
}

View File

@ -5,7 +5,7 @@ import androidx.room.ForeignKey
import androidx.room.Index
import org.pixeldroid.app.utils.db.entities.UserDatabaseEntity
import java.io.Serializable
import java.util.Date
import java.time.OffsetDateTime
/*
Represents a notification of an event relevant to the user.
@ -27,7 +27,7 @@ data class Notification(
//Required attributes
override val id: String,
val type: NotificationType?,
val created_at: Date?, //ISO 8601 Datetime
val created_at: OffsetDateTime?, //ISO 8601 Datetime
val account: Account?,
//Optional attributes
val status: Status? = null,

View File

@ -13,6 +13,7 @@ import org.pixeldroid.app.R
import org.pixeldroid.app.posts.getDomain
import java.io.File
import java.io.Serializable
import java.time.OffsetDateTime
import java.util.*
/**
@ -24,7 +25,7 @@ open class Status(
//Base attributes
override val id: String,
val uri: String? = "",
val created_at: Date? = Date(0), //ISO 8601 Datetime
val created_at: OffsetDateTime?, //ISO 8601 Datetime
val account: Account?,
val content: String? = "", //HTML
val visibility: Visibility? = Visibility.public,

View File

@ -3,6 +3,8 @@ package org.pixeldroid.app.utils.db
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import org.pixeldroid.app.utils.db.dao.*
import org.pixeldroid.app.utils.db.dao.feedContent.NotificationDao
import org.pixeldroid.app.utils.db.dao.feedContent.posts.HomePostDao
@ -20,7 +22,7 @@ import org.pixeldroid.app.utils.api.objects.Notification
PublicFeedStatusDatabaseEntity::class,
Notification::class
],
version = 3
version = 4
)
@TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
@ -29,4 +31,12 @@ abstract class AppDatabase : RoomDatabase() {
abstract fun homePostDao(): HomePostDao
abstract fun publicPostDao(): PublicPostDao
abstract fun notificationDao(): NotificationDao
}
val MIGRATION_3_4 = object : Migration(3, 4) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DELETE FROM homePosts")
database.execSQL("DELETE FROM publicPosts")
database.execSQL("DELETE FROM notifications")
}
}

View File

@ -1,14 +1,30 @@
package org.pixeldroid.app.utils.db
import android.os.Build
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import org.pixeldroid.app.utils.api.objects.*
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
import java.util.*
class Converters {
private val gson = Gson()
private val formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME
@TypeConverter
fun toOffsetDateTime(value: String?): OffsetDateTime? {
return value?.let {
return formatter.parse(value, OffsetDateTime::from)
}
}
@TypeConverter
fun fromOffsetDateTime(date: OffsetDateTime?): String? {
return date?.format(formatter)
}
@TypeConverter
fun listToJson(list: List<String>): String = gson.toJson(list)
@ -16,12 +32,6 @@ class Converters {
fun jsonToList(json: String): List<String> =
gson.fromJson(json, Array<String>::class.java).toList()
@TypeConverter
fun dateToJson(date: Date): String = gson.toJson(date)
@TypeConverter
fun jsonToDate(json: String): Date = gson.fromJson(json, Date::class.java)
@TypeConverter
fun accountToJson(account: Account): String = gson.toJson(account)

View File

@ -12,7 +12,7 @@ interface NotificationDao: FeedContentDao<Notification> {
override suspend fun clearFeedContent(userId: String, instanceUri: String)
@Query("""SELECT * FROM notifications WHERE user_id=:userId AND instance_uri=:instanceUri
ORDER BY CAST(created_at AS FLOAT) DESC""")
ORDER BY datetime(created_at) DESC""")
override fun feedContent(userId: String, instanceUri: String): PagingSource<Int, Notification>
@Query("DELETE FROM notifications WHERE user_id=:userId AND instance_uri=:instanceUri AND id=:id")

View File

@ -9,7 +9,7 @@ import org.pixeldroid.app.utils.db.entities.HomeStatusDatabaseEntity
@Dao
interface HomePostDao: FeedContentDao<HomeStatusDatabaseEntity> {
@Query("""SELECT * FROM homePosts WHERE user_id=:userId AND instance_uri=:instanceUri
ORDER BY CAST(created_at AS FLOAT)""")
ORDER BY datetime(created_at) DESC""")
override fun feedContent(userId: String, instanceUri: String): PagingSource<Int, HomeStatusDatabaseEntity>
@Query("DELETE FROM homePosts WHERE user_id=:userId AND instance_uri=:instanceUri")

View File

@ -9,7 +9,7 @@ import org.pixeldroid.app.utils.db.entities.PublicFeedStatusDatabaseEntity
@Dao
interface PublicPostDao: FeedContentDao<PublicFeedStatusDatabaseEntity> {
@Query("""SELECT * FROM publicPosts WHERE user_id=:userId AND instance_uri=:instanceUri
ORDER BY CAST(created_at AS FLOAT)""")
ORDER BY datetime(created_at) DESC""")
override fun feedContent(userId: String, instanceUri: String): PagingSource<Int, PublicFeedStatusDatabaseEntity>
@Query("DELETE FROM publicPosts WHERE user_id=:userId AND instance_uri=:instanceUri")

View File

@ -4,6 +4,7 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import org.pixeldroid.app.utils.api.objects.*
import java.time.OffsetDateTime
import java.util.*
@Entity(
@ -56,7 +57,7 @@ class HomeStatusDatabaseEntity(
//Constructor to make Room happy. This sucks, and I know it.
constructor(id: String,
uri: String? = "",
created_at: Date? = Date(0),
created_at: OffsetDateTime?,
account: Account?,
content: String? = "",
visibility: Visibility? = Visibility.public,

View File

@ -4,6 +4,7 @@ import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import org.pixeldroid.app.utils.api.objects.*
import java.time.OffsetDateTime
import java.util.*
@Entity(
@ -56,7 +57,7 @@ class PublicFeedStatusDatabaseEntity(
//Constructor to make Room happy. This sucks, and I know it.
constructor(id: String,
uri: String? = "",
created_at: Date? = Date(0),
created_at: OffsetDateTime?,
account: Account?,
content: String? = "",
visibility: Visibility? = Visibility.public,

View File

@ -5,6 +5,7 @@ import androidx.room.Room
import org.pixeldroid.app.utils.db.AppDatabase
import dagger.Module
import dagger.Provides
import org.pixeldroid.app.utils.db.MIGRATION_3_4
import javax.inject.Singleton
@Module
@ -16,6 +17,6 @@ class DatabaseModule(private val context: Context) {
return Room.databaseBuilder(
context,
AppDatabase::class.java, "pixeldroid"
).allowMainThreadQueries().build()
).addMigrations(MIGRATION_3_4).allowMainThreadQueries().build()
}
}

View File

@ -8,7 +8,7 @@ import kotlinx.coroutines.runBlocking
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
import java.text.SimpleDateFormat
import java.time.OffsetDateTime
/**
@ -18,7 +18,7 @@ import java.text.SimpleDateFormat
*/
class APIUnitTest {
private val referenceFirstStatus = Status(id="140364967936397312", uri="https://pixelfed.de/p/Miike/140364967936397312",
created_at= SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.Z").parse("2020-03-03T08:00:16.+0000"),
created_at= OffsetDateTime.parse("2020-03-03T08:00:16+00:00"),
account=Account(id="115114166443970560", username="Miike", acct="Miike",
url="https://pixelfed.de/Miike", display_name="Miike Duart", note="",
avatar="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",
@ -36,14 +36,14 @@ class APIUnitTest {
emojis= emptyList(), reblogs_count=0, favourites_count=0, replies_count=0, url="https://pixelfed.de/p/Miike/140364967936397312",
in_reply_to_id=null, in_reply_to_account=null, reblog=null, poll=null, card=null, language=null, text=null, favourited=null, reblogged=null, muted=null, bookmarked=null, pinned=null)
val sampleNotification = Notification("45723", Notification.NotificationType.favourite,
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss+hh:mm").parse("2020-03-14T15:01:49+00:00")!!,
OffsetDateTime.parse("2020-03-14T15:01:49+00:00")!!,
Account("79574199701737472", "Spaziergaenger",
"Spaziergaenger", "https://pixelfed.de/Spaziergaenger",
"anonymous", "", "https://pixelfed.de/storage/avatars/007/957/419/970/173/747/2/KEg4YgCgsmzdgyVztszz_avatar.jpeg?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",
"https://pixelfed.de/storage/avatars/007/957/419/970/173/747/2/KEg4YgCgsmzdgyVztszz_avatar.jpeg?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",
locked=false, followers_count = 40, following_count = 0, statuses_count = 891, created_at = "1568728767", header = "", discoverable = true, emojis = emptyList(), header_static = ""),
Status("144456497894658048","https://pixelfed.de/p/dante/144456497894658048",
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.hhmmss'Z'").parse("2020-03-03T08:00:16.000000Z"), in_reply_to_id = null,
OffsetDateTime.parse("2020-03-03T08:00:16+00:00"), in_reply_to_id = null,
in_reply_to_account = null, reblog = null,content = "Saturn V launch", emojis = emptyList(), reblogs_count = 0,
favourites_count = 1, reblogged = false, favourited = false, muted = false, sensitive = false,
spoiler_text = "", visibility = Status.Visibility.public, application = Application("web", null),
@ -163,7 +163,7 @@ fun assertStatusEqualsToReference(actual: Status){
assert(
((actual.id=="140364967936397312"
&& actual.uri=="https://pixelfed.de/p/Miike/140364967936397312"
&& actual.created_at==SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.Z").parse("2020-03-03T08:00:16.+0000")
&& actual.created_at == OffsetDateTime.parse("2020-03-03T08:00:16.+00:00")
&& actual.account!!.id=="115114166443970560"&& actual.account!!.username=="Miike"&& actual.account!!.acct=="Miike" &&
actual.account!!.url=="https://pixelfed.de/Miike"&& actual.account!!.display_name=="Miike Duart"&& actual.account!!.note==""&&
actual.account!!.avatar=="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35"&&

View File

@ -4,10 +4,11 @@ import org.pixeldroid.app.utils.api.objects.*
import org.junit.Assert
import org.junit.Test
import java.text.SimpleDateFormat
import java.time.OffsetDateTime
class PostUnitTest {
private val status = Status(id="140364967936397312", uri="https://pixelfed.de/p/Miike/140364967936397312",
created_at= SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.hhmmss'Z'").parse("2020-03-03T08:00:16.000000Z"),
created_at= OffsetDateTime.parse("2020-03-03T08:00:16+00:00"),
account= Account(id="115114166443970560", username="Miike", acct="Miike",
url="https://pixelfed.de/Miike", display_name="Miike Duart", note="",
avatar="https://pixelfed.de/storage/avatars/011/511/416/644/397/056/0/ZhaopLJWTWJ3hsVCS5pS_avatar.png?v=d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35",