WIP: Implement local database caching/networking with KMP
This commit is contained in:
parent
f1e36df8c4
commit
cf4226d20c
19 changed files with 280 additions and 11 deletions
|
@ -77,8 +77,8 @@ class CategoryFormActivity : AppCompatActivity() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item?.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
val upIntent: Intent? = NavUtils.getParentActivityIntent(this)
|
val upIntent: Intent? = NavUtils.getParentActivityIntent(this)
|
||||||
|
|
||||||
|
|
|
@ -171,8 +171,8 @@ class TransactionFormActivity : AppCompatActivity(), CoroutineScope {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
when (item?.itemId) {
|
when (item.itemId) {
|
||||||
android.R.id.home -> onNavigateUp()
|
android.R.id.home -> onNavigateUp()
|
||||||
R.id.action_save -> {
|
R.id.action_save -> {
|
||||||
val date = GregorianCalendar.getInstance().apply {
|
val date = GregorianCalendar.getInstance().apply {
|
||||||
|
|
|
@ -4,11 +4,11 @@ apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 30
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
|
|
@ -16,6 +16,7 @@ buildscript {
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.1.1'
|
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||||
|
classpath 'com.squareup.sqldelight:gradle-plugin:1.4.3'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,12 @@ apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 30
|
||||||
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
include ':android', ':budgetlib', ':common', ':storage'
|
include ':android', ':budgetlib', ':common', ':storage', ':shared'
|
||||||
|
|
1
shared/.gitignore
vendored
Normal file
1
shared/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/build
|
98
shared/build.gradle.kts
Normal file
98
shared/build.gradle.kts
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("multiplatform")
|
||||||
|
id("com.android.library")
|
||||||
|
id("kotlin-android-extensions")
|
||||||
|
kotlin("plugin.serialization") version "1.4.10"
|
||||||
|
id("com.squareup.sqldelight")
|
||||||
|
}
|
||||||
|
group = "com.wbrawner.twigs"
|
||||||
|
version = "1.0-SNAPSHOT"
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
gradlePluginPortal()
|
||||||
|
google()
|
||||||
|
jcenter()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
kotlin {
|
||||||
|
android()
|
||||||
|
ios {
|
||||||
|
binaries {
|
||||||
|
framework {
|
||||||
|
baseName = "twigs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sourceSets {
|
||||||
|
val commonMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation("io.ktor:ktor-client-core:1.4.2")
|
||||||
|
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
|
||||||
|
implementation("io.ktor:ktor-client-serialization:1.4.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val commonTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-common"))
|
||||||
|
implementation(kotlin("test-annotations-common"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val androidMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation("com.google.android.material:material:1.2.0")
|
||||||
|
implementation("com.squareup.sqldelight:android-driver:1.4.3")
|
||||||
|
api("io.ktor:ktor-client-android:1.4.2")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val androidTest by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlin("test-junit"))
|
||||||
|
implementation("junit:junit:4.12")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val iosMain by getting {
|
||||||
|
dependencies {
|
||||||
|
implementation("io.ktor:ktor-client-ios:1.4.2")
|
||||||
|
implementation("com.squareup.sqldelight:native-driver:1.4.3")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val iosTest by getting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sqldelight {
|
||||||
|
database("TwigsDatabase") {
|
||||||
|
packageName = "com.wbrawner.twigs"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion(30)
|
||||||
|
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||||
|
defaultConfig {
|
||||||
|
minSdkVersion(23)
|
||||||
|
targetSdkVersion(30)
|
||||||
|
versionCode = 1
|
||||||
|
versionName = "1.0"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
getByName("release") {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val packForXcode by tasks.creating(Sync::class) {
|
||||||
|
group = "build"
|
||||||
|
val mode = System.getenv("CONFIGURATION") ?: "DEBUG"
|
||||||
|
val sdkName = System.getenv("SDK_NAME") ?: "iphonesimulator"
|
||||||
|
val targetName = "ios" + if (sdkName.startsWith("iphoneos")) "Arm64" else "X64"
|
||||||
|
val framework = kotlin.targets.getByName<KotlinNativeTarget>(targetName).binaries.getFramework(mode)
|
||||||
|
inputs.property("mode", mode)
|
||||||
|
dependsOn(framework.linkTask)
|
||||||
|
val targetDir = File(buildDir, "xcode-frameworks")
|
||||||
|
from({ framework.outputDirectory })
|
||||||
|
into(targetDir)
|
||||||
|
}
|
||||||
|
tasks.getByName("build").dependsOn(packForXcode)
|
21
shared/proguard-rules.pro
vendored
Normal file
21
shared/proguard-rules.pro
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.kts.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
2
shared/src/androidMain/AndroidManifest.xml
Normal file
2
shared/src/androidMain/AndroidManifest.xml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.wbrawner.twigs.android"/>
|
|
@ -0,0 +1,12 @@
|
||||||
|
package com.wbrawner.twigs.shared
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import com.squareup.sqldelight.android.AndroidSqliteDriver
|
||||||
|
import com.squareup.sqldelight.db.SqlDriver
|
||||||
|
import com.wbrawner.twigs.TwigsDatabase
|
||||||
|
|
||||||
|
actual class DriverFactory(private val context: Context) {
|
||||||
|
actual fun createDriver(): SqlDriver {
|
||||||
|
return AndroidSqliteDriver(TwigsDatabase.Schema, context, "twigs.db")
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.wbrawner.twigs.shared
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Summary(
|
||||||
|
@SerialName("domains_being_blocked")
|
||||||
|
val domainsBeingBlocked: String,
|
||||||
|
@SerialName("dns_queries_today")
|
||||||
|
val dnsQueriesToday: String,
|
||||||
|
@SerialName("ads_blocked_today")
|
||||||
|
val adsBlockedToday: String,
|
||||||
|
@SerialName("ads_percentage_today")
|
||||||
|
val adsPercentageToday: String,
|
||||||
|
@SerialName("unique_domains")
|
||||||
|
val uniqueDomains: String,
|
||||||
|
@SerialName("queries_forwarded")
|
||||||
|
val queriesForwarded: String,
|
||||||
|
@SerialName("clients_ever_seen")
|
||||||
|
val clientsEverSeen: String,
|
||||||
|
@SerialName("unique_clients")
|
||||||
|
val uniqueClients: String,
|
||||||
|
@SerialName("dns_queries_all_types")
|
||||||
|
val dnsQueriesAllTypes: String,
|
||||||
|
@SerialName("queries_cached")
|
||||||
|
val queriesCached: String,
|
||||||
|
@SerialName("no_data_replies")
|
||||||
|
val noDataReplies: String? = null,
|
||||||
|
@SerialName("nx_domain_replies")
|
||||||
|
val nxDomainReplies: String? = null,
|
||||||
|
@SerialName("cname_replies")
|
||||||
|
val cnameReplies: String? = null,
|
||||||
|
@SerialName("in_replies")
|
||||||
|
val ipReplies: String? = null,
|
||||||
|
@SerialName("privacy_level")
|
||||||
|
val privacyLevel: String,
|
||||||
|
override val status: Status,
|
||||||
|
@SerialName("gravity_last_updated")
|
||||||
|
val gravity: Gravity? = null,
|
||||||
|
val type: String? = null,
|
||||||
|
val version: Int? = null
|
||||||
|
) : StatusProvider
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
enum class Status {
|
||||||
|
@SerialName("enabled")
|
||||||
|
ENABLED,
|
||||||
|
@SerialName("disabled")
|
||||||
|
DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Gravity(
|
||||||
|
@SerialName("file_exists")
|
||||||
|
val fileExists: Boolean,
|
||||||
|
val absolute: Int,
|
||||||
|
val relative: Relative
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Relative(
|
||||||
|
val days: String,
|
||||||
|
val hours: String,
|
||||||
|
val minutes: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class VersionResponse(val version: Int)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TopItemsResponse(
|
||||||
|
@SerialName("top_queries") val topQueries: Map<String, String>,
|
||||||
|
@SerialName("top_ads") val topAds: Map<String, Double>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class StatusResponse(
|
||||||
|
override val status: Status
|
||||||
|
) : StatusProvider
|
||||||
|
|
||||||
|
interface StatusProvider {
|
||||||
|
val status: Status
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package com.wbrawner.twigs.shared
|
||||||
|
|
||||||
|
import com.squareup.sqldelight.db.SqlDriver
|
||||||
|
import com.wbrawner.twigs.TwigsDatabase
|
||||||
|
|
||||||
|
expect class DriverFactory {
|
||||||
|
fun createDriver(): SqlDriver
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createDatabase(driverFactory: DriverFactory): TwigsDatabase {
|
||||||
|
val driver = driverFactory.createDriver()
|
||||||
|
val database = TwigsDatabase(driver)
|
||||||
|
|
||||||
|
// Do more work with the database (see below).
|
||||||
|
return database
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS budget (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
currencyCode TEXT
|
||||||
|
);
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS budget (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
currencyCode TEXT
|
||||||
|
);
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS budget (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
currencyCode TEXT
|
||||||
|
);
|
|
@ -0,0 +1,6 @@
|
||||||
|
CREATE TABLE IF NOT EXISTS budget (
|
||||||
|
id TEXT PRIMARY KEY,
|
||||||
|
name TEXT NOT NULL UNIQUE,
|
||||||
|
description TEXT,
|
||||||
|
currencyCode TEXT
|
||||||
|
);
|
|
@ -0,0 +1,10 @@
|
||||||
|
package com.wbrawner.twigs.shared
|
||||||
|
|
||||||
|
import com.squareup.sqldelight.db.SqlDriver
|
||||||
|
import com.wbrawner.twigs.TwigsDatabase
|
||||||
|
|
||||||
|
actual class DriverFactory {
|
||||||
|
actual fun createDriver(): SqlDriver {
|
||||||
|
return NativeSqliteDriver(TwigsDatabase.Schema, "twigs.db")
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,12 +4,12 @@ apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 29
|
compileSdkVersion 30
|
||||||
|
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 23
|
minSdkVersion 23
|
||||||
targetSdkVersion 29
|
targetSdkVersion 30
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue