mirror of
https://github.com/AllanWang/Frost-for-Facebook.git
synced 2024-11-10 04:52:38 +01:00
commit
e7a499f631
@ -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() {
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
||||
|
@ -9,7 +9,8 @@
|
||||
<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="Update theme" />
|
||||
<item text="Update translations" />
|
||||
<item text="" />
|
||||
<item text="" />
|
||||
<item text="" />
|
||||
|
@ -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()
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,25 @@
|
||||
(function () {
|
||||
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.
|
||||
*/
|
||||
@ -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);
|
||||
|
@ -17,7 +17,7 @@ APP_ID=Frost
|
||||
APP_GROUP=com.pitchedapps
|
||||
|
||||
KAU=4.0.0
|
||||
KOTLIN=1.3.21
|
||||
KOTLIN=1.3.31
|
||||
|
||||
# https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google
|
||||
ANDROID_GRADLE=3.3.2
|
||||
@ -41,7 +41,7 @@ DBFLOW=4.2.4
|
||||
# https://github.com/brianwernick/ExoMedia/releases
|
||||
EXOMEDIA=4.3.0
|
||||
# https://github.com/InsertKoinIO/koin/blob/master/CHANGELOG.md
|
||||
KOIN=1.0.2
|
||||
KOIN=2.0.0-rc-2
|
||||
# https://github.com/mockk/mockk/releases
|
||||
MOCKK=1.9.3
|
||||
# https://mvnrepository.com/artifact/androidx.core/core-ktx?repo=google
|
||||
@ -56,10 +56,10 @@ LEAK_CANARY=1.6.2
|
||||
# https://github.com/zsmb13/MaterialDrawerKt/releases
|
||||
MATERIAL_DRAWER_KT=2.0.1
|
||||
# https://github.com/square/okhttp/releases
|
||||
OKHTTP=3.14.0
|
||||
# http://robolectric.org/getting-started/
|
||||
OKHTTP=3.14.1
|
||||
# https://developer.android.com/jetpack/androidx/releases/room
|
||||
ROOM=2.1.0-alpha04
|
||||
# http://robolectric.org/getting-started/
|
||||
ROBOELECTRIC=4.2
|
||||
# https://github.com/davemorrissey/subsampling-scale-image-view#quick-start
|
||||
SCALE_IMAGE_VIEW=3.10.0
|
||||
|
Loading…
Reference in New Issue
Block a user