aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-12-11 17:52:24 -0500
committerGitHub <noreply@github.com>2017-12-11 17:52:24 -0500
commitdb262e95779e0a17275bdb94be2b0ac12819178e (patch)
tree42b89edf8796e85e362ca86dead1170cb38f6434 /app/src/main/kotlin
parent1d4380cee77fc049a54d280a27dcefa3fa6ff1fd (diff)
downloadfrost-db262e95779e0a17275bdb94be2b0ac12819178e.tar.gz
frost-db262e95779e0a17275bdb94be2b0ac12819178e.tar.bz2
frost-db262e95779e0a17275bdb94be2b0ac12819178e.zip
Feature/tab customization (#522)
* Add initial tab customizing view * Add rest of content for now * Delete project file backups * Stash * Support full tab customization * Test activity animations * Update kau and fix sound uri * Try catch download, resolves #523
Diffstat (limited to 'app/src/main/kotlin')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt34
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt131
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt7
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt52
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt23
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt17
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt19
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt12
19 files changed, 304 insertions, 59 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
index 8c70f5f2..9888c377 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
@@ -1,10 +1,12 @@
package com.pitchedapps.frost
+import android.content.Context
import android.os.Bundle
import ca.allanwang.kau.internal.KauBaseActivity
import com.pitchedapps.frost.activities.LoginActivity
import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.activities.SelectorActivity
+import com.pitchedapps.frost.activities.TabCustomizerActivity
import com.pitchedapps.frost.dbflow.loadFbCookiesAsync
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.utils.L
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 97afd480..6ab65399 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
@@ -2,6 +2,7 @@ package com.pitchedapps.frost.activities
import android.content.res.Configuration
import android.os.Bundle
+import android.transition.Fade
import ca.allanwang.kau.internal.KauBaseActivity
import ca.allanwang.kau.searchview.SearchViewHolder
import com.pitchedapps.frost.contracts.VideoViewHolder
@@ -28,6 +29,7 @@ abstract class BaseActivity : KauBaseActivity() {
super.onCreate(savedInstanceState)
if (this !is WebOverlayActivityBase) setFrostTheme()
}
+
//
// private var networkDisposable: Disposable? = null
// private var networkConsumer: ((Connectivity) -> Unit)? = null
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 57cda44a..1ba7f4c3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
@@ -49,6 +49,7 @@ import com.pitchedapps.frost.contracts.ActivityWebContract
import com.pitchedapps.frost.contracts.FileChooserContract
import com.pitchedapps.frost.contracts.FileChooserDelegate
import com.pitchedapps.frost.contracts.VideoViewHolder
+import com.pitchedapps.frost.dbflow.TAB_COUNT
import com.pitchedapps.frost.dbflow.loadFbCookie
import com.pitchedapps.frost.dbflow.loadFbTabs
import com.pitchedapps.frost.enums.MainActivityLayout
@@ -134,7 +135,7 @@ class MainActivity : BaseActivity(),
setSupportActionBar(toolbar)
adapter = SectionsPagerAdapter(supportFragmentManager, loadFbTabs())
viewPager.adapter = adapter
- viewPager.offscreenPageLimit = 5
+ viewPager.offscreenPageLimit = TAB_COUNT
viewPager.addOnPageChangeListener(object : ViewPager.SimpleOnPageChangeListener() {
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
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 293be694..f17ccf20 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
@@ -37,10 +37,16 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() {
private const val REQUEST_RINGTONE = 0b10111 shl 5
const val REQUEST_NOTIFICATION_RINGTONE = REQUEST_RINGTONE or 1
const val REQUEST_MESSAGE_RINGTONE = REQUEST_RINGTONE or 2
+ const val ACTIVITY_REQUEST_TABS = 29
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (fetchRingtone(requestCode, resultCode, data)) return
+ if (requestCode == ACTIVITY_REQUEST_TABS) {
+ if (resultCode == Activity.RESULT_OK)
+ shouldRestartMain()
+ return
+ }
if (!onActivityResultBilling(requestCode, resultCode, data))
super.onActivityResult(requestCode, resultCode, data)
reloadList()
@@ -52,14 +58,22 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() {
*/
private fun fetchRingtone(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
if (requestCode and REQUEST_RINGTONE != REQUEST_RINGTONE || resultCode != Activity.RESULT_OK) return false
- val uri: String = data?.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)?.toString() ?: ""
+ val uri = data?.getParcelableExtra<Uri>(RingtoneManager.EXTRA_RINGTONE_PICKED_URI)
+ val uriString: String = uri?.toString() ?: ""
+ if (uri != null) {
+ try {
+ grantUriPermission("com.android.systemui", uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ } catch (e: Exception) {
+ L.e(e, "grantUriPermission")
+ }
+ }
when (requestCode) {
REQUEST_NOTIFICATION_RINGTONE -> {
- Prefs.notificationRingtone = uri
+ Prefs.notificationRingtone = uriString
reloadByTitle(R.string.notification_ringtone)
}
REQUEST_MESSAGE_RINGTONE -> {
- Prefs.messageRingtone = uri
+ Prefs.messageRingtone = uriString
reloadByTitle(R.string.message_ringtone)
}
}
@@ -106,24 +120,28 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() {
descRes = R.string.get_pro_desc
iicon = GoogleMaterial.Icon.gmd_star
visible = { !IS_FROST_PRO }
- onClick = { _, _, _ -> restorePurchases(); true }
+ onClick = { restorePurchases() }
}
plainText(R.string.about_frost) {
descRes = R.string.about_frost_desc
iicon = GoogleMaterial.Icon.gmd_info
- onClick = { _, _, _ -> startActivityForResult(AboutActivity::class.java, 9, true); true }
+ onClick = {
+ startActivityForResult(AboutActivity::class.java, 9, bundleBuilder = {
+ withSceneTransitionAnimation(this@SettingsActivity)
+ })
+ }
}
plainText(R.string.help_translate) {
descRes = R.string.help_translate_desc
iicon = GoogleMaterial.Icon.gmd_translate
- onClick = { _, _, _ -> startLink(R.string.translation_url); true }
+ onClick = { startLink(R.string.translation_url) }
}
plainText(R.string.replay_intro) {
iicon = GoogleMaterial.Icon.gmd_replay
- onClick = { _, _, _ -> launchIntroActivity(cookies()); true }
+ onClick = { launchIntroActivity(cookies()) }
}
subItems(R.string.debug_frost, getDebugPrefs()) {
@@ -138,7 +156,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IabSettings() {
}
fun KPrefItemBase.BaseContract<*>.dependsOnPro() {
- onDisabledClick = { _, _, _ -> purchasePro(); true }
+ onDisabledClick = { purchasePro() }
enabler = { IS_FROST_PRO }
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
new file mode 100644
index 00000000..bac352af
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt
@@ -0,0 +1,131 @@
+package com.pitchedapps.frost.activities
+
+import android.app.Activity
+import android.content.res.ColorStateList
+import android.os.Bundle
+import android.support.design.widget.FloatingActionButton
+import android.support.v7.widget.GridLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.support.v7.widget.helper.ItemTouchHelper
+import android.view.View
+import android.view.animation.AnimationUtils
+import android.widget.TextView
+import ca.allanwang.kau.kotlin.lazyContext
+import ca.allanwang.kau.utils.bindView
+import ca.allanwang.kau.utils.scaleXY
+import ca.allanwang.kau.utils.setIcon
+import ca.allanwang.kau.utils.withAlpha
+import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter
+import com.mikepenz.fastadapter_extensions.drag.ItemTouchCallback
+import com.mikepenz.fastadapter_extensions.drag.SimpleDragCallback
+import com.mikepenz.google_material_typeface_library.GoogleMaterial
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.dbflow.TAB_COUNT
+import com.pitchedapps.frost.dbflow.loadFbTabs
+import com.pitchedapps.frost.dbflow.save
+import com.pitchedapps.frost.facebook.FbItem
+import com.pitchedapps.frost.iitems.TabIItem
+import com.pitchedapps.frost.utils.Prefs
+import com.pitchedapps.frost.utils.setFrostColors
+import java.util.*
+
+/**
+ * Created by Allan Wang on 26/11/17.
+ */
+class TabCustomizerActivity : BaseActivity() {
+
+ val toolbar: View by bindView(R.id.pseudo_toolbar)
+ val recycler: RecyclerView by bindView(R.id.tab_recycler)
+ val instructions: TextView by bindView(R.id.instructions)
+ val divider: View by bindView(R.id.divider)
+ val adapter = FastItemAdapter<TabIItem>()
+ val fabCancel: FloatingActionButton by bindView(R.id.fab_cancel)
+ val fabSave: FloatingActionButton by bindView(R.id.fab_save)
+
+ private val wobble = lazyContext { AnimationUtils.loadAnimation(it, R.anim.rotate_delta) }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setContentView(R.layout.activity_tab_customizer)
+
+ toolbar.setBackgroundColor(Prefs.headerColor)
+
+ recycler.layoutManager = GridLayoutManager(this, TAB_COUNT, GridLayoutManager.VERTICAL, false)
+ recycler.adapter = adapter
+ recycler.setHasFixedSize(true)
+
+ divider.setBackgroundColor(Prefs.textColor.withAlpha(30))
+ instructions.setTextColor(Prefs.textColor)
+
+ val tabs = loadFbTabs().toMutableList()
+ val remaining = FbItem.values().toMutableList()
+ remaining.removeAll(tabs)
+ tabs.addAll(remaining)
+
+ adapter.add(tabs.map(::TabIItem))
+ bindSwapper(adapter, recycler)
+
+ adapter.withOnClickListener { view, _, _, _ -> view.wobble(); true }
+
+ setResult(Activity.RESULT_CANCELED)
+
+ fabSave.setIcon(GoogleMaterial.Icon.gmd_check, Prefs.iconColor)
+ fabSave.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor)
+ fabSave.setOnClickListener {
+ adapter.adapterItems.subList(0, TAB_COUNT).map(TabIItem::item).save()
+ setResult(Activity.RESULT_OK)
+ finish()
+ }
+ fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, Prefs.iconColor)
+ fabCancel.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor)
+ fabCancel.setOnClickListener { finish() }
+ setFrostColors(themeWindow = true)
+ }
+
+ private fun View.wobble() = startAnimation(wobble(context))
+
+ private fun bindSwapper(adapter: FastItemAdapter<*>, recycler: RecyclerView) {
+ val dragCallback = TabDragCallback(SimpleDragCallback.ALL, swapper(adapter))
+ ItemTouchHelper(dragCallback).attachToRecyclerView(recycler)
+ }
+
+ private fun swapper(adapter: FastItemAdapter<*>) = object : ItemTouchCallback {
+ override fun itemTouchOnMove(oldPosition: Int, newPosition: Int): Boolean {
+ Collections.swap(adapter.adapterItems, oldPosition, newPosition)
+ adapter.notifyAdapterDataSetChanged()
+ return true
+ }
+
+ override fun itemTouchDropped(oldPosition: Int, newPosition: Int) = Unit
+ }
+
+
+ private class TabDragCallback(
+ directions: Int, itemTouchCallback: ItemTouchCallback
+ ) : SimpleDragCallback(directions, itemTouchCallback) {
+
+ private var draggingView: TabIItem.ViewHolder? = null
+
+ override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
+ super.onSelectedChanged(viewHolder, actionState)
+ when (actionState) {
+ ItemTouchHelper.ACTION_STATE_DRAG -> {
+ (viewHolder as? TabIItem.ViewHolder)?.apply {
+ draggingView = this
+ itemView.animate().scaleXY(1.3f)
+ text.animate().alpha(0f)
+ }
+ }
+ ItemTouchHelper.ACTION_STATE_IDLE -> {
+ draggingView?.apply {
+ itemView.animate().scaleXY(1f)
+ text.animate().alpha(1f)
+ }
+ draggingView = null
+ }
+ }
+ }
+
+ }
+
+}
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 ff46856c..762dd4c1 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt
@@ -52,10 +52,10 @@ fun loadFbCookiesAsync(callback: (cookies: List<CookieModel>) -> Unit) {
fun loadFbCookiesSync(): List<CookieModel> = (select from CookieModel::class).orderBy(CookieModel_Table.name, true).queryList()
-fun saveFbCookie(cookie: CookieModel, callback: (() -> Unit)? = null) {
+inline fun saveFbCookie(cookie: CookieModel, crossinline callback: (() -> Unit) = {}) {
cookie.async save {
L.d("Fb cookie saved", cookie.toString())
- callback?.invoke()
+ callback()
}
}
@@ -65,7 +65,7 @@ fun removeCookie(id: Long) {
}
}
-fun CookieModel.fetchUsername(callback: (String) -> Unit) {
+inline fun CookieModel.fetchUsername(crossinline callback: (String) -> Unit) {
ReactiveNetwork.checkInternetConnectivity().subscribeOn(Schedulers.io()).subscribe { yes, _ ->
if (!yes) return@subscribe callback("")
var result = ""
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
index 7fc56af0..18f0e2e8 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt
@@ -6,13 +6,16 @@ import com.pitchedapps.frost.utils.L
import com.raizlabs.android.dbflow.annotation.Database
import com.raizlabs.android.dbflow.annotation.PrimaryKey
import com.raizlabs.android.dbflow.annotation.Table
+import com.raizlabs.android.dbflow.kotlinextensions.database
+import com.raizlabs.android.dbflow.kotlinextensions.fastSave
import com.raizlabs.android.dbflow.kotlinextensions.from
-import com.raizlabs.android.dbflow.sql.language.SQLite
+import com.raizlabs.android.dbflow.kotlinextensions.select
import com.raizlabs.android.dbflow.structure.BaseModel
/**
* Created by Allan Wang on 2017-05-30.
*/
+const val TAB_COUNT = 4
@Database(version = FbTabsDb.VERSION)
object FbTabsDb {
@@ -23,13 +26,17 @@ object FbTabsDb {
@Table(database = FbTabsDb::class, allFields = true)
data class FbTabModel(@PrimaryKey var position: Int = -1, var tab: FbItem = FbItem.FEED) : BaseModel()
+/**
+ * Load tabs synchronously
+ * Note that tab length should never be a big number anyways
+ */
fun loadFbTabs(): List<FbItem> {
- val tabs: List<FbTabModel>? = SQLite.select().from(FbTabModel::class).orderBy(FbTabModel_Table.position, true).queryList()
- if (tabs?.isNotEmpty() ?: false) return tabs!!.map { it.tab }
- L.d("No tabs; loading default")
+ val tabs: List<FbTabModel>? = (select from (FbTabModel::class)).orderBy(FbTabModel_Table.position, true).queryList()
+ if (tabs?.size == TAB_COUNT) return tabs.map(FbTabModel::tab)
+ L.d("No tabs (${tabs?.size}); loading default")
return defaultTabs()
}
-fun List<FbItem>.saveAsync() {
- mapIndexed { index, fbTab -> FbTabModel(index, fbTab) }.replace(FbTabsDb.NAME)
+fun List<FbItem>.save() {
+ database<FbTabsDb>().beginTransactionAsync(mapIndexed(::FbTabModel).fastSave().build()).execute()
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt
index 2f478d44..27479691 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt
@@ -10,7 +10,12 @@ import com.pitchedapps.frost.web.FrostWebViewClient
import com.pitchedapps.frost.web.FrostWebViewClientMenu
import com.pitchedapps.frost.web.FrostWebViewCore
-enum class FbItem(@StringRes val titleId: Int, val icon: IIcon, relativeUrl: String, val webClient: ((webCore: FrostWebViewCore) -> FrostWebViewClient)? = null) {
+enum class FbItem(
+ @StringRes val titleId: Int,
+ val icon: IIcon,
+ relativeUrl: String,
+ val webClient: ((webCore: FrostWebViewCore) -> FrostWebViewClient)? = null
+) {
ACTIVITY_LOG(R.string.activity_log, GoogleMaterial.Icon.gmd_list, "me/allactivity"),
BIRTHDAYS(R.string.birthdays, GoogleMaterial.Icon.gmd_cake, "events/birthdays"),
CHAT(R.string.chat, GoogleMaterial.Icon.gmd_chat, "buddylist"),
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt
new file mode 100644
index 00000000..73d80538
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt
@@ -0,0 +1,52 @@
+package com.pitchedapps.frost.iitems
+
+import android.graphics.Color
+import android.view.View
+import android.widget.ImageView
+import android.widget.TextView
+import ca.allanwang.kau.iitems.KauIItem
+import ca.allanwang.kau.utils.*
+import com.mikepenz.fastadapter.FastAdapter
+import com.mikepenz.fastadapter.IItem
+import com.mikepenz.fastadapter_extensions.drag.IDraggable
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.facebook.FbItem
+import com.pitchedapps.frost.utils.L
+import com.pitchedapps.frost.utils.Prefs
+
+/**
+ * Created by Allan Wang on 26/11/17.
+ */
+class TabIItem(val item: FbItem) : KauIItem<TabIItem, TabIItem.ViewHolder>(
+ R.layout.iitem_tab_preview,
+ { ViewHolder(it) }
+), IDraggable<TabIItem, IItem<*, *>> {
+
+ override fun withIsDraggable(draggable: Boolean): TabIItem = this
+
+ override fun isDraggable() = true
+
+ class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TabIItem>(itemView) {
+
+ val image: ImageView by bindView(R.id.image)
+ val text: TextView by bindView(R.id.text)
+
+ override fun bindView(item: TabIItem, payloads: MutableList<Any>) {
+ val isInToolbar = adapterPosition < 4
+ val color = if (isInToolbar) Prefs.iconColor else Prefs.textColor
+ image.setIcon(item.item.icon, 20, color)
+ if (isInToolbar)
+ text.invisible()
+ else {
+ text.visible().setText(item.item.titleId)
+ text.setTextColor(color.withAlpha(200))
+ }
+ }
+
+ override fun unbindView(item: TabIItem) {
+ image.setImageDrawable(null)
+ text.visible().text = null
+ }
+
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt
index 5b26ebac..de268360 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt
@@ -21,7 +21,10 @@ enum class CssHider(vararg val items: String) : InjectorContract {
NON_RECENT("article:not([data-store*=actor_name])")
;
- val injector: JsInjector by lazy { JsBuilder().css("${items.joinToString(separator = ",")}{display:none!important}").build() }
+ val injector: JsInjector by lazy {
+ JsBuilder().css("${items.joinToString(separator = ",")}{display:none !important}")
+ .single(name).build()
+ }
override fun inject(webView: WebView, callback: ((String) -> Unit)?) {
injector.inject(webView, callback)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt
index 0e46225c..beb60293 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt
@@ -19,7 +19,7 @@ enum class JsAssets : InjectorContract {
var injector = lazyContext {
try {
val content = it.assets.open("js/$file").bufferedReader().use { it.readText() }
- JsBuilder().js(singleInjector(content)).build()
+ JsBuilder().js(content).single(name).build()
} catch (e: FileNotFoundException) {
L.e(e, "JsAssets file not found")
JsInjector(JsActions.EMPTY.function)
@@ -30,12 +30,4 @@ enum class JsAssets : InjectorContract {
injector(webView.context).inject(webView, callback)
}
- private fun singleInjector(content: String) = StringBuilder().apply {
- val name = "_frost_$name"
- append("if (!window.hasOwnProperty(\"$name\")) {")
- append("console.log(\"Registering $name\");")
- append("window.$name = true;")
- append(content)
- append("}")
- }.toString()
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
index a29ff55e..4fed2db9 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt
@@ -7,11 +7,14 @@ import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.subjects.SingleSubject
import org.apache.commons.text.StringEscapeUtils
+import java.util.*
class JsBuilder {
private val css = StringBuilder()
private val js = StringBuilder()
+ private var tag: String? = null
+
fun css(css: String): JsBuilder {
this.css.append(StringEscapeUtils.escapeEcmaScript(css))
return this
@@ -22,6 +25,11 @@ class JsBuilder {
return this
}
+ fun single(tag: String): JsBuilder {
+ this.tag = tag
+ return this
+ }
+
fun build() = JsInjector(toString())
override fun toString(): String {
@@ -32,8 +40,19 @@ class JsBuilder {
}
if (js.isNotBlank())
builder.append(js)
- return builder.append("}()").toString()
+ var content = builder.append("}()").toString()
+ if (tag != null) content = singleInjector(tag!!, content)
+ return content
}
+
+ private fun singleInjector(tag: String, content: String) = StringBuilder().apply {
+ val name = "_frost_${tag.toLowerCase(Locale.CANADA)}"
+ append("if (!window.hasOwnProperty(\"$name\")) {")
+ append("console.log(\"Registering $name\");")
+ append("window.$name = true;")
+ append(content)
+ append("}")
+ }.toString()
}
/**
@@ -72,4 +91,4 @@ class JsInjector(val function: String) : InjectorContract {
override fun inject(webView: WebView, callback: ((String) -> Unit)?) {
webView.evaluateJavascript(function, { value -> callback?.invoke(value) })
}
-}
+} \ No newline at end of file
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 382b2dad..2c229830 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
@@ -23,7 +23,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
header(R.string.theme_customization)
text(R.string.theme, { Prefs.theme }, { Prefs.theme = it }) {
- onClick = { _, _, item ->
+ onClick = {
materialDialogThemed {
title(R.string.theme)
items(Theme.values()
@@ -46,7 +46,6 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
true
}
}
- true
}
textGetter = {
string(Theme(it).textRes)
@@ -55,12 +54,12 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
fun KPrefColorPicker.KPrefColorContract.dependsOnCustom() {
enabler = { Prefs.isCustomTheme }
- onDisabledClick = { _, _, _ -> frostSnackbar(R.string.requires_custom_theme); true }
+ onDisabledClick = { frostSnackbar(R.string.requires_custom_theme) }
allowCustom = true
}
fun invalidateCustomTheme() {
- CssAssets.CUSTOM.injector = null
+ CssAssets.CUSTOM.injector.invalidate()
}
colorPicker(R.string.text_color, { Prefs.customTextColor }, {
@@ -119,9 +118,9 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
text(R.string.main_activity_layout, { Prefs.mainActivityLayoutType }, { Prefs.mainActivityLayoutType = it }) {
textGetter = { string(Prefs.mainActivityLayout.titleRes) }
- onClick = { _, _, item ->
+ onClick = {
materialDialogThemed {
- title(R.string.set_main_activity_layout)
+ title(R.string.main_activity_layout_desc)
items(MainActivityLayout.values.map { string(it.titleRes) })
itemsCallbackSingleChoice(item.pref) { _, _, which, _ ->
if (item.pref != which) {
@@ -132,10 +131,14 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
true
}
}
- true
}
}
+ plainText(R.string.main_tabs) {
+ descRes = R.string.main_tabs_desc
+ onClick = { launchTabCustomizerActivity() }
+ }
+
checkbox(R.string.rounded_icons, { Prefs.showRoundedIcons }, {
Prefs.showRoundedIcons = it
setFrostResult(MainActivity.REQUEST_REFRESH)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt
index fc008765..60397158 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt
@@ -36,7 +36,7 @@ fun SettingsActivity.getDebugPrefs(): KPrefAdapterBuilder.() -> Unit = {
Debugger.values().forEach {
plainText(it.data.titleId) {
iicon = it.data.icon
- onClick = { itemView, _, _ -> it.debug(itemView.context); true }
+ onClick = { it.debug(itemView.context) }
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
index aad2fe9a..ed011af9 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
@@ -39,10 +39,9 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = {
plainText(R.string.restart_frost) {
descRes = R.string.restart_frost_desc
- onClick = { _, _, _ ->
+ onClick = {
setFrostResult(MainActivity.REQUEST_RESTART_APPLICATION)
finish()
- true
}
}
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt
index e3a0872a..2a0f913c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt
@@ -7,7 +7,6 @@ import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.activities.SettingsActivity
import com.pitchedapps.frost.enums.FeedSort
import com.pitchedapps.frost.utils.Prefs
-import com.pitchedapps.frost.utils.launchWebOverlay
import com.pitchedapps.frost.utils.materialDialogThemed
/**
@@ -17,7 +16,7 @@ fun SettingsActivity.getFeedPrefs(): KPrefAdapterBuilder.() -> Unit = {
text(R.string.newsfeed_sort, { Prefs.feedSort }, { Prefs.feedSort = it }) {
descRes = R.string.newsfeed_sort_desc
- onClick = { _, _, item ->
+ onClick = {
materialDialogThemed {
title(R.string.newsfeed_sort)
items(FeedSort.values().map { string(it.textRes) })
@@ -29,7 +28,6 @@ fun SettingsActivity.getFeedPrefs(): KPrefAdapterBuilder.() -> Unit = {
true
})
}
- true
}
textGetter = { string(FeedSort(it).textRes) }
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
index f46517ac..4bd41802 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
@@ -25,7 +25,7 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
text(R.string.notification_frequency, { Prefs.notificationFreq }, { Prefs.notificationFreq = it }) {
val options = longArrayOf(-1, 15, 30, 60, 120, 180, 300, 1440, 2880)
val texts = options.map { if (it <= 0) string(R.string.no_notifications) else minuteToText(it) }
- onClick = { _, _, item ->
+ onClick = {
materialDialogThemed {
title(R.string.notification_frequency)
items(texts)
@@ -35,14 +35,13 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
true
})
}
- true
}
textGetter = { minuteToText(it) }
}
plainText(R.string.notification_keywords) {
descRes = R.string.notification_keywords_desc
- onClick = { _, _, _ ->
+ onClick = {
val keywordView = Keywords(this@getNotificationPrefs)
materialDialogThemed {
title(R.string.notification_keywords)
@@ -50,7 +49,6 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
dismissListener { keywordView.save() }
positiveText(R.string.kau_done)
}
- true
}
}
@@ -76,7 +74,7 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
else RingtoneManager.getRingtone(this@getNotificationPrefs, Uri.parse(it))
?.getTitle(this@getNotificationPrefs) ?: "---" //todo figure out why this happens
}
- onClick = { _, _, item ->
+ onClick = {
val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply {
putExtra(RingtoneManager.EXTRA_RINGTONE_TITLE, string(R.string.select_ringtone))
putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false)
@@ -86,7 +84,6 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, Uri.parse(item.pref))
}
startActivityForResult(intent, code)
- true
}
}
@@ -104,10 +101,9 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
plainText(R.string.notification_fetch_now) {
descRes = R.string.notification_fetch_now_desc
- onClick = { _, _, _ ->
+ onClick = {
val text = if (fetchNotifications()) R.string.notification_fetch_success else R.string.notification_fetch_fail
frostSnackbar(text)
- true
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt
index e6db8eee..2c638dfd 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt
@@ -9,14 +9,12 @@ import android.webkit.URLUtil
import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE
import ca.allanwang.kau.permissions.kauRequestPermissions
import ca.allanwang.kau.utils.isAppEnabled
+import ca.allanwang.kau.utils.showAppInfo
import ca.allanwang.kau.utils.string
+import ca.allanwang.kau.utils.toast
import com.pitchedapps.frost.R
import com.pitchedapps.frost.dbflow.loadFbCookie
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
-import android.support.v4.content.ContextCompat.startActivity
-import android.content.Intent
-import android.content.ActivityNotFoundException
-import ca.allanwang.kau.utils.showAppInfo
/**
@@ -40,8 +38,10 @@ fun Context.frostDownload(uri: Uri?,
contentLength: Long = 0L) {
uri ?: return
L.d("Received download request", "Download $uri")
- if (uri.scheme != "http" && uri.scheme != "https")
- return L.e("Invalid download attempt", uri.toString())
+ if (uri.scheme != "http" && uri.scheme != "https") {
+ toast(R.string.error_invalid_download)
+ return L.e(string(R.string.error_invalid_download), uri.toString())
+ }
if (!isAppEnabled(DOWNLOAD_MANAGER_PACKAGE)) {
materialDialogThemed {
title(R.string.no_download_manager)
@@ -66,7 +66,12 @@ fun Context.frostDownload(uri: Uri?,
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "Frost/$title")
val dm = getSystemService(DOWNLOAD_SERVICE) as DownloadManager
- dm.enqueue(request)
+ try {
+ dm.enqueue(request)
+ } catch (e: Exception) {
+ toast(R.string.error_generic)
+ L.e(e, "Download")
+ }
}
}
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 d8fa2ce9..ccc4033c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -10,6 +10,7 @@ import android.net.Uri
import android.support.annotation.StringRes
import android.support.design.internal.SnackbarContentLayout
import android.support.design.widget.Snackbar
+import android.support.v4.app.ActivityOptionsCompat
import android.support.v7.widget.Toolbar
import android.view.View
import android.widget.FrameLayout
@@ -80,13 +81,24 @@ fun Context.launchWebOverlay(url: String, clazz: Class<out WebOverlayActivityBas
})
}
+private fun Context.fadeBundle() = ActivityOptionsCompat.makeCustomAnimation(this,
+ android.R.anim.fade_in, android.R.anim.fade_out).toBundle()
+
fun Context.launchImageActivity(imageUrl: String, text: String?) {
startActivity(ImageActivity::class.java, intentBuilder = {
+ putExtras(fadeBundle())
putExtra(ARG_IMAGE_URL, imageUrl)
putExtra(ARG_TEXT, text)
})
}
+fun Activity.launchTabCustomizerActivity() {
+ startActivityForResult(TabCustomizerActivity::class.java,
+ SettingsActivity.ACTIVITY_REQUEST_TABS, bundleBuilder = {
+ with(fadeBundle())
+ })
+}
+
fun Activity.launchIntroActivity(cookieList: ArrayList<CookieModel>)
= launchNewTask(IntroActivity::class.java, cookieList, true)