diff --git a/app/build.gradle b/app/build.gradle index f3b69919..b210edd2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,22 +15,32 @@ * */ -apply plugin: 'com.android.application' -apply plugin: 'kotlin-android' -apply plugin: 'kotlin-kapt' -apply plugin: "androidx.navigation.safeargs" -apply plugin: 'kotlin-android-extensions' +plugins { + id 'com.android.application' + id 'kotlin-android' + id 'kotlin-kapt' + id 'androidx.navigation.safeargs.kotlin' +} android { compileSdkVersion 30 defaultConfig { applicationId "com.example.android.devbyteviewer" - minSdkVersion 19 + minSdkVersion 21 targetSdkVersion 30 versionCode 1 versionName "1.0" multiDexEnabled true vectorDrawables.useSupportLibrary = true + + javaCompileOptions { + annotationProcessorOptions { + arguments += [ + "room.schemaLocation":"$projectDir/schemas".toString(), + "room.incremental":"true" + ] + } + } } buildTypes { release { @@ -38,11 +48,20 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } - + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = '1.8' + } buildFeatures { dataBinding true } - + packagingOptions { + exclude 'DebugProbesKt.bin' + exclude 'META-INF/atomicfu.kotlin_module' + } } dependencies { @@ -51,15 +70,15 @@ dependencies { // Support libraries implementation "androidx.appcompat:appcompat:$version_appcompat" - implementation "androidx.fragment:fragment:$version_fragment" + implementation "androidx.fragment:fragment-ktx:$version_fragment" implementation "androidx.constraintlayout:constraintlayout:$version_constraint_layout" // Android KTX implementation "androidx.core:core-ktx:$version_core" // Navigation - implementation "android.arch.navigation:navigation-fragment-ktx:$version_navigation" - implementation "android.arch.navigation:navigation-ui-ktx:$version_navigation" + implementation "androidx.navigation:navigation-fragment-ktx:$version_navigation" + implementation "androidx.navigation:navigation-ui-ktx:$version_navigation" // Coroutines for getting off the UI thread implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines" @@ -68,7 +87,6 @@ dependencies { // Retrofit for networking implementation "com.squareup.retrofit2:retrofit:$version_retrofit" implementation "com.squareup.retrofit2:converter-moshi:$version_retrofit" - implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$version_retrofit_coroutines_adapter" // Moshi for parsing the JSON format implementation "com.squareup.moshi:moshi:$version_moshi" @@ -95,5 +113,5 @@ dependencies { implementation "androidx.room:room-ktx:$version_room" // WorkManager - implementation "android.arch.work:work-runtime-ktx:$version_work" + implementation "androidx.work:work-runtime-ktx:$work_version" } diff --git a/app/schemas/com.example.android.devbyteviewer.database.DevBytesDatabase/1.json b/app/schemas/com.example.android.devbyteviewer.database.DevBytesDatabase/1.json new file mode 100644 index 00000000..a3a7fcf9 --- /dev/null +++ b/app/schemas/com.example.android.devbyteviewer.database.DevBytesDatabase/1.json @@ -0,0 +1,58 @@ +{ + "formatVersion": 1, + "database": { + "version": 1, + "identityHash": "21c90e8223ebcb03b6bfb045f4a26142", + "entities": [ + { + "tableName": "videos", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`url` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `updated` TEXT NOT NULL, `thumbnail` TEXT NOT NULL, PRIMARY KEY(`url`))", + "fields": [ + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "description", + "columnName": "description", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "updated", + "columnName": "updated", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "thumbnail", + "columnName": "thumbnail", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "columnNames": [ + "url" + ], + "autoGenerate": false + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '21c90e8223ebcb03b6bfb045f4a26142')" + ] + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/android/devbyteviewer/DevByteApplication.kt b/app/src/main/java/com/example/android/devbyteviewer/DevByteApplication.kt index 68a15670..11308ce3 100644 --- a/app/src/main/java/com/example/android/devbyteviewer/DevByteApplication.kt +++ b/app/src/main/java/com/example/android/devbyteviewer/DevByteApplication.kt @@ -18,13 +18,22 @@ package com.example.android.devbyteviewer import android.app.Application +import androidx.work.* +import androidx.work.impl.Schedulers +import com.example.android.devbyteviewer.work.RefreshDataWork +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import timber.log.Timber +import java.util.concurrent.TimeUnit /** * Override application to setup background work via WorkManager */ class DevByteApplication : Application() { + private val applicationScope = CoroutineScope(Dispatchers.Default) + /** * onCreate is called before the first screen is shown to the user. * @@ -34,5 +43,31 @@ class DevByteApplication : Application() { override fun onCreate() { super.onCreate() Timber.plant(Timber.DebugTree()) + delayedInit() + } + + private fun delayedInit() { + applicationScope.launch { setupRecurringWork() } + } + + private fun setupRecurringWork() { + val constraints = Constraints.Builder() + .setRequiredNetworkType(NetworkType.UNMETERED) + .setRequiresBatteryNotLow(true) + .setRequiresCharging(true) + .apply { + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + setRequiresDeviceIdle(true) + } + } + .build() + val repeatingRequest = PeriodicWorkRequestBuilder(1, TimeUnit.DAYS) + .setConstraints(constraints) + .build() + WorkManager.getInstance(this).enqueueUniquePeriodicWork( + RefreshDataWork.WORK_NAME, + ExistingPeriodicWorkPolicy.KEEP, + repeatingRequest + ) } } diff --git a/app/src/main/java/com/example/android/devbyteviewer/database/DatabaseEntities.kt b/app/src/main/java/com/example/android/devbyteviewer/database/DatabaseEntities.kt index 777e11bd..adbe9c6e 100644 --- a/app/src/main/java/com/example/android/devbyteviewer/database/DatabaseEntities.kt +++ b/app/src/main/java/com/example/android/devbyteviewer/database/DatabaseEntities.kt @@ -17,3 +17,29 @@ package com.example.android.devbyteviewer.database +import androidx.room.ColumnInfo +import androidx.room.Entity +import androidx.room.PrimaryKey +import com.example.android.devbyteviewer.domain.Video + +@Entity( + tableName = "videos", +) +data class DatabaseVideo( + @PrimaryKey @ColumnInfo(name = "url") val url: String, + @ColumnInfo(name = "title") val title: String, + @ColumnInfo(name = "description") val description: String, + @ColumnInfo(name = "updated") val updated: String, + @ColumnInfo(name = "thumbnail") val thumbnail: String, +) + +fun List.asDomainModel(): List