aboutsummaryrefslogtreecommitdiff
path: root/app/src/main/kotlin/com/pitchedapps
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-07-13 13:50:00 -0700
committerGitHub <noreply@github.com>2017-07-13 13:50:00 -0700
commit91119de328bf5f4e8c945f8fb470453319b9f0ed (patch)
tree9ba1786f9cd8488a0cc0dfb247e1b387a4161cfb /app/src/main/kotlin/com/pitchedapps
parentde34d09f975079d5c044eae6da7ed92605009faf (diff)
downloadfrost-91119de328bf5f4e8c945f8fb470453319b9f0ed.tar.gz
frost-91119de328bf5f4e8c945f8fb470453319b9f0ed.tar.bz2
frost-91119de328bf5f4e8c945f8fb470453319b9f0ed.zip
Dev 1.2.2 - Add framework for messenger notifications (#47)
* Update KAU to v2.0 * Only inject theme for facebook and inject js after * Clean up menu loading logic * Add path null check * Remove .idea files * Add url formatter testers * Update tests and check url nullability - Fixes * Create instant messaging parser * Shorted notification log and remove unnecessary null checks * Make migration buildable * Test message parser * finalize messenger notifs for now
Diffstat (limited to 'app/src/main/kotlin/com/pitchedapps')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/SettingsActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt9
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt22
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt103
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt8
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/RippleCanvas.kt83
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt22
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClientMenu.kt45
19 files changed, 157 insertions, 175 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
index 36809535..6cab2a59 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/AboutActivity.kt
@@ -7,10 +7,10 @@ import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import ca.allanwang.kau.about.AboutActivityBase
+import ca.allanwang.kau.about.LibraryIItem
import ca.allanwang.kau.adapters.FastItemThemedAdapter
import ca.allanwang.kau.adapters.ThemableIItem
import ca.allanwang.kau.adapters.ThemableIItemDelegate
-import ca.allanwang.kau.iitems.LibraryIItem
import ca.allanwang.kau.utils.*
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.entity.Library
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/SettingsActivity.kt
index 66c541ed..e0be330d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/SettingsActivity.kt
@@ -5,12 +5,12 @@ import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import ca.allanwang.kau.changelog.showChangelog
-import ca.allanwang.kau.kpref.CoreAttributeContract
-import ca.allanwang.kau.kpref.KPrefActivity
-import ca.allanwang.kau.kpref.KPrefAdapterBuilder
-import ca.allanwang.kau.kpref.items.KPrefItemBase
+import ca.allanwang.kau.kpref.activity.CoreAttributeContract
+import ca.allanwang.kau.kpref.activity.KPrefActivity
+import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.items.KPrefItemBase
+import ca.allanwang.kau.ui.views.RippleCanvas
import ca.allanwang.kau.utils.*
-import ca.allanwang.kau.views.RippleCanvas
import com.mikepenz.community_material_typeface_library.CommunityMaterial
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.pitchedapps.frost.settings.*
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
index dda6c066..d197918d 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/WebOverlayActivity.kt
@@ -41,6 +41,9 @@ open class WebOverlayActivity : AppCompatActivity(),
const val ARG_USER_ID = "arg_user_id"
}
+ val urlTest: String?
+ get() = intent.extras?.getString(ARG_URL) ?: intent.dataString
+
open val url: String
get() = (intent.extras?.getString(ARG_URL) ?: intent.dataString).formattedFbUrl
@@ -49,6 +52,12 @@ open class WebOverlayActivity : AppCompatActivity(),
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
+ if (urlTest == null) {
+ L.eThrow("Empty link on web overlay")
+ toast(R.string.null_url_overlay)
+ finish()
+ return
+ }
setContentView(R.layout.activity_web_overlay)
setSupportActionBar(toolbar)
supportActionBar?.setDisplayShowHomeEnabled(true)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt
index 1585e425..66f5ae64 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt
@@ -1,11 +1,10 @@
package com.pitchedapps.frost.dbflow
import com.pitchedapps.frost.utils.L
-import com.raizlabs.android.dbflow.annotation.ConflictAction
-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.annotation.*
import com.raizlabs.android.dbflow.kotlinextensions.*
+import com.raizlabs.android.dbflow.sql.SQLiteType
+import com.raizlabs.android.dbflow.sql.migration.AlterTableMigration
import com.raizlabs.android.dbflow.structure.BaseModel
/**
@@ -15,13 +14,22 @@ import com.raizlabs.android.dbflow.structure.BaseModel
@Database(name = NotificationDb.NAME, version = NotificationDb.VERSION)
object NotificationDb {
const val NAME = "Notifications"
- const val VERSION = 1
+ const val VERSION = 2
+}
+
+@Migration(version = 2, database = NotificationDb::class)
+class NotificationMigration2(modelClass: Class<NotificationModel>) : AlterTableMigration<NotificationModel>(modelClass) {
+ override fun onPreMigrate() {
+ super.onPreMigrate()
+ addColumn(SQLiteType.INTEGER, "epochIm")
+ L.d("Added column")
+ }
}
@Table(database = NotificationDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE)
-data class NotificationModel(@PrimaryKey var id: Long = -1L, var epoch: Long = -1L) : BaseModel()
+data class NotificationModel(@PrimaryKey var id: Long = -1L, var epoch: Long = -1L, var epochIm: Long = -1) : BaseModel()
-fun lastNotificationTime(id: Long): Long = (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle()?.epoch ?: -1L
+fun lastNotificationTime(id: Long): NotificationModel = (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle() ?: NotificationModel(id = id)
fun saveNotificationTime(notificationModel: NotificationModel, callback: (() -> Unit)? = null) {
notificationModel.async save {
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 1090f1f3..e53bb202 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
@@ -15,8 +15,9 @@ class FbUrlFormatter(url: String) {
init {
var cleanedUrl = url
discardable.forEach { cleanedUrl = cleanedUrl.replace(it, "") }
+ val changed = cleanedUrl != url //note that discardables strip away the first ?
decoder.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v) }
- val qm = cleanedUrl.indexOf("?")
+ val qm = cleanedUrl.indexOf(if (changed)"&" else "?")
if (qm > -1) {
cleanedUrl.substring(qm + 1).split("&").forEach {
val p = it.split("=")
@@ -58,7 +59,8 @@ class FbUrlFormatter(url: String) {
"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="
+ "https://touch.facebook.com/l.php?u=",
+ "/video_redirect/?src="
)
@JvmStatic val discardableQueries = arrayOf("ref", "refid")
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 a83e87dc..cb33e527 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt
@@ -15,7 +15,8 @@ enum class CssHider(vararg val items: String) : InjectorContract {
"article[data-xt*=sponsor]",
"article[data-store*=sponsor]"
),
- PEOPLE_YOU_MAY_KNOW("article._d2r")
+ PEOPLE_YOU_MAY_KNOW("article._d2r"),
+ MESSENGER("._s15", "[data-testid=info_panel]", "js_i")
;
val injector: JsInjector by lazy { JsBuilder().css("${items.joinToString(separator = ",")}{display:none!important}").build() }
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 6af6b1db..2cea55b4 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt
@@ -64,6 +64,7 @@ class FrostNotificationTarget(val context: Context,
data class NotificationContent(val data: CookieModel,
val notifId: Int,
val href: String,
+ val title: String? = null,
val text: String,
val timestamp: Long,
val profileUrl: String) {
@@ -81,7 +82,7 @@ data class NotificationContent(val data: CookieModel,
val group = "frost_${data.id}"
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val notifBuilder = context.frostNotification
- .setContentTitle(context.string(R.string.app_name))
+ .setContentTitle(title ?: context.string(R.string.app_name))
.setContentText(text)
.setContentIntent(pendingIntent)
.setCategory(Notification.CATEGORY_SOCIAL)
@@ -133,7 +134,7 @@ const val NOTIFICATION_JOB_NOW = 6
/**
* Run notification job right now
*/
-fun Context.fetchNotifications():Boolean {
+fun Context.fetchNotifications(): Boolean {
val scheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
val serviceComponent = ComponentName(this, NotificationService::class.java)
val builder = JobInfo.Builder(NOTIFICATION_JOB_NOW, serviceComponent)
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 4c03f056..f9d0c63c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
@@ -7,9 +7,13 @@ import android.support.v4.app.NotificationManagerCompat
import ca.allanwang.kau.utils.string
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
-import com.pitchedapps.frost.dbflow.*
+import com.pitchedapps.frost.dbflow.CookieModel
+import com.pitchedapps.frost.dbflow.lastNotificationTime
+import com.pitchedapps.frost.dbflow.loadFbCookie
+import com.pitchedapps.frost.dbflow.loadFbCookiesSync
import com.pitchedapps.frost.facebook.FACEBOOK_COM
import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.frostAnswersCustom
@@ -31,6 +35,7 @@ class NotificationService : JobService() {
companion object {
val epochMatcher: Regex by lazy { Regex(":([0-9]*?),") }
val notifIdMatcher: Regex by lazy { Regex("notif_id\":([0-9]*?),") }
+ val messageNotifIdMatcher: Regex by lazy { Regex("thread_fbid_([0-9]+)") }
val profMatcher: Regex by lazy { Regex("url\\(\"(.*?)\"\\)") }
}
@@ -59,14 +64,26 @@ class NotificationService : JobService() {
return true
}
+ fun logNotif(text: String): NotificationContent? {
+ L.eThrow("NotificationService: $text")
+ return null
+ }
+
fun fetchNotifications(data: CookieModel) {
+ fetchGeneralNotifications(data)
+// fetchMessageNotifications(data)
+ debugNotification("Hello")
+ }
+
+ fun fetchGeneralNotifications(data: CookieModel) {
L.i("Notif fetch for $data")
- val doc = Jsoup.connect(FbTab.NOTIFICATIONS.url).cookie(FACEBOOK_COM, data.cookie).get()
+ 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").getElementsByClass("aclb")
+ val unreadNotifications = (doc.getElementById("notifications_list") ?: return L.eThrow("Notification list not found")).getElementsByClass("aclb")
var notifCount = 0
// val prevLatestEpoch = 1498931565L // for testing
- val prevLatestEpoch = lastNotificationTime(data.id)
+ val prevNotifTime = lastNotificationTime(data.id)
+ val prevLatestEpoch = prevNotifTime.epoch
L.v("Notif Prev Latest Epoch $prevLatestEpoch")
var newLatestEpoch = prevLatestEpoch
unreadNotifications.forEach unread@ {
@@ -79,31 +96,77 @@ class NotificationService : JobService() {
newLatestEpoch = notif.timestamp
notifCount++
}
- if (newLatestEpoch != prevLatestEpoch) saveNotificationTime(NotificationModel(data.id, newLatestEpoch))
- frostAnswersCustom("Notifications") { putCustomAttribute("Count", notifCount) }
+ if (newLatestEpoch != prevLatestEpoch) prevNotifTime.copy(epoch = newLatestEpoch).update()
+ frostAnswersCustom("Notifications") {
+ putCustomAttribute("Type", "General")
+ putCustomAttribute("Count", notifCount)
+ }
summaryNotification(data.id, notifCount)
}
fun parseNotification(data: CookieModel, element: Element): NotificationContent? {
- val a = element.getElementsByTag("a").first() ?: return null
- //fetch id
- val dataStore = a.attr("data-store")
- val notifId = if (dataStore == null) System.currentTimeMillis()
- else notifIdMatcher.find(dataStore)?.groups?.get(1)?.value?.toLong() ?: System.currentTimeMillis()
+ val a = element.getElementsByTag("a").first() ?: return logNotif("IM No a tag")
val abbr = element.getElementsByTag("abbr")
- val timeString = abbr?.text()
- var text = a.text().replace("\u00a0", " ") //remove &nbsp;
+ val epoch = epochMatcher.find(abbr.attr("data-store"))?.groups?.get(1)?.value?.toLong() ?: return logNotif("IM No epoch")
+ //fetch id
+ val notifId = notifIdMatcher.find(a.attr("data-store"))?.groups?.get(1)?.value?.toLong() ?: System.currentTimeMillis()
+ val timeString = abbr.text()
+ val text = a.text().replace("\u00a0", " ").removeSuffix(timeString).trim() //remove &nbsp;
if (Prefs.notificationKeywords.any { text.contains(it, ignoreCase = true) }) return null //notification filtered out
- if (timeString != null) text = text.removeSuffix(timeString)
- text = text.trim()
- //fetch epoch
- val abbrData = abbr?.attr("data-store")
- val epoch = if (abbrData == null) -1L else epochMatcher.find(abbrData)?.groups?.get(1)?.value?.toLong() ?: -1L
//fetch profpic
val p = element.select("i.img[style*=url]")
- val pUrl = profMatcher.find(p.getOrNull(0)?.attr("style") ?: "")?.groups?.get(1)?.value ?: ""
- return NotificationContent(data, notifId.toInt(), a.attr("href"), text, epoch, pUrl)
+ val pUrl = profMatcher.find(p.attr("style"))?.groups?.get(1)?.value ?: ""
+ return NotificationContent(data, notifId.toInt(), a.attr("href"), null, text, epoch, pUrl)
+ }
+
+ fun fetchMessageNotifications(data: CookieModel) {
+ if (!Prefs.notificationsInstantMessages) return
+ L.i("Notif IM fetch for $data")
+ val doc = Jsoup.connect(FbTab.MESSAGES.url).cookie(FACEBOOK_COM, data.cookie).userAgent(USER_AGENT_BASIC).get()
+ val unreadNotifications = (doc.getElementById("threadlist_rows") ?: return L.eThrow("Notification messages not found")).getElementsByClass("aclb")
+ var notifCount = 0
+ L.d("IM notif count ${unreadNotifications.size}")
+ unreadNotifications.forEach {
+ with(it) {
+ L.d("notif ${id()} ${className()}")
+ }
+ }
+ val prevNotifTime = lastNotificationTime(data.id)
+ val prevLatestEpoch = prevNotifTime.epochIm
+ L.v("Notif Prev Latest Im Epoch $prevLatestEpoch")
+ var newLatestEpoch = prevLatestEpoch
+ unreadNotifications.forEach unread@ {
+ elem ->
+ val notif = parseMessageNotification(data, elem) ?: return@unread
+ L.v("Notif im timestamp ${notif.timestamp}")
+ if (notif.timestamp <= prevLatestEpoch) return@unread
+ notif.createNotification(this@NotificationService)
+ if (notif.timestamp > newLatestEpoch)
+ newLatestEpoch = notif.timestamp
+ notifCount++
+ }
+// if (newLatestEpoch != prevLatestEpoch) prevNotifTime.copy(epochIm = newLatestEpoch).update()
+ frostAnswersCustom("Notifications") {
+ putCustomAttribute("Type", "Message")
+ putCustomAttribute("Count", notifCount)
+ }
+ summaryNotification(data.id, notifCount)
+ }
+
+ fun parseMessageNotification(data: CookieModel, element: Element): NotificationContent? {
+ val a = element.getElementsByTag("a").first() ?: return null
+ val abbr = element.getElementsByTag("abbr")
+ val epoch = epochMatcher.find(abbr.attr("data-store"))?.groups?.get(1)?.value?.toLong() ?: return logNotif("No epoch")
+ val thread = element.getElementsByAttributeValueContaining("id", "thread_fbid_").first() ?: return null
+ //fetch id
+ val notifId = messageNotifIdMatcher.find(thread.id())?.groups?.get(1)?.value?.toLong() ?: System.currentTimeMillis()
+ val text = element.select("span.snippet").firstOrNull()?.text()?.trim() ?: getString(R.string.new_message)
+ if (Prefs.notificationKeywords.any { text.contains(it, ignoreCase = true) }) return null //notification filtered out
+ //fetch convo pic
+ val p = element.select("i.img[style*=url]")
+ val pUrl = profMatcher.find(p.attr("style"))?.groups?.get(1)?.value ?: ""
+ return NotificationContent(data, notifId.toInt(), a.attr("href"), a.text(), text, epoch, pUrl)
}
private fun Context.debugNotification(text: String) {
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 68d3fbc6..e05d0dd3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
@@ -1,10 +1,10 @@
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.kpref.activity.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.items.KPrefColorPicker
+import ca.allanwang.kau.kpref.activity.items.KPrefSeekbar
+import ca.allanwang.kau.ui.views.RippleCanvas
import ca.allanwang.kau.utils.string
-import ca.allanwang.kau.views.RippleCanvas
import com.pitchedapps.frost.MainActivity
import com.pitchedapps.frost.R
import com.pitchedapps.frost.SettingsActivity
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 2d121073..b912c103 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt
@@ -1,6 +1,6 @@
package com.pitchedapps.frost.settings
-import ca.allanwang.kau.kpref.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
import com.pitchedapps.frost.R
import com.pitchedapps.frost.SettingsActivity
import com.pitchedapps.frost.utils.Prefs
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 6022ee26..86bd356b 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
@@ -1,6 +1,6 @@
package com.pitchedapps.frost.settings
-import ca.allanwang.kau.kpref.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
import com.pitchedapps.frost.MainActivity
import com.pitchedapps.frost.R
import com.pitchedapps.frost.SettingsActivity
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 b8bfb086..29256950 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt
@@ -1,6 +1,6 @@
package com.pitchedapps.frost.settings
-import ca.allanwang.kau.kpref.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
import ca.allanwang.kau.utils.string
import com.pitchedapps.frost.MainActivity
import com.pitchedapps.frost.R
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 5986a998..86cfcc16 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt
@@ -1,6 +1,6 @@
package com.pitchedapps.frost.settings
-import ca.allanwang.kau.kpref.KPrefAdapterBuilder
+import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
import ca.allanwang.kau.utils.minuteToText
import ca.allanwang.kau.utils.snackbar
import com.pitchedapps.frost.R
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 7ce8ca10..64ec08cd 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
@@ -87,6 +87,8 @@ object Prefs : KPref() {
var notificationAllAccounts: Boolean by kpref("notification_all_accounts", true)
+ var notificationsInstantMessages: Boolean by kpref("notification_im", true)
+
/**
* Cache like value to determine if user has or had pro
* In most cases, [com.pitchedapps.frost.utils.iab.IS_FROST_PRO] should be looked at instead
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt
index 1d5abdd6..4f65b7f8 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt
@@ -67,7 +67,7 @@ fun Activity.playStoreNotFound() {
}
fun Activity.playStoreProNotAvailable() {
- playStoreLog("Pro query; store not available")
+ L.d("Pro query; store not available")
materialDialogThemed {
title(R.string.uh_oh)
content(R.string.play_store_not_found_pro_query)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt
index 1d8f308d..4249cd09 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt
@@ -2,7 +2,7 @@ package com.pitchedapps.frost.views
import android.annotation.SuppressLint
import android.util.TypedValue
-import ca.allanwang.kau.kpref.items.KPrefSeekbar
+import ca.allanwang.kau.kpref.activity.items.KPrefSeekbar
import com.pitchedapps.frost.R
/**
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/RippleCanvas.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/RippleCanvas.kt
deleted file mode 100644
index 719a01cc..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/RippleCanvas.kt
+++ /dev/null
@@ -1,83 +0,0 @@
-package com.pitchedapps.frost.views
-
-import android.animation.ValueAnimator
-import android.content.Context
-import android.graphics.Canvas
-import android.graphics.Color
-import android.graphics.Paint
-import android.util.AttributeSet
-import android.view.View
-
-/**
- * Created by Allan Wang on 2016-11-17.
- *
- *
- * Canvas drawn ripples that keep the previous color
- * Extends to view dimensions
- * Supports multiple ripples from varying locations
- */
-class RippleCanvas @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
-) : View(context, attrs, defStyleAttr) {
- val paint: Paint = Paint()
- var baseColor = Color.TRANSPARENT
- val ripples: MutableList<Ripple> = mutableListOf()
-
- init {
- paint.isAntiAlias = true
- paint.style = Paint.Style.FILL
- }
-
- override fun onDraw(canvas: Canvas) {
- canvas.drawColor(baseColor)
- val itr = ripples.iterator()
- while (itr.hasNext()) {
- val r = itr.next()
- paint.color = r.color
- canvas.drawCircle(r.x, r.y, r.radius, paint)
- if (r.radius == r.maxRadius) {
- itr.remove()
- baseColor = r.color
- }
- }
- }
-
- @JvmOverloads fun ripple(color: Int, startX: Float = 0f, startY: Float = 0f, duration: Int = 1000) {
- var x = startX
- var y = startY
- val w = width.toFloat()
- val h = height.toFloat()
- if (x == MIDDLE)
- x = w / 2
- else if (x > w) x = 0f
- if (y == MIDDLE)
- y = h / 2
- else if (y > h) y = 0f
- val maxRadius = Math.hypot(Math.max(x, w - x).toDouble(), Math.max(y, h - y).toDouble()).toFloat()
- val ripple = Ripple(color, x, y, 0f, maxRadius)
- ripples.add(ripple)
- val animator = ValueAnimator.ofFloat(0f, maxRadius)
- animator.duration = duration.toLong()
- animator.addUpdateListener { animation ->
- ripple.setRadius(animation.animatedValue as Float)
- invalidate()
- }
- animator.start()
- }
-
- fun set(color: Int) {
- baseColor = color
- ripples.clear()
- invalidate()
- }
-
- inner class Ripple internal constructor(val color: Int, val x: Float, val y: Float, var radius: Float, val maxRadius: Float) {
- internal fun setRadius(r: Float) {
- radius = r
- }
- }
-
- companion object {
- val MIDDLE = -1.0f
- }
-}
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 16a4a092..0a254c50 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
@@ -45,15 +45,15 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : WebViewClient() {
refreshObservable.onNext(false)
return
}
- view.jsInject(JsActions.LOGIN_CHECK,
+ view.jsInject(
CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons),
CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && Prefs.pro),
- CssHider.ADS.maybe(!Prefs.showFacebookAds && Prefs.pro),
- JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null))
+ CssHider.ADS.maybe(!Prefs.showFacebookAds && Prefs.pro)
+ )
onPageFinishedActions(url)
}
- open internal fun onPageFinishedActions(url: String?) {
+ open internal fun onPageFinishedActions(url: String) {
injectAndFinish()
}
@@ -61,9 +61,15 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : WebViewClient() {
L.d("Page finished reveal")
webCore.jsInject(CssHider.HEADER,
Prefs.themeInjector,
- JsAssets.CLICK_A.maybe(webCore.baseEnum != null),
- JsAssets.CONTEXT_A,
- callback = { refreshObservable.onNext(false) })
+ callback = {
+ refreshObservable.onNext(false)
+ webCore.jsInject(
+ JsActions.LOGIN_CHECK,
+ JsAssets.CLICK_A.maybe(webCore.baseEnum != null),
+ JsAssets.CONTEXT_A,
+ JsAssets.HEADER_BADGES.maybe(webCore.baseEnum != null)
+ )
+ })
}
open fun handleHtml(html: String) {
@@ -86,7 +92,7 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean {
L.i("Url Loading ${request.url}")
- val path = request.url.path
+ val path = request.url.path ?: return super.shouldOverrideUrlLoading(view, request)
if (path.startsWith("/composer/")) return launchRequest(request)
return super.shouldOverrideUrlLoading(view, request)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClientMenu.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClientMenu.kt
index 0f08bcf3..10648e73 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClientMenu.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClientMenu.kt
@@ -1,42 +1,26 @@
package com.pitchedapps.frost.web
-import android.graphics.Bitmap
import android.webkit.WebView
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.injectors.JsAssets
import com.pitchedapps.frost.injectors.jsInject
-import com.pitchedapps.frost.utils.L
-import io.reactivex.subjects.Subject
/**
* Created by Allan Wang on 2017-05-31.
*/
class FrostWebViewClientMenu(webCore: FrostWebViewCore) : FrostWebViewClient(webCore) {
- var content: String? = null
- val progressObservable: Subject<Int> = webCore.progressObservable
- private val contentBaseUrl = "${FB_URL_BASE}notifications"
-
- override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
- super.onPageStarted(view, url, favicon)
- if (content != null) {
- when (url.removePrefix(FB_URL_BASE)) {
- "settings",
- "settings#",
- "settings#!/settings?soft=bookmarks" -> {
- L.d("Load from stored $url")
- view.stopLoading()
- view.loadDataWithBaseURL(contentBaseUrl, content, "text/html", "utf-8", "https://google.ca/test")
- }
- }
- }
+ private val String.shouldInjectMenu
+ get() = when (removePrefix(FB_URL_BASE)) {
+ "settings",
+ "settings#",
+ "settings#!/settings?soft=bookmarks" -> true
+ else -> false
}
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
- if (url == webCore.baseUrl && content == null) {
- jsInject(JsAssets.MENU)
- }
+ if (url.shouldInjectMenu) jsInject(JsAssets.MENU)
}
override fun emit(flag: Int) {
@@ -44,19 +28,8 @@ class FrostWebViewClientMenu(webCore: FrostWebViewCore) : FrostWebViewClient(web
super.injectAndFinish()
}
- override fun onPageFinishedActions(url: String?) {
- when (url?.removePrefix(FB_URL_BASE)) {
- "settings",
- "settings#",
- "settings#!/settings?soft=bookmarks" -> {
- //do nothing; we will further inject before revealing
- }
- else -> injectAndFinish()
- }
+ override fun onPageFinishedActions(url: String) {
+ if (!url.shouldInjectMenu) injectAndFinish()
}
- override fun handleHtml(html: String) {
- super.handleHtml(html)
- content = html //we will not save this locally in case things change
- }
} \ No newline at end of file