1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-10 04:52:38 +01:00

add more cookie handling

This commit is contained in:
Allan Wang 2017-05-31 17:11:46 -07:00
parent 9a41937a33
commit 8618670b82
26 changed files with 346 additions and 258 deletions

View File

@ -30,6 +30,7 @@ android {
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
test.java.srcDirs += 'src/test/kotlin'
}
}
@ -41,6 +42,7 @@ dependencies {
testCompile 'junit:junit:4.12'
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"
compile "com.android.support:appcompat-v7:${ANDROID_SUPPORT_LIBS}"
compile "com.android.support:support-v4:${ANDROID_SUPPORT_LIBS}"
@ -83,6 +85,8 @@ dependencies {
compile "com.jakewharton.rxbinding2:rxbinding:${RX_BINDING}"
compile "com.jakewharton.rxbinding2:rxbinding-appcompat-v7:${RX_BINDING}"
compile "org.greenrobot:eventbus:${EVENT_BUS}"
compile "com.facebook.stetho:stetho-okhttp3:${STETHO}"
compile "com.lapism:searchview:${SEARCH_VIEW}"
@ -104,6 +108,8 @@ dependencies {
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}"
compile "com.f2prateek.rx.preferences2:rx-preferences:${RX_PREFS}"
}
kapt {

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.pitchedapps.frost">
<!-- To auto-complete the email text field in the login form with the user's emails -->
@ -92,37 +91,17 @@
android:scheme="https" />
</intent-filter>
</activity>
<activity android:name=".LoginActivity" />
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
tools:replace="android:theme" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<receiver
android:name=".services.NotificationReceiver"
android:enabled="true"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="com.pitchedapps.frost.NOTIFICATIONS" />
</intent-filter>
</activity>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="@string/facebook_app_id" />
<meta-data
android:name="com.facebook.sdk.ApplicationName"
android:value="@string/facebook_app_name" />
<provider
android:name="com.facebook.FacebookContentProvider"
android:authorities="@string/facebook_authorities"
android:exported="true" />
</receiver>
</application>
</manifest>

View File

@ -4,6 +4,7 @@ import android.app.Application
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.retro.FrostApi
import com.pitchedapps.frost.utils.CrashReportingTree
import com.pitchedapps.frost.utils.GlideUtils
import com.pitchedapps.frost.utils.Prefs
import com.raizlabs.android.dbflow.config.FlowConfig
import com.raizlabs.android.dbflow.config.FlowManager
@ -21,8 +22,9 @@ class FrostApp : Application() {
else Timber.plant(CrashReportingTree())
FlowManager.init(FlowConfig.Builder(this).build())
Prefs(this)
GlideUtils(this)
FrostApi(this)
FbCookie.init()
FbCookie()
super.onCreate()
}

View File

@ -24,9 +24,7 @@ import com.pitchedapps.frost.utils.*
import io.reactivex.subjects.PublishSubject
import io.reactivex.subjects.Subject
class MainActivity : AppCompatActivity(), KeyPairObservable {
override val observable: Subject<Pair<Int, Int>> = PublishSubject.create<Pair<Int, Int>>()
class MainActivity : AppCompatActivity() {
lateinit var adapter: SectionsPagerAdapter
val toolbar: Toolbar by bindView(R.id.toolbar)
@ -75,7 +73,7 @@ class MainActivity : AppCompatActivity(), KeyPairObservable {
finish()
}
R.id.action_changelog -> Changelog.show(this)
R.id.action_call -> frostApi.me().enqueueFrost { _, response -> L.e(response.toString())}
R.id.action_call -> frostApi.me().enqueueFrost { _, response -> L.e(response.toString()) }
R.id.action_db -> adapter.pages.saveAsync(this)
R.id.action_restart -> {
finish();

View File

@ -1,6 +1,5 @@
package com.pitchedapps.frost.dbflow
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.raizlabs.android.dbflow.annotation.ConflictAction
@ -23,10 +22,16 @@ object CookiesDb {
@Table(database = CookiesDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE)
data class CookieModel(@PrimaryKey var id: Long = Prefs.userIdDefault, var cookie: String? = null) : BaseModel()
fun loadFbCookie(): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq Prefs.userId)).querySingle()
fun loadFbCookie(id: Long): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq id)).querySingle()
fun saveFbCookie() {
CookieModel(FbCookie.userId, FbCookie.webCookie).async save {
fun saveFbCookie(id: Long, cookie: String?) {
CookieModel(id, cookie).async save {
L.d("Fb cookie saved")
}
}
fun removeCookie(id: Long) {
loadFbCookie(id)?.async?.delete({
L.d("Fb cookie deleted")
})
}

View File

@ -1,10 +1,9 @@
package com.pitchedapps.frost.utils
package com.pitchedapps.frost.dbflow
import android.content.Context
import com.pitchedapps.frost.utils.L
import com.raizlabs.android.dbflow.config.FlowManager
import com.raizlabs.android.dbflow.kotlinextensions.*
import com.raizlabs.android.dbflow.structure.database.transaction.FastStoreModelTransaction
import com.raizlabs.android.dbflow.structure.database.transaction.Transaction
/**
* Created by Allan Wang on 2017-05-30.

View File

@ -7,9 +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.facebook.FB_KEY
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.replace
import com.raizlabs.android.dbflow.annotation.Database
import com.raizlabs.android.dbflow.annotation.ForeignKey
import com.raizlabs.android.dbflow.annotation.PrimaryKey
@ -66,7 +64,7 @@ enum class FbUrl(@StringRes val titleId: Int, val icon: IIcon, relativeUrl: Stri
PROFILE(R.string.profile, CommunityMaterial.Icon.cmd_account, "me"),
EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event, "events/upcoming"),
FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_people, "friends/center/requests"),
MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages"),
MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages?disable_interstitial=1"),
NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications");
val url = "$FB_URL_BASE$relativeUrl"

View File

@ -0,0 +1,22 @@
package com.pitchedapps.frost.events
import com.pitchedapps.frost.web.FrostWebView
/**
* Created by Allan Wang on 2017-05-31.
*/
class WebEvent(val key: Int, val urlMatch: String? = null) {
companion object {
const val REFRESH = 0
const val REFRESH_BASE = 1
}
fun execute(webView: FrostWebView) {
if (urlMatch != null && !webView.url.contains(urlMatch)) return
when (key) {
REFRESH -> webView.reload()
REFRESH_BASE -> webView.loadUrl(webView.baseUrl)
}
}
}

View File

@ -3,24 +3,30 @@ package com.pitchedapps.frost.facebook
import android.webkit.CookieManager
import com.pitchedapps.frost.dbflow.FB_URL_BASE
import com.pitchedapps.frost.dbflow.loadFbCookie
import com.pitchedapps.frost.dbflow.removeCookie
import com.pitchedapps.frost.dbflow.saveFbCookie
import com.pitchedapps.frost.events.WebEvent
import com.pitchedapps.frost.utils.GlideUtils
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import org.greenrobot.eventbus.EventBus
/**
* Created by Allan Wang on 2017-05-30.
*/
object FbCookie {
var userId: Long = Prefs.userIdDefault
var dbCookie: String? = null
var webCookie: String?
get() = CookieManager.getInstance().getCookie(FB_URL_BASE)
set(value) = CookieManager.getInstance().setCookie(FB_URL_BASE, value)
set(value) {
CookieManager.getInstance().setCookie(FB_URL_BASE, value)
CookieManager.getInstance().flush()
}
fun init() {
userId = Prefs.userId
dbCookie = loadFbCookie()?.cookie
operator fun invoke() {
L.d("User ${Prefs.userId}")
dbCookie = loadFbCookie(Prefs.userId)?.cookie
if (dbCookie != null && webCookie == null) {
L.d("DbCookie found & WebCookie is null; setting webcookie")
webCookie = dbCookie
@ -30,34 +36,47 @@ object FbCookie {
private val userMatcher: Regex by lazy { Regex("c_user=([0-9]*);") }
fun checkUserId(url: String, cookie: String?) {
if (userId != Prefs.userIdDefault || cookie == null) return
if (Prefs.userId != Prefs.userIdDefault || cookie == null) return
L.d("Checking cookie for $url\n\t$cookie")
if (!url.contains("facebook") || !cookie.contains(userMatcher)) return
val id = userMatcher.find(cookie)?.groups?.get(1)?.value
if (id != null) {
try {
userId = id.toLong()
save()
save(id.toLong())
} catch (e: NumberFormatException) {
//todo send report that id has changed
}
}
}
fun save() {
L.d("New cookie found for $userId")
Prefs.userId = userId
fun save(id: Long) {
L.d("New cookie found for $id")
Prefs.userId = id
CookieManager.getInstance().flush()
saveFbCookie()
EventBus.getDefault().post(WebEvent(WebEvent.REFRESH_BASE))
saveFbCookie(Prefs.userId, webCookie)
GlideUtils.downloadProfile(id)
}
//TODO reset when new account is added; reset and clear when account is logged out
fun reset() {
Prefs.userId = Prefs.userIdDefault
userId = Prefs.userIdDefault
with(CookieManager.getInstance()) {
removeAllCookies(null)
flush()
}
}
fun switchUser(id: Long) {
val cookie = loadFbCookie(id) ?: return
Prefs.userId = id
dbCookie = cookie.cookie
webCookie = dbCookie
}
fun logout() {
L.d("Logging out user ${Prefs.userId}")
removeCookie(Prefs.userId)
reset()
}
}

View File

@ -1,28 +0,0 @@
package com.pitchedapps.frost.facebook
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.dbflow.FbTab
/**
* Created by Allan Wang on 2017-05-29.
*/
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"),

View File

@ -12,12 +12,10 @@ import io.reactivex.functions.Consumer
* Created by Allan Wang on 2017-05-29.
*/
interface BaseFragmentContract {
fun onActivityEvent(position: Int, key: Int)
fun onBackPressed(): Boolean
}
abstract class BaseFragment : Fragment(), Consumer<Pair<Int, Int>>, BaseFragmentContract {
var disposable: Disposable? = null
abstract class BaseFragment : Fragment(), BaseFragmentContract {
val position: Int by lazy { arguments.getInt(ARG_POSITION) }
companion object {
@ -29,21 +27,4 @@ abstract class BaseFragment : Fragment(), Consumer<Pair<Int, Int>>, BaseFragment
}
}
override fun onAttach(context: Context?) {
super.onAttach(context)
if (activity is KeyPairObservable && disposable == null)
disposable = (activity as KeyPairObservable).observable.subscribe(this, Consumer {
t: Throwable ->
L.e(t.message ?: "Observable error")
})
}
override fun onDestroyView() {
disposable?.dispose()
disposable = null
super.onDestroyView()
}
override fun accept(t: Pair<Int, Int>) = onActivityEvent(t.first, t.second)
}

View File

@ -8,13 +8,10 @@ import android.view.ViewGroup
import butterknife.ButterKnife
import butterknife.Unbinder
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FbUrl
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.bindView
import com.pitchedapps.frost.utils.putString
import com.pitchedapps.frost.views.FrostWebView
import com.pitchedapps.frost.views.SwipeRefreshBase
import com.pitchedapps.frost.views.WebStatus
import com.pitchedapps.frost.web.FrostWebView
import com.pitchedapps.frost.web.WebStatus
/**
* Created by Allan Wang on 2017-05-29.
@ -23,10 +20,6 @@ import com.pitchedapps.frost.views.WebStatus
class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
override fun onActivityEvent(position: Int, key: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onRefresh() {
web.reload()
}
@ -34,10 +27,9 @@ class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
companion object {
private val ARG_URL = "arg_url"
fun newInstance(position: Int, url: String) = BaseFragment.newInstance(WebFragment(), position).putString(ARG_URL, url)
fun newInstance(position: Int, url: FbUrl = FbUrl.FEED) = newInstance(position, url.url)
}
val refresh: SwipeRefreshBase by bindView(R.id.swipe_refresh)
val refresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh)
val web: FrostWebView by bindView(R.id.frost_webview)
lateinit var url: String
private lateinit var unbinder: Unbinder
@ -56,6 +48,7 @@ class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
web.baseUrl = url
web.observable.subscribe {
t: WebStatus ->
when (t) {
@ -64,10 +57,10 @@ class WebFragment : BaseFragment(), SwipeRefreshLayout.OnRefreshListener {
}
}
refresh.setOnRefreshListener(this)
refresh.shouldSwipe = {
L.e("Y ${web.scrollY}")
SwipeRefreshBase.shouldScroll(web)
}
// refresh.shouldSwipe = {
// L.e("Y ${web.scrollY}")
// SwipeRefreshBase.shouldScroll(web)
// }
web.loadUrl(url)
}

View File

@ -0,0 +1,36 @@
package com.pitchedapps.frost.injectors
import android.webkit.WebView
/**
* Created by Allan Wang on 2017-05-31.
*/
class JsBuilder {
private val builder = StringBuilder()
init {
builder.append("javascript:(function(){")
}
private fun getElementById(id: String) = "document.getElementById(\"$id\")"
private fun hideElementById(id: String) {
builder.append(getElementById(id)).append(".style.display=\"none\";")
}
fun hideElementById(vararg ids: String) {
ids.forEach { hideElementById(it) }
}
fun build() = builder.toString() + "})()"
fun inject(webView: WebView) {
webView.loadUrl(build())
}
fun removeAllStyles() {
}
override fun toString() = build()
}

View File

@ -5,28 +5,8 @@ import android.webkit.WebView
/**
* Created by Allan Wang on 2017-05-31.
*/
class JsInjector {
private val builder = StringBuilder()
init {
builder.append("javascript:(function(){")
}
private fun getElementById(id: String) = "document.getElementById(\"$id\")"
private fun hideElementById(id: String) {
builder.append(getElementById(id)).append(".style.display=\"none\";")
}
fun hideElementById(vararg ids: String) {
ids.forEach { hideElementById(it) }
}
fun build() = builder.toString() + "})()"
object JsInjector {
fun inject(webView: WebView) {
webView.loadUrl(build())
}
override fun toString() = build()
}
}

View File

@ -0,0 +1,20 @@
package com.pitchedapps.frost.services
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
/**
* Created by Allan Wang on 2017-05-31.
*/
class NotificationReceiver : BroadcastReceiver() {
companion object {
const val ACTION = "com.pitchedapps.frost.NOTIFICATIONS"
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != ACTION) return
}
}

View File

@ -0,0 +1,26 @@
package com.pitchedapps.frost.utils
import android.content.Context
import com.bumptech.glide.Glide
/**
* Created by Allan Wang on 2017-05-31.
*/
object GlideUtils {
lateinit var applicationContext: Context
operator fun invoke(applicationContext: Context) {
this.applicationContext = applicationContext
}
fun downloadForLater(url: String) {
Glide.with(applicationContext).download(url)
}
fun downloadProfile(id: Long) {
L.d("Downloading profile photo")
downloadForLater("http://graph.facebook.com/$id/picture?type=large")
}
}

View File

@ -8,7 +8,7 @@ import timber.log.Timber
* Created by Allan Wang on 2017-05-28.
*/
object L {
val TAG = "Frost: %s"
const val TAG = "Frost: %s"
fun e(s: String) = Timber.e(TAG, s)
fun d(s: String) = Timber.d(TAG, s)
}

View File

@ -5,6 +5,8 @@ import android.content.SharedPreferences
/**
* Created by Allan Wang on 2017-05-28.
*
* Shared Preference object with lazy cached retrievals
*/
private val PREFERENCE_NAME = "${com.pitchedapps.frost.BuildConfig.APPLICATION_ID}.prefs"
@ -13,6 +15,8 @@ private val USER_ID = "user_id"
object Prefs {
private const val prefDefaultLong = -2L
lateinit private var c: Context
operator fun invoke(c: Context) {
this.c = c
@ -21,17 +25,36 @@ object Prefs {
private val sp: SharedPreferences by lazy { c.getSharedPreferences(PREFERENCE_NAME, Context.MODE_PRIVATE) }
var lastActive: Long
get() = sp.getLong(LAST_ACTIVE, -1)
set(value) = set(LAST_ACTIVE, System.currentTimeMillis())
var lastActive: Long = prefDefaultLong
get() {
if (field == prefDefaultLong) field = sp.getLong(LAST_ACTIVE, -1)
return field
}
set(value) {
field = value
if (value != prefDefaultLong) set(LAST_ACTIVE, System.currentTimeMillis())
}
const val userIdDefault = -1L
var userId: Long
get() = sp.getLong(USER_ID, userIdDefault)
set(value) = set(USER_ID, value)
var userId: Long = prefDefaultLong
get() {
if (field == prefDefaultLong) field = sp.getLong(USER_ID, userIdDefault)
return field
}
set(value) {
field = value
if (value != prefDefaultLong) set(USER_ID, value)
}
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()
private fun set(key: String, value: String) = sp.edit().putString(key, value).apply()
}
fun clear() {
L.d("Clearing Prefs")
sp.edit().clear().apply()
lastActive = prefDefaultLong
userId = prefDefaultLong
}
}

View File

@ -1,73 +0,0 @@
package com.pitchedapps.frost.views
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.net.UrlQuerySanitizer
import android.util.AttributeSet
import android.view.View
import android.webkit.WebResourceError
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
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
import retrofit2.Response
/**
* Created by Allan Wang on 2017-05-29.
*/
class LoginWebView @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : WebView(context, attrs, defStyleAttr) {
init {
setupWebview()
}
@SuppressLint("SetJavaScriptEnabled")
fun setupWebview() {
settings.javaScriptEnabled = true
setLayerType(View.LAYER_TYPE_HARDWARE, null)
setWebViewClient(object : WebViewClient() {
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
super.onReceivedError(view, request, error)
L.e("Error ${request}")
}
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
L.d("Loading $url")
}
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
if (url == null) return
val sanitizer = UrlQuerySanitizer(url)
val accessToken = sanitizer.getValue("access_token")
val expiresIn = sanitizer.getValue("expires_in")
val grantedScopes = sanitizer.getValue("granted_scopes")
val deniedScopes = sanitizer.getValue("deniedScopes")
L.d("Loaded $url")
}
})
}
fun saveAccessToken(accessToken: String, expiresIn: String, grantedScopes: String?, deniedScopes: String?) {
L.d("Granted $grantedScopes")
L.d("Denied $deniedScopes")
frostApi.me().enqueueFrost { call, response ->
}
}
}

View File

@ -1,8 +1,7 @@
package com.pitchedapps.frost.views
package com.pitchedapps.frost.web
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Bitmap
import android.support.v4.view.MotionEventCompat
import android.support.v4.view.NestedScrollingChild
import android.support.v4.view.NestedScrollingChildHelper
@ -10,12 +9,13 @@ import android.support.v4.view.ViewCompat
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.webkit.*
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.L
import android.webkit.WebView
import com.pitchedapps.frost.events.WebEvent
import com.pitchedapps.frost.utils.ObservableContainer
import io.reactivex.subjects.BehaviorSubject
import io.reactivex.subjects.Subject
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
enum class WebStatus {
LOADING, LOADED, ERROR
@ -37,7 +37,8 @@ class FrostWebView @JvmOverloads constructor(
private val scrollOffset = IntArray(2)
private val scrollConsumed = IntArray(2)
private var nestedOffsetY: Int = 0
override val observable: Subject<WebStatus>
override val observable: Subject<WebStatus> //TODO see if we need this
var baseUrl: String? = null
init {
isNestedScrollingEnabled = true
@ -49,25 +50,12 @@ class FrostWebView @JvmOverloads constructor(
fun setupWebview() {
settings.javaScriptEnabled = true
setLayerType(View.LAYER_TYPE_HARDWARE, null)
setWebViewClient(object : WebViewClient() {
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
super.onReceivedError(view, request, error)
observable.onNext(WebStatus.ERROR)
L.e("FWV Error ${request}")
}
setWebViewClient(FrostWebViewClient(observable))
}
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
observable.onNext(WebStatus.LOADING)
L.d("FWV Loading $url")
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
observable.onNext(WebStatus.LOADED)
FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url))
}
})
override fun loadUrl(url: String?) {
if (url != null)
super.loadUrl(url)
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
@ -110,6 +98,19 @@ class FrostWebView @JvmOverloads constructor(
return returnValue
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
EventBus.getDefault().register(this);
}
override fun onDetachedFromWindow() {
EventBus.getDefault().unregister(this)
super.onDetachedFromWindow()
}
@Subscribe
fun webEvent(event: WebEvent) = event.execute(this)
// Nested Scroll implements
override fun setNestedScrollingEnabled(enabled: Boolean) {
childHelper.isNestedScrollingEnabled = enabled

View File

@ -0,0 +1,48 @@
package com.pitchedapps.frost.web
import android.graphics.Bitmap
import android.webkit.*
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.L
import io.reactivex.subjects.Subject
/**
* Created by Allan Wang on 2017-05-31.
*/
class FrostWebViewClient(val observable: Subject<WebStatus>) : WebViewClient() {
private var injectionCount: Int = 0
companion object {
//Collections of jewels mapped with url match -> id
val jewelMap: Map<String, String> = mapOf("a" to "b")
fun test() {
}
}
override fun onReceivedError(view: WebView?, request: WebResourceRequest?, error: WebResourceError?) {
super.onReceivedError(view, request, error)
observable.onNext(WebStatus.ERROR)
L.e("FWV Error ${request}")
}
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
super.onPageStarted(view, url, favicon)
injectionCount = 0
observable.onNext(WebStatus.LOADING)
L.d("FWV Loading $url")
if (url.contains("logout.php")) FbCookie.logout()
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
observable.onNext(WebStatus.LOADED)
FbCookie.checkUserId(url, CookieManager.getInstance().getCookie(url))
}
fun logout() {
}
}

View File

@ -1,11 +1,10 @@
package com.pitchedapps.frost.views
package com.pitchedapps.frost.web
import android.content.Context
import android.support.v4.widget.SwipeRefreshLayout
import android.util.AttributeSet
import android.view.MotionEvent
import android.webkit.WebView
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Utils

View File

@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<com.pitchedapps.frost.views.SwipeRefreshBase xmlns:android="http://schemas.android.com/apk/res/android"
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/swipe_refresh"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.pitchedapps.frost.views.FrostWebView
<com.pitchedapps.frost.web.FrostWebView
android:id="@+id/frost_webview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</com.pitchedapps.frost.views.SwipeRefreshBase>
</android.support.v4.widget.SwipeRefreshLayout>

View File

@ -7,6 +7,7 @@ import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.RuntimeEnvironment
import org.robolectric.annotation.Config
import timber.log.Timber
/**
* Created by Allan Wang on 2017-05-30.
@ -22,4 +23,14 @@ abstract class BaseUnitTest {
val context: Context
get() = RuntimeEnvironment.application
init {
Timber.plant(TestTree())
}
internal class TestTree : Timber.Tree() {
override fun log(priority: Int, tag: String, message: String, t: Throwable?) {
System.out.println("$tag-$priority: $message")
}
}
}

View File

@ -0,0 +1,41 @@
package com.pitchedapps.frost.utils
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Allan Wang on 2017-05-31.
*/
class PrefsTest {
//Replicate logic
var test: Long = -1L
get() {
if (field == -1L) field = file
return field
}
set(value) {
field = value
if (value != -1L) file = value
}
var file: Long = -1L
@Before
fun verify() {
test = -1L
file = -1L
}
@Test
fun laziness() {
assertEquals(-1L, test)
file = 2L
assertEquals(2L, test)
file = -3L
assertEquals(2L, test)
test = 3L
assertEquals(3L, file)
}
}

View File

@ -21,18 +21,18 @@ VERSION_NAME=0.1
ANDROID_SUPPORT_LIBS=25.3.1
TIMBER=4.5.1
MD=0.9.4.3
ICONICS=2.8.3
ICONICS=2.8.5
IICON_GOOGLE=3.0.1.0
IICON_MATERIAL=2.2.0.2
IICON_COMMUNITY=1.9.32.1
BUTTERKNIFE=8.5.1
BUTTERKNIFE=8.6.0
SEARCH_VIEW=4.0
RX_JAVA=2.0.7
RX_JAVA=2.1.0
RX_ANDROID=2.0.1
RX_BINDING=2.0.0
JSOUP=1.10.2
FB_SDK=[4,5)
STETHO=1.4.2
STETHO=1.5.0
ANKO=0.10.0
GLIDE=4.0.0-RC0
RETROFIT=2.2.0
@ -41,4 +41,6 @@ SQL_CIPHER=3.5.7
OKHTTP_INTERCEPTOR=3.6.0
ROBOELECTRIC=3.3.2
AUTO=1.4.1
AUTO_VALUE_PARCEL=0.2.5
AUTO_VALUE_PARCEL=0.2.5
RX_PREFS=2.0.0-RC2
EVENT_BUS=3.0.0