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:
parent
9a41937a33
commit
8618670b82
@ -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 {
|
||||
|
@ -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>
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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")
|
||||
})
|
||||
}
|
@ -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.
|
@ -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"
|
||||
|
22
app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt
Normal file
22
app/src/main/kotlin/com/pitchedapps/frost/events/WebEvent.kt
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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"),
|
@ -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)
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
||||
|
||||
}
|
@ -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")
|
||||
}
|
||||
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 ->
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
41
app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt
Normal file
41
app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt
Normal 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)
|
||||
}
|
||||
}
|
@ -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
|
Loading…
Reference in New Issue
Block a user