aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt11
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt18
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt5
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt4
-rw-r--r--app/src/main/res/xml/frost_changelog.xml7
-rw-r--r--app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt10
-rw-r--r--app/src/web/scss/core/_core_text.scss2
-rw-r--r--app/src/web/ts/click_a.ts93
-rw-r--r--app/src/web/ts/context_a.ts33
12 files changed, 136 insertions, 56 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index 41c6ff4b..0c762b41 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -45,7 +45,9 @@ import com.raizlabs.android.dbflow.config.DatabaseConfig
import com.raizlabs.android.dbflow.config.FlowConfig
import com.raizlabs.android.dbflow.config.FlowManager
import com.raizlabs.android.dbflow.runtime.ContentResolverNotifier
-import org.koin.android.ext.android.startKoin
+import org.koin.android.ext.koin.androidContext
+import org.koin.android.ext.koin.androidLogger
+import org.koin.core.context.startKoin
import java.util.Random
import kotlin.reflect.KClass
@@ -134,7 +136,12 @@ class FrostApp : Application() {
L.d { "Activity ${activity.localClassName} created" }
}
})
- startKoin(this, listOf(FrostDatabase.module(this)))
+ startKoin {
+ if (BuildConfig.DEBUG)
+ androidLogger()
+ androidContext(this@FrostApp)
+ modules(FrostDatabase.module(this@FrostApp))
+ }
}
private fun initBugsnag() {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt b/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt
index 67372e23..cd5fce02 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/db/Database.kt
@@ -21,8 +21,8 @@ import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import com.pitchedapps.frost.BuildConfig
-import org.koin.dsl.module.module
-import org.koin.standalone.StandAloneContext
+import org.koin.core.context.GlobalContext
+import org.koin.dsl.module
interface FrostPrivateDao {
fun cookieDao(): CookieDao
@@ -101,6 +101,6 @@ class FrostDatabase(private val privateDb: FrostPrivateDatabase, private val pub
* Get from koin
* For the most part, you can retrieve directly from other koin components
*/
- fun get(): FrostDatabase = StandAloneContext.getKoin().koinContext.get()
+ fun get(): FrostDatabase = GlobalContext.get().koin.get()
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt
index 24c39e28..6af21259 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt
@@ -76,7 +76,7 @@ const val FALLBACK_TIME_MOD = 1000000
data class FrostLink(val text: String, val href: String)
-data class ParseResponse<out T: ParseData>(val cookie: String, val data: T) {
+data class ParseResponse<out T : ParseData>(val cookie: String, val data: T) {
override fun toString() = "ParseResponse\ncookie: $cookie\ndata:\n$data"
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt
index 9a9f4082..db901073 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/BiometricUtils.kt
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2019 Allan Wang
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
package com.pitchedapps.frost.utils
import android.content.Context
@@ -91,4 +107,4 @@ object BiometricUtils {
pool?.shutdown()
pool = null
}
-} \ No newline at end of file
+}
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 76ffd8cd..557980af 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -186,7 +186,8 @@ fun MaterialDialog.Builder.theme(): MaterialDialog.Builder {
}
fun Activity.setFrostTheme(forceTransparent: Boolean = false) {
- val isTransparent = (Color.alpha(Prefs.bgColor) != 255) || (Color.alpha(Prefs.headerColor) != 255) || forceTransparent
+ val isTransparent =
+ (Color.alpha(Prefs.bgColor) != 255) || (Color.alpha(Prefs.headerColor) != 255) || forceTransparent
if (Prefs.bgColor.isColorDark)
setTheme(if (isTransparent) R.style.FrostTheme_Transparent else R.style.FrostTheme)
else
@@ -357,7 +358,7 @@ val dependentSegments = arrayOf(
)
inline val String?.isExplicitIntent
- get() = this != null && startsWith("intent://")
+ get() = this != null && (startsWith("intent://") || startsWith("market://"))
fun Context.frostChangelog() = showChangelog(R.xml.frost_changelog, Prefs.textColor) {
theme()
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
index 81ade98f..b06208a6 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt
@@ -75,7 +75,6 @@ fun FrostWebView.requestWebOverlay(url: String): Boolean {
}
if (!Prefs.overlayEnabled) return false
if (context is WebOverlayActivityBase) {
- L.v { "Check web request from overlay" }
val shouldUseDesktop = url.formattedFbUrl.shouldUseDesktopAgent
//already overlay; manage user agent
if (userAgentString != USER_AGENT_DESKTOP && shouldUseDesktop) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt b/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt
index 594da00a..66176aba 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/widgets/NotificationWidget.kt
@@ -47,8 +47,8 @@ import com.pitchedapps.frost.services.NotificationContent
import com.pitchedapps.frost.services.NotificationType
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.toReadableTime
-import org.koin.standalone.KoinComponent
-import org.koin.standalone.inject
+import org.koin.core.KoinComponent
+import org.koin.core.inject
class NotificationWidget : AppWidgetProvider() {
diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml
index 560b1111..3e4f9036 100644
--- a/app/src/main/res/xml/frost_changelog.xml
+++ b/app/src/main/res/xml/frost_changelog.xml
@@ -9,9 +9,10 @@
<version title="v2.3.0" />
<item text="Converted internals of Facebook data storage; auto migration will only work from 2.2.x to 2.3.x" />
<item text="Added notification widget" />
- <item text="" />
- <item text="" />
- <item text="" />
+ <item text="Update theme" />
+ <item text="Update translations" />
+ <item text="Add fingerprint unlock screen" />
+ <item text="Fix messenger redirect" />
<item text="" />
<item text="" />
<item text="" />
diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt
index e93f507c..5cde7323 100644
--- a/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt
+++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/CoroutineTest.kt
@@ -246,6 +246,8 @@ class CoroutineTest {
}
}
+ class TestException(msg: String) : RuntimeException(msg)
+
@Test
fun exceptionChecks() {
val mainTag = "main-test"
@@ -257,7 +259,7 @@ class CoroutineTest {
val job = SupervisorJob()
val flyweight = Flyweight<Int, Int>(GlobalScope, 200L) {
- throw java.lang.RuntimeException("Flyweight exception")
+ throw TestException("Flyweight exception")
}
suspend fun crash(): Boolean = withContext(Dispatchers.IO) {
@@ -266,7 +268,7 @@ class CoroutineTest {
flyweight.fetch(0).await()
}
true
- } catch (e: java.lang.Exception) {
+ } catch (e: TestException) {
false
}
}
@@ -282,10 +284,6 @@ class CoroutineTest {
println("B")
channel.offer(1)
}
-// launch {
-// delay(2000)
-// job.cancel()
-// }
}
}
}
diff --git a/app/src/web/scss/core/_core_text.scss b/app/src/web/scss/core/_core_text.scss
index 63622610..2142ef73 100644
--- a/app/src/web/scss/core/_core_text.scss
+++ b/app/src/web/scss/core/_core_text.scss
@@ -19,7 +19,7 @@ textarea:not([style*="color: rgb"]), ._24pi, ._4en9, ._1kb, ._5p7j, ._2klz, ._57
div.sharerSelector, .footer, ._4pv_, ._1dbp, ._3kad, ._20zc, ._2i5v, ._2i5w,
a, ._5fpq, ._4gux, ._3bg5 ._52x1, ._3bg5 ._52x2, ._6dsj ._3gin, ._hdn._hdn,
.mentions-input:not([style*="color: rgb"]), .mentions-placeholder:not([style*="color: rgb"]),
-.largeStatusBox .placeHolder, .fcw, ._2rgt, ._67i4 ._5hu6 ._59tt,
+.largeStatusBox .placeHolder, .fcw, ._2rgt, ._67i4 ._5hu6 ._59tt, ._2bu3, ._2bu4,
._5-7t, .fcl, ._4qas, .thread-title, .title, ._46pa, ._336p, ._1rrd, ._2om4,
._3m1m, ._2om2, ._5n_e, .appListExplanation, ._5yt8, ._8he, ._2luw, ._5rgs,
h1, h2, h3, h4, h5, h6 {
diff --git a/app/src/web/ts/click_a.ts b/app/src/web/ts/click_a.ts
index 5023610e..8d1d545b 100644
--- a/app/src/web/ts/click_a.ts
+++ b/app/src/web/ts/click_a.ts
@@ -1,34 +1,81 @@
(function () {
let prevented = false;
+ /**
+ * Go up at most [depth] times, to retrieve a parent matching the provided predicate
+ * If one is found, it is returned immediately.
+ * Otherwise, null is returned.
+ */
+ function _parentEl(el: HTMLElement, depth: number, predicate: (el: HTMLElement) => boolean): HTMLElement | null {
+ for (let i = 0; i < depth + 1; i++) {
+ if (predicate(el)) {
+ return el
+ }
+ const parent = el.parentElement;
+ if (!parent) {
+ return null
+ }
+ el = parent
+ }
+ return null
+ }
+
+ /**
+ * Attempts to find a url entry at most [depth] away
+ * A url is found if the element has tag 'A', and the url isn't blank
+ */
+ function _parentUrl(el: HTMLElement, depth: number): string | null {
+ const element = _parentEl(el, depth, (el) => el.tagName === 'A');
+ if (!element) {
+ return null;
+ }
+ const url = element.getAttribute('href');
+ if (!url || url === '#') {
+ return null;
+ }
+ return url
+ }
+
+ /**
+ * Given event and target, return true if handled and false otherwise.
+ */
+ type EventHandler = (e: Event, target: HTMLElement) => Boolean
+
+ const _frostGeneral: EventHandler = (e, target) => {
+ // Notifications are two layers under
+ const url = _parentUrl(target, 2);
+ return Frost.loadUrl(url);
+ };
+
+ const _frostLaunchpadClick: EventHandler = (e, target) => {
+ if (!_parentEl(target, 6, (el) => el.id === 'launchpad')) {
+ return false
+ }
+ console.log('Clicked launchpad');
+ const url = _parentUrl(target, 5);
+ return Frost.loadUrl(url);
+ };
+
+ const handlers: EventHandler[] = [_frostLaunchpadClick, _frostGeneral];
+
const _frostAClick = (e: Event) => {
- // check for valid target
+ if (prevented) {
+ console.log("Click intercept prevented");
+ return
+ }
+ /*
+ * Commonality; check for valid target
+ */
const target = e.target || e.currentTarget || e.srcElement;
- if (!(target instanceof Element)) {
+ if (!(target instanceof HTMLElement)) {
console.log("No element found");
return
}
- let element: Element = target;
- // Notifications are two layers under
- for (let i = 0; i < 2; i++) {
- if (element.tagName !== 'A') {
- element = <Element>element.parentElement;
- }
- }
- if (element.tagName === 'A') {
- if (!prevented) {
- const url = element.getAttribute('href');
- if (!url || url === '#') {
- return
- }
- console.log(`Click intercept ${url}`);
- // If Frost is injected, check if loading the url through an overlay works
- if (Frost.loadUrl(url)) {
- e.stopPropagation();
- e.preventDefault();
- }
- } else {
- console.log("Click intercept prevented")
+ for (const h of handlers) {
+ if (h(e, target)) {
+ e.stopPropagation();
+ e.preventDefault();
+ return
}
}
};
diff --git a/app/src/web/ts/context_a.ts b/app/src/web/ts/context_a.ts
index 5eec7611..b9549f3f 100644
--- a/app/src/web/ts/context_a.ts
+++ b/app/src/web/ts/context_a.ts
@@ -7,6 +7,25 @@
let longClick = false;
/**
+ * Go up at most [depth] times, to retrieve a parent matching the provided predicate
+ * If one is found, it is returned immediately.
+ * Otherwise, null is returned.
+ */
+ function _parentEl(el: HTMLElement, depth: number, predicate: (el: HTMLElement) => boolean): HTMLElement | null {
+ for (let i = 0; i < depth + 1; i++) {
+ if (predicate(el)) {
+ return el
+ }
+ const parent = el.parentElement;
+ if (!parent) {
+ return null
+ }
+ el = parent
+ }
+ return null
+ }
+
+ /**
* Given event and target, return true if handled and false otherwise.
*/
type EventHandler = (e: Event, target: HTMLElement) => Boolean
@@ -55,16 +74,8 @@
* Opens image activity for posts with just one image
*/
const _frostImage: EventHandler = (e, target) => {
- let element: Element = target;
- // Notifications are two layers under
- for (let i = 0; i < 2; i++) {
- if (element.tagName !== 'A') {
- element = <Element>element.parentElement;
- } else {
- break
- }
- }
- if (element.tagName !== 'A') {
+ const element = _parentEl(target, 2, (el) => el.tagName === 'A');
+ if (!element) {
return false;
}
const url = element.getAttribute('href');
@@ -92,7 +103,7 @@
return true;
};
- const handlers = [_frostImage, _frostCopyComment, _frostCopyPost];
+ const handlers: EventHandler[] = [_frostImage, _frostCopyComment, _frostCopyPost];
const _frostAContext = (e: Event) => {
Frost.longClick(true);