165: Allow backup and restore of saved posts r=msfjarvis a=msfjarvis

Very much WIP, lacks essentially everything right now.


Co-authored-by: Aditya Wasan <adityawasan55@gmail.com>
Co-authored-by: Harsh Shandilya <me@msfjarvis.dev>
This commit is contained in:
bors[bot] 2021-04-03 10:03:10 +00:00 committed by GitHub
commit e50a8e8d68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 389 additions and 28 deletions

8
.idea/artifacts/database_jvm.xml generated Normal file
View file

@ -0,0 +1,8 @@
<component name="ArtifactManager">
<artifact type="jar" name="database-jvm">
<output-path>$PROJECT_DIR$/database/build/libs</output-path>
<root id="archive" name="database-jvm.jar">
<element id="module-output" name="database.Claw.database.jvmMain" />
</root>
</artifact>
</component>

View file

@ -44,7 +44,6 @@ dependencies {
implementation(Dependencies.ThirdParty.accompanistFlow) implementation(Dependencies.ThirdParty.accompanistFlow)
implementation(Dependencies.ThirdParty.Moshi.lib) implementation(Dependencies.ThirdParty.Moshi.lib)
implementation(Dependencies.ThirdParty.Retrofit.moshi) implementation(Dependencies.ThirdParty.Retrofit.moshi)
implementation(Dependencies.ThirdParty.SQLDelight.androidDriver)
testImplementation(kotlin("test-junit")) testImplementation(kotlin("test-junit"))
androidTestImplementation(kotlin("test-junit")) androidTestImplementation(kotlin("test-junit"))
} }

View file

@ -24,6 +24,7 @@ class LobstersTopBarTest : ScreenshotTest {
LobstersTopAppBar( LobstersTopAppBar(
currentDestination = Destination.Hottest, currentDestination = Destination.Hottest,
toggleSortingOrder = {}, toggleSortingOrder = {},
launchSettings = {},
) )
} }
} }
@ -38,6 +39,7 @@ class LobstersTopBarTest : ScreenshotTest {
LobstersTopAppBar( LobstersTopAppBar(
currentDestination = Destination.Hottest, currentDestination = Destination.Hottest,
toggleSortingOrder = {}, toggleSortingOrder = {},
launchSettings = {},
) )
} }
} }
@ -52,6 +54,7 @@ class LobstersTopBarTest : ScreenshotTest {
LobstersTopAppBar( LobstersTopAppBar(
currentDestination = Destination.Saved, currentDestination = Destination.Saved,
toggleSortingOrder = {}, toggleSortingOrder = {},
launchSettings = {},
) )
} }
} }
@ -66,6 +69,7 @@ class LobstersTopBarTest : ScreenshotTest {
LobstersTopAppBar( LobstersTopAppBar(
currentDestination = Destination.Saved, currentDestination = Destination.Saved,
toggleSortingOrder = {}, toggleSortingOrder = {},
launchSettings = {},
) )
} }
} }

View file

@ -25,6 +25,14 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.settings.SettingsActivity"
android:theme="@style/Platform.Theme.Claw"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
</activity>
</application> </application>
</manifest> </manifest>

View file

@ -0,0 +1,32 @@
package dev.msfjarvis.lobsters.data.backup
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import dev.msfjarvis.lobsters.data.local.SavedPost
import dev.msfjarvis.lobsters.database.LobstersDatabase
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@OptIn(ExperimentalStdlibApi::class)
class BackupHandler
@Inject
constructor(
private val database: LobstersDatabase,
moshi: Moshi,
) {
private val adapter = moshi.adapter<List<SavedPost>>()
suspend fun exportSavedPosts(): ByteArray {
val posts =
withContext(Dispatchers.IO) { database.savedPostQueries.selectAllPosts().executeAsList() }
return adapter.toJson(posts).toByteArray(Charsets.UTF_8)
}
suspend fun importSavedPosts(json: ByteArray) {
withContext(Dispatchers.IO) {
val posts = requireNotNull(adapter.fromJson(json.toString(Charsets.UTF_8)))
database.transaction { posts.forEach { database.savedPostQueries.insertOrReplacePost(it) } }
}
}
}

View file

@ -0,0 +1,21 @@
package dev.msfjarvis.lobsters.injection
import com.squareup.moshi.Moshi
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import dev.msfjarvis.lobsters.data.backup.BackupHandler
import dev.msfjarvis.lobsters.database.LobstersDatabase
@Module
@InstallIn(ActivityComponent::class)
object BackupModule {
@Provides
fun provideBackupHandler(
database: LobstersDatabase,
moshi: Moshi,
): BackupHandler {
return BackupHandler(database, moshi)
}
}

