aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/build.gradle23
-rw-r--r--app/src/main/AndroidManifest.xml2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt14
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt60
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt85
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt42
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/FrostApi.kt20
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/IFrost.kt22
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt33
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/LazyResettable.kt51
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Realm.kt18
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt11
-rw-r--r--app/src/main/res/menu/menu_main.xml5
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher_round.pngbin4208 -> 3924 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher_round.pngbin6114 -> 5972 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher_round.pngbin10056 -> 9569 bytes
-rw-r--r--app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.pngbin14696 -> 12529 bytes
-rw-r--r--app/src/test/java/com/pitchedapps/frost/ExampleUnitTest.java17
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt25
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/DbFlowTestRule.kt38
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/ImmediateTransactionManager.kt38
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/TestDatabase.kt21
27 files changed, 443 insertions, 120 deletions
diff --git a/app/build.gradle b/app/build.gradle
index 92167ac7..4fffb72c 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,13 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
-apply plugin: 'realm-android'
android {
compileSdkVersion Integer.parseInt(project.TARGET_SDK)
buildToolsVersion project.BUILD_TOOLS
defaultConfig {
- applicationId "${project.APP_GROUP}." + project.APP_ID.toLowerCase() + ".sample"
+ applicationId "${project.APP_GROUP}." + project.APP_ID.toLowerCase()
minSdkVersion Integer.parseInt(project.MIN_SDK)
targetSdkVersion Integer.parseInt(project.TARGET_SDK)
versionCode Integer.parseInt(project.VERSION_CODE)
@@ -57,6 +56,18 @@ dependencies {
//Dialog
compile "com.afollestad.material-dialogs:core:${MD}"
+ compile "com.github.Raizlabs.DBFlow:dbflow:${DBFLOW}"
+ compile "com.github.Raizlabs.DBFlow:dbflow-core:${DBFLOW}"
+ annotationProcessor "com.github.Raizlabs.DBFlow:dbflow-processor:${DBFLOW}"
+ kapt "com.github.Raizlabs.DBFlow:dbflow-processor:${DBFLOW}"
+ compile "com.github.Raizlabs.DBFlow:dbflow-kotlinextensions:${DBFLOW}"
+ compile "com.github.Raizlabs.DBFlow:dbflow-rx2:${DBFLOW}"
+ compile "com.github.Raizlabs.DBFlow:dbflow-rx2-kotlinextensions:${DBFLOW}"
+ compile "com.github.Raizlabs.DBFlow:dbflow-sqlcipher:${DBFLOW}"
+ compile "net.zetetic:android-database-sqlcipher:${SQL_CIPHER}@aar"
+
+ testCompile "org.robolectric:robolectric:${ROBOELECTRIC}"
+
//Icons
compile "com.mikepenz:iconics-core:${ICONICS}@aar"
compile "com.mikepenz:google-material-typeface:${IICON_GOOGLE}.original@aar"
@@ -89,4 +100,12 @@ dependencies {
compile "com.github.bumptech.glide:glide:${GLIDE}"
annotationProcessor "com.github.bumptech.glide:compiler:${GLIDE}"
+
+ compile "com.google.auto.value:auto-value:${AUTO}"
+ annotationProcessor "com.google.auto.value:auto-value:${AUTO}"
+ annotationProcessor "com.ryanharter.auto.value:auto-value-parcel:${AUTO_VALUE_PARCEL}"
+}
+
+kapt {
+ generateStubs = true
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ff98de24..793e3983 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -21,7 +21,7 @@
<application
android:name=".FrostApp"
android:allowBackup="true"
- android:icon="@mipmap/ic_launcher"
+ android:icon="@mipmap/ic_launcher_round"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index 0fb4e7db..1ea3f0e0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -2,10 +2,10 @@ package com.pitchedapps.frost
import android.app.Application
import com.pitchedapps.frost.facebook.retro.FrostApi
-import com.pitchedapps.frost.facebook.retro.IFrost
import com.pitchedapps.frost.utils.CrashReportingTree
import com.pitchedapps.frost.utils.Prefs
-import io.realm.Realm
+import com.raizlabs.android.dbflow.config.FlowConfig
+import com.raizlabs.android.dbflow.config.FlowManager
import timber.log.Timber
import timber.log.Timber.DebugTree
@@ -18,9 +18,11 @@ class FrostApp : Application() {
override fun onCreate() {
if (BuildConfig.DEBUG) Timber.plant(DebugTree())
else Timber.plant(CrashReportingTree())
- Prefs(applicationContext)
- FrostApi(applicationContext)
- Realm.init(applicationContext)
+ FlowManager.init(FlowConfig.Builder(this).build())
+ Prefs(this)
+ FrostApi(this)
super.onCreate()
}
+
+
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
index deb4f5d6..fae83580 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
@@ -13,14 +13,13 @@ import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
import butterknife.ButterKnife
-import com.pitchedapps.frost.facebook.FbTab
-import com.pitchedapps.frost.facebook.loadFbTab
+import com.pitchedapps.frost.dbflow.FbTab
+import com.pitchedapps.frost.dbflow.loadFbTabs
+import com.pitchedapps.frost.facebook.retro.FrostApi.frostApi
+import com.pitchedapps.frost.facebook.retro.enqueueFrost
import com.pitchedapps.frost.fragments.BaseFragment
import com.pitchedapps.frost.fragments.WebFragment
-import com.pitchedapps.frost.utils.Changelog
-import com.pitchedapps.frost.utils.KeyPairObservable
-import com.pitchedapps.frost.utils.bindView
-import com.pitchedapps.frost.utils.toDrawable
+import com.pitchedapps.frost.utils.*
import io.reactivex.subjects.PublishSubject
import io.reactivex.subjects.Subject
@@ -40,7 +39,7 @@ class MainActivity : AppCompatActivity(), KeyPairObservable {
ButterKnife.bind(this)
setSupportActionBar(toolbar)
- adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTab(this@MainActivity))
+ adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTabs(this@MainActivity))
viewPager.adapter = adapter
viewPager.offscreenPageLimit = 5
setupTabs()
@@ -75,6 +74,7 @@ class MainActivity : AppCompatActivity(), KeyPairObservable {
finish()
}
R.id.action_changelog -> Changelog.show(this)
+ R.id.action_call -> frostApi.me().enqueueFrost { call, response -> L.e(response.toString())}
else -> return super.onOptionsItemSelected(item)
}
return true
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
index 390efb1a..e8c65be3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
@@ -11,7 +11,7 @@ class StartActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- startActivity(Intent(this, LoginActivity::class.java))
+ startActivity(Intent(this, MainActivity::class.java))
finish()
}
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
new file mode 100644
index 00000000..ab39118a
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
@@ -0,0 +1,60 @@
+package com.pitchedapps.frost.dbflow
+
+import com.raizlabs.android.dbflow.annotation.Database
+import com.raizlabs.android.dbflow.annotation.ForeignKey
+import com.raizlabs.android.dbflow.annotation.PrimaryKey
+import com.raizlabs.android.dbflow.annotation.Table
+import com.raizlabs.android.dbflow.structure.BaseModel
+import okhttp3.Cookie
+import java.io.Serializable
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+
+@Database(name = CookiesDb.NAME, version = CookiesDb.VERSION)
+object CookiesDb {
+ const val NAME = "Cookies"
+ const val VERSION = 1
+}
+
+//@Database(name = CookieDb.NAME, version = CookieDb.VERSION)
+//object CookieDb {
+// const val NAME = "Cookie"
+// const val VERSION = 1
+//}
+
+@Table(database = CookiesDb::class, allFields = true)
+data class CookieModel(@PrimaryKey var name: String,
+ var value: String,
+ var expiresAt: Long,
+ var domain: String,
+ var path: String,
+ var secure: Boolean,
+ var httpOnly: Boolean) {
+
+ constructor(cookie: Cookie) : this(cookie.name(), cookie.value(), cookie.expiresAt(), cookie.domain(), cookie.path(), cookie.secure(), cookie.httpOnly())
+ constructor() : this("", "", 0L, "", "", false, false)
+
+ fun toCookie(): Cookie {
+ val builder = Cookie.Builder().name(name).value(value).expiresAt(expiresAt).domain(domain).path(path)
+ if (secure) builder.secure()
+ if (httpOnly) builder.httpOnly()
+ return builder.build()
+ }
+
+ fun isSecure() = secure
+ fun isHttpOnly() = httpOnly
+}
+
+//class CookieList(val cookies: List<Cookie>)
+//class CookieDbList(val cookies: List<CookieDb>)
+
+//@com.raizlabs.android.dbflow.annotation.TypeConverter
+//class CookieTypeConverter() : TypeConverter<CookieDbList, CookieList>() {
+// override fun getModelValue(data: CookieDbList): CookieList = CookieList(data.cookies.map { it.toCookie() })
+// override fun getDBValue(model: CookieList): CookieDbList = CookieDbList(model.cookies.map { CookieDb(it) })
+//}
+
+@Table(database = CookiesDb::class)
+data class Cookies(@PrimaryKey var url: String = "", @ForeignKey var cookie: CookieModel = CookieModel()) : BaseModel(), Serializable \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
new file mode 100644
index 00000000..05dac758
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
@@ -0,0 +1,85 @@
+package com.pitchedapps.frost.dbflow
+
+import android.content.Context
+import android.support.annotation.StringRes
+import com.mikepenz.community_material_typeface_library.CommunityMaterial
+import com.mikepenz.google_material_typeface_library.GoogleMaterial
+import com.mikepenz.iconics.typeface.IIcon
+import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.facebook.FB_KEY
+import com.raizlabs.android.dbflow.annotation.Database
+import com.raizlabs.android.dbflow.annotation.ForeignKey
+import com.raizlabs.android.dbflow.annotation.PrimaryKey
+import com.raizlabs.android.dbflow.annotation.Table
+import com.raizlabs.android.dbflow.kotlinextensions.from
+import com.raizlabs.android.dbflow.sql.language.SQLite
+import com.raizlabs.android.dbflow.structure.BaseModel
+import java.io.Serializable
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+
+@Database(name = FbTabsDb.NAME, version = FbTabsDb.VERSION)
+object FbTabsDb {
+ const val NAME = "FrostTabs"
+ const val VERSION = 1
+}
+
+data class FbTab(val title: String, val icon: IIcon, val url: String)
+
+@Table(database = FbTabsDb::class, allFields = true)
+data class FbTabModel(
+ var title: String = "Home",
+ @ForeignKey var icon: IIconModel = IIconModel(),
+ @PrimaryKey var url: String = ""
+) : BaseModel(), Serializable {
+ constructor(fbTab: FbTab) : this(fbTab.title, IIconModel(fbTab.icon), fbTab.url)
+
+ fun toFbTab() = FbTab(title, icon.toIIcon(), url)
+}
+
+@Table(database = FbTabsDb::class, allFields = true)
+data class IIconModel(var type: Int = -1, @PrimaryKey var name: String = "") : BaseModel(), Serializable {
+ constructor(icon: IIcon) : this(when (icon) {
+ is CommunityMaterial -> 0
+ is GoogleMaterial -> 1
+ is MaterialDesignIconic -> 2
+ else -> -1
+ }, icon.toString())
+
+ fun toIIcon(): IIcon = when (type) {
+ 0 -> CommunityMaterial.Icon.valueOf(name)
+ 1 -> GoogleMaterial.Icon.valueOf(name)
+ 2 -> MaterialDesignIconic.Icon.valueOf(name)
+ else -> CommunityMaterial.Icon.cmd_newspaper
+ }
+}
+
+enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, val url: String) {
+ LOGIN(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://www.facebook.com/v2.9/dialog/oauth?client_id=${FB_KEY}&redirect_uri=https://touch.facebook.com/&response_type=token,granted_scopes"),
+ FEED(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, "https://touch.facebook.com/"),
+ PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "https://touch.facebook.com/me/"),
+ EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event, "https://touch.facebook.com/events/upcoming"),
+ FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_people, "https://touch.facebook.com/friends/center/requests/"),
+ MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "https://touch.facebook.com/messages"),
+ NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "https://touch.facebook.com/notifications");
+
+ fun tabInfo(c: Context) = FbTab(c.getString(titleId), icon, url)
+}
+
+//BOOKMARKS("https://touch.facebook.com/bookmarks"),
+//SEARCH("https://touch.facebook.com/search"),
+
+fun loadFbTabs(c: Context): List<FbTab> {
+ val tabs = SQLite.select()
+ .from(FbTabModel::class)
+ .queryList()
+ if (tabs.isNotEmpty()) return tabs.map { it.toFbTab() }
+ return listOf(FbUrl.FEED, FbUrl.MESSAGES, FbUrl.FRIENDS, FbUrl.NOTIFICATIONS).map { it.tabInfo(c) }
+}
+
+fun List<FbTab>.saveAsync() {
+
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt
index d5f9db6e..c5c2a86b 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/UrlData.kt
@@ -7,12 +7,7 @@ import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.mikepenz.iconics.typeface.IIcon
import com.mikepenz.material_design_iconic_typeface_library.MaterialDesignIconic
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.utils.RealmFiles
-import com.pitchedapps.frost.utils.realm
-import io.realm.Realm
-import io.realm.RealmList
-import io.realm.RealmObject
-import io.realm.annotations.PrimaryKey
+import com.pitchedapps.frost.dbflow.FbTab
/**
* Created by Allan Wang on 2017-05-29.
@@ -30,37 +25,4 @@ enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, val url: String)
}
//BOOKMARKS("https://touch.facebook.com/bookmarks"),
-//SEARCH("https://touch.facebook.com/search"),
-
-class FbTab(var title: String, var icon: IIcon, var url: String) {
- constructor(realm: FbTabRealm) : this(realm.title, when (realm.iconCategory) {
- 0 -> GoogleMaterial.Icon.valueOf(realm.iconString)
- 1 -> CommunityMaterial.Icon.valueOf(realm.iconString)
- 2 -> MaterialDesignIconic.Icon.valueOf(realm.iconString)
- else -> GoogleMaterial.Icon.gmd_error
- }, realm.url)
-}
-
-open class FbTabRealm(var title: String, var iconCategory: Int, var iconString: String, @PrimaryKey var url: String) : RealmObject() {
- constructor(tab: FbTab) : this(tab.title, when (tab.icon.typeface) {
- is GoogleMaterial -> 0
- is CommunityMaterial -> 1
- is MaterialDesignIconic -> 2
- else -> -1
- }, tab.icon.toString(), tab.url)
-
- constructor() : this("", -1, "", "")
-}
-
-fun List<FbTab>.save() {
- val list = RealmList(*this.map { FbTabRealm(it) }.toTypedArray())
- realm(RealmFiles.TABS, Realm.Transaction { it.copyToRealmOrUpdate(list) })
-}
-
-fun loadFbTab(c: Context): List<FbTab> {
- val realmList = mutableListOf<FbTabRealm>()
- realm(RealmFiles.TABS, Realm.Transaction { it.copyFromRealm(realmList) })
- if (realmList.isNotEmpty()) return realmList.map { FbTab(it) }
- return listOf(FbUrl.FEED, FbUrl.MESSAGES, FbUrl.NOTIFICATIONS).map { it.tabInfo(c) }
-}
-
+//SEARCH("https://touch.facebook.com/search"), \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/FrostApi.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/FrostApi.kt
index 746bf0df..f82c041c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/FrostApi.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/FrostApi.kt
@@ -4,9 +4,9 @@ import android.content.Context
import com.facebook.stetho.okhttp3.StethoInterceptor
import com.google.gson.GsonBuilder
import com.pitchedapps.frost.BuildConfig
+import com.pitchedapps.frost.utils.L
import io.reactivex.schedulers.Schedulers
-import okhttp3.Cache
-import okhttp3.OkHttpClient
+import okhttp3.*
import okhttp3.logging.HttpLoggingInterceptor
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
@@ -20,7 +20,7 @@ import java.io.File
*/
object FrostApi {
- internal lateinit var frostApi: IFrost
+ lateinit var frostApi: IFrost
operator fun invoke(context: Context) {
val cacheDir = File(context.cacheDir, "responses")
@@ -29,6 +29,18 @@ object FrostApi {
val client = OkHttpClient.Builder()
.addInterceptor(FrostInterceptor(context))
+ .cookieJar(object : CookieJar {
+ override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
+ L.e("COOKIES")
+ L.e(url.toString())
+ cookies.forEach { c -> L.e(c.toString()) }
+ }
+
+ override fun loadForRequest(url: HttpUrl): List<Cookie> {
+ TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
+ }
+
+ })
.cache(cache)
@@ -42,7 +54,7 @@ object FrostApi {
val gson = GsonBuilder().setLenient()
val retrofit = Retrofit.Builder()
- .baseUrl("https://graph.facebook.com/")
+ .baseUrl("https://touch.facebook.com/")
.addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
.addConverterFactory(GsonConverterFactory.create(gson.create()))
.client(client.build())
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/IFrost.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/IFrost.kt
index 6c50fa74..b9048fe0 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/IFrost.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/retro/IFrost.kt
@@ -1,7 +1,11 @@
package com.pitchedapps.frost.facebook.retro
import com.pitchedapps.frost.facebook.token
+import com.pitchedapps.frost.utils.L
+import okhttp3.ResponseBody
import retrofit2.Call
+import retrofit2.Callback
+import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query
@@ -11,6 +15,22 @@ import retrofit2.http.Query
interface IFrost {
@GET("me")
- fun me(@Query(ACCESS_TOKEN) accessToken: String? = token): Call<Me>
+ fun me(): Call<ResponseBody>
+
+}
+
+fun <T> Call<T>.enqueueFrost(success: (call: Call<T>, response: Response<T>) -> Unit) {
+ this.enqueue(object : Callback<T> {
+ override fun onFailure(call: Call<T>?, t: Throwable?) {
+ L.e("Frost enqueue error")
+ }
+
+ override fun onResponse(call: Call<T>, response: Response<T>) {
+ if (response.isSuccessful && !call.isCanceled)
+ success.invoke(call, response)
+ else
+ L.e("Frost response received but not successful")
+ }
+ })
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt
new file mode 100644
index 00000000..dc16f6cc
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/DbUtils.kt
@@ -0,0 +1,33 @@
+package com.pitchedapps.frost.utils
+
+import android.content.Context
+import com.raizlabs.android.dbflow.config.FlowManager
+import com.raizlabs.android.dbflow.kotlinextensions.processInTransactionAsync
+import com.raizlabs.android.dbflow.structure.BaseModel
+import com.raizlabs.android.dbflow.structure.database.transaction.Transaction
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+object DbUtils {
+
+ fun db(name: String) = FlowManager.getDatabase(name)
+ fun dbName(name: String) = "$name.db"
+
+ inline fun <reified T : BaseModel> replace(
+ context: Context, dbName: String, type: Class<T>, data: List<T>,
+ crossinline callback: ((successful: Boolean) -> Unit)) {
+ db(dbName).reset(context)
+ data.processInTransactionAsync({
+ t, databaseWrapper ->
+ t.save(databaseWrapper)
+ },
+ Transaction.Success {
+ callback.invoke(true)
+ },
+ Transaction.Error { _, error ->
+ L.e(error.message ?: "DbReplace error")
+ callback.invoke(false)
+ })
+ }
+}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt
index 0151b0ae..fe1fdc7c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt
@@ -4,16 +4,13 @@ import android.util.Log
import timber.log.Timber
-
/**
* Created by Allan Wang on 2017-05-28.
*/
-class L {
- companion object {
- val TAG = "Frost: %s"
- fun e(s: String) = Timber.e(TAG, s)
- fun d(s: String) = Timber.d(TAG, s)
- }
+object L {
+ val TAG = "Frost: %s"
+ fun e(s: String) = Timber.e(TAG, s)
+ fun d(s: String) = Timber.d(TAG, s)
}
internal class CrashReportingTree : Timber.Tree() {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/LazyResettable.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/LazyResettable.kt
new file mode 100644
index 00000000..c8365f5c
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/LazyResettable.kt
@@ -0,0 +1,51 @@
+package com.pitchedapps.frost.utils
+
+import java.io.Serializable
+import kotlin.reflect.KProperty
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ *
+ * Lazy delegate that can be invalidated if needed
+ * https://stackoverflow.com/a/37294840/4407321
+ */
+private object UNINITIALIZED
+
+fun <T : Any> lazyResettable(initializer: () -> T): LazyResettable<T> = LazyResettable<T>(initializer)
+
+class LazyResettable<T : Any>(private val initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
+ @Volatile private var _value: Any = UNINITIALIZED
+ private val lock = lock ?: this
+
+ fun invalidate() {
+ _value = UNINITIALIZED
+ }
+
+ override val value: T
+ get() {
+ val _v1 = _value
+ if (_v1 !== UNINITIALIZED)
+ @Suppress("UNCHECKED_CAST")
+ return _v1 as T
+
+ return synchronized(lock) {
+ val _v2 = _value
+ if (_v2 !== UNINITIALIZED) {
+ @Suppress("UNCHECKED_CAST")
+ _v2 as T
+ } else {
+ val typedValue = initializer()
+ _value = typedValue
+ typedValue
+ }
+ }
+ }
+
+ override fun isInitialized(): Boolean = _value !== UNINITIALIZED
+
+ override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
+
+ operator fun setValue(any: Any, property: KProperty<*>, t: T) {
+ _value = t
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
index ad222145..710da845 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
@@ -17,6 +17,7 @@ object Prefs {
lateinit private var c: Context
operator fun invoke(c: Context) {
this.c = c
+ lastActive = 0
}
private val sp: SharedPreferences by lazy { c.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) }
@@ -25,10 +26,6 @@ object Prefs {
get() = sp.getLong(LAST_ACTIVE, -1)
set(value) = set(LAST_ACTIVE, System.currentTimeMillis())
- init {
- lastActive = 0
- }
-
private fun set(key: String, value: Boolean) = sp.edit().putBoolean(key, value).apply()
private fun set(key: String, value: Int) = sp.edit().putInt(key, value).apply()
private fun set(key: String, value: Long) = sp.edit().putLong(key, value).apply()
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Realm.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Realm.kt
deleted file mode 100644
index 1eded8c9..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Realm.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.pitchedapps.frost.utils
-
-import io.realm.Realm
-import io.realm.RealmConfiguration
-
-/**
- * Created by Allan Wang on 2017-05-29.
- */
-@JvmOverloads fun realm(name: String = RealmFiles.main, transaction: Realm.Transaction) {
- val realm = Realm.getInstance(RealmConfiguration.Builder().name(name).build())
- realm.executeTransaction(transaction)
- realm.close()
-}
-
-object RealmFiles {
- val main = "frost.realm"
- val TABS = "tabs.realm"
-} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt
index f09887d8..a59fa3b1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt
@@ -10,10 +10,7 @@ import android.support.v4.view.ViewCompat
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
-import android.webkit.WebResourceError
-import android.webkit.WebResourceRequest
-import android.webkit.WebView
-import android.webkit.WebViewClient
+import android.webkit.*
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.ObservableContainer
import io.reactivex.subjects.BehaviorSubject
@@ -67,8 +64,9 @@ class FrostWebView @JvmOverloads constructor(
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
observable.onNext(WebStatus.LOADED)
-// CookieManager.getInstance().flush()
+ val cookie = CookieManager.getInstance().getCookie(url)
L.d("Loaded $url")
+ L.d("Cookie $cookie")
}
})
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt
index 7d1948fe..17557b4d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/LoginWebView.kt
@@ -14,6 +14,7 @@ import com.facebook.AccessToken
import com.pitchedapps.frost.facebook.FB_KEY
import com.pitchedapps.frost.facebook.retro.FrostApi.frostApi
import com.pitchedapps.frost.facebook.retro.Me
+import com.pitchedapps.frost.facebook.retro.enqueueFrost
import com.pitchedapps.frost.utils.L
import retrofit2.Call
import retrofit2.Callback
@@ -63,15 +64,9 @@ class LoginWebView @JvmOverloads constructor(
fun saveAccessToken(accessToken: String, expiresIn: String, grantedScopes: String?, deniedScopes: String?) {
L.d("Granted $grantedScopes")
L.d("Denied $deniedScopes")
- frostApi.me(accessToken).enqueue(object : Callback<Me> {
- override fun onFailure(call: Call<Me>?, t: Throwable?) {
- TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
- }
+ frostApi.me().enqueueFrost { call, response ->
- override fun onResponse(call: Call<Me>, response: Response<Me>) {
- AccessToken.setCurrentAccessToken(AccessToken(accessToken, FB_KEY.toString(), response.body().id, null, null, null, null, null))
- }
- })
+ }
}
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
index b4140da4..4edd60de 100644
--- a/app/src/main/res/menu/menu_main.xml
+++ b/app/src/main/res/menu/menu_main.xml
@@ -12,4 +12,9 @@
android:orderInCategory="200"
android:title="@string/changelog"
app:showAsAction="never" />
+ <item
+ android:id="@+id/action_call"
+ android:orderInCategory="300"
+ android:title="Call"
+ app:showAsAction="never" />
</menu>
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 9a078e3e..618290a8 100644
--- a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 3af2608a..44c43db9 100644
--- a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index 9bec2e62..120ecda4 100644
--- a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 34947cd6..ce8ca288 100644
--- a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
+++ b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
Binary files differ
diff --git a/app/src/test/java/com/pitchedapps/frost/ExampleUnitTest.java b/app/src/test/java/com/pitchedapps/frost/ExampleUnitTest.java
deleted file mode 100644
index a702863a..00000000
--- a/app/src/test/java/com/pitchedapps/frost/ExampleUnitTest.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.pitchedapps.frost;
-
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Example local unit test, which will execute on the development machine (host).
- *
- * @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
- */
-public class ExampleUnitTest {
- @Test
- public void addition_isCorrect() throws Exception {
- assertEquals(4, 2 + 2);
- }
-} \ No newline at end of file
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt
new file mode 100644
index 00000000..55208aae
--- /dev/null
+++ b/app/src/test/kotlin/com/pitchedapps/frost/BaseUnitTest.kt
@@ -0,0 +1,25 @@
+package com.pitchedapps.frost
+
+import android.content.Context
+import android.os.Build
+import org.junit.Rule
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+import org.robolectric.RuntimeEnvironment
+import org.robolectric.annotation.Config
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+@RunWith(RobolectricTestRunner::class)
+@Config(constants = BuildConfig::class, sdk = intArrayOf(Build.VERSION_CODES.LOLLIPOP),
+ assetDir = "build/intermediates/classes/test/")
+abstract class BaseUnitTest {
+
+ @JvmField
+ @Rule
+ var dblflowTestRule = DBFlowTestRule.create()
+
+ val context: Context
+ get() = RuntimeEnvironment.application
+}
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/DbFlowTestRule.kt b/app/src/test/kotlin/com/pitchedapps/frost/DbFlowTestRule.kt
new file mode 100644
index 00000000..aaf38a0f
--- /dev/null
+++ b/app/src/test/kotlin/com/pitchedapps/frost/DbFlowTestRule.kt
@@ -0,0 +1,38 @@
+package com.pitchedapps.frost
+
+import com.raizlabs.android.dbflow.config.DatabaseConfig
+import com.raizlabs.android.dbflow.config.FlowConfig
+import com.raizlabs.android.dbflow.config.FlowManager
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+import org.robolectric.RuntimeEnvironment
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+
+class DBFlowTestRule : TestRule {
+
+ override fun apply(base: Statement, description: Description): Statement {
+ return object : Statement() {
+
+ @Throws(Throwable::class)
+ override fun evaluate() {
+ FlowManager.init(FlowConfig.Builder(RuntimeEnvironment.application)
+ .addDatabaseConfig(DatabaseConfig.Builder(TestDatabase::class.java)
+ .transactionManagerCreator(::ImmediateTransactionManager)
+ .build()).build())
+ try {
+ base.evaluate()
+ } finally {
+ FlowManager.destroy()
+ }
+ }
+ }
+ }
+
+ companion object {
+ fun create() = DBFlowTestRule()
+ }
+} \ No newline at end of file
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/ImmediateTransactionManager.kt b/app/src/test/kotlin/com/pitchedapps/frost/ImmediateTransactionManager.kt
new file mode 100644
index 00000000..f3d17e76
--- /dev/null
+++ b/app/src/test/kotlin/com/pitchedapps/frost/ImmediateTransactionManager.kt
@@ -0,0 +1,38 @@
+package com.pitchedapps.frost
+
+import com.raizlabs.android.dbflow.config.DatabaseDefinition
+import com.raizlabs.android.dbflow.runtime.BaseTransactionManager
+import com.raizlabs.android.dbflow.structure.database.transaction.ITransactionQueue
+import com.raizlabs.android.dbflow.structure.database.transaction.Transaction
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+class ImmediateTransactionManager(databaseDefinition: DatabaseDefinition)
+ : BaseTransactionManager(ImmediateTransactionQueue(), databaseDefinition)
+
+
+class ImmediateTransactionQueue : ITransactionQueue {
+
+ override fun add(transaction: Transaction?) {
+ if (transaction != null) {
+ transaction.newBuilder()
+ .runCallbacksOnSameThread(true)
+ .build()
+ .executeSync()
+ }
+ }
+
+ override fun cancel(transaction: Transaction?) {
+
+ }
+
+ override fun startIfNotAlive() {
+ }
+
+ override fun cancel(name: String?) {
+ }
+
+ override fun quit() {
+ }
+
+} \ No newline at end of file
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/TestDatabase.kt b/app/src/test/kotlin/com/pitchedapps/frost/TestDatabase.kt
new file mode 100644
index 00000000..328233ac
--- /dev/null
+++ b/app/src/test/kotlin/com/pitchedapps/frost/TestDatabase.kt
@@ -0,0 +1,21 @@
+package com.pitchedapps.frost
+
+import com.raizlabs.android.dbflow.annotation.Database
+import com.raizlabs.android.dbflow.annotation.Migration
+import com.raizlabs.android.dbflow.sql.migration.UpdateTableMigration
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+
+/**
+ * Description:
+ */
+@Database(version = TestDatabase.VERSION, name = TestDatabase.NAME)
+object TestDatabase {
+
+ const val VERSION = 1
+
+ const val NAME = "TestDatabase"
+
+} \ No newline at end of file