mirror of
https://github.com/KokaKiwi/BarInsta
synced 2024-11-25 16:17:29 +00:00
Convert AppDatabase to kotlin
This commit is contained in:
parent
66b60e6830
commit
54ff196bb1
@ -1,6 +1,7 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: "androidx.navigation.safeargs"
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply from: 'sentry.gradle'
|
||||
|
||||
def getGitHash = { ->
|
||||
@ -146,6 +147,7 @@ android {
|
||||
// Error: Duplicate files during packaging of APK
|
||||
exclude 'META-INF/LICENSE.md'
|
||||
exclude 'META-INF/LICENSE-notice.md'
|
||||
exclude 'META-INF/atomicfu.kotlin_module'
|
||||
}
|
||||
|
||||
testOptions.unitTests {
|
||||
@ -196,6 +198,7 @@ dependencies {
|
||||
implementation "androidx.room:room-runtime:$room_version"
|
||||
implementation "androidx.room:room-guava:$room_version"
|
||||
implementation "androidx.room:room-ktx:$room_version"
|
||||
kapt "androidx.room:room-compiler:$room_version"
|
||||
annotationProcessor "androidx.room:room-compiler:$room_version"
|
||||
|
||||
// CameraX
|
||||
|
@ -1,97 +1,80 @@
|
||||
package awais.instagrabber.db;
|
||||
package awais.instagrabber.db
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import android.util.Log
|
||||
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
|
||||
import awais.instagrabber.db.dao.AccountDao
|
||||
import awais.instagrabber.db.dao.DMLastNotifiedDao
|
||||
import awais.instagrabber.db.dao.FavoriteDao
|
||||
import awais.instagrabber.db.dao.RecentSearchDao
|
||||
import awais.instagrabber.db.entities.Account
|
||||
import awais.instagrabber.db.entities.DMLastNotified
|
||||
import awais.instagrabber.db.entities.Favorite
|
||||
import awais.instagrabber.db.entities.RecentSearch
|
||||
import awais.instagrabber.utils.Utils
|
||||
import awais.instagrabber.utils.extensions.TAG
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.util.*
|
||||
|
||||
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;
|
||||
@Database(entities = [Account::class, Favorite::class, DMLastNotified::class, RecentSearch::class], version = 6)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun accountDao(): AccountDao
|
||||
abstract fun favoriteDao(): FavoriteDao
|
||||
abstract fun dmLastNotifiedDao(): DMLastNotifiedDao
|
||||
abstract fun recentSearchDao(): RecentSearchDao
|
||||
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
companion object {
|
||||
private lateinit var INSTANCE: AppDatabase
|
||||
|
||||
import awais.instagrabber.db.dao.AccountDao;
|
||||
import awais.instagrabber.db.dao.DMLastNotifiedDao;
|
||||
import awais.instagrabber.db.dao.FavoriteDao;
|
||||
import awais.instagrabber.db.dao.RecentSearchDao;
|
||||
import awais.instagrabber.db.entities.Account;
|
||||
import awais.instagrabber.db.entities.DMLastNotified;
|
||||
import awais.instagrabber.db.entities.Favorite;
|
||||
import awais.instagrabber.db.entities.RecentSearch;
|
||||
import awais.instagrabber.models.enums.FavoriteType;
|
||||
import awais.instagrabber.utils.Utils;
|
||||
|
||||
@Database(entities = {Account.class, Favorite.class, DMLastNotified.class, RecentSearch.class},
|
||||
version = 6)
|
||||
@TypeConverters({Converters.class})
|
||||
public abstract class AppDatabase extends RoomDatabase {
|
||||
private static final String TAG = AppDatabase.class.getSimpleName();
|
||||
|
||||
private static AppDatabase INSTANCE;
|
||||
|
||||
public abstract AccountDao accountDao();
|
||||
|
||||
public abstract FavoriteDao favoriteDao();
|
||||
|
||||
public abstract DMLastNotifiedDao dmLastNotifiedDao();
|
||||
|
||||
public abstract RecentSearchDao recentSearchDao();
|
||||
|
||||
public static AppDatabase getDatabase(final Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (AppDatabase.class) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "cookiebox.db")
|
||||
fun getDatabase(context: Context): AppDatabase {
|
||||
if (!this::INSTANCE.isInitialized) {
|
||||
synchronized(AppDatabase::class.java) {
|
||||
if (!this::INSTANCE.isInitialized) {
|
||||
INSTANCE = Room.databaseBuilder(context.applicationContext, AppDatabase::class.java, "cookiebox.db")
|
||||
.addMigrations(MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4, MIGRATION_4_5, MIGRATION_5_6)
|
||||
.build();
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
return INSTANCE
|
||||
}
|
||||
|
||||
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
db.execSQL("ALTER TABLE cookies ADD " + Account.COL_FULL_NAME + " TEXT");
|
||||
db.execSQL("ALTER TABLE cookies ADD " + Account.COL_PROFILE_PIC + " TEXT");
|
||||
private val MIGRATION_1_2: Migration = object : Migration(1, 2) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
db.execSQL("ALTER TABLE cookies ADD " + Account.COL_FULL_NAME + " TEXT")
|
||||
db.execSQL("ALTER TABLE cookies ADD " + Account.COL_PROFILE_PIC + " TEXT")
|
||||
}
|
||||
};
|
||||
|
||||
static final Migration MIGRATION_2_3 = new Migration(2, 3) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
final List<Favorite> oldFavorites = backupOldFavorites(db);
|
||||
}
|
||||
private val MIGRATION_2_3: Migration = object : Migration(2, 3) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
val oldFavorites = backupOldFavorites(db)
|
||||
// recreate with new columns (as there will be no doubt about the `query_display` column being present or not in the future versions)
|
||||
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME);
|
||||
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME)
|
||||
db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + " ("
|
||||
+ Favorite.COL_ID + " INTEGER PRIMARY KEY,"
|
||||
+ Favorite.COL_QUERY + " TEXT,"
|
||||
+ Favorite.COL_TYPE + " TEXT,"
|
||||
+ Favorite.COL_DISPLAY_NAME + " TEXT,"
|
||||
+ Favorite.COL_PIC_URL + " TEXT,"
|
||||
+ Favorite.COL_DATE_ADDED + " INTEGER)");
|
||||
+ Favorite.COL_DATE_ADDED + " INTEGER)")
|
||||
// add the old favorites back
|
||||
for (final Favorite oldFavorite : oldFavorites) {
|
||||
insertOrUpdateFavorite(db, oldFavorite);
|
||||
for (oldFavorite in oldFavorites) {
|
||||
insertOrUpdateFavorite(db, oldFavorite)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static final Migration MIGRATION_3_4 = new Migration(3, 4) {
|
||||
@Override
|
||||
public void migrate(@NonNull SupportSQLiteDatabase db) {
|
||||
}
|
||||
private val MIGRATION_3_4: Migration = object : Migration(3, 4) {
|
||||
override fun migrate(db: SupportSQLiteDatabase) {
|
||||
// Required when migrating to Room.
|
||||
// The original table primary keys were not 'NOT NULL', so the migration to Room were failing without the below migration.
|
||||
// Taking this opportunity to rename cookies table to accounts
|
||||
@ -103,7 +86,7 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
+ Account.COL_USERNAME + " TEXT,"
|
||||
+ Account.COL_COOKIE + " TEXT,"
|
||||
+ Account.COL_FULL_NAME + " TEXT,"
|
||||
+ Account.COL_PROFILE_PIC + " TEXT)");
|
||||
+ Account.COL_PROFILE_PIC + " TEXT)")
|
||||
// Insert all data from table 'cookies' to 'accounts'
|
||||
db.execSQL("INSERT INTO " + Account.TABLE_NAME + " ("
|
||||
+ Account.COL_UID + ","
|
||||
@ -117,9 +100,9 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
+ Account.COL_COOKIE + ","
|
||||
+ Account.COL_FULL_NAME + ","
|
||||
+ Account.COL_PROFILE_PIC
|
||||
+ " FROM cookies");
|
||||
+ " FROM cookies")
|
||||
// Drop old cookies table
|
||||
db.execSQL("DROP TABLE cookies");
|
||||
db.execSQL("DROP TABLE cookies")
|
||||
|
||||
// Create favorite backup table
|
||||
db.execSQL("CREATE TABLE " + Favorite.TABLE_NAME + "_backup ("
|
||||
@ -128,7 +111,7 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
+ Favorite.COL_TYPE + " TEXT,"
|
||||
+ Favorite.COL_DISPLAY_NAME + " TEXT,"
|
||||
+ Favorite.COL_PIC_URL + " TEXT,"
|
||||
+ Favorite.COL_DATE_ADDED + " INTEGER)");
|
||||
+ Favorite.COL_DATE_ADDED + " INTEGER)")
|
||||
// Insert all data from table 'favorite' to 'favorite_backup'
|
||||
db.execSQL("INSERT INTO " + Favorite.TABLE_NAME + "_backup ("
|
||||
+ Favorite.COL_QUERY + ","
|
||||
@ -142,29 +125,25 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
+ Favorite.COL_DISPLAY_NAME + ","
|
||||
+ Favorite.COL_PIC_URL + ","
|
||||
+ Favorite.COL_DATE_ADDED
|
||||
+ " FROM " + Favorite.TABLE_NAME);
|
||||
+ " FROM " + Favorite.TABLE_NAME)
|
||||
// Drop favorites
|
||||
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME);
|
||||
db.execSQL("DROP TABLE " + Favorite.TABLE_NAME)
|
||||
// Rename favorite_backup to favorites
|
||||
db.execSQL("ALTER TABLE " + Favorite.TABLE_NAME + "_backup RENAME TO " + Favorite.TABLE_NAME);
|
||||
db.execSQL("ALTER TABLE " + Favorite.TABLE_NAME + "_backup RENAME TO " + Favorite.TABLE_NAME)
|
||||
}
|
||||
};
|
||||
|
||||
static final Migration MIGRATION_4_5 = new Migration(4, 5) {
|
||||
@Override
|
||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||
}
|
||||
private val MIGRATION_4_5: Migration = object : Migration(4, 5) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS `dm_last_notified` (" +
|
||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
|
||||
"`thread_id` TEXT, " +
|
||||
"`last_notified_msg_ts` INTEGER, " +
|
||||
"`last_notified_at` INTEGER)");
|
||||
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_dm_last_notified_thread_id` ON `dm_last_notified` (`thread_id`)");
|
||||
"`last_notified_at` INTEGER)")
|
||||
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_dm_last_notified_thread_id` ON `dm_last_notified` (`thread_id`)")
|
||||
}
|
||||
};
|
||||
|
||||
static final Migration MIGRATION_5_6 = new Migration(5, 6) {
|
||||
@Override
|
||||
public void migrate(@NonNull final SupportSQLiteDatabase database) {
|
||||
}
|
||||
private val MIGRATION_5_6: Migration = object : Migration(5, 6) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.execSQL("CREATE TABLE IF NOT EXISTS `recent_searches` (" +
|
||||
"`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
|
||||
"`ig_id` TEXT NOT NULL, " +
|
||||
@ -172,99 +151,102 @@ public abstract class AppDatabase extends RoomDatabase {
|
||||
"`username` TEXT, " +
|
||||
"`pic_url` TEXT, " +
|
||||
"`type` TEXT NOT NULL, " +
|
||||
"`last_searched_on` INTEGER NOT NULL)");
|
||||
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_recent_searches_ig_id_type` ON `recent_searches` (`ig_id`, `type`)");
|
||||
"`last_searched_on` INTEGER NOT NULL)")
|
||||
database.execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_recent_searches_ig_id_type` ON `recent_searches` (`ig_id`, `type`)")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@NonNull
|
||||
private static List<Favorite> backupOldFavorites(@NonNull final SupportSQLiteDatabase db) {
|
||||
private fun backupOldFavorites(db: SupportSQLiteDatabase): List<Favorite> {
|
||||
// check if old favorites table had the column query_display
|
||||
final boolean queryDisplayExists = checkColumnExists(db, Favorite.TABLE_NAME, "query_display");
|
||||
Log.d(TAG, "backupOldFavorites: queryDisplayExists: " + queryDisplayExists);
|
||||
final List<Favorite> oldModels = new ArrayList<>();
|
||||
final String sql = "SELECT "
|
||||
val queryDisplayExists = checkColumnExists(db, Favorite.TABLE_NAME, "query_display")
|
||||
Log.d(TAG, "backupOldFavorites: queryDisplayExists: $queryDisplayExists")
|
||||
val oldModels: MutableList<Favorite> = ArrayList()
|
||||
val sql = ("SELECT "
|
||||
+ "query_text,"
|
||||
+ "date_added"
|
||||
+ (queryDisplayExists ? ",query_display" : "")
|
||||
+ " FROM " + Favorite.TABLE_NAME;
|
||||
try (final Cursor cursor = db.query(sql)) {
|
||||
+ (if (queryDisplayExists) ",query_display" else "")
|
||||
+ " FROM " + Favorite.TABLE_NAME)
|
||||
try {
|
||||
db.query(sql).use { cursor ->
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
do {
|
||||
try {
|
||||
final String queryText = cursor.getString(cursor.getColumnIndex("query_text"));
|
||||
final Pair<FavoriteType, String> favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText);
|
||||
if (favoriteTypeQueryPair == null) continue;
|
||||
final FavoriteType type = favoriteTypeQueryPair.first;
|
||||
final String query = favoriteTypeQueryPair.second;
|
||||
final long epochMillis = cursor.getLong(cursor.getColumnIndex("date_added"));
|
||||
final LocalDateTime localDateTime = LocalDateTime.ofInstant(
|
||||
val queryText = cursor.getString(cursor.getColumnIndex("query_text"))
|
||||
val favoriteTypeQueryPair = Utils.migrateOldFavQuery(queryText) ?: continue
|
||||
val type = favoriteTypeQueryPair.first
|
||||
val query = favoriteTypeQueryPair.second
|
||||
val epochMillis = cursor.getLong(cursor.getColumnIndex("date_added"))
|
||||
val localDateTime = LocalDateTime.ofInstant(
|
||||
Instant.ofEpochMilli(epochMillis),
|
||||
ZoneId.systemDefault()
|
||||
);
|
||||
oldModels.add(new Favorite(
|
||||
)
|
||||
oldModels.add(Favorite(
|
||||
0,
|
||||
query,
|
||||
type,
|
||||
queryDisplayExists ? cursor.getString(cursor.getColumnIndex("query_display")) : null,
|
||||
if (queryDisplayExists) cursor.getString(cursor.getColumnIndex("query_display")) else null,
|
||||
null,
|
||||
localDateTime
|
||||
));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onUpgrade", e);
|
||||
))
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "onUpgrade", e)
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "onUpgrade", e);
|
||||
}
|
||||
Log.d(TAG, "backupOldFavorites: oldModels:" + oldModels);
|
||||
return oldModels;
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, "onUpgrade", e)
|
||||
}
|
||||
Log.d(TAG, "backupOldFavorites: oldModels:$oldModels")
|
||||
return oldModels
|
||||
}
|
||||
|
||||
private static synchronized void insertOrUpdateFavorite(@NonNull final SupportSQLiteDatabase db, @NonNull final Favorite model) {
|
||||
final ContentValues values = new ContentValues();
|
||||
values.put(Favorite.COL_QUERY, model.getQuery());
|
||||
values.put(Favorite.COL_TYPE, model.getType().toString());
|
||||
values.put(Favorite.COL_DISPLAY_NAME, model.getDisplayName());
|
||||
values.put(Favorite.COL_PIC_URL, model.getPicUrl());
|
||||
values.put(Favorite.COL_DATE_ADDED, model.getDateAdded().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
|
||||
int rows;
|
||||
if (model.getId() >= 1) {
|
||||
rows = db.update(Favorite.TABLE_NAME,
|
||||
@Synchronized
|
||||
private fun insertOrUpdateFavorite(db: SupportSQLiteDatabase, model: Favorite) {
|
||||
val values = ContentValues()
|
||||
values.put(Favorite.COL_QUERY, model.query)
|
||||
values.put(Favorite.COL_TYPE, model.type.toString())
|
||||
values.put(Favorite.COL_DISPLAY_NAME, model.displayName)
|
||||
values.put(Favorite.COL_PIC_URL, model.picUrl)
|
||||
values.put(Favorite.COL_DATE_ADDED, model.dateAdded!!.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())
|
||||
val rows: Int = if (model.id >= 1) {
|
||||
db.update(Favorite.TABLE_NAME,
|
||||
SQLiteDatabase.CONFLICT_IGNORE,
|
||||
values,
|
||||
Favorite.COL_ID + "=?",
|
||||
new String[]{String.valueOf(model.getId())});
|
||||
Favorite.COL_ID + "=?", arrayOf(model.id.toString()))
|
||||
} else {
|
||||
rows = db.update(Favorite.TABLE_NAME,
|
||||
db.update(Favorite.TABLE_NAME,
|
||||
SQLiteDatabase.CONFLICT_IGNORE,
|
||||
values,
|
||||
Favorite.COL_QUERY + "=?" + " AND " + Favorite.COL_TYPE + "=?",
|
||||
new String[]{model.getQuery(), model.getType().toString()});
|
||||
Favorite.COL_QUERY + "=?" + " AND " + Favorite.COL_TYPE + "=?", arrayOf(model.query, model.type.toString()))
|
||||
}
|
||||
if (rows != 1) {
|
||||
db.insert(Favorite.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values);
|
||||
db.insert(Favorite.TABLE_NAME, SQLiteDatabase.CONFLICT_IGNORE, values)
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkColumnExists(@NonNull final SupportSQLiteDatabase db,
|
||||
@NonNull final String tableName,
|
||||
@NonNull final String columnName) {
|
||||
boolean exists = false;
|
||||
try (Cursor cursor = db.query("PRAGMA table_info(" + tableName + ")")) {
|
||||
@Suppress("SameParameterValue")
|
||||
private fun checkColumnExists(
|
||||
db: SupportSQLiteDatabase,
|
||||
tableName: String,
|
||||
columnName: String,
|
||||
): Boolean {
|
||||
var exists = false
|
||||
try {
|
||||
db.query("PRAGMA table_info($tableName)").use { cursor ->
|
||||
if (cursor.moveToFirst()) {
|
||||
do {
|
||||
final String currentColumn = cursor.getString(cursor.getColumnIndex("name"));
|
||||
if (currentColumn.equals(columnName)) {
|
||||
exists = true;
|
||||
val currentColumn = cursor.getString(cursor.getColumnIndex("name"))
|
||||
if (currentColumn == columnName) {
|
||||
exists = true
|
||||
}
|
||||
} while (cursor.moveToNext())
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Log.e(TAG, "checkColumnExists", ex)
|
||||
}
|
||||
return exists
|
||||
}
|
||||
} while (cursor.moveToNext());
|
||||
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, "checkColumnExists", ex);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
}
|
@ -7,8 +7,7 @@ import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZoneOffset
|
||||
|
||||
object Converters {
|
||||
@JvmStatic
|
||||
class Converters {
|
||||
@TypeConverter
|
||||
fun fromFavoriteTypeString(value: String?): FavoriteType? =
|
||||
if (value == null) null
|
||||
@ -18,16 +17,13 @@ object Converters {
|
||||
null
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@TypeConverter
|
||||
fun favoriteTypeToString(favoriteType: FavoriteType?): String? = favoriteType?.toString()
|
||||
|
||||
@JvmStatic
|
||||
@TypeConverter
|
||||
fun fromTimestampToLocalDateTime(value: Long?): LocalDateTime? =
|
||||
if (value == null) null else LocalDateTime.ofInstant(Instant.ofEpochMilli(value), ZoneOffset.systemDefault())
|
||||
|
||||
@JvmStatic
|
||||
@TypeConverter
|
||||
fun localDateTimeToTimestamp(localDateTime: LocalDateTime?): Long? = localDateTime?.atZone(ZoneId.systemDefault())?.toInstant()?.toEpochMilli()
|
||||
}
|
Loading…
Reference in New Issue
Block a user