diff options
29 files changed, 245 insertions, 123 deletions
diff --git a/app/build.gradle b/app/build.gradle index 671e8471..6227423b 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -177,7 +177,8 @@ dependencies { implementation "com.sothree.slidinguppanel:library:${SLIDING_PANEL}" //Reactive Libs - compile "io.reactivex.rxjava2:rxkotlin:${RX_KOTLIN}" - compile "io.reactivex.rxjava2:rxandroid:${RX_ANDROID}" + implementation "io.reactivex.rxjava2:rxkotlin:${RX_KOTLIN}" + implementation "io.reactivex.rxjava2:rxandroid:${RX_ANDROID}" + implementation "com.github.pwittchen:reactivenetwork-rx2:${RX_NETWORK}" }
\ No newline at end of file diff --git a/app/src/main/assets/js/menu.js b/app/src/main/assets/js/menu.js index 7394c824..a43b1820 100644 --- a/app/src/main/assets/js/menu.js +++ b/app/src/main/assets/js/menu.js @@ -4,6 +4,8 @@ if (!window.hasOwnProperty('frost_menu')) { window.frost_menu = true; var viewport = document.querySelector('#viewport'); var root = document.querySelector('#root'); + if (!viewport) console.log('Menu.js: viewport is null'); + if (!root) console.log('Menu.js: root is null'); var y = new MutationObserver(function(mutations) { viewport.removeAttribute('style'); root.removeAttribute('style'); @@ -21,18 +23,24 @@ if (!window.hasOwnProperty('frost_menu')) { console.log('Found side menu'); while (root.firstChild) root.removeChild(root.firstChild); - while (menu.childNodes.length) - root.appendChild(menu.childNodes[0]); - Frost.emit(0); + while (menu.childNodes.length) { + console.log('append'); + viewport.appendChild(menu.childNodes[0]); + } + if (typeof Frost !== 'undefined') Frost.emit(0); setTimeout(function() { y.disconnect(); console.log('Unhook styler'); }, 500); } }); - x.observe(document.querySelector('#mJewelNav'), { + var jewel = document.querySelector('#mJewelNav'); + if (!jewel) console.log('Menu.js: jewel is null'); + x.observe(jewel, { childList: true, subtree: true }); - document.querySelector('#bookmarks_jewel').querySelector('a').click(); + var menuA = document.querySelector('#bookmarks_jewel').querySelector('a'); + if (!menuA) console.log('Menu.js: jewel is null') + menuA.click(); } diff --git a/app/src/main/assets/js/menu.min.js b/app/src/main/assets/js/menu.min.js index 5403e03a..5b65ac9b 100644 --- a/app/src/main/assets/js/menu.min.js +++ b/app/src/main/assets/js/menu.min.js @@ -1,8 +1,10 @@ if(!window.hasOwnProperty("frost_menu")){ console.log("Registering frost_menu"),window.frost_menu=!0 -;var viewport=document.querySelector("#viewport"),root=document.querySelector("#root"),y=new MutationObserver(function(e){ -viewport.removeAttribute("style"), -root.removeAttribute("style") +;var viewport=document.querySelector("#viewport"),root=document.querySelector("#root") +;viewport||console.log("Menu.js: viewport is null"), +root||console.log("Menu.js: root is null") +;var y=new MutationObserver(function(e){ +viewport.removeAttribute("style"),root.removeAttribute("style") }) ;y.observe(viewport,{ attributes:!0 @@ -13,14 +15,19 @@ attributes:!0 var o=document.querySelector(".mSideMenu") ;if(null!==o){ for(x.disconnect(),console.log("Found side menu");root.firstChild;)root.removeChild(root.firstChild) -;for(;o.childNodes.length;)root.appendChild(o.childNodes[0]) -;Frost.emit(0),setTimeout(function(){ +;for(;o.childNodes.length;)console.log("append"), +viewport.appendChild(o.childNodes[0]) +;"undefined"!=typeof Frost&&Frost.emit(0),setTimeout(function(){ y.disconnect(),console.log("Unhook styler") },500) } -}) -;x.observe(document.querySelector("#mJewelNav"),{ +}),jewel=document.querySelector("#mJewelNav") +;jewel||console.log("Menu.js: jewel is null"), +x.observe(jewel,{ childList:!0, subtree:!0 -}),document.querySelector("#bookmarks_jewel").querySelector("a").click() +}) +;var menuA=document.querySelector("#bookmarks_jewel").querySelector("a") +;menuA||console.log("Menu.js: jewel is null"), +menuA.click() }
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt index 77a20d04..c7ca5ec7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt @@ -2,10 +2,16 @@ package com.pitchedapps.frost.activities import android.os.Bundle import ca.allanwang.kau.internal.KauBaseActivity +import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity +import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.pitchedapps.frost.R +import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.materialDialogThemed import com.pitchedapps.frost.utils.setFrostTheme +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers /** * Created by Allan Wang on 2017-06-12. @@ -29,4 +35,41 @@ abstract class BaseActivity : KauBaseActivity() { setFrostTheme() } + private var networkDisposable: Disposable? = null + private var networkConsumer: ((Connectivity) -> Unit)? = null + + fun setNetworkObserver(consumer: (connectivity: Connectivity) -> Unit) { + this.networkConsumer = consumer + } + + fun observeNetworkConnectivity() { + val consumer = networkConsumer ?: return + networkDisposable = ReactiveNetwork.observeNetworkConnectivity(applicationContext) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + connectivity: Connectivity -> + connectivity.apply { + L.d("Network connectivity changed: isAvailable: $isAvailable isRoaming: $isRoaming") + consumer(connectivity) + } + } + } + + fun disposeNetworkConnectivity() { + if (!(networkDisposable?.isDisposed ?: true)) + networkDisposable?.dispose() + networkDisposable = null + } + + override fun onResume() { + super.onResume() + disposeNetworkConnectivity() + observeNetworkConnectivity() + } + + override fun onPause() { + super.onPause() + disposeNetworkConnectivity() + } }
\ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt index 47c286fa..eb991599 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -79,7 +79,7 @@ class LoginActivity : BaseActivity() { refresh = false if (!foundImage) { L.eThrow("Could not get profile photo; Invalid userId?") - L.i("-\t$cookie") + L.i(null, cookie.toString()) } textview.text = String.format(getString(R.string.welcome), name) textview.fadeIn() diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt index 58c7b121..af7db2f0 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt @@ -60,6 +60,7 @@ import com.pitchedapps.frost.utils.iab.IS_FROST_PRO import com.pitchedapps.frost.views.BadgedIcon import com.pitchedapps.frost.views.FrostViewPager import com.pitchedapps.frost.web.SearchWebView +import com.pitchedapps.frost.web.shouldLoadImages import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers @@ -160,14 +161,10 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, // } setFrostColors(toolbar, themeWindow = false, headers = arrayOf(tabs, appBar), backgrounds = arrayOf(viewPager)) onCreateBilling() - if (Prefs.installDate < 1501454310304 && Showcase.intro) - materialDialogThemed { - title(R.string.intro_title) - content(R.string.intro_desc) - positiveText(R.string.kau_yes) - negativeText(R.string.kau_no) - onPositive { _, _ -> launchIntroActivity(cookies()) } - } + setNetworkObserver { + connectivity -> + shouldLoadImages = !connectivity.isRoaming + } } fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) { @@ -370,11 +367,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, if (Prefs.searchBar) { if (firstLoadFinished && hiddenSearchView == null) hiddenSearchView = SearchWebView(this, this) if (searchView == null) searchView = bindSearchView(menu, R.id.action_search, Prefs.iconColor) { - textCallback = { - query, _ -> - hiddenSearchView?.query(query) - } - textDebounceInterval = 200L + textCallback = { query, _ -> runOnUiThread { hiddenSearchView?.query(query) } } foregroundColor = Prefs.textColor backgroundColor = Prefs.bgColor.withMinAlpha(200) openListener = { hiddenSearchView?.pauseLoad = false } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt index 200c5fa4..3fd3e3b5 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -67,6 +67,11 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { iicon = GoogleMaterial.Icon.gmd_notifications } + subItems(R.string.network, getNetworkPrefs()) { + descRes = R.string.network_desc + iicon = GoogleMaterial.Icon.gmd_network_cell + } + subItems(R.string.experimental, getExperimentalPrefs()) { descRes = R.string.experimental_desc iicon = CommunityMaterial.Icon.cmd_flask_outline diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt index 7cd93d14..69b2ba41 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt @@ -33,7 +33,7 @@ class FbUrlFormatter(url: String) { if (cleanedUrl.startsWith("#!/")) cleanedUrl = cleanedUrl.substring(2) if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1) cleanedUrl = cleanedUrl.replaceFirst(".facebook.com//", ".facebook.com/") //sometimes we are given a bad url - L.v("Formatted url from $url to $cleanedUrl") + L.v(null, "Formatted url from $url to $cleanedUrl") cleaned = cleanedUrl } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt index 0992a9cb..b9b35956 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt @@ -3,7 +3,9 @@ package com.pitchedapps.frost.injectors import android.graphics.Color import android.webkit.WebView import ca.allanwang.kau.utils.* +import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs +import java.io.FileNotFoundException /** * Created by Allan Wang on 2017-05-31. @@ -19,28 +21,33 @@ enum class CssAssets(val folder: String = "themes") : InjectorContract { override fun inject(webView: WebView, callback: ((String) -> Unit)?) { if (injector == null) { - var content = webView.context.assets.open("css/$folder/$file").bufferedReader().use { it.readText() } - if (this == CUSTOM) { - var bbt = Prefs.bgColor - val bt: String - if (Color.alpha(bbt) == 255) { - bbt = bbt.adjustAlpha(0.2f).colorToForeground(0.35f) - bt = Prefs.bgColor.toRgbaString() - } else { - bbt = bbt.adjustAlpha(0.05f).colorToForeground(0.5f) - bt = "transparent" + try { + var content = webView.context.assets.open("css/$folder/$file").bufferedReader().use { it.readText() } + if (this == CUSTOM) { + var bbt = Prefs.bgColor + val bt: String + if (Color.alpha(bbt) == 255) { + bbt = bbt.adjustAlpha(0.2f).colorToForeground(0.35f) + bt = Prefs.bgColor.toRgbaString() + } else { + bbt = bbt.adjustAlpha(0.05f).colorToForeground(0.5f) + bt = "transparent" + } + content = content + .replace("\$T\$", Prefs.textColor.toRgbaString()) + .replace("\$TT\$", Prefs.textColor.colorToBackground(0.05f).toRgbaString()) + .replace("\$B\$", Prefs.bgColor.toRgbaString()) + .replace("\$BT\$", bt) + .replace("\$BBT\$", bbt.toRgbaString()) + .replace("\$O\$", Prefs.bgColor.withAlpha(255).toRgbaString()) + .replace("\$OO\$", Prefs.bgColor.colorToForeground(0.35f).withAlpha(255).toRgbaString()) + .replace("\$D\$", Prefs.textColor.adjustAlpha(0.3f).toRgbaString()) } - content = content - .replace("\$T\$", Prefs.textColor.toRgbaString()) - .replace("\$TT\$", Prefs.textColor.colorToBackground(0.05f).toRgbaString()) - .replace("\$B\$", Prefs.bgColor.toRgbaString()) - .replace("\$BT\$", bt) - .replace("\$BBT\$", bbt.toRgbaString()) - .replace("\$O\$", Prefs.bgColor.withAlpha(255).toRgbaString()) - .replace("\$OO\$", Prefs.bgColor.colorToForeground(0.35f).withAlpha(255).toRgbaString()) - .replace("\$D\$", Prefs.textColor.adjustAlpha(0.3f).toRgbaString()) + injector = JsBuilder().css(content).build() + } catch (e: FileNotFoundException) { + L.e(e, "CssAssets file not found") + injector = JsInjector(JsActions.EMPTY.function) } - injector = JsBuilder().css(content).build() } injector!!.inject(webView, callback) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt index 2453d3b0..52a1a5f9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt @@ -99,7 +99,7 @@ data class NotificationContent(val data: CookieModel, .setGroup(group) if (timestamp != -1L) notifBuilder.setWhen(timestamp * 1000) - L.v("Notif load $this") + L.v("Notif load", this.toString()) NotificationManagerCompat.from(context).notify(group, notifId, notifBuilder.withBigText.build().frostConfig()) if (profileUrl.isNotBlank()) { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt index fe7758cc..972014a3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt @@ -96,7 +96,7 @@ class NotificationService : JobService() { } fun fetchGeneralNotifications(data: CookieModel) { - L.i("Notif fetch for $data") + L.i("Notif fetch", data.toString()) val doc = Jsoup.connect(FbTab.NOTIFICATIONS.url).cookie(FACEBOOK_COM, data.cookie).userAgent(USER_AGENT_BASIC).get() //aclb for unread, acw for read val unreadNotifications = (doc.getElementById("notifications_list") ?: return L.eThrow("Notification list not found")).getElementsByClass("aclb") @@ -139,7 +139,7 @@ class NotificationService : JobService() { } fun fetchMessageNotifications(data: CookieModel, content: String) { - L.i("Notif IM fetch for $data") + L.i("Notif IM fetch", data.toString()) val doc = Jsoup.parseBodyFragment(content) val unreadNotifications = (doc.getElementById("threadlist_rows") ?: return L.eThrow("Notification messages not found")).getElementsByClass("aclb") var notifCount = 0 @@ -175,7 +175,7 @@ class NotificationService : JobService() { //fetch convo pic val p = element.select("i.img[style*=url]") val pUrl = profMatcher.find(p.attr("style"))?.groups?.get(1)?.value ?: "" - L.v("url ${a.attr("href")}") + L.v("url", a.attr("href")) return NotificationContent(data, notifId.toInt(), a.attr("href"), a.text(), text, epoch, pUrl.formattedFbUrl) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt new file mode 100644 index 00000000..30ab2579 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt @@ -0,0 +1,17 @@ +package com.pitchedapps.frost.settings + +import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder +import com.pitchedapps.frost.R +import com.pitchedapps.frost.activities.SettingsActivity +import com.pitchedapps.frost.utils.Prefs + +/** + * Created by Allan Wang on 2017-08-08. + */ +fun SettingsActivity.getNetworkPrefs(): KPrefAdapterBuilder.() -> Unit = { + + checkbox(R.string.network_media_on_metered, { Prefs.loadMediaOnMeteredNetwork }, { Prefs.loadMediaOnMeteredNetwork = it }) { + descRes = R.string.network_media_on_metered_desc + } + +}
\ 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 b053b9dd..e52109c4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -128,4 +128,6 @@ object Prefs : KPref() { var viewpagerSwipe: Boolean by kpref("viewpager_swipe", true) + var loadMediaOnMeteredNetwork: Boolean by kpref("media_on_metered_network", true) + } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt index 496a6b5b..91c5ca23 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -56,8 +56,8 @@ fun Activity.cookies(): ArrayList<CookieModel> { fun Context.launchWebOverlay(url: String) { val argUrl = url.formattedFbUrl - L.v("Launch received $url") - L.i("Launch web overlay: $argUrl") + L.v("Launch received", url) + L.i("Launch web overlay", argUrl) startActivity(WebOverlayActivity::class.java, false, intentBuilder = { putExtra(ARG_URL, argUrl) }) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt index 47331833..b4dc2294 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt @@ -57,13 +57,13 @@ abstract class IABBinder : FrostBilling { activityRef.clear() } - override fun onBillingInitialized() = L.d("IAB initialized") + override fun onBillingInitialized() = L.i("IAB initialized") override fun onPurchaseHistoryRestored() = L.d("IAB restored") override fun onProductPurchased(productId: String, details: TransactionDetails?) { bp.doAsync { - L.d("IAB $productId purchased") + L.i("IAB $productId purchased") val listing = weakRef.get()?.getPurchaseListingDetails(productId) ?: return@doAsync val currency = try { Currency.getInstance(listing.currency) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt index 6bc27256..61711092 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt @@ -34,15 +34,9 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() { val activityContract = (webCore.context as? ActivityWebContract) val context = webCore.context!! - companion object { - val consoleBlacklist = setOf( - "edge-chat" - ) - } - override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { if (consoleBlacklist.any { consoleMessage.message().contains(it) }) return true - L.i("Chrome Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}") + L.d("Chrome Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}") return true } @@ -63,10 +57,10 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() { } override fun onGeolocationPermissionsShowPrompt(origin: String, callback: GeolocationPermissions.Callback) { - L.d("Requesting geolocation") + L.i("Requesting geolocation") context.kauRequestPermissions(PERMISSION_ACCESS_FINE_LOCATION) { granted, _ -> - L.d("Geolocation response received; ${if (granted) "granted" else "denied"}") + L.i("Geolocation response received; ${if (granted) "granted" else "denied"}") callback(origin, granted, true) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt index 3f2891d0..1a907f7f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt @@ -5,6 +5,7 @@ import android.webkit.WebResourceResponse import android.webkit.WebView import ca.allanwang.kau.utils.use import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs import okhttp3.HttpUrl import java.io.ByteArrayInputStream @@ -15,17 +16,17 @@ import java.io.ByteArrayInputStream * Handler to decide when a request should be done by us * This is the crux of Frost's optimizations for the web browser */ -val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) } +private val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) } //these hosts will redirect to a blank resource -val blacklistHost: Set<String> by lazy { +private val blacklistHost: Set<String> by lazy { setOf( "edge-chat.facebook.com" ) } //these hosts will return null and skip logging -val whitelistHost: Set<String> by lazy { +private val whitelistHost: Set<String> by lazy { setOf( "static.xx.fbcdn.net", "m.facebook.com", @@ -35,13 +36,13 @@ val whitelistHost: Set<String> by lazy { //these hosts will skip ad inspection //this list does not have to include anything from the two above -val adWhitelistHost: Set<String> by lazy { +private val adWhitelistHost: Set<String> by lazy { setOf( "scontent-sea1-1.xx.fbcdn.net" ) } -var adblock: Set<String>? = null +private var adblock: Set<String>? = null fun shouldFrostInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? { val httpUrl = HttpUrl.parse(request.url?.toString() ?: return null) ?: return null @@ -53,7 +54,8 @@ fun shouldFrostInterceptRequest(view: WebView, request: WebResourceRequest): Web if (adblock == null) adblock = view.context.assets.open("adblock.txt").bufferedReader().use { it.readLines().toSet() } if (adblock?.any { url.contains(it) } ?: false) return blankResource } - L.v("Intercept Request ${host} ${url}") + if (!shouldLoadImages && !Prefs.loadMediaOnMeteredNetwork && request.isMedia) return blankResource + L.v("Intercept Request", "$host $url") return null } @@ -64,16 +66,25 @@ fun WebResourceRequest.query(action: (url: String) -> Boolean): Boolean { return action(url?.path ?: return false) } +val WebResourceRequest.isImage: Boolean + get() = query { it.contains(".jpg") || it.contains(".png") } + +val WebResourceRequest.isMedia: Boolean + get() = query { it.contains(".jpg") || it.contains(".png") || it.contains("video") } + /** * Generic filter passthrough * If Resource is already nonnull, pass it, otherwise check if filter is met and override the response accordingly */ -fun WebResourceResponse?.filter(request: WebResourceRequest, filter: (url: String) -> Boolean): WebResourceResponse? - = this ?: if (request.query { filter(it) }) blankResource else null +fun WebResourceResponse?.filter(request: WebResourceRequest, filter: (url: String) -> Boolean) + = filter(request.query { filter(it) }) + +fun WebResourceResponse?.filter(filter: Boolean): WebResourceResponse? + = this ?: if (filter) blankResource else null fun WebResourceResponse?.filterCss(request: WebResourceRequest): WebResourceResponse? = filter(request) { it.endsWith(".css") } fun WebResourceResponse?.filterImage(request: WebResourceRequest): WebResourceResponse? - = filter(request) { it.contains(".jpg") || it.contains(".png") } + = filter(request.isImage) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt index f3068c43..3c08fda9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt @@ -2,6 +2,7 @@ package com.pitchedapps.frost.web import android.content.Context import android.graphics.Bitmap +import android.graphics.Color import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebView @@ -17,6 +18,7 @@ import com.pitchedapps.frost.injectors.* import com.pitchedapps.frost.utils.* import com.pitchedapps.frost.utils.iab.IS_FROST_PRO import io.reactivex.subjects.Subject +import org.jetbrains.anko.withAlpha /** * Created by Allan Wang on 2017-05-31. @@ -41,18 +43,19 @@ open class BaseWebViewClient : WebViewClient() { open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient() { val refreshObservable: Subject<Boolean> = webCore.refreshObservable + val isMain = webCore.baseEnum != null override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) { super.onPageStarted(view, url, favicon) if (url == null) return - L.i("FWV Loading $url") -// L.v("Cookies ${CookieManager.getInstance().getCookie(url)}") + L.i("FWV Loading", url) refreshObservable.onNext(true) if (!url.contains(FACEBOOK_COM)) return if (url.contains("logout.php")) FbCookie.logout(Prefs.userId, { launchLogin(view.context) }) else if (url.contains("login.php")) FbCookie.reset({ launchLogin(view.context) }) } + fun launchLogin(c: Context) { if (c is MainActivity && c.cookies().isNotEmpty()) c.launchNewTask(SelectorActivity::class.java, c.cookies()) @@ -60,19 +63,28 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient c.launchNewTask(LoginActivity::class.java) } + fun injectBackgroundColor() + = webCore.setBackgroundColor(if (isMain) Color.TRANSPARENT else Prefs.bgColor.withAlpha(255)) + + + override fun onPageCommitVisible(view: WebView, url: String?) { + super.onPageCommitVisible(view, url) + injectBackgroundColor() + view.jsInject( + CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons), + CssHider.HEADER, + CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && IS_FROST_PRO), + Prefs.themeInjector, + CssHider.NON_RECENT.maybe(webCore.url?.contains("?sk=h_chr") ?: false)) + } + override fun onPageFinished(view: WebView, url: String?) { - super.onPageFinished(view, url) - if (url == null) return - L.i("Page finished $url") + url ?: return + L.i("Page finished", url) if (!url.contains(FACEBOOK_COM)) { refreshObservable.onNext(false) return } - view.jsInject( - CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons), - CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && IS_FROST_PRO), - CssHider.ADS.maybe(!Prefs.showFacebookAds && IS_FROST_PRO) - ) onPageFinishedActions(url) } @@ -82,19 +94,16 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient internal fun injectAndFinish() { L.d("Page finished reveal") - webCore.jsInject(CssHider.HEADER, - CssHider.NON_RECENT.maybe(webCore.url.contains("?sk=h_chr")), - Prefs.themeInjector, - callback = { - refreshObservable.onNext(false) - webCore.jsInject( - JsActions.LOGIN_CHECK, - JsAssets.CLICK_A.maybe(webCore.baseEnum != null && Prefs.overlayEnabled), - JsAssets.TEXTAREA_LISTENER, - JsAssets.CONTEXT_A, - JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null) - ) - }) + refreshObservable.onNext(false) + injectBackgroundColor() + webCore.jsInject( + JsActions.LOGIN_CHECK, + JsAssets.CLICK_A.maybe(webCore.baseEnum != null && Prefs.overlayEnabled), + JsAssets.TEXTAREA_LISTENER, + CssHider.ADS.maybe(!Prefs.showFacebookAds && IS_FROST_PRO), + JsAssets.CONTEXT_A, + JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null) + ) } open fun handleHtml(html: String?) { @@ -111,26 +120,26 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient * returns false if we are already in an overlaying activity */ private fun launchRequest(request: WebResourceRequest): Boolean { - L.d("Launching Url", request.url.toString()) + L.d("Launching Url", request.url?.toString() ?: "null") if (webCore.context is WebOverlayActivity) return false webCore.context.launchWebOverlay(request.url.toString()) return true } - private fun launchImage(request: WebResourceRequest, text: String? = null): Boolean { - L.d("Launching Image", request.url.toString()) - webCore.context.launchImageActivity(request.url.toString(), text) + private fun launchImage(url: String, text: String? = null): Boolean { + L.d("Launching Image", url) + webCore.context.launchImageActivity(url, text) if (webCore.canGoBack()) webCore.goBack() return true } override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { - L.i("Url Loading ${request.url}") - val path = request.url.path ?: return super.shouldOverrideUrlLoading(view, request) - L.v("Url Loading Path $path") + L.i("Url Loading", request.url?.toString()) + val path = request.url?.path ?: return super.shouldOverrideUrlLoading(view, request) + L.v("Url Loading Path", path) if (path.startsWith("/composer/")) return launchRequest(request) if (request.url.toString().contains("scontent-sea1-1.xx.fbcdn.net") && (path.endsWith(".jpg") || path.endsWith(".png"))) - return launchImage(request) + return launchImage(request.url.toString()) if (view.context.resolveActivityForUri(request.url)) return true return super.shouldOverrideUrlLoading(view, request) } @@ -162,6 +171,7 @@ class FrostWebViewClientMenu(webCore: FrostWebViewCore) : FrostWebViewClient(web } override fun onPageFinishedActions(url: String) { + L.d("Should inject ${url.shouldInjectMenu}") if (!url.shouldInjectMenu) injectAndFinish() } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt index d8edc15c..390055cd 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt @@ -76,7 +76,7 @@ class FrostWebViewCore @JvmOverloads constructor( if (isVisible) fadeOut(duration = 200L) } else if (loading) { dispose?.dispose() - if (animate && Prefs.animate) circularReveal(offset = 150L) + if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY) else fadeIn(duration = 100L) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt index 31be4450..aea25337 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt @@ -60,7 +60,7 @@ class LoginWebView @JvmOverloads constructor( view.jsInject(CssHider.HEADER.maybe(containsFacebook), CssHider.CORE.maybe(containsFacebook), Prefs.themeInjector.maybe(containsFacebook), - callback = { if (!view.isVisible) view.fadeIn(offset = 150L) }) + callback = { if (!view.isVisible) view.fadeIn(offset = WEB_LOAD_DELAY) }) } fun checkForLogin(url: String?, onFound: (id: Long, cookie: String) -> Unit) { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt index fb4e5bf7..f63f4fdc 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/SearchWebView.kt @@ -56,13 +56,17 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co addJavascriptInterface(SearchJSI(), "Frost") searchSubject.debounce(300, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread()) .map { - Jsoup.parse(it).select("a:not([rel*='keywords(']):not([href=#])[rel]").map { + val doc = Jsoup.parse(it) + L.d(doc.getElementById("main-search_input")?.html()) + val searchQuery = doc.getElementById("main-search-input")?.text() ?: "Null input" + L.d("Search query", searchQuery) + doc.select("a:not([rel*='keywords(']):not([href=#])[rel]").map { element -> //split text into separate items - L.v("Search element ${element.attr("href")}") + L.v("Search element", element.attr("href")) val texts = element.select("div").map { it.text() }.filter { !it.isNullOrBlank() } val pair = Pair(texts, element.attr("href")) - L.v("Search element potential $pair") + L.v("Search element potential", pair.toString()) pair }.filter { it.first.isNotEmpty() } } @@ -124,6 +128,9 @@ class SearchWebView(context: Context, val contract: SearchContract) : WebView(co searchSubject.onComplete() contract.searchOverlayDispose() } + 2 -> { + L.v("Search emission received") + } } } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt new file mode 100644 index 00000000..ad1fe467 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/WebStates.kt @@ -0,0 +1,11 @@ +package com.pitchedapps.frost.web + +/** + * Created by Allan Wang on 2017-08-08. + * + * Global variables that are define states or constants for web contents + */ +const val WEB_LOAD_DELAY = 50L +var shouldLoadImages = false + +val consoleBlacklist = setOf("edge-chat")
\ No newline at end of file diff --git a/app/src/main/res/values/strings_pref_networks.xml b/app/src/main/res/values/strings_pref_networks.xml new file mode 100644 index 00000000..29eca24a --- /dev/null +++ b/app/src/main/res/values/strings_pref_networks.xml @@ -0,0 +1,4 @@ +<resources> + <string name="network_media_on_metered">Load images on metered network.</string> + <string name="network_media_on_metered_desc">If a metered network is detected, Frost will automatically stop all images and videos from loading.</string> +</resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings_pref_notifications.xml b/app/src/main/res/values/strings_pref_notifications.xml index 00c30b57..3cd953f6 100644 --- a/app/src/main/res/values/strings_pref_notifications.xml +++ b/app/src/main/res/values/strings_pref_notifications.xml @@ -19,5 +19,4 @@ <string name="notification_vibrate">Notification vibration</string> <string name="notification_lights">Notification lights</string> - </resources>
\ No newline at end of file diff --git a/app/src/main/res/values/strings_preferences.xml b/app/src/main/res/values/strings_preferences.xml index c2ba0b36..3cacf684 100644 --- a/app/src/main/res/values/strings_preferences.xml +++ b/app/src/main/res/values/strings_preferences.xml @@ -10,6 +10,9 @@ <string name="behaviour">Behaviour</string> <string name="behaviour_desc">Define how the app interacts in certain settings</string> + <string name="network">Network</string> + <string name="network_desc">Define options that affect metered networks</string> + <string name="experimental">Experimental</string> <string name="experimental_desc">Enable early access to potentially unstable features</string> diff --git a/app/src/main/res/values/strings_temp.xml b/app/src/main/res/values/strings_temp.xml deleted file mode 100644 index 526b102d..00000000 --- a/app/src/main/res/values/strings_temp.xml +++ /dev/null @@ -1,6 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<resources> - <string name="intro_title">Frost now has an intro screen</string> - <string name="intro_desc">Would you like to see it? You can always replay it under settings</string> - -</resources>
\ No newline at end of file diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml index ddaa6312..8f0c90a8 100644 --- a/app/src/main/res/xml/frost_changelog.xml +++ b/app/src/main/res/xml/frost_changelog.xml @@ -11,9 +11,13 @@ <!--<version title="Beta Updates" />--> <version title="Beta Updates"/> - <item text="Fixed notification titles" /> - <item text="Added support for downloading videos" /> + <item text="Fix notification titles" /> + <item text="ALPHA: Add support for downloading videos (hit the download button)" /> <item text="Deny intents for login so the page loads properly (thank you @Zenexer)" /> + <item text="Reduce injection offset and move injectors to an earlier method" /> + <item text="Add option to disable media loading on metered network" /> + <item text="Fix menu section" /> + <item text="Add more background setters to help transparent themes" /> <item text="" /> <item text="" /> diff --git a/docs/Changelog.md b/docs/Changelog.md index 50154ff5..a7a855f7 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -4,6 +4,7 @@ * Fixed notification titles * Added support for downloading videos * Deny intents for login so the page loads properly (thank you @Zenexer) +* Reduce injection offset and move injectors to an earlier method ## v1.5.0 * Experimental: Add notifications for messages; report to me if this drains your battery diff --git a/gradle.properties b/gradle.properties index a1c9cab9..c0cc3b0a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -17,12 +17,12 @@ MIN_SDK=21 TARGET_SDK=26 BUILD_TOOLS=26.0.1 -KAU=3.3.0 +KAU=c2dd5d6 KOTLIN=1.1.3-2 CRASHLYTICS=2.6.8 DBFLOW=4.0.5 -IAB=1.0.43 +IAB=1.0.44 IICON_COMMUNITY=1.9.32.2 IICON_MATERIAL=2.2.0.3 JSOUP=1.10.3 @@ -35,5 +35,6 @@ RX_ANDROID=2.0.1 RX_BINDING=2.0.0 RX_JAVA=2.1.2 RX_KOTLIN=2.1.0 +RX_NETWORK=0.11.0 SCALE_IMAGE_VIEW=3.6.0 SLIDING_PANEL=3.3.1
\ No newline at end of file |