aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/kotlin/com')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt62
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostWebActivity.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt76
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt45
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt21
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt47
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt21
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebContextMenu.kt100
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt6
22 files changed, 289 insertions, 188 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
index 7aa4eac3..36809535 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
@@ -1,10 +1,10 @@
package com.pitchedapps.frost
-import android.graphics.Color
import android.support.constraint.ConstraintLayout
import android.support.constraint.ConstraintSet
import android.support.v7.widget.RecyclerView
import android.view.View
+import android.view.ViewGroup
import android.widget.ImageView
import ca.allanwang.kau.about.AboutActivityBase
import ca.allanwang.kau.adapters.FastItemThemedAdapter
@@ -12,7 +12,6 @@ import ca.allanwang.kau.adapters.ThemableIItem
import ca.allanwang.kau.adapters.ThemableIItemDelegate
import ca.allanwang.kau.iitems.LibraryIItem
import ca.allanwang.kau.utils.*
-import ca.allanwang.kau.views.createSimpleRippleDrawable
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.entity.Library
import com.mikepenz.aboutlibraries.entity.License
@@ -27,7 +26,7 @@ import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-06-26.
*/
-class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
+class AboutActivity : AboutActivityBase(null, {
textColor = Prefs.textColor
accentColor = Prefs.accentColor
backgroundColor = Prefs.bgColor.withMinAlpha(200)
@@ -37,10 +36,16 @@ class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
override fun getLibraries(libs: Libs): List<Library> {
val include = arrayOf(
- "materialdialogs",
- "kotterknife",
+ "AboutLibraries",
+ "AndroidIconics",
+ "dbflow",
+ "fastadapter",
"glide",
- "jsoup"
+ "Jsoup",
+ "kau",
+ "kotterknife",
+ "materialdialogs",
+ "materialdrawer"
)
/*
@@ -58,7 +63,7 @@ class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
"recyclerview_v7",
"support_v4"
)
- val l = libs.prepareLibraries(this, include, exclude, true, true)
+ val l = libs.prepareLibraries(this, include, null, false, true)
// l.forEach { KL.d("Lib ${it.definedName}") }
return l
}
@@ -93,7 +98,7 @@ class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
override fun bindView(holder: ViewHolder, payloads: MutableList<Any>?) {
super.bindView(holder, payloads)
with(holder) {
- bindIconColor(*icons.toTypedArray())
+ bindIconColor(*images.toTypedArray())
bindBackgroundColor(container)
}
}
@@ -101,7 +106,7 @@ class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
val container: ConstraintLayout by bindView(R.id.about_icons_container)
- val icons: List<ImageView>
+ val images: List<ImageView>
/**
* There are a lot of constraints to be added to each item just to have them chained properly
@@ -111,35 +116,28 @@ class AboutActivity : AboutActivityBase(R.string::class.java, configBuilder = {
*/
init {
val c = itemView.context
- val iconData = arrayOf<Pair<Pair<Int, IIcon>, () -> Unit>>(
- R.id.about_rate to GoogleMaterial.Icon.gmd_star to { c.startPlayStoreLink(R.string.play_store_package_id) },
- R.id.about_reddit to CommunityMaterial.Icon.cmd_reddit to { c.startLink("https://www.reddit.com/r/FrostForFacebook/") },
- R.id.about_github to CommunityMaterial.Icon.cmd_github_circle to { c.startLink("https://github.com/AllanWang/Frost-for-Facebook") }
- ).map {
- //decouple and setup, then only return the image
- (pair, onClick) ->
- val (id, icon: IIcon) = pair
- val image = itemView.findViewById<ImageView>(id)
- setup(image, icon, onClick)
- Pair(image, id)
+ val size = c.dimenPixelSize(R.dimen.kau_avatar_bounds)
+ images = arrayOf<Pair<IIcon, () -> Unit>>(
+ GoogleMaterial.Icon.gmd_star to { c.startPlayStoreLink(R.string.play_store_package_id) },
+ CommunityMaterial.Icon.cmd_reddit to { c.startLink("https://www.reddit.com/r/FrostForFacebook/") },
+ CommunityMaterial.Icon.cmd_github_circle to { c.startLink("https://github.com/AllanWang/Frost-for-Facebook") }
+ ).mapIndexed { i, (icon, onClick) ->
+ ImageView(c).apply {
+ layoutParams = ViewGroup.LayoutParams(size, size)
+ id = 109389 + i
+ setImageDrawable(icon.toDrawable(context, 32))
+ scaleType = ImageView.ScaleType.CENTER
+ background = context.resolveDrawable(android.R.attr.selectableItemBackgroundBorderless)
+ setOnClickListener({ onClick() })
+ container.addView(this)
+ }
}
- icons = iconData.map { it.first }
- val ids = iconData.map { it.second }.toIntArray()
val set = ConstraintSet()
set.clone(container)
set.createHorizontalChain(ConstraintSet.PARENT_ID, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT,
- ids, null, ConstraintSet.CHAIN_SPREAD_INSIDE)
+ images.map { it.id }.toIntArray(), null, ConstraintSet.CHAIN_SPREAD_INSIDE)
set.applyTo(container)
}
-
- fun setup(image: ImageView, icon: IIcon, onClick: () -> Unit) {
- with(image) {
- setImageDrawable(icon.toDrawable(context, 32))
- scaleType = ImageView.ScaleType.CENTER
- background = context.resolveDrawable(android.R.attr.selectableItemBackgroundBorderless)
- setOnClickListener({ onClick() })
- }
- }
}
}
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostWebActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostWebActivity.kt
index 98b5897f..3e337813 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostWebActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostWebActivity.kt
@@ -2,7 +2,6 @@ package com.pitchedapps.frost
import android.os.Bundle
import com.pitchedapps.frost.utils.Prefs
-import com.pitchedapps.frost.utils.formattedFbUrl
/**
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
index 592c3b5b..f9a597db 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
@@ -52,6 +52,7 @@ import com.pitchedapps.frost.fragments.WebFragment
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.iab.validatePro
import com.pitchedapps.frost.views.BadgedIcon
+import com.pitchedapps.frost.views.FrostViewPager
import com.pitchedapps.frost.web.FrostWebViewSearch
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
@@ -65,7 +66,7 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract,
lateinit var adapter: SectionsPagerAdapter
val toolbar: Toolbar by bindView(R.id.toolbar)
- val viewPager: ViewPager by bindView(R.id.container)
+ val viewPager: FrostViewPager by bindView(R.id.container)
val fab: FloatingActionButton by bindView(R.id.fab)
val tabs: TabLayout by bindView(R.id.tabs)
val appBar: AppBarLayout by bindView(R.id.appbar)
@@ -89,7 +90,6 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract,
get() = searchView?.isOpen ?: false
companion object {
- const val FRAGMENT_REFRESH = 99
const val ACTIVITY_SETTINGS = 97
/*
* Possible responses from the SettingsActivity
@@ -97,6 +97,7 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract,
*/
const val REQUEST_RESTART = 90909
const val REQUEST_REFRESH = 80808
+ const val REQUEST_WEB_ZOOM = 50505
const val REQUEST_NAV = 10101
const val REQUEST_SEARCH = 70707
const val REQUEST_RESTART_APPLICATION = 60606
@@ -333,7 +334,7 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract,
}
fun refreshAll() {
- webFragmentObservable.onNext(FRAGMENT_REFRESH)
+ webFragmentObservable.onNext(WebFragment.REQUEST_REFRESH)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -384,8 +385,9 @@ class MainActivity : BaseActivity(), FrostWebViewSearch.SearchContract,
if (requestCode == ACTIVITY_SETTINGS) {
when (resultCode) {
REQUEST_RESTART -> restart()
- REQUEST_REFRESH -> webFragmentObservable.onNext(FRAGMENT_REFRESH)
+ REQUEST_REFRESH -> webFragmentObservable.onNext(WebFragment.REQUEST_REFRESH)
REQUEST_NAV -> frostNavigationBar()
+ REQUEST_WEB_ZOOM -> webFragmentObservable.onNext(WebFragment.REQUEST_TEXT_ZOOM)
REQUEST_SEARCH -> invalidateOptionsMenu()
REQUEST_RESTART_APPLICATION -> { //completely restart application
L.d("Restart Application Requested")
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
index c256b674..dda6c066 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
@@ -22,6 +22,7 @@ import com.pitchedapps.frost.contracts.ActivityWebContract
import com.pitchedapps.frost.contracts.FileChooserContract
import com.pitchedapps.frost.contracts.FileChooserDelegate
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.web.FrostWebView
@@ -80,7 +81,7 @@ open class WebOverlayActivity : AppCompatActivity(),
*/
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
- val newUrl = (intent.extras?.getString(ARG_URL) ?: intent.dataString).formattedFbUrl
+ val newUrl = (intent.extras?.getString(ARG_URL) ?: intent.dataString ?: return).formattedFbUrl
L.d("New intent")
if (url != newUrl) {
this.intent = intent
@@ -143,12 +144,7 @@ open class WebOverlayActivity : AppCompatActivity(),
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_copy_link -> copyToClipboard(frostWeb.web.url)
- R.id.action_share -> {
- val intent = Intent(Intent.ACTION_SEND)
- intent.type = "text/plain"
- intent.putExtra(Intent.EXTRA_TEXT, frostWeb.web.url)
- startActivity(Intent.createChooser(intent, string(R.string.share)))
- }
+ R.id.action_share -> shareText(frostWeb.web.url)
else -> return super.onOptionsItemSelected(item)
}
return true
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
index 932324f2..901ba02d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
@@ -14,6 +14,7 @@ import com.raizlabs.android.dbflow.structure.BaseModel
import org.jetbrains.anko.doAsync
import org.jsoup.Jsoup
import paperparcel.PaperParcel
+import java.net.UnknownHostException
/**
* Created by Allan Wang on 2017-05-30.
@@ -71,7 +72,8 @@ fun CookieModel.fetchUsername(callback: (String) -> Unit) {
.get().title()
L.d("Fetch username found", result)
} catch (e: Exception) {
- L.e(e, "Fetch username failed")
+ if (e !is UnknownHostException)
+ L.e(e, "Fetch username failed")
} finally {
if (result.isBlank() && (name?.isNotBlank() ?: false)) {
callback(name!!)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
new file mode 100644
index 00000000..1090f1f3
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
@@ -0,0 +1,76 @@
+package com.pitchedapps.frost.facebook
+
+/**
+ * Created by Allan Wang on 2017-07-07.
+ *
+ * Custom url builder so we can easily test it without the Android framework
+ */
+val String.formattedFbUrl: String
+ get() = FbUrlFormatter(this).toString()
+
+class FbUrlFormatter(url: String) {
+ val queries = mutableMapOf<String, String>()
+ val cleaned: String
+
+ init {
+ var cleanedUrl = url
+ discardable.forEach { cleanedUrl = cleanedUrl.replace(it, "") }
+ decoder.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v) }
+ val qm = cleanedUrl.indexOf("?")
+ if (qm > -1) {
+ cleanedUrl.substring(qm + 1).split("&").forEach {
+ val p = it.split("=")
+ queries.put(p[0], p.elementAtOrNull(1) ?: "")
+ }
+ cleanedUrl = cleanedUrl.substring(0, qm)
+ }
+ discardableQueries.forEach { queries.remove(it) }
+ if (cleanedUrl.startsWith("#!/")) cleanedUrl = cleanedUrl.substring(2)
+ if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1)
+ cleaned = cleanedUrl
+ }
+
+ override fun toString(): String {
+ val builder = StringBuilder()
+ builder.append(cleaned)
+ if (queries.isNotEmpty()) {
+ builder.append("?")
+ queries.forEach { (k, v) -> builder.append("$k=$v&") }
+ }
+ return builder.removeSuffix("&").toString()
+ }
+
+ fun toLogList(): List<String> {
+ val list = mutableListOf(cleaned)
+ queries.forEach { (k, v) -> list.add("- $k\t=\t$v") }
+ return list
+ }
+
+ companion object {
+ /**
+ * Items here are explicitly removed from the url
+ * Taken from FaceSlim
+ * https://github.com/indywidualny/FaceSlim/blob/master/app/src/main/java/org/indywidualni/fblite/util/Miscellany.java
+ */
+ @JvmStatic val discardable = arrayOf(
+ "http://lm.facebook.com/l.php?u=",
+ "https://lm.facebook.com/l.php?u=",
+ "http://m.facebook.com/l.php?u=",
+ "https://m.facebook.com/l.php?u=",
+ "http://touch.facebook.com/l.php?u=",
+ "https://touch.facebook.com/l.php?u="
+ )
+
+ @JvmStatic val discardableQueries = arrayOf("ref", "refid")
+
+ @JvmStatic val decoder = mapOf(
+ "%3C" to "<", "%3E" to ">", "%23" to "#", "%25" to "%",
+ "%7B" to "{", "%7D" to "}", "%7C" to "|", "%5C" to "\\",
+ "%5E" to "^", "%7E" to "~", "%5B" to "[", "%5D" to "]",
+ "%60" to "`", "%3B" to ";", "%2F" to "/", "%3F" to "?",
+ "%3A" to ":", "%40" to "@", "%3D" to "=", "%26" to "&",
+ "%24" to "$", "%2B" to "+", "%22" to "\"", "%2C" to ",",
+ "%20" to " "
+ )
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt
index 764c0bc9..87afc434 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragment.kt
@@ -27,6 +27,8 @@ class WebFragment : Fragment() {
private const val ARG_URL = "arg_url"
private const val ARG_URL_ENUM = "arg_url_enum"
private const val ARG_POSITION = "arg_position"
+ const val REQUEST_TEXT_ZOOM = 17
+ const val REQUEST_REFRESH = 99
operator fun invoke(data: FbTab, position: Int) = WebFragment().withArguments(
ARG_URL to data.url,
@@ -96,7 +98,7 @@ class WebFragment : Fragment() {
* Flags between -10 and 10 are reserved for viewpager events
*/
when (it) {
- MainActivity.FRAGMENT_REFRESH -> {
+ REQUEST_REFRESH -> {
web.clearHistory()
web.loadBaseUrl(true)
}
@@ -107,6 +109,7 @@ class WebFragment : Fragment() {
-(position + 1) -> { //we are moving away from this fragment
if (!frostWebView.refresh.isRefreshing) pauseLoad = true
}
+ REQUEST_TEXT_ZOOM -> frostWebView.web.settings.textZoom = Prefs.webTextScaling
}
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
index 135e621f..68d3fbc6 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
@@ -2,6 +2,7 @@ package com.pitchedapps.frost.settings
import ca.allanwang.kau.kpref.KPrefAdapterBuilder
import ca.allanwang.kau.kpref.items.KPrefColorPicker
+import ca.allanwang.kau.kpref.items.KPrefSeekbar
import ca.allanwang.kau.utils.string
import ca.allanwang.kau.views.RippleCanvas
import com.pitchedapps.frost.MainActivity
@@ -11,6 +12,7 @@ import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import com.pitchedapps.frost.utils.iab.openPlayProPurchase
+import com.pitchedapps.frost.views.KPrefTextSeekbar
/**
* Created by Allan Wang on 2017-06-29.
@@ -119,4 +121,9 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
}) {
descRes = R.string.tint_nav_desc
}
+
+ list.add(KPrefTextSeekbar(
+ KPrefSeekbar.KPrefSeekbarBuilder(
+ globalOptions,
+ R.string.web_text_scaling, { Prefs.webTextScaling }, { Prefs.webTextScaling = it; setResult(MainActivity.REQUEST_WEB_ZOOM) })))
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt
index ae7fd061..2d121073 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt
@@ -14,6 +14,14 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = {
descRes = R.string.fancy_animations_desc
}
+ checkbox(R.string.overlay_full_screen_swipe, { Prefs.overlayFullScreenSwipe }, { Prefs.overlayFullScreenSwipe = it }) {
+ descRes = R.string.overlay_full_screen_swipe_desc
+ }
+
+ checkbox(R.string.viewpager_swipe, { Prefs.viewpagerSwipe }, { Prefs.viewpagerSwipe = it }) {
+ descRes = R.string.viewpager_swipe_desc
+ }
+
checkbox(R.string.exit_confirmation, { Prefs.exitConfirmation }, { Prefs.exitConfirmation = it }) {
descRes = R.string.exit_confirmation_desc
}
@@ -22,8 +30,4 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = {
descRes = R.string.analytics_desc
}
- checkbox(R.string.overlay_full_screen_swipe, { Prefs.overlayFullScreenSwipe }, { Prefs.overlayFullScreenSwipe = it }) {
- descRes = R.string.overlay_full_screen_swipe_desc
- }
-
}
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 7b5eca2a..95642a7a 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
@@ -71,6 +71,8 @@ object Prefs : KPref() {
var tintNavBar: Boolean by kpref("tint_nav_bar", true)
+ var webTextScaling: Int by kpref("web_text_scaling", 100)
+
var feedSort: Int by kpref("feed_sort", FeedSort.DEFAULT.ordinal)
var showRoundedIcons: Boolean by kpref("rounded_icons", true)
@@ -101,4 +103,6 @@ object Prefs : KPref() {
var overlayFullScreenSwipe: Boolean by kpref("overlay_full_screen_swipe", true)
+ var viewpagerSwipe: Boolean by kpref("viewpager_swipe", 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 9fee3571..6f3459d7 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -23,8 +23,8 @@ import com.crashlytics.android.answers.Answers
import com.crashlytics.android.answers.CustomEvent
import com.pitchedapps.frost.*
import com.pitchedapps.frost.dbflow.CookieModel
-import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.services.NotificationService
/**
@@ -51,17 +51,6 @@ fun Activity.cookies(): ArrayList<CookieModel> {
return intent?.extras?.getParcelableArrayList<CookieModel>(EXTRA_COOKIES) ?: arrayListOf()
}
-val String.formattedFbUrl: String
- get() {
- var url = this
- if (url.startsWith("#!/")) url = url.substring(2)
- if (url.startsWith('/')) url = FB_URL_BASE + url.substring(1)
- url = url.replace("/#!/", "/")
- val ref = url.indexOf("?ref")
- if (ref != -1) url = url.substring(0, ref)
- return url
- }
-
fun Context.launchWebOverlay(url: String) {
val argUrl = url.formattedFbUrl
L.v("Launch received $url")
@@ -172,4 +161,5 @@ fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {})
fun Activity.frostNavigationBar() {
navigationBarColor = if (Prefs.tintNavBar) Prefs.headerColor else Color.BLACK
-} \ No newline at end of file
+}
+
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
new file mode 100644
index 00000000..67c20a5a
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
@@ -0,0 +1,45 @@
+package com.pitchedapps.frost.utils
+
+import android.content.Context
+import ca.allanwang.kau.utils.copyToClipboard
+import ca.allanwang.kau.utils.shareText
+import ca.allanwang.kau.utils.string
+import com.pitchedapps.frost.MainActivity
+import com.pitchedapps.frost.R
+
+/**
+ * Created by Allan Wang on 2017-07-07.
+ */
+fun Context.showWebContextMenu(wc: WebContext) {
+
+ var title = wc.url
+ title = title.substring(title.indexOf("m/") + 1) //just so if defaults to 0 in case it's not .com/
+ if (title.length > 100) title = title.substring(0, 100) + '\u2026'
+
+ materialDialogThemed {
+ title(title)
+ items(WebContextType.values.map { this@showWebContextMenu.string(it.textId) })
+ itemsCallback {
+ _, _, position, _ ->
+ WebContextType[position].onClick(this@showWebContextMenu, wc)
+ }
+ dismissListener {
+ //showing the dialog interrupts the touch down event, so we must ensure that the viewpager's swipe is enabled
+ (this@showWebContextMenu as? MainActivity)?.viewPager?.enableSwipe = true
+ }
+ }
+}
+
+class WebContext(val url: String, val text: String)
+
+enum class WebContextType(val textId: Int, val onClick: (c: Context, wc: WebContext) -> Unit) {
+ COPY_LINK(R.string.copy_link, { c, wc -> c.copyToClipboard(wc.url) }),
+ COPY_TEXT(R.string.copy_text, { c, wc -> c.copyToClipboard(wc.text) }),
+ SHARE_LINK(R.string.share_link, { c, wc -> c.shareText(wc.url) })
+ ;
+
+ companion object {
+ val values = values()
+ operator fun get(index: Int) = values[index]
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt
index a2dc82f3..21326efa 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IAB.kt
@@ -170,7 +170,10 @@ fun Activity.getInventory(
helper.queryInventoryAsync {
res, inv ->
L.d("Inventory query finished")
- if (res.isFailure || inv == null) onFailed()
+ if (res.isFailure || inv == null) {
+ L.e("Res error ${res.message}")
+ onFailed()
+ }
else onSuccess(inv, helper)
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt
index c9ee5a76..0fb9dbbb 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt
@@ -5,6 +5,7 @@ import android.support.v7.widget.AppCompatTextView
import android.support.v7.widget.RecyclerView
import android.view.View
import android.widget.ImageView
+import ca.allanwang.kau.iitems.KauIItem
import ca.allanwang.kau.utils.bindView
import ca.allanwang.kau.utils.fadeIn
import ca.allanwang.kau.utils.toDrawable
@@ -15,7 +16,6 @@ import com.bumptech.glide.load.resource.bitmap.CircleCrop
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.Target
-import com.mikepenz.fastadapter.items.AbstractItem
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.pitchedapps.frost.R
import com.pitchedapps.frost.dbflow.CookieModel
@@ -25,13 +25,8 @@ import com.pitchedapps.frost.utils.Prefs
/**
* Created by Allan Wang on 2017-06-05.
*/
-class AccountItem(val cookie: CookieModel?) : AbstractItem<AccountItem, AccountItem.ViewHolder>() {
-
- override fun getType(): Int = R.id.item_account
-
- override fun getViewHolder(v: View) = ViewHolder(v)
-
- override fun getLayoutRes(): Int = R.layout.view_account
+class AccountItem(val cookie: CookieModel?) : KauIItem<AccountItem, AccountItem.ViewHolder>
+(R.layout.view_account, { ViewHolder(it) }, R.id.item_account) {
override fun bindView(viewHolder: ViewHolder, payloads: List<Any>?) {
super.bindView(viewHolder, payloads)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt
new file mode 100644
index 00000000..b856f973
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt
@@ -0,0 +1,21 @@
+package com.pitchedapps.frost.views
+
+import android.content.Context
+import android.support.v4.view.ViewPager
+import android.util.AttributeSet
+import android.view.MotionEvent
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
+
+/**
+ * Created by Allan Wang on 2017-07-07.
+ *
+ * Basic override to allow us to control swiping
+ */
+class FrostViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(context, attrs) {
+ var enableSwipe = true
+
+ override fun onInterceptTouchEvent(ev: MotionEvent?) = Prefs.viewpagerSwipe && enableSwipe && super.onInterceptTouchEvent(ev)
+
+ override fun onTouchEvent(ev: MotionEvent?): Boolean = Prefs.viewpagerSwipe && enableSwipe && super.onTouchEvent(ev)
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt
new file mode 100644
index 00000000..1d8f308d
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt
@@ -0,0 +1,47 @@
+package com.pitchedapps.frost.views
+
+import android.annotation.SuppressLint
+import android.util.TypedValue
+import ca.allanwang.kau.kpref.items.KPrefSeekbar
+import com.pitchedapps.frost.R
+
+/**
+ * Created by Allan Wang on 2017-07-07.
+ */
+class KPrefTextSeekbar(builder: KPrefSeekbarContract) : KPrefSeekbar(builder) {
+
+ var descOriginalSize = 1f
+
+ init {
+ with(builder) {
+ min = 50
+ max = 200
+ descRes = R.string.web_text_scaling_desc
+ textViewConfigs = {
+ minEms = 2
+ setOnLongClickListener {
+ pref = 100
+ reloadSelf()
+ true
+ }
+ }
+ }
+ }
+
+ @SuppressLint("MissingSuperCall")
+ override fun onPostBindView(viewHolder: ViewHolder, textColor: Int?, accentColor: Int?) {
+ descOriginalSize = viewHolder.desc?.textSize ?: 1f
+ viewHolder.desc?.layoutParams
+ builder.toText = {
+ viewHolder.desc?.setTextSize(TypedValue.COMPLEX_UNIT_PX, descOriginalSize * it.toFloat() / 100)
+ "$it%"
+ }
+
+ super.onPostBindView(viewHolder, textColor, accentColor)
+ }
+
+ override fun unbindView(holder: ViewHolder) {
+ holder.desc?.setTextSize(TypedValue.COMPLEX_UNIT_PX, descOriginalSize)
+ super.unbindView(holder)
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
index 68163333..3340e7d2 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt
@@ -2,8 +2,10 @@ package com.pitchedapps.frost.web
import android.content.Context
import android.webkit.JavascriptInterface
+import ca.allanwang.kau.logging.KL
import com.pitchedapps.frost.MainActivity
import com.pitchedapps.frost.dbflow.CookieModel
+import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.utils.*
import io.reactivex.subjects.Subject
@@ -11,7 +13,7 @@ import io.reactivex.subjects.Subject
/**
* Created by Allan Wang on 2017-06-01.
*/
-class FrostJSI(val context: Context, val webView: FrostWebViewCore, val contextMenu: FrostWebContextMenu) {
+class FrostJSI(val context: Context, val webView: FrostWebViewCore) {
val headerObservable: Subject<String>? = (context as? MainActivity)?.headerBadgeObservable
@@ -33,8 +35,17 @@ class FrostJSI(val context: Context, val webView: FrostWebViewCore, val contextM
}
@JavascriptInterface
- fun contextMenu(url: String) {
- contextMenu.post { contextMenu.show(url) }
+ fun contextMenu(url: String, text: String) {
+ webView.post { webView.context.showWebContextMenu(WebContext(url.formattedFbUrl, text)) }
+ }
+
+ /**
+ * Get notified when a stationary long click starts or ends
+ * This will be used to toggle the main activities viewpager swipe
+ */
+ @JavascriptInterface
+ fun longClick(start: Boolean) {
+ (webView.context as? MainActivity)?.viewPager?.enableSwipe = !start
}
@JavascriptInterface
@@ -44,12 +55,12 @@ class FrostJSI(val context: Context, val webView: FrostWebViewCore, val contextM
@JavascriptInterface
fun emit(flag: Int) {
- webView.post { webView.frostWebClient!!.emit(flag) }
+ webView.post { webView.frostWebClient.emit(flag) }
}
@JavascriptInterface
fun handleHtml(html: String) {
- webView.post { webView.frostWebClient!!.handleHtml(html) }
+ webView.post { webView.frostWebClient.handleHtml(html) }
}
@JavascriptInterface
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebContextMenu.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebContextMenu.kt
deleted file mode 100644
index e0aa5ebd..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebContextMenu.kt
+++ /dev/null
@@ -1,100 +0,0 @@
-package com.pitchedapps.frost.web
-
-import android.content.Context
-import android.support.constraint.ConstraintLayout
-import android.support.constraint.ConstraintSet
-import android.text.method.ScrollingMovementMethod
-import android.util.AttributeSet
-import android.widget.TextView
-import ca.allanwang.kau.logging.KL
-import ca.allanwang.kau.utils.*
-import com.pitchedapps.frost.R
-import com.pitchedapps.frost.utils.Prefs
-
-/**
- * Created by Allan Wang on 2017-07-06.
- */
-class FrostWebContextMenu @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
-) : ConstraintLayout(context, attrs, defStyleAttr) {
-
- var url = ""
-
- val urlHolder = TextView(context, attrs, defStyleAttr)
-
- init {
- layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
- elevation = 20f
- setBackgroundColor(0x80000000.toInt())
- gone()
-
- val tc = Prefs.textColor
- val bg = Prefs.bgColor.colorToForeground(0.1f).withAlpha(255)
-
- urlHolder.apply {
- isVerticalScrollBarEnabled = true
- movementMethod = ScrollingMovementMethod()
- maxHeight = 60.dpToPx
- }
- addView(urlHolder)
-
- //collection of items in our menu and their click event
- val data = arrayOf(
- R.string.copy_link to { context.copyToClipboard(url) }
- )
-
- //add views and extract ids
- val views = data.map {
- (textId, onClick) ->
- val tv = TextView(context).apply {
- text = context.string(textId)
- setOnClickListener({ onClick(); close() })
- }
- addView(tv)
- tv
- }.toMutableList()
-
- views.add(0, urlHolder)
-
- val ids = views.mapIndexed { index, textView ->
- textView.apply {
- id = 74329 + index //totally arbitrary
- setTextColor(tc)
- setBackgroundColor(bg)
- }
- KL.d("ID ${textView.text}")
- textView.id
- }
-
- //clone to set only after ids are set
- val set = ConstraintSet()
- set.clone(this)
-
- ids.forEach {
- set.connect(it, ConstraintSet.START, ConstraintSet.PARENT_ID, ConstraintSet.START, 16)
- set.connect(it, ConstraintSet.END, ConstraintSet.PARENT_ID, ConstraintSet.END, 16)
- }
-
-
- set.createVerticalChain(ConstraintSet.PARENT_ID, ConstraintSet.TOP, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM,
- ids.toIntArray(), null, ConstraintSet.CHAIN_PACKED)
-
- set.applyTo(this)
- setOnClickListener {
- close()
- }
- }
-
- fun close() {
- transitionAuto()
- gone()
- }
-
- fun show(url: String) {
- this.url = url
- urlHolder.text = this.url
- transitionAuto()
- visible()
- }
-
-} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
index 64bdf888..5583c63d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
@@ -28,7 +28,6 @@ class FrostWebView @JvmOverloads constructor(
val refresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh)
val web: FrostWebViewCore by bindView(R.id.frost_webview_core)
val progress: ProgressBar by bindView(R.id.progress_bar)
- val contextMenu: FrostWebContextMenu by bindView(R.id.context_menu)
init {
inflate(getContext(), R.layout.swipe_webview, this)
@@ -55,7 +54,7 @@ class FrostWebView @JvmOverloads constructor(
@SuppressLint("SetJavaScriptEnabled")
fun setupWebview(url: String, enum: FbTab? = null) {
- with (web) {
+ with(web) {
baseUrl = url
baseEnum = enum
with(settings) {
@@ -63,12 +62,13 @@ class FrostWebView @JvmOverloads constructor(
userAgentString = com.pitchedapps.frost.facebook.USER_AGENT_BASIC
allowFileAccess = true
defaultFontSize
+ textZoom = Prefs.webTextScaling
}
setLayerType(View.LAYER_TYPE_HARDWARE, null)
frostWebClient = baseEnum?.webClient?.invoke(this) ?: FrostWebViewClient(this)
webViewClient = frostWebClient
webChromeClient = FrostChromeClient(this)
- addJavascriptInterface(FrostJSI(context, this, contextMenu), "Frost")
+ addJavascriptInterface(FrostJSI(context, this), "Frost")
setBackgroundColor(Color.TRANSPARENT)
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
index 4484dcdb..16a4a092 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
@@ -62,7 +62,7 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : WebViewClient() {
webCore.jsInject(CssHider.HEADER,
Prefs.themeInjector,
JsAssets.CLICK_A.maybe(webCore.baseEnum != null),
-// JsAssets.CONTEXT_A,
+ JsAssets.CONTEXT_A,
callback = { refreshObservable.onNext(false) })
}
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 76b04f23..1e023dca 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt
@@ -1,15 +1,12 @@
package com.pitchedapps.frost.web
import android.animation.ValueAnimator
-import android.annotation.SuppressLint
import android.content.Context
-import android.graphics.Color
import android.support.v4.view.NestedScrollingChild
import android.support.v4.view.NestedScrollingChildHelper
import android.support.v4.view.ViewCompat
import android.util.AttributeSet
import android.view.MotionEvent
-import android.view.View
import android.view.animation.DecelerateInterpolator
import android.webkit.WebView
import ca.allanwang.kau.utils.circularReveal
@@ -17,7 +14,6 @@ import ca.allanwang.kau.utils.fadeIn
import ca.allanwang.kau.utils.fadeOut
import ca.allanwang.kau.utils.isVisible
import com.pitchedapps.frost.facebook.FbTab
-import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
import com.pitchedapps.frost.utils.Prefs
import io.reactivex.Scheduler
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -45,7 +41,7 @@ class FrostWebViewCore @JvmOverloads constructor(
var baseUrl: String? = null
var baseEnum: FbTab? = null //only viewpager items should pass the base enum
- internal var frostWebClient: FrostWebViewClient? = null
+ internal lateinit var frostWebClient: FrostWebViewClient
init {
isNestedScrollingEnabled = true
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt
index fb2e1851..d4d08958 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt
@@ -14,6 +14,7 @@ import com.pitchedapps.frost.injectors.JsAssets
import com.pitchedapps.frost.injectors.JsBuilder
import com.pitchedapps.frost.injectors.jsInject
import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
import io.reactivex.schedulers.Schedulers
import io.reactivex.subjects.PublishSubject
import org.jetbrains.anko.runOnUiThread
@@ -62,10 +63,10 @@ class FrostWebViewSearch(context: Context, val contract: SearchContract) : WebVi
Jsoup.parse(it).select("a:not([rel*='keywords(']):not([href=#])[rel]").map {
element ->
//split text into separate items
- L.i("Search element ${element.attr("href")}")
+ L.v("Search element ${element.attr("href")}")
val texts = element.select("div").map { (it.ownText()) }.filter { it.isNotBlank() }
val pair = Pair(texts, element.attr("href"))
- L.i("Search element potential $pair")
+ L.v("Search element potential $pair")
pair
}.filter { it.first.isNotEmpty() }
}
@@ -135,6 +136,7 @@ class FrostWebViewSearch(context: Context, val contract: SearchContract) : WebVi
}
1 -> { //something is not found in the search view; this is effectively useless
L.eThrow("Search subject error; reverting to full overlay")
+ Prefs.searchBar = false
searchSubject.onComplete()
contract.searchOverlayDispose()
}