View file

@ -1,41 +1,29 @@
package dev.msfjarvis.lobsters.injection package dev.msfjarvis.lobsters.injection
import android.content.Context import android.content.Context
import com.squareup.sqldelight.android.AndroidSqliteDriver
import com.squareup.sqldelight.db.SqlDriver
import dagger.Module import dagger.Module
import dagger.Provides import dagger.Provides
import dagger.Reusable
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import dev.msfjarvis.lobsters.data.local.SavedPost import dev.msfjarvis.lobsters.data.local.DriverFactory
import dev.msfjarvis.lobsters.data.local.createDatabase
import dev.msfjarvis.lobsters.database.LobstersDatabase import dev.msfjarvis.lobsters.database.LobstersDatabase
import dev.msfjarvis.lobsters.model.TagsAdapter
import javax.inject.Singleton import javax.inject.Singleton
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
object DatabaseModule { object DatabaseModule {
@Provides
@Reusable
fun providesTagsAdapter(): TagsAdapter {
return TagsAdapter()
}
@Provides @Provides
@Singleton @Singleton
fun providesSqlDriver(@ApplicationContext context: Context): SqlDriver { fun providesDriverFactory(@ApplicationContext context: Context): DriverFactory {
return AndroidSqliteDriver(LobstersDatabase.Schema, context, "SavedPosts.db") return DriverFactory(context)
} }
@Provides @Provides
@Singleton @Singleton
fun providesLobstersDatabase(sqlDriver: SqlDriver, tagsAdapter: TagsAdapter): LobstersDatabase { fun providesLobstersDatabase(driverFactory: DriverFactory): LobstersDatabase {
return LobstersDatabase( return createDatabase(driverFactory)
sqlDriver,
SavedPost.Adapter(tagsAdapter),
)
} }
} }

View file

@ -1,5 +1,6 @@
package dev.msfjarvis.lobsters.ui.main package dev.msfjarvis.lobsters.ui.main
import android.content.Intent
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.BottomNavigation import androidx.compose.material.BottomNavigation
@ -11,6 +12,7 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag import androidx.compose.ui.platform.testTag
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.KEY_ROUTE import androidx.navigation.compose.KEY_ROUTE
@ -24,6 +26,7 @@ import androidx.paging.compose.collectAsLazyPagingItems
import dev.msfjarvis.lobsters.ui.navigation.Destination import dev.msfjarvis.lobsters.ui.navigation.Destination
import dev.msfjarvis.lobsters.ui.posts.NetworkPosts import dev.msfjarvis.lobsters.ui.posts.NetworkPosts
import dev.msfjarvis.lobsters.ui.posts.SavedPosts import dev.msfjarvis.lobsters.ui.posts.SavedPosts
import dev.msfjarvis.lobsters.ui.settings.SettingsActivity
import dev.msfjarvis.lobsters.ui.viewmodel.LobstersViewModel import dev.msfjarvis.lobsters.ui.viewmodel.LobstersViewModel
import dev.msfjarvis.lobsters.util.IconResource import dev.msfjarvis.lobsters.util.IconResource
import dev.msfjarvis.lobsters.utils.get import dev.msfjarvis.lobsters.utils.get
@ -32,6 +35,7 @@ import kotlinx.coroutines.launch
@Composable @Composable
fun LobstersApp() { fun LobstersApp() {
val viewModel: LobstersViewModel = viewModel() val viewModel: LobstersViewModel = viewModel()
val context = LocalContext.current
val navController = rememberNavController() val navController = rememberNavController()
val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems() val hottestPosts = viewModel.hottestPosts.collectAsLazyPagingItems()
val newestPosts = viewModel.newestPosts.collectAsLazyPagingItems() val newestPosts = viewModel.newestPosts.collectAsLazyPagingItems()
@ -70,7 +74,7 @@ fun LobstersApp() {
LobstersTopAppBar( LobstersTopAppBar(
currentDestination, currentDestination,
viewModel::toggleSortOrder, viewModel::toggleSortOrder,
) ) { context.startActivity(Intent(context, SettingsActivity::class.java)) }
}, },
bottomBar = { bottomBar = {
LobstersBottomNav( LobstersBottomNav(

View file

@ -22,6 +22,7 @@ import kotlinx.coroutines.launch
fun LobstersTopAppBar( fun LobstersTopAppBar(
currentDestination: Destination, currentDestination: Destination,
toggleSortingOrder: suspend () -> Unit, toggleSortingOrder: suspend () -> Unit,
launchSettings: () -> Unit,
) { ) {
val scope = rememberCoroutineScope() val scope = rememberCoroutineScope()
TopAppBar( TopAppBar(
@ -42,6 +43,14 @@ fun LobstersTopAppBar(
}, },
) )
} }
IconResource(
resourceId = R.drawable.ic_app_settings_24px,
contentDescription = Strings.Settings.get(),
modifier =
Modifier.padding(horizontal = 8.dp, vertical = 8.dp).clickable {
scope.launch { launchSettings() }
},
)
} }
) )
} }

