Skip to content

Commit

Permalink
feat: offline support (#11)
Browse files Browse the repository at this point in the history
use room to store data locally
follow one source of trust pattern, using local data.

closes #8
  • Loading branch information
ffgiraldez committed Apr 14, 2018
1 parent f265edd commit 0b07cd9
Show file tree
Hide file tree
Showing 16 changed files with 575 additions and 77 deletions.
13 changes: 9 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@ My way to MVVM using RxJava with new Android databinding

## Summary
* Use [MVVM][1] using [architecture components][6] with to separate Android Framework with a [clean architecture][2] to my domain logic.
* Use [Android Databinding][3] to glue view model and Android
* Use [Android Databinding][3] wih [LiveData][8] to glue [ViewModel][9] and Android
* Asynchronous communications implemented with [Rx][4].
* Rest API from [ComicVine][5]
* Store data using [Room][7]

## Dependencies
* architecture components
* livedata
* room
* viewmodel
* rx-java
* floating search
* okhttp
Expand All @@ -22,8 +26,6 @@ TODO LIST

* Better UI, with Material Design concepts and so on
* Add unit tests, allways fail on that :(
* Implement a local datasource with Realm to test it


Developed By
------------
Expand All @@ -40,7 +42,7 @@ Fernando Franco Giráldez - <ffrancogiraldez@gmail.com>
License
-------

Copyright 2015 Fernando Franco Giráldez
Copyright 2018 Fernando Franco Giráldez
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
Expand All @@ -59,3 +61,6 @@ License
[4]: http://reactivex.io/
[5]: http://www.comicvine.com/api/
[6]: https://developer.android.com/topic/libraries/architecture/index.html
[7]: https://developer.android.com/topic/libraries/architecture/room.html
[8]: https://developer.android.com/topic/libraries/architecture/livedata.html
[9]: https://developer.android.com/topic/libraries/architecture/viewmodel.html
16 changes: 15 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ android {
dataBinding {
enabled = true
}

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
Expand All @@ -44,11 +44,22 @@ android {
}
}

kapt {
arguments {
arg("room.schemaLocation", "$projectDir/schemas".toString())
}
}


dependencies {
kapt libs.databinding_compiler
kapt libs.arch_comp_room_compiler
kaptTest libs.arch_comp_room_compiler

implementation libs.arch_comp_livedata
implementation libs.arch_comp_viewmodel
implementation libs.arch_comp_room
implementation libs.arch_comp_room_rxjava
implementation libs.constraint
implementation libs.design
implementation libs.floating_search
Expand All @@ -64,7 +75,10 @@ dependencies {
implementation libs.retrofit_rx_java
implementation libs.rx_java
implementation libs.rx_android
implementation libs.steho

testImplementation libs.arch_comp_room_test
testImplementation libs.arch_comp_test
testImplementation libs.junit
testImplementation libs.koin_test
testImplementation libs.mockito_kotlin
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
{
"formatVersion": 1,
"database": {
"version": 1,
"identityHash": "843b5908f7967726e53a210136b5cda2",
"entities": [
{
"tableName": "queries",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`query_identifier` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `search_term` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "queryId",
"columnName": "query_identifier",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "searchTerm",
"columnName": "search_term",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"query_identifier"
],
"autoGenerate": true
},
"indices": [
{
"name": "idx_query_identifier",
"unique": false,
"columnNames": [
"query_identifier"
],
"createSql": "CREATE INDEX `idx_query_identifier` ON `${TABLE_NAME}` (`query_identifier`)"
},
{
"name": "idx_query_term",
"unique": false,
"columnNames": [
"search_term"
],
"createSql": "CREATE INDEX `idx_query_term` ON `${TABLE_NAME}` (`search_term`)"
}
],
"foreignKeys": []
},
{
"tableName": "suggestions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`suggestionId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `query_id` INTEGER NOT NULL, `title` TEXT NOT NULL, FOREIGN KEY(`query_id`) REFERENCES `queries`(`query_identifier`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "suggestionId",
"columnName": "suggestionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "queryId",
"columnName": "query_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"suggestionId"
],
"autoGenerate": true
},
"indices": [
{
"name": "idx_suggestion_id",
"unique": false,
"columnNames": [
"query_id"
],
"createSql": "CREATE INDEX `idx_suggestion_id` ON `${TABLE_NAME}` (`query_id`)"
}
],
"foreignKeys": [
{
"table": "queries",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"query_id"
],
"referencedColumns": [
"query_identifier"
]
}
]
},
{
"tableName": "search",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`search_identifier` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `search_term` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "queryId",
"columnName": "search_identifier",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "searchTerm",
"columnName": "search_term",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"search_identifier"
],
"autoGenerate": true
},
"indices": [
{
"name": "idx_search_identifier",
"unique": false,
"columnNames": [
"search_identifier"
],
"createSql": "CREATE INDEX `idx_search_identifier` ON `${TABLE_NAME}` (`search_identifier`)"
},
{
"name": "idx_search_term",
"unique": false,
"columnNames": [
"search_term"
],
"createSql": "CREATE INDEX `idx_search_term` ON `${TABLE_NAME}` (`search_term`)"
}
],
"foreignKeys": []
},
{
"tableName": "volumes",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`suggestionId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `search_id` INTEGER NOT NULL, `title` TEXT NOT NULL, `author` TEXT NOT NULL, `url` TEXT NOT NULL, FOREIGN KEY(`search_id`) REFERENCES `search`(`search_identifier`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "suggestionId",
"columnName": "suggestionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "queryId",
"columnName": "search_id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "author",
"columnName": "author",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"columnNames": [
"suggestionId"
],
"autoGenerate": true
},
"indices": [
{
"name": "idx_search_id",
"unique": false,
"columnNames": [
"search_id"
],
"createSql": "CREATE INDEX `idx_search_id` ON `${TABLE_NAME}` (`search_id`)"
}
],
"foreignKeys": [
{
"table": "search",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"search_id"
],
"referencedColumns": [
"search_identifier"
]
}
]
}
],
"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, \"843b5908f7967726e53a210136b5cda2\")"
]
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package es.ffgiraldez.comicsearch

import android.app.Application
import com.facebook.stetho.Stetho
import es.ffgiraldez.comicsearch.di.comicContext
import org.koin.android.ext.android.startKoin

class ComicApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin(this, listOf(comicContext));
startKoin(this, listOf(comicContext))
Stetho.initializeWithDefaults(this)
}
}
Loading

0 comments on commit 0b07cd9

Please sign in to comment.