diff options
Diffstat (limited to 'app')
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 Binary files differindex 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 diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png Binary files differindex 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 diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png Binary files differindex 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 diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png Binary files differindex 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 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 |