View file

@ -0,0 +1,60 @@
package dev.msfjarvis.lobsters.ui.settings
import android.content.Context
import androidx.activity.compose.registerForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.runtime.Composable
import dev.msfjarvis.lobsters.data.backup.BackupHandler
import dev.msfjarvis.lobsters.utils.Strings
import dev.msfjarvis.lobsters.utils.get
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
private const val JSON_MINE = "application/json"
@Composable
fun BackupOption(
context: Context,
backupHandler: BackupHandler,
coroutineScope: CoroutineScope,
) {
val result =
registerForActivityResult(ActivityResultContracts.CreateDocument()) { uri ->
if (uri == null) return@registerForActivityResult
context.contentResolver.openOutputStream(uri)?.let {
coroutineScope.launch(Dispatchers.IO) {
it.write(backupHandler.exportSavedPosts())
it.close()
}
}
}
SettingsActionItem(
Strings.SettingsBackup.get(),
Strings.SettingsBackupDescription.get(),
onClick = { result.launch("Claw-export.json") }
)
}
@Composable
fun RestoreOption(
context: Context,
backupHandler: BackupHandler,
coroutineScope: CoroutineScope,
) {
val result =
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
if (uri == null) return@registerForActivityResult
context.contentResolver.openInputStream(uri)?.let {
coroutineScope.launch(Dispatchers.IO) {
backupHandler.importSavedPosts(it.readBytes())
it.close()
}
}
}
SettingsActionItem(
title = Strings.SettingsRestore.get(),
description = Strings.SettingsRestoreDescription.get(),
onClick = { result.launch(JSON_MINE) }
)
}

View file

@ -0,0 +1,95 @@
package dev.msfjarvis.lobsters.ui.settings
import android.content.Context
import androidx.activity.ComponentActivity
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Icon
import androidx.compose.material.ListItem
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.TopAppBar
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ArrowBack
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import dev.msfjarvis.lobsters.data.backup.BackupHandler
import dev.msfjarvis.lobsters.utils.Strings
import dev.msfjarvis.lobsters.utils.get
import kotlinx.coroutines.CoroutineScope
@Composable
fun LobstersSettings(
backupHandler: BackupHandler,
) {
val context = LocalContext.current
val scope = rememberCoroutineScope()
Scaffold(
topBar = { SettingsTopBar(context) },
content = { SettingsBody(context, backupHandler, scope) },
)
}
@Composable
fun SettingsTopBar(
context: Context,
) {
TopAppBar(
title = { Text(Strings.Settings.get()) },
navigationIcon = {
Icon(
Icons.Default.ArrowBack,
contentDescription = Strings.Settings.get(),
modifier =
Modifier.padding(start = 16.dp).clickable { (context as ComponentActivity).finish() },
)
},
)
}
@Composable
fun SettingsBody(
context: Context,
backupHandler: BackupHandler,
scope: CoroutineScope,
) {
LazyColumn {
item {
BackupOption(
context,
backupHandler,
scope,
)
}
item {
RestoreOption(
context,
backupHandler,
scope,
)
}
}
}
@Composable
fun SettingsActionItem(
title: String,
description: String? = null,
singleLineDescription: Boolean = true,
icon: ImageVector? = null,
onClick: (() -> Unit)? = null,
) {
ListItem(
text = { Text(title) },
secondaryText = { description?.let { Text(it) } },
icon = { icon?.let { Icon(icon, null, Modifier.height(32.dp)) } },
singleLineSecondaryText = singleLineDescription,
modifier = Modifier.clickable { onClick?.invoke() },
)
}

View file

@ -0,0 +1,20 @@
package dev.msfjarvis.lobsters.ui.settings
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import dagger.hilt.android.AndroidEntryPoint
import dev.msfjarvis.lobsters.data.backup.BackupHandler
import dev.msfjarvis.lobsters.ui.theme.LobstersTheme
import javax.inject.Inject
@AndroidEntryPoint
class SettingsActivity : ComponentActivity() {
@Inject lateinit var backupHandler: BackupHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent { LobstersTheme { LobstersSettings(backupHandler) } }
}
}

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M21.81,12.74l-0.82,-0.63v-0.22l0.8,-0.63c0.16,-0.12 0.2,-0.34 0.1,-0.51l-0.85,-1.48c-0.07,-0.13 -0.21,-0.2 -0.35,-0.2 -0.05,0 -0.1,0.01 -0.15,0.03l-0.95,0.38c-0.08,-0.05 -0.11,-0.07 -0.19,-0.11l-0.15,-1.01c-0.03,-0.21 -0.2,-0.36 -0.4,-0.36h-1.71c-0.2,0 -0.37,0.15 -0.4,0.34l-0.14,1.01c-0.03,0.02 -0.07,0.03 -0.1,0.05l-0.09,0.06 -0.95,-0.38c-0.05,-0.02 -0.1,-0.03 -0.15,-0.03 -0.14,0 -0.27,0.07 -0.35,0.2l-0.85,1.48c-0.1,0.17 -0.06,0.39 0.1,0.51l0.8,0.63v0.23l-0.8,0.63c-0.16,0.12 -0.2,0.34 -0.1,0.51l0.85,1.48c0.07,0.13 0.21,0.2 0.35,0.2 0.05,0 0.1,-0.01 0.15,-0.03l0.95,-0.37c0.08,0.05 0.12,0.07 0.2,0.11l0.15,1.01c0.03,0.2 0.2,0.34 0.4,0.34h1.71c0.2,0 0.37,-0.15 0.4,-0.34l0.15,-1.01c0.03,-0.02 0.07,-0.03 0.1,-0.05l0.09,-0.06 0.95,0.38c0.05,0.02 0.1,0.03 0.15,0.03 0.14,0 0.27,-0.07 0.35,-0.2l0.85,-1.48c0.1,-0.17 0.06,-0.39 -0.1,-0.51zM18,13.5c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM17,17h2v4c0,1.1 -0.9,2 -2,2H7c-1.1,0 -2,-0.9 -2,-2V3c0,-1.1 0.9,-2 2,-2h10c1.1,0 2,0.9 2,2v4h-2V6H7v12h10v-1z" />
</vector>

View file

@ -11,13 +11,18 @@ private fun stringEnumMapper(stringEnum: Strings): Int {
Strings.AvatarContentDescription -> R.string.avatar_content_description Strings.AvatarContentDescription -> R.string.avatar_content_description
Strings.ChangeSortingOrder -> R.string.change_sorting_order Strings.ChangeSortingOrder -> R.string.change_sorting_order
Strings.HottestPosts -> R.string.hottest_posts Strings.HottestPosts -> R.string.hottest_posts
Strings.NewestPosts -> R.string.newest_posts
Strings.NoSavedPost -> R.string.no_saved_posts Strings.NoSavedPost -> R.string.no_saved_posts
Strings.OpenComments -> R.string.open_comments Strings.OpenComments -> R.string.open_comments
Strings.RefreshPostsContentDescription -> R.string.refresh_posts_content_description Strings.RefreshPostsContentDescription -> R.string.refresh_posts_content_description
Strings.RemoveFromSavedPosts -> R.string.remove_from_saved_posts Strings.RemoveFromSavedPosts -> R.string.remove_from_saved_posts
Strings.SavedPosts -> R.string.saved_posts Strings.SavedPosts -> R.string.saved_posts
Strings.SubmittedBy -> R.string.submitted_by Strings.SubmittedBy -> R.string.submitted_by
Strings.NewestPosts -> R.string.newest_posts Strings.Settings -> R.string.settings
Strings.SettingsBackup -> R.string.settings_backup
Strings.SettingsBackupDescription -> R.string.settings_backup_desc
Strings.SettingsRestore -> R.string.settings_restore
Strings.SettingsRestoreDescription -> R.string.settings_restore_desc
} }
} }

View file

@ -11,4 +11,9 @@
<string name="open_comments">Open comments</string> <string name="open_comments">Open comments</string>
<string name="change_sorting_order">Change sort order</string> <string name="change_sorting_order">Change sort order</string>
<string name="newest_posts">Newest</string> <string name="newest_posts">Newest</string>
<string name="settings">Settings</string>
<string name="settings_backup">Backup saved posts</string>
<string name="settings_backup_desc">Export saved posts in a JSON file that can be restored later</string>
<string name="settings_restore">Restore saved posts</string>
<string name="settings_restore_desc">Import a previously exported copy of saved posts. Existing saved posts are not cleared</string>
</resources> </resources>

View file

@ -13,4 +13,9 @@ enum class Strings {
SavedPosts, SavedPosts,
SubmittedBy, SubmittedBy,
NewestPosts, NewestPosts,
Settings,
SettingsBackup,
SettingsBackupDescription,
SettingsRestore,
SettingsRestoreDescription,
} }

View file

@ -16,6 +16,13 @@ private fun stringEnumMapper(stringEnum: Strings): String {
Strings.SavedPosts -> "Saved" Strings.SavedPosts -> "Saved"
Strings.SubmittedBy -> "submitted by %1s" Strings.SubmittedBy -> "submitted by %1s"
Strings.NewestPosts -> "Newest" Strings.NewestPosts -> "Newest"
Strings.Settings -> "Settings"
Strings.SettingsBackup -> "Backup saved posts"
Strings.SettingsBackupDescription ->
"Export saved posts in a JSON file that can be restored later"
Strings.SettingsRestore -> "Restore saved posts"
Strings.SettingsRestoreDescription ->
"Import a previously exported copy of saved posts. Existing saved posts are not cleared"
} }
} }

View file

@ -1,11 +1,48 @@
plugins { plugins {
kotlin("jvm") kotlin("multiplatform")
id("com.android.library")
id("com.squareup.sqldelight") id("com.squareup.sqldelight")
`lobsters-plugin` `lobsters-plugin`
} }
dependencies { // workaround for https://youtrack.jetbrains.com/issue/KT-43944
testImplementation(Dependencies.Kotlin.Coroutines.core) android {
testImplementation(Dependencies.ThirdParty.SQLDelight.jvmDriver) configurations {
testImplementation(kotlin("test-junit")) create("androidTestApi")
create("androidTestDebugApi")
create("androidTestReleaseApi")
create("testApi")
create("testDebugApi")
create("testReleaseApi")
}
}
kotlin {
jvm()
android()
sourceSets {
val commonMain by getting {
}
val jvmTest by getting {
dependencies {
implementation(Dependencies.Kotlin.Coroutines.core)
implementation(kotlin("test-junit"))
}
}
val jvmMain by getting {
dependencies {
implementation(Dependencies.ThirdParty.SQLDelight.jvmDriver)
}
}
val androidMain by getting {
dependencies {
implementation(Dependencies.ThirdParty.SQLDelight.androidDriver)
}
}
}
}
android {
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
} }

View file

@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.msfjarvis.lobsters.database" />

View file

@ -0,0 +1,12 @@
package dev.msfjarvis.lobsters.data.local
import android.content.Context
import com.squareup.sqldelight.android.AndroidSqliteDriver
import com.squareup.sqldelight.db.SqlDriver
import dev.msfjarvis.lobsters.database.LobstersDatabase
actual class DriverFactory(private val context: Context) {
actual fun createDriver(): SqlDriver {
return AndroidSqliteDriver(LobstersDatabase.Schema, context, LobstersDatabaseName)
}
}

View file

@ -0,0 +1,18 @@
package dev.msfjarvis.lobsters.data.local
import com.squareup.sqldelight.db.SqlDriver
import dev.msfjarvis.lobsters.data.model.TagsAdapter
import dev.msfjarvis.lobsters.database.LobstersDatabase
internal const val LobstersDatabaseName = "SavedPosts.db"
expect class DriverFactory {
fun createDriver(): SqlDriver
}
private fun getTagsAdapter() = TagsAdapter()
fun createDatabase(driverFactory: DriverFactory): LobstersDatabase {
val driver = driverFactory.createDriver()
return LobstersDatabase(driver, SavedPost.Adapter(getTagsAdapter()))
}

View file

@ -1,4 +1,4 @@
package dev.msfjarvis.lobsters.model package dev.msfjarvis.lobsters.data.model
import com.squareup.sqldelight.ColumnAdapter import com.squareup.sqldelight.ColumnAdapter

View file

@ -0,0 +1,13 @@
package dev.msfjarvis.lobsters.data.local
import com.squareup.sqldelight.db.SqlDriver
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
import dev.msfjarvis.lobsters.database.LobstersDatabase
actual class DriverFactory {
actual fun createDriver(): SqlDriver {
val driver: SqlDriver = JdbcSqliteDriver(JdbcSqliteDriver.IN_MEMORY)
LobstersDatabase.Schema.create(driver)
return driver
}
}

View file

@ -1,8 +1,8 @@
package dev.msfjarvis.lobsters.data.local package dev.msfjarvis.lobsters.data.local
import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver import com.squareup.sqldelight.sqlite.driver.JdbcSqliteDriver
import dev.msfjarvis.lobsters.data.model.TagsAdapter
import dev.msfjarvis.lobsters.database.LobstersDatabase import dev.msfjarvis.lobsters.database.LobstersDatabase
import dev.msfjarvis.lobsters.model.TagsAdapter
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking