1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-08 12:02:33 +01:00

Update theme providers and readd koin modules

This commit is contained in:
Allan Wang 2021-04-17 17:49:18 -07:00
parent cb2adc75d8
commit d96d1d06a7
No known key found for this signature in database
GPG Key ID: 69D90B885D405BDB
81 changed files with 606 additions and 427 deletions

View File

@ -26,11 +26,6 @@ import com.pitchedapps.frost.utils.ARG_COOKIE
import com.pitchedapps.frost.utils.ARG_IMAGE_URL
import com.pitchedapps.frost.utils.ARG_TEXT
import com.pitchedapps.frost.utils.isIndirectImageUrl
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import okhttp3.internal.closeQuietly
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
@ -46,6 +41,11 @@ import org.junit.rules.RuleChain
import org.junit.rules.TestRule
import org.junit.rules.Timeout
import org.junit.runner.RunWith
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
@RunWith(AndroidJUnit4::class)
class ImageActivityTest {

View File

@ -20,9 +20,9 @@ import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.runner.RunWith
import kotlin.test.AfterTest
import kotlin.test.BeforeTest
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
abstract class BaseDbTest {

View File

@ -16,11 +16,11 @@
*/
package com.pitchedapps.frost.db
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
import kotlinx.coroutines.runBlocking
class CacheDbTest : BaseDbTest() {

View File

@ -16,10 +16,10 @@
*/
package com.pitchedapps.frost.db
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull
import kotlinx.coroutines.runBlocking
class CookieDbTest : BaseDbTest() {

View File

@ -21,8 +21,8 @@ import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import kotlin.test.Test
import org.junit.runner.RunWith
import kotlin.test.Test
@RunWith(AndroidJUnit4::class)
class CookieMigrationTest {

View File

@ -17,13 +17,13 @@
package com.pitchedapps.frost.db
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.runner.RunWith
import org.koin.core.error.NoBeanDefFoundException
import org.koin.test.KoinTest
import kotlin.reflect.KClass
import kotlin.reflect.full.functions
import kotlin.test.Test
import kotlin.test.assertTrue
import org.junit.runner.RunWith
import org.koin.core.error.NoBeanDefFoundException
import org.koin.test.KoinTest
@RunWith(AndroidJUnit4::class)
class DatabaseTest : KoinTest {

View File

@ -18,9 +18,9 @@ package com.pitchedapps.frost.db
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.defaultTabs
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlinx.coroutines.runBlocking
class GenericDbTest : BaseDbTest() {

View File

@ -19,11 +19,11 @@ package com.pitchedapps.frost.db
import com.pitchedapps.frost.services.NOTIF_CHANNEL_GENERAL
import com.pitchedapps.frost.services.NOTIF_CHANNEL_MESSAGES
import com.pitchedapps.frost.services.NotificationContent
import kotlinx.coroutines.runBlocking
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlinx.coroutines.runBlocking
class NotificationDbTest : BaseDbTest() {

View File

@ -17,8 +17,8 @@
package com.pitchedapps.frost.facebook
import android.webkit.CookieManager
import kotlin.test.assertTrue
import org.junit.Test
import kotlin.test.assertTrue
class FbCookieTest {

View File

@ -35,14 +35,14 @@ import com.pitchedapps.frost.services.setupNotificationChannels
import com.pitchedapps.frost.utils.FrostPglAdBlock
import com.pitchedapps.frost.utils.L
import dagger.hilt.android.HiltAndroidApp
import java.util.Random
import javax.inject.Inject
import org.koin.android.ext.koin.androidContext
import org.koin.android.ext.koin.androidLogger
import org.koin.core.component.KoinComponent
import org.koin.core.context.startKoin
import org.koin.core.module.Module
import org.koin.dsl.module
import java.util.Random
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-05-28.

View File

@ -45,9 +45,9 @@ import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.launchNewTask
import com.pitchedapps.frost.utils.loadAssets
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch
import java.util.ArrayList
import javax.inject.Inject
import kotlinx.coroutines.launch
/**
* Created by Allan Wang on 2017-05-28.
@ -94,10 +94,10 @@ class StartActivity : KauBaseActivity() {
L.i { "Cookies loaded at time ${System.currentTimeMillis()}" }
L._d {
"Cookies: ${
cookies.joinToString(
"\t",
transform = CookieEntity::toSensitiveString
)
cookies.joinToString(
"\t",
transform = CookieEntity::toSensitiveString
)
}"
}
loadAssets(themeProvider)
@ -106,11 +106,13 @@ class StartActivity : KauBaseActivity() {
cookies.isEmpty() -> launchNewTask<LoginActivity>()
// Has cookies but no selected account
prefs.userId == -1L -> launchNewTask<SelectorActivity>(cookies)
else -> startActivity<MainActivity>(intentBuilder = {
putParcelableArrayListExtra(EXTRA_COOKIES, cookies)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_SINGLE_TOP
})
else -> startActivity<MainActivity>(
intentBuilder = {
putParcelableArrayListExtra(EXTRA_COOKIES, cookies)
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or
Intent.FLAG_ACTIVITY_SINGLE_TOP
}
)
}
} catch (e: Exception) {
L._e(e) { "Load start failed" }

View File

@ -144,7 +144,8 @@ class AboutActivity : AboutActivityBase(null) {
}
}
class AboutLinks : AbstractItem<AboutLinks.ViewHolder>(),
class AboutLinks :
AbstractItem<AboutLinks.ViewHolder>(),
ThemableIItem by ThemableIItemDelegate() {
override fun getViewHolder(v: View): ViewHolder = ViewHolder(v)
@ -186,12 +187,14 @@ class AboutActivity : AboutActivityBase(null) {
)
images =
(icons.map { (icon, onClick) -> c.drawable(icon) to onClick } + iicons.map { (icon, onClick) ->
icon.toDrawable(
c,
32
) to onClick
}).mapIndexed { i, (icon, onClick) ->
(
icons.map { (icon, onClick) -> c.drawable(icon) to onClick } + iicons.map { (icon, onClick) ->
icon.toDrawable(
c,
32
) to onClick
}
).mapIndexed { i, (icon, onClick) ->
ImageView(c).apply {
layoutParams = ViewGroup.LayoutParams(size, size)
id = 109389 + i

View File

@ -129,10 +129,10 @@ import com.pitchedapps.frost.views.FrostVideoViewer
import com.pitchedapps.frost.views.FrostViewPager
import com.pitchedapps.frost.widgets.NotificationWidget
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlin.math.abs
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.math.abs
/**
* Created by Allan Wang on 20/12/17.
@ -141,9 +141,12 @@ import kotlinx.coroutines.launch
*/
@UseExperimental(ExperimentalCoroutinesApi::class)
@AndroidEntryPoint
abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
abstract class BaseMainActivity :
BaseActivity(),
MainActivityContract,
FileChooserContract by FileChooserDelegate(),
VideoViewHolder, SearchViewHolder {
VideoViewHolder,
SearchViewHolder {
/**
* Note that tabs themselves are initialized through a coroutine during onCreate
@ -341,15 +344,17 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
shouldShow = false
fab.backgroundTintList = ColorStateList.valueOf(themeProvider.headerColor.withMinAlpha(200))
fab.hide()
appbar.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (!hasFab) return@OnOffsetChangedListener
val percent = abs(verticalOffset.toFloat() / appBarLayout.totalScrollRange)
val shouldShow = percent < 0.2
if (this@BaseMainActivity.shouldShow != shouldShow) {
this@BaseMainActivity.shouldShow = shouldShow
fab.showIf(shouldShow)
appbar.addOnOffsetChangedListener(
AppBarLayout.OnOffsetChangedListener { appBarLayout, verticalOffset ->
if (!hasFab) return@OnOffsetChangedListener
val percent = abs(verticalOffset.toFloat() / appBarLayout.totalScrollRange)
val shouldShow = percent < 0.2
if (this@BaseMainActivity.shouldShow != shouldShow) {
this@BaseMainActivity.shouldShow = shouldShow
fab.showIf(shouldShow)
}
}
})
)
}
override fun showFab(iicon: IIcon, clickEvent: () -> Unit) {
@ -851,11 +856,13 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract,
this@SectionsPagerAdapter.pages.forEachIndexed { index, fbItem ->
tabs.addTab(
tabs.newTab()
.setCustomView(BadgedIcon(this@BaseMainActivity).apply {
iicon = fbItem.icon
}.also {
it.setAllAlpha(if (index == 0) SELECTED_TAB_ALPHA else UNSELECTED_TAB_ALPHA)
})
.setCustomView(
BadgedIcon(this@BaseMainActivity).apply {
iicon = fbItem.icon
}.also {
it.setAllAlpha(if (index == 0) SELECTED_TAB_ALPHA else UNSELECTED_TAB_ALPHA)
}
)
)
}
lastPosition = 0

View File

@ -34,12 +34,12 @@ import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.createFreshDir
import com.pitchedapps.frost.utils.setFrostColors
import java.io.File
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.CoroutineExceptionHandler
import org.koin.android.ext.android.inject
import org.koin.core.component.inject
import java.io.File
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
/**
* Created by Allan Wang on 05/01/18.

View File

@ -67,11 +67,6 @@ import com.pitchedapps.frost.utils.frostUriFromFile
import com.pitchedapps.frost.utils.isIndirectImageUrl
import com.pitchedapps.frost.utils.logFrostEvent
import com.pitchedapps.frost.utils.setFrostColors
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import kotlin.math.abs
import kotlin.math.max
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
@ -80,6 +75,11 @@ import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import org.koin.core.component.inject
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import kotlin.math.abs
import kotlin.math.max
/**
* Created by Allan Wang on 2017-07-15.
@ -219,11 +219,11 @@ class ImageActivity : KauBaseActivity() {
setState(FabStates.SHARE)
}
imagePhoto.setOnImageEventListener(object :
SubsamplingScaleImageView.DefaultOnImageEventListener() {
override fun onImageLoadError(e: Exception) {
loadError(e)
}
})
SubsamplingScaleImageView.DefaultOnImageEventListener() {
override fun onImageLoadError(e: Exception) {
loadError(e)
}
})
setFrostColors {
themeWindow = false
}

View File

@ -63,7 +63,9 @@ import org.koin.android.ext.android.inject
* A beautiful intro activity
* Phone showcases are drawn via layers
*/
class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer,
class IntroActivity :
KauBaseActivity(),
ViewPager.PageTransformer,
ViewPager.OnPageChangeListener {
private val prefs: Prefs by inject()

View File

@ -48,8 +48,6 @@ import com.pitchedapps.frost.utils.logFrostEvent
import com.pitchedapps.frost.utils.setFrostColors
import com.pitchedapps.frost.utils.uniqueOnly
import com.pitchedapps.frost.web.LoginWebView
import java.net.UnknownHostException
import kotlin.coroutines.resume
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
@ -59,6 +57,8 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withTimeout
import org.koin.android.ext.android.inject
import java.net.UnknownHostException
import kotlin.coroutines.resume
/**
* Created by Allan Wang on 2017-06-01.

View File

@ -175,9 +175,12 @@ class SettingsActivity : KPrefActivity() {
descRes = R.string.about_frost_desc
iicon = GoogleMaterial.Icon.gmd_info
onClick = {
startActivityForResult<AboutActivity>(9, bundleBuilder = {
withSceneTransitionAnimation(this@SettingsActivity)
})
startActivityForResult<AboutActivity>(
9,
bundleBuilder = {
withSceneTransitionAnimation(this@SettingsActivity)
}
)
}
}

View File

@ -43,10 +43,10 @@ import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.iitems.TabIItem
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.setFrostColors
import java.util.Collections
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import java.util.Collections
/**
* Created by Allan Wang on 26/11/17.

View File

@ -156,9 +156,12 @@ class WebOverlayDesktopActivity : WebOverlayActivityBase(USER_AGENT_DESKTOP_CONS
class WebOverlayActivity : WebOverlayActivityBase()
@UseExperimental(ExperimentalCoroutinesApi::class)
abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT) : BaseActivity(),
ActivityContract, FrostContentContainer,
VideoViewHolder, FileChooserContract by FileChooserDelegate() {
abstract class WebOverlayActivityBase(private val userAgent: String = USER_AGENT) :
BaseActivity(),
ActivityContract,
FrostContentContainer,
VideoViewHolder,
FileChooserContract by FileChooserDelegate() {
override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper)
val toolbar: Toolbar by bindView(R.id.overlay_toolbar)

View File

@ -36,12 +36,14 @@ import kotlinx.android.parcel.Parcelize
@Entity(
tableName = "frost_cache",
primaryKeys = ["id", "type"],
foreignKeys = [ForeignKey(
entity = CookieEntity::class,
parentColumns = ["cookie_id"],
childColumns = ["id"],
onDelete = ForeignKey.CASCADE
)]
foreignKeys = [
ForeignKey(
entity = CookieEntity::class,
parentColumns = ["cookie_id"],
childColumns = ["id"],
onDelete = ForeignKey.CASCADE
)
]
)
@Parcelize
data class CacheEntity(

View File

@ -26,8 +26,8 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import org.koin.dsl.module
import javax.inject.Singleton
interface FrostPrivateDao {
fun cookieDao(): CookieDao

View File

@ -32,12 +32,14 @@ import com.pitchedapps.frost.utils.L
@Entity(
tableName = "notifications",
primaryKeys = ["notif_id", "userId"],
foreignKeys = [ForeignKey(
entity = CookieEntity::class,
parentColumns = ["cookie_id"],
childColumns = ["userId"],
onDelete = ForeignKey.CASCADE
)],
foreignKeys = [
ForeignKey(
entity = CookieEntity::class,
parentColumns = ["cookie_id"],
childColumns = ["userId"],
onDelete = ForeignKey.CASCADE
)
],
indices = [Index("notif_id"), Index("userId")]
)
data class NotificationEntity(

View File

@ -26,12 +26,6 @@ import com.pitchedapps.frost.utils.createFreshDir
import com.pitchedapps.frost.utils.createFreshFile
import com.pitchedapps.frost.utils.frostJsoup
import com.pitchedapps.frost.utils.unescapeHtml
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.withContext
@ -43,6 +37,12 @@ import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.nodes.Entities
import java.io.File
import java.io.FileOutputStream
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.atomic.AtomicInteger
import java.util.zip.ZipEntry
import java.util.zip.ZipOutputStream
/**
* Created by Allan Wang on 04/01/18.

View File

@ -28,13 +28,17 @@ enum class MainActivityLayout(
val iconColor: (ThemeProvider) -> Int
) {
TOP_BAR(R.string.top_bar,
TOP_BAR(
R.string.top_bar,
{ it.headerColor },
{ it.iconColor }),
{ it.iconColor }
),
BOTTOM_BAR(R.string.bottom_bar,
BOTTOM_BAR(
R.string.bottom_bar,
{ it.bgColor },
{ it.textColor });
{ it.textColor }
);
companion object {
val values = values() // save one instance

View File

@ -39,53 +39,65 @@ enum class Theme(
val iconColorGetter: (ThemePrefs) -> Int
) {
DEFAULT(R.string.kau_default,
DEFAULT(
R.string.kau_default,
"default",
{ 0xde000000.toInt() },
{ FACEBOOK_BLUE },
{ 0xfffafafa.toInt() },
{ FACEBOOK_BLUE },
{ Color.WHITE }),
{ Color.WHITE }
),
LIGHT(R.string.kau_light,
LIGHT(
R.string.kau_light,
"material_light",
{ 0xde000000.toInt() },
{ FACEBOOK_BLUE },
{ 0xfffafafa.toInt() },
{ FACEBOOK_BLUE },
{ Color.WHITE }),
{ Color.WHITE }
),
DARK(R.string.kau_dark,
DARK(
R.string.kau_dark,
"material_dark",
{ Color.WHITE },
{ BLUE_LIGHT },
{ 0xff303030.toInt() },
{ 0xff2e4b86.toInt() },
{ Color.WHITE }),
{ Color.WHITE }
),
AMOLED(R.string.kau_amoled,
AMOLED(
R.string.kau_amoled,
"material_amoled",
{ Color.WHITE },
{ BLUE_LIGHT },
{ Color.BLACK },
{ Color.BLACK },
{ Color.WHITE }),
{ Color.WHITE }
),
GLASS(R.string.kau_glass,
GLASS(
R.string.kau_glass,
"material_glass",
{ Color.WHITE },
{ BLUE_LIGHT },
{ 0x80000000.toInt() },
{ 0xb3000000.toInt() },
{ Color.WHITE }),
{ Color.WHITE }
),
CUSTOM(R.string.kau_custom,
CUSTOM(
R.string.kau_custom,
"custom",
{ it.customTextColor },
{ it.customAccentColor },
{ it.customBackgroundColor },
{ it.customHeaderColor },
{ it.customIconColor });
{ it.customIconColor }
);
@VisibleForTesting
internal val file = file?.let { "$it.css" }

View File

@ -28,15 +28,15 @@ import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.cookies
import com.pitchedapps.frost.utils.launchLogin
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.withContext
import org.koin.dsl.module
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
/**
* Created by Allan Wang on 2017-05-30.

View File

@ -90,31 +90,33 @@ private class SearchParserImpl : FrostParserBase<FrostSearches>(false) {
?: doc.getElementById("root")
?: return null
return FrostSearches(container.select("table[role=presentation]").mapNotNull { el ->
// Our assumption is that search entries start with an image, followed by general info
// There may be other <td />s, but we will not be parsing them
// Furthermore, the <td /> entry wraps a link, containing all the necessary info
val a = el.select("td")
.getOrNull(1)
?.selectFirst("a")
?: return@mapNotNull null
val url =
a.attr("href").takeIf { it.isNotEmpty() }
?.formattedFbUrl?.formattedSearchUrl
return FrostSearches(
container.select("table[role=presentation]").mapNotNull { el ->
// Our assumption is that search entries start with an image, followed by general info
// There may be other <td />s, but we will not be parsing them
// Furthermore, the <td /> entry wraps a link, containing all the necessary info
val a = el.select("td")
.getOrNull(1)
?.selectFirst("a")
?: return@mapNotNull null
// Currently, children should all be <div /> elements, where the first entry is the name/title
// And the other entries are additional info.
// There are also cases of nested tables, eg for the "join" button in groups.
// Those elements have <span /> texts, so we will filter by div to ignore those
val texts = a.children().filter { it.tagName() == "div" && it.hasText() }
val title = texts.firstOrNull()?.text() ?: return@mapNotNull null
val info = texts.takeIf { it.size > 1 }?.last()?.text()
L.e { a }
create(
href = url,
title = title,
description = info
).also { L.e { it } }
})
val url =
a.attr("href").takeIf { it.isNotEmpty() }
?.formattedFbUrl?.formattedSearchUrl
?: return@mapNotNull null
// Currently, children should all be <div /> elements, where the first entry is the name/title
// And the other entries are additional info.
// There are also cases of nested tables, eg for the "join" button in groups.
// Those elements have <span /> texts, so we will filter by div to ignore those
val texts = a.children().filter { it.tagName() == "div" && it.hasText() }
val title = texts.firstOrNull()?.text() ?: return@mapNotNull null
val info = texts.takeIf { it.size > 1 }?.last()?.text()
L.e { a }
create(
href = url,
title = title,
description = info
).also { L.e { it } }
}
)
}
}

View File

@ -41,7 +41,6 @@ import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.REQUEST_REFRESH
import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM
import com.pitchedapps.frost.utils.frostEvent
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
@ -51,6 +50,7 @@ import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koin.core.component.inject
import kotlin.coroutines.CoroutineContext
/**
* Created by Allan Wang on 2017-11-07.
@ -59,7 +59,10 @@ import org.koin.core.component.inject
* Must be attached to activities implementing [MainActivityContract]
*/
@UseExperimental(ExperimentalCoroutinesApi::class)
abstract class BaseFragment : Fragment(), CoroutineScope, FragmentContract,
abstract class BaseFragment :
Fragment(),
CoroutineScope,
FragmentContract,
DynamicUiContract {
companion object {

View File

@ -77,7 +77,8 @@ open class HeaderIItem(
itemId: Int = R.layout.iitem_header
) : KauIItem<HeaderIItem.ViewHolder>(R.layout.iitem_header, ::ViewHolder, itemId) {
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<HeaderIItem>(itemView),
class ViewHolder(itemView: View) :
FastAdapter.ViewHolder<HeaderIItem>(itemView),
KoinComponent {
private val themeProvider: ThemeProvider by inject()

View File

@ -101,7 +101,8 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) :
}
}
class ViewHolder(itemView: View) : FastAdapter.ViewHolder<NotificationIItem>(itemView),
class ViewHolder(itemView: View) :
FastAdapter.ViewHolder<NotificationIItem>(itemView),
KoinComponent {
private val themeProvider: ThemeProvider by inject()

View File

@ -36,10 +36,12 @@ import org.koin.core.component.inject
/**
* Created by Allan Wang on 26/11/17.
*/
class TabIItem(val item: FbItem) : KauIItem<TabIItem.ViewHolder>(
R.layout.iitem_tab_preview,
{ ViewHolder(it) }
), IDraggable {
class TabIItem(val item: FbItem) :
KauIItem<TabIItem.ViewHolder>(
R.layout.iitem_tab_preview,
{ ViewHolder(it) }
),
IDraggable {
override val isDraggable: Boolean = true

View File

@ -22,11 +22,11 @@ import androidx.annotation.VisibleForTesting
import ca.allanwang.kau.kotlin.lazyContext
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.BufferedReader
import java.io.FileNotFoundException
import java.util.Locale
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
/**
* Created by Allan Wang on 2017-05-31.

View File

@ -21,8 +21,8 @@ import androidx.annotation.VisibleForTesting
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.web.FrostWebViewClient
import kotlin.random.Random
import org.apache.commons.text.StringEscapeUtils
import kotlin.random.Random
class JsBuilder {
private val css = StringBuilder()

View File

@ -30,63 +30,109 @@ import com.pitchedapps.frost.enums.Theme
import com.pitchedapps.frost.enums.ThemeCategory
import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.BufferedReader
import java.io.FileNotFoundException
import javax.inject.Inject
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.context.GlobalContext
import java.io.BufferedReader
import java.io.FileNotFoundException
import javax.inject.Inject
import javax.inject.Singleton
interface ThemeProvider {
val textColor: Int
val accentColor: Int
val accentColorForWhite: Int
val nativeBgColor: Int
fun nativeBgColor(unread: Boolean): Int
val bgColor: Int
val headerColor: Int
val iconColor: Int
val isCustomTheme: Boolean
/**
* Note that while this can be loaded from any thread, it is typically done through [preload]]
*/
fun injector(category: ThemeCategory): InjectorContract
fun setTheme(id: Int)
fun reset()
suspend fun preload()
companion object {
fun get(): ThemeProvider = GlobalContext.get().get()
fun module() = org.koin.dsl.module {
single<ThemeProvider> { ThemeProviderImpl(get(), get()) }
}
}
}
/**
* Provides [InjectorContract] for each [ThemeCategory].
* Can be reloaded to take in changes from [Prefs]
*/
class ThemeProvider @Inject internal constructor(
class ThemeProviderImpl @Inject internal constructor(
@ApplicationContext private val context: Context,
private val prefs: Prefs
) {
) : ThemeProvider {
private var theme: Theme = Theme.values[prefs.theme]
set(value) {
field = value
prefs.theme = value.ordinal
}
private val injectors: MutableMap<ThemeCategory, InjectorContract> = mutableMapOf()
val textColor: Int
override val textColor: Int
get() = theme.textColorGetter(prefs)
val accentColor: Int
override val accentColor: Int
get() = theme.accentColorGetter(prefs)
val accentColorForWhite: Int
override val accentColorForWhite: Int
get() = when {
accentColor.isColorVisibleOn(Color.WHITE) -> accentColor
textColor.isColorVisibleOn(Color.WHITE) -> textColor
else -> FACEBOOK_BLUE
}
val nativeBgColor: Int
override val nativeBgColor: Int
get() = bgColor.withAlpha(30)
fun nativeBgColor(unread: Boolean) = bgColor
override fun nativeBgColor(unread: Boolean) = bgColor
.colorToForeground(if (unread) 0.7f else 0.0f)
.withAlpha(30)
val bgColor: Int
override val bgColor: Int
get() = theme.backgroundColorGetter(prefs)
val headerColor: Int
override val headerColor: Int
get() = theme.headerColorGetter(prefs)
val iconColor: Int
override val iconColor: Int
get() = theme.iconColorGetter(prefs)
val isCustomTheme: Boolean
override val isCustomTheme: Boolean
get() = theme == Theme.CUSTOM
/**
* Note that while this can be loaded from any thread, it is typically done through [preload]]
*/
fun injector(category: ThemeCategory): InjectorContract =
override fun injector(category: ThemeCategory): InjectorContract =
injectors.getOrPut(category) { createInjector(category) }
/**
@ -128,28 +174,28 @@ class ThemeProvider @Inject internal constructor(
}
}
fun setTheme(id: Int) {
override fun setTheme(id: Int) {
if (theme.ordinal == id) return
theme = Theme.values[id]
reset()
}
fun reset() {
override fun reset() {
injectors.clear()
}
suspend fun preload() {
override suspend fun preload() {
withContext(Dispatchers.IO) {
reset()
ThemeCategory.values().forEach { injector(it) }
}
}
companion object {
fun get(): ThemeProvider = GlobalContext.get().get()
fun module() = org.koin.dsl.module {
single { ThemeProvider(get(), get()) }
}
}
}
@Module
@InstallIn(SingletonComponent::class)
interface ThemeProviderModule {
@Binds
@Singleton
fun themeProvider(to: ThemeProviderImpl): ThemeProvider
}

View File

@ -64,7 +64,7 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) {
private fun View.setThemeClick(theme: Theme) {
setOnClickListener { v ->
prefs.theme = theme.ordinal
themeProvider.setTheme(theme.ordinal)
(activity as IntroActivity).apply {
binding.ripple.ripple(themeProvider.bgColor, v.x + v.pivotX, v.y + v.pivotY)
theme()

View File

@ -35,9 +35,9 @@ import com.pitchedapps.frost.R
import com.pitchedapps.frost.activities.IntroActivity
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import kotlin.math.abs
import org.koin.android.ext.android.inject
import org.koin.core.component.inject
import kotlin.math.abs
/**
* Created by Allan Wang on 2017-07-28.

View File

@ -16,12 +16,12 @@
*/
package com.pitchedapps.frost.kotlin
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BroadcastChannel
import kotlinx.coroutines.launch
import kotlin.coroutines.CoroutineContext
@UseExperimental(ExperimentalCoroutinesApi::class)
fun <T> BroadcastChannel<T>.subscribeDuringJob(

View File

@ -17,7 +17,6 @@
package com.pitchedapps.frost.kotlin
import com.pitchedapps.frost.utils.L
import java.util.concurrent.ConcurrentHashMap
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineExceptionHandler
@ -29,6 +28,7 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.selects.select
import java.util.concurrent.ConcurrentHashMap
/**
* Flyweight to keep track of values so long as they are valid.

View File

@ -20,6 +20,7 @@ import ca.allanwang.kau.kpref.KPref
import ca.allanwang.kau.kpref.KPrefFactory
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.enums.FeedSort
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-05-28.
@ -29,7 +30,8 @@ import com.pitchedapps.frost.enums.FeedSort
* As of 2020-07-18, prefs have been split up into multiple folders
*/
@Deprecated(level = DeprecationLevel.WARNING, message = "Use pref segments")
class OldPrefs(factory: KPrefFactory) : KPref("${BuildConfig.APPLICATION_ID}.prefs", factory) {
class OldPrefs @Inject internal constructor(factory: KPrefFactory) :
KPref("${BuildConfig.APPLICATION_ID}.prefs", factory) {
var lastLaunch: Long by kpref("last_launch", -1L)

View File

@ -37,10 +37,10 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Inject
import javax.inject.Singleton
import org.koin.core.context.GlobalContext
import org.koin.dsl.module
import javax.inject.Inject
import javax.inject.Singleton
/**
* [Prefs] is no longer an actual pref, but we will expose the reset function as it is used elsewhere
@ -62,12 +62,12 @@ interface Prefs :
fun get(): Prefs = GlobalContext.get().get()
fun module() = module {
single<BehaviourPrefs> { BehaviourPrefsImpl(factory = get()) }
single<CorePrefs> { CorePrefsImpl(factory = get()) }
single<FeedPrefs> { FeedPrefsImpl(factory = get()) }
single<NotifPrefs> { NotifPrefsImpl(factory = get()) }
single<ThemePrefs> { ThemePrefsImpl(factory = get()) }
single<ShowcasePrefs> { ShowcasePrefsImpl(factory = get()) }
single<BehaviourPrefs> { BehaviourPrefsImpl(get(), get()) }
single<CorePrefs> { CorePrefsImpl(get(), get()) }
single<FeedPrefs> { FeedPrefsImpl(get(), get()) }
single<NotifPrefs> { NotifPrefsImpl(get(), get()) }
single<ThemePrefs> { ThemePrefsImpl(get(), get()) }
single<ShowcasePrefs> { ShowcasePrefsImpl(get()) }
single<Prefs> {
PrefsImpl(
behaviourPrefs = get(),

View File

@ -22,8 +22,6 @@ import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.prefs.OldPrefs
import com.pitchedapps.frost.prefs.PrefsBase
import javax.inject.Inject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
interface BehaviourPrefs : PrefsBase {
var biometricsEnabled: Boolean
@ -52,11 +50,9 @@ interface BehaviourPrefs : PrefsBase {
}
class BehaviourPrefsImpl @Inject internal constructor(
factory: KPrefFactory
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.behaviour", factory),
BehaviourPrefs, KoinComponent {
private val oldPrefs: OldPrefs by inject()
factory: KPrefFactory,
oldPrefs: OldPrefs,
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.behaviour", factory), BehaviourPrefs {
override var biometricsEnabled: Boolean by kpref(
"biometrics_enabled",

View File

@ -22,8 +22,6 @@ import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.prefs.OldPrefs
import com.pitchedapps.frost.prefs.PrefsBase
import javax.inject.Inject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
interface CorePrefs : PrefsBase {
var lastLaunch: Long
@ -58,11 +56,9 @@ interface CorePrefs : PrefsBase {
}
class CorePrefsImpl @Inject internal constructor(
factory: KPrefFactory
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.core", factory),
CorePrefs, KoinComponent {
private val oldPrefs: OldPrefs by inject()
factory: KPrefFactory,
oldPrefs: OldPrefs,
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.core", factory), CorePrefs {
override var lastLaunch: Long by kpref("last_launch", oldPrefs.lastLaunch /* -1L */)

View File

@ -23,8 +23,6 @@ import com.pitchedapps.frost.enums.MainActivityLayout
import com.pitchedapps.frost.prefs.OldPrefs
import com.pitchedapps.frost.prefs.PrefsBase
import javax.inject.Inject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
interface FeedPrefs : PrefsBase {
var webTextScaling: Int
@ -53,11 +51,9 @@ interface FeedPrefs : PrefsBase {
}
class FeedPrefsImpl @Inject internal constructor(
factory: KPrefFactory
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.feed", factory),
FeedPrefs, KoinComponent {
private val oldPrefs: OldPrefs by inject()
factory: KPrefFactory,
oldPrefs: OldPrefs
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.feed", factory), FeedPrefs {
override var webTextScaling: Int by kpref("web_text_scaling", oldPrefs.webTextScaling /* 100 */)

View File

@ -22,8 +22,6 @@ import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.prefs.OldPrefs
import com.pitchedapps.frost.prefs.PrefsBase
import javax.inject.Inject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
interface NotifPrefs : PrefsBase {
var notificationKeywords: Set<String>
@ -50,11 +48,9 @@ interface NotifPrefs : PrefsBase {
}
class NotifPrefsImpl @Inject internal constructor(
factory: KPrefFactory
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.notif", factory),
NotifPrefs, KoinComponent {
private val oldPrefs: OldPrefs by inject()
factory: KPrefFactory,
oldPrefs: OldPrefs,
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.notif", factory), NotifPrefs {
override var notificationKeywords: Set<String> by kpref(
"notification_keywords",

View File

@ -38,8 +38,7 @@ interface ShowcasePrefs : PrefsBase {
*/
class ShowcasePrefsImpl @Inject internal constructor(
factory: KPrefFactory
) : KPref("${BuildConfig.APPLICATION_ID}.showcase", factory),
ShowcasePrefs {
) : KPref("${BuildConfig.APPLICATION_ID}.showcase", factory), ShowcasePrefs {
override val firstWebOverlay: Boolean by kprefSingle("first_web_overlay")

View File

@ -19,12 +19,9 @@ package com.pitchedapps.frost.prefs.sections
import ca.allanwang.kau.kpref.KPref
import ca.allanwang.kau.kpref.KPrefFactory
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.OldPrefs
import com.pitchedapps.frost.prefs.PrefsBase
import javax.inject.Inject
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
interface ThemePrefs : PrefsBase {
var theme: Int
@ -43,16 +40,15 @@ interface ThemePrefs : PrefsBase {
}
class ThemePrefsImpl @Inject internal constructor(
factory: KPrefFactory
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.theme", factory),
ThemePrefs, KoinComponent {
factory: KPrefFactory,
oldPrefs: OldPrefs,
) : KPref("${BuildConfig.APPLICATION_ID}.prefs.theme", factory), ThemePrefs {
private val oldPrefs: OldPrefs by inject()
private val themeProvider: ThemeProvider by inject()
override var theme: Int by kpref("theme", oldPrefs.theme /* 0 */) {
themeProvider.setTheme(it)
}
/**
* Note that this is purely for the pref storage. Updating themes should use
* ThemeProvider
*/
override var theme: Int by kpref("theme", oldPrefs.theme /* 0 */)
override var customTextColor: Int by kpref(
"color_text",

View File

@ -20,9 +20,9 @@ import android.app.job.JobParameters
import android.app.job.JobService
import androidx.annotation.CallSuper
import ca.allanwang.kau.utils.ContextHelper
import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job
import kotlin.coroutines.CoroutineContext
abstract class BaseJobService : JobService(), CoroutineScope {

View File

@ -24,10 +24,10 @@ import android.content.Context
import android.os.PersistableBundle
import com.pitchedapps.frost.activities.ImageActivity
import com.pitchedapps.frost.utils.L
import java.io.FileFilter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.FileFilter
class LocalService : BaseJobService() {

View File

@ -43,7 +43,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
header(R.string.theme_customization)
text(R.string.theme, prefs::theme, { prefs.theme = it }) {
text(R.string.theme, prefs::theme, { themeProvider.setTheme(it) }) {
onClick = {
materialDialog {
title(R.string.theme)
@ -78,53 +78,68 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
themeProvider.reset()
}
colorPicker(R.string.text_color, prefs::customTextColor, {
prefs.customTextColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
}) {
colorPicker(
R.string.text_color, prefs::customTextColor,
{
prefs.customTextColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
}
) {
dependsOnCustom()
allowCustomAlpha = false
}
colorPicker(R.string.accent_color, prefs::customAccentColor, {
prefs.customAccentColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
}) {
colorPicker(
R.string.accent_color, prefs::customAccentColor,
{
prefs.customAccentColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
}
) {
dependsOnCustom()
allowCustomAlpha = false
}
colorPicker(R.string.background_color, prefs::customBackgroundColor, {
prefs.customBackgroundColor = it
bgCanvas.ripple(it, duration = 500L)
invalidateCustomTheme()
setFrostTheme(themeProvider, true)
shouldRestartMain()
}) {
colorPicker(
R.string.background_color, prefs::customBackgroundColor,
{
prefs.customBackgroundColor = it
bgCanvas.ripple(it, duration = 500L)
invalidateCustomTheme()
setFrostTheme(themeProvider, true)
shouldRestartMain()
}
) {
dependsOnCustom()
allowCustomAlpha = true
}
colorPicker(R.string.header_color, prefs::customHeaderColor, {
prefs.customHeaderColor = it
frostNavigationBar(prefs, themeProvider)
toolbarCanvas.ripple(it, RippleCanvas.MIDDLE, RippleCanvas.END, duration = 500L)
reload()
shouldRestartMain()
}) {
colorPicker(
R.string.header_color, prefs::customHeaderColor,
{
prefs.customHeaderColor = it
frostNavigationBar(prefs, themeProvider)
toolbarCanvas.ripple(it, RippleCanvas.MIDDLE, RippleCanvas.END, duration = 500L)
reload()
shouldRestartMain()
}
) {
dependsOnCustom()
allowCustomAlpha = true
}
colorPicker(R.string.icon_color, prefs::customIconColor, {
prefs.customIconColor = it
invalidateOptionsMenu()
shouldRestartMain()
}) {
colorPicker(
R.string.icon_color, prefs::customIconColor,
{
prefs.customIconColor = it
invalidateOptionsMenu()
shouldRestartMain()
}
) {
dependsOnCustom()
allowCustomAlpha = false
}
@ -134,7 +149,8 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
text(
R.string.main_activity_layout,
prefs::mainActivityLayoutType,
{ prefs.mainActivityLayoutType = it }) {
{ prefs.mainActivityLayoutType = it }
) {
textGetter = { string(prefs.mainActivityLayout.titleRes) }
onClick = {
materialDialog {
@ -158,11 +174,14 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
onClick = { launchTabCustomizerActivity() }
}
checkbox(R.string.tint_nav, prefs::tintNavBar, {
prefs.tintNavBar = it
frostNavigationBar(prefs, themeProvider)
setFrostResult(REQUEST_NAV)
}) {
checkbox(
R.string.tint_nav, prefs::tintNavBar,
{
prefs.tintNavBar = it
frostNavigationBar(prefs, themeProvider)
setFrostResult(REQUEST_NAV)
}
) {
descRes = R.string.tint_nav_desc
}
@ -174,12 +193,16 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
) {
prefs.webTextScaling = it
setFrostResult(REQUEST_TEXT_ZOOM)
})
}
)
)
checkbox(R.string.enforce_black_media_bg, prefs::blackMediaBg, {
prefs.blackMediaBg = it
}) {
checkbox(
R.string.enforce_black_media_bg, prefs::blackMediaBg,
{
prefs.blackMediaBg = it
}
) {
descRes = R.string.enforce_black_media_bg_desc
}
}

View File

@ -36,21 +36,24 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(
R.string.overlay_swipe,
prefs::overlayEnabled,
{ prefs.overlayEnabled = it; shouldRefreshMain() }) {
{ prefs.overlayEnabled = it; shouldRefreshMain() }
) {
descRes = R.string.overlay_swipe_desc
}
checkbox(
R.string.overlay_full_screen_swipe,
prefs::overlayFullScreenSwipe,
{ prefs.overlayFullScreenSwipe = it }) {
{ prefs.overlayFullScreenSwipe = it }
) {
descRes = R.string.overlay_full_screen_swipe_desc
}
checkbox(
R.string.open_links_in_default,
prefs::linksInDefaultApp,
{ prefs.linksInDefaultApp = it }) {
{ prefs.linksInDefaultApp = it }
) {
descRes = R.string.open_links_in_default_desc
}
@ -61,14 +64,16 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(
R.string.force_message_bottom,
prefs::messageScrollToBottom,
{ prefs.messageScrollToBottom = it }) {
{ prefs.messageScrollToBottom = it }
) {
descRes = R.string.force_message_bottom_desc
}
checkbox(
R.string.auto_expand_text_box,
prefs::autoExpandTextBox,
{ prefs.autoExpandTextBox = it; shouldRefreshMain() }) {
{ prefs.autoExpandTextBox = it; shouldRefreshMain() }
) {
descRes = R.string.auto_expand_text_box_desc
}

View File

@ -39,11 +39,11 @@ import com.pitchedapps.frost.facebook.parsers.SearchParser
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostUriFromFile
import com.pitchedapps.frost.utils.sendFrostEmail
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import java.io.File
/**
* Created by Allan Wang on 2017-06-30.

View File

@ -36,10 +36,13 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = {
// Experimental content ends here --------------------
checkbox(R.string.verbose_logging, prefs::verboseLogging, {
prefs.verboseLogging = it
KL.shouldLog = { it != Log.VERBOSE }
}) {
checkbox(
R.string.verbose_logging, prefs::verboseLogging,
{
prefs.verboseLogging = it
KL.shouldLog = { it != Log.VERBOSE }
}
) {
descRes = R.string.verbose_logging_desc
}

View File

@ -49,66 +49,93 @@ fun SettingsActivity.getFeedPrefs(): KPrefAdapterBuilder.() -> Unit = {
textGetter = { string(FeedSort(it).textRes) }
}
checkbox(R.string.aggressive_recents, prefs::aggressiveRecents, {
prefs.aggressiveRecents = it
shouldRefreshMain()
}) {
checkbox(
R.string.aggressive_recents, prefs::aggressiveRecents,
{
prefs.aggressiveRecents = it
shouldRefreshMain()
}
) {
descRes = R.string.aggressive_recents_desc
}
checkbox(R.string.composer, prefs::showComposer, {
prefs.showComposer = it
shouldRefreshMain()
}) {
checkbox(
R.string.composer, prefs::showComposer,
{
prefs.showComposer = it
shouldRefreshMain()
}
) {
descRes = R.string.composer_desc
}
checkbox(R.string.create_fab, prefs::showCreateFab, {
prefs.showCreateFab = it
setFrostResult(REQUEST_FAB)
}) {
checkbox(
R.string.create_fab, prefs::showCreateFab,
{
prefs.showCreateFab = it
setFrostResult(REQUEST_FAB)
}
) {
descRes = R.string.create_fab_desc
}
checkbox(R.string.suggested_friends, prefs::showSuggestedFriends, {
prefs.showSuggestedFriends = it
shouldRefreshMain()
}) {
checkbox(
R.string.suggested_friends, prefs::showSuggestedFriends,
{
prefs.showSuggestedFriends = it
shouldRefreshMain()
}
) {
descRes = R.string.suggested_friends_desc
}
checkbox(R.string.suggested_groups, prefs::showSuggestedGroups, {
prefs.showSuggestedGroups = it
shouldRefreshMain()
}) {
checkbox(
R.string.suggested_groups, prefs::showSuggestedGroups,
{
prefs.showSuggestedGroups = it
shouldRefreshMain()
}
) {
descRes = R.string.suggested_groups_desc
}
checkbox(R.string.show_stories, prefs::showStories, {
prefs.showStories = it
shouldRefreshMain()
}) {
checkbox(
R.string.show_stories, prefs::showStories,
{
prefs.showStories = it
shouldRefreshMain()
}
) {
descRes = R.string.show_stories_desc
}
checkbox(R.string.show_post_actions, prefs::showPostActions, {
prefs.showPostActions = it
shouldRefreshMain()
}) {
checkbox(
R.string.show_post_actions, prefs::showPostActions,
{
prefs.showPostActions = it
shouldRefreshMain()
}
) {
descRes = R.string.show_post_actions_desc
}
checkbox(R.string.show_post_reactions, prefs::showPostReactions, {
prefs.showPostReactions = it
shouldRefreshMain()
}) {
checkbox(
R.string.show_post_reactions, prefs::showPostReactions,
{
prefs.showPostReactions = it
shouldRefreshMain()
}
) {
descRes = R.string.show_post_reactions_desc
}
checkbox(R.string.full_size_image, prefs::fullSizeImage, {
prefs.fullSizeImage = it
shouldRefreshMain()
}) {
checkbox(
R.string.full_size_image, prefs::fullSizeImage,
{
prefs.fullSizeImage = it
shouldRefreshMain()
}
) {
descRes = R.string.full_size_image_desc
}
}

View File

@ -28,7 +28,8 @@ fun SettingsActivity.getNetworkPrefs(): KPrefAdapterBuilder.() -> Unit = {
checkbox(
R.string.network_media_on_metered,
{ !prefs.loadMediaOnMeteredNetwork },
{ prefs.loadMediaOnMeteredNetwork = !it }) {
{ prefs.loadMediaOnMeteredNetwork = !it }
) {
descRes = R.string.network_media_on_metered_desc
}
}

View File

@ -54,7 +54,8 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
text(
R.string.notification_frequency,
prefs::notificationFreq,
{ prefs.notificationFreq = it }) {
{ prefs.notificationFreq = it }
) {
val options = longArrayOf(15, 30, 60, 120, 180, 300, 1440, 2880)
val texts =
options.map { if (it <= 0) string(R.string.no_notifications) else minuteToText(it) }
@ -87,34 +88,42 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
checkbox(R.string.notification_general, prefs::notificationsGeneral,
checkbox(
R.string.notification_general, prefs::notificationsGeneral,
{
prefs.notificationsGeneral = it
reloadByTitle(R.string.notification_general_all_accounts)
if (!prefs.notificationsInstantMessages)
reloadByTitle(R.string.notification_frequency)
}) {
}
) {
descRes = R.string.notification_general_desc
}
checkbox(R.string.notification_general_all_accounts, prefs::notificationAllAccounts,
{ prefs.notificationAllAccounts = it }) {
checkbox(
R.string.notification_general_all_accounts, prefs::notificationAllAccounts,
{ prefs.notificationAllAccounts = it }
) {
descRes = R.string.notification_general_all_accounts_desc
enabler = { prefs.notificationsGeneral }
}
checkbox(R.string.notification_messages, prefs::notificationsInstantMessages,
checkbox(
R.string.notification_messages, prefs::notificationsInstantMessages,
{
prefs.notificationsInstantMessages = it
reloadByTitle(R.string.notification_messages_all_accounts)
if (!prefs.notificationsGeneral)
reloadByTitle(R.string.notification_frequency)
}) {
}
) {
descRes = R.string.notification_messages_desc
}
checkbox(R.string.notification_messages_all_accounts, prefs::notificationsImAllAccounts,
{ prefs.notificationsImAllAccounts = it }) {
checkbox(
R.string.notification_messages_all_accounts, prefs::notificationsImAllAccounts,
{ prefs.notificationsImAllAccounts = it }
) {
descRes = R.string.notification_messages_all_accounts_desc
enabler = { prefs.notificationsInstantMessages }
}
@ -129,13 +138,16 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
} else {
checkbox(R.string.notification_sound, prefs::notificationSound, {
prefs.notificationSound = it
reloadByTitle(
R.string.notification_ringtone,
R.string.message_ringtone
)
})
checkbox(
R.string.notification_sound, prefs::notificationSound,
{
prefs.notificationSound = it
reloadByTitle(
R.string.notification_ringtone,
R.string.message_ringtone
)
}
)
fun KPrefText.KPrefTextContract<String>.ringtone(code: Int) {
enabler = prefs::notificationSound
@ -162,21 +174,29 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = {
}
}
text(R.string.notification_ringtone, prefs::notificationRingtone,
{ prefs.notificationRingtone = it }) {
text(
R.string.notification_ringtone, prefs::notificationRingtone,
{ prefs.notificationRingtone = it }
) {
ringtone(SettingsActivity.REQUEST_NOTIFICATION_RINGTONE)
}
text(R.string.message_ringtone, prefs::messageRingtone,
{ prefs.messageRingtone = it }) {
text(
R.string.message_ringtone, prefs::messageRingtone,
{ prefs.messageRingtone = it }
) {
ringtone(SettingsActivity.REQUEST_MESSAGE_RINGTONE)
}
checkbox(R.string.notification_vibrate, prefs::notificationVibrate,
{ prefs.notificationVibrate = it })
checkbox(
R.string.notification_vibrate, prefs::notificationVibrate,
{ prefs.notificationVibrate = it }
)
checkbox(R.string.notification_lights, prefs::notificationLights,
{ prefs.notificationLights = it })
checkbox(
R.string.notification_lights, prefs::notificationLights,
{ prefs.notificationLights = it }
)
}
if (BuildConfig.DEBUG) {

View File

@ -31,18 +31,21 @@ fun SettingsActivity.getSecurityPrefs(): KPrefAdapterBuilder.() -> Unit = {
descRes = R.string.security_disclaimer_info
}
checkbox(R.string.enable_biometrics, prefs::biometricsEnabled, {
launch {
checkbox(
R.string.enable_biometrics, prefs::biometricsEnabled,
{
launch {
/*
* For security, we should request authentication when:
* - enabling to ensure that it is supported
* - disabling to ensure that it is permitted
*/
BiometricUtils.authenticate(this@getSecurityPrefs, prefs, force = true).await()
prefs.biometricsEnabled = it
reloadByTitle(R.string.enable_biometrics)
BiometricUtils.authenticate(this@getSecurityPrefs, prefs, force = true).await()
prefs.biometricsEnabled = it
reloadByTitle(R.string.enable_biometrics)
}
}
}) {
) {
descRes = R.string.enable_biometrics_desc
enabler = { BiometricUtils.isSupported(this@getSecurityPrefs) }
}

View File

@ -27,10 +27,10 @@ import androidx.lifecycle.OnLifecycleEvent
import ca.allanwang.kau.utils.string
import com.pitchedapps.frost.R
import com.pitchedapps.frost.prefs.Prefs
import kotlinx.coroutines.CompletableDeferred
import java.util.concurrent.Executor
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
import kotlinx.coroutines.CompletableDeferred
typealias BiometricDeferred = CompletableDeferred<BiometricPrompt.CryptoObject?>

View File

@ -72,12 +72,6 @@ import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.injectors.JsAssets
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import java.io.File
import java.io.IOException
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.util.ArrayList
import java.util.Locale
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import org.apache.commons.text.StringEscapeUtils
@ -86,6 +80,12 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
import java.io.IOException
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.util.ArrayList
import java.util.Locale
/**
* Created by Allan Wang on 2017-06-03.
@ -101,9 +101,12 @@ inline fun <reified T : Activity> Context.launchNewTask(
cookieList: ArrayList<CookieEntity> = arrayListOf(),
clearStack: Boolean = false
) {
startActivity<T>(clearStack, intentBuilder = {
putParcelableArrayListExtra(EXTRA_COOKIES, cookieList)
})
startActivity<T>(
clearStack,
intentBuilder = {
putParcelableArrayListExtra(EXTRA_COOKIES, cookieList)
}
)
}
fun Context.launchLogin(cookieList: ArrayList<CookieEntity>, clearStack: Boolean = true) {
@ -133,9 +136,12 @@ private inline fun <reified T : WebOverlayActivityBase> Context.launchWebOverlay
fbCookie.logout(this@launchWebOverlayImpl)
}
} else if (!(prefs.linksInDefaultApp && resolveActivityForUri(Uri.parse(argUrl)))) {
startActivity<T>(false, intentBuilder = {
putExtra(ARG_URL, argUrl)
})
startActivity<T>(
false,
intentBuilder = {
putExtra(ARG_URL, argUrl)
}
)
}
}
@ -155,12 +161,14 @@ private fun Context.fadeBundle() = ActivityOptions.makeCustomAnimation(
).toBundle()
fun Context.launchImageActivity(imageUrl: String, text: String? = null, cookie: String? = null) {
startActivity<ImageActivity>(intentBuilder = {
putExtras(fadeBundle())
putExtra(ARG_IMAGE_URL, imageUrl)
putExtra(ARG_TEXT, text)
putExtra(ARG_COOKIE, cookie)
})
startActivity<ImageActivity>(
intentBuilder = {
putExtras(fadeBundle())
putExtra(ARG_IMAGE_URL, imageUrl)
putExtra(ARG_TEXT, text)
putExtra(ARG_COOKIE, cookie)
}
)
}
fun Activity.launchTabCustomizerActivity() {
@ -168,7 +176,8 @@ fun Activity.launchTabCustomizerActivity() {
SettingsActivity.ACTIVITY_REQUEST_TABS,
bundleBuilder = {
with(fadeBundle())
})
}
)
}
fun WebOverlayActivity.url(): String {
@ -177,9 +186,11 @@ fun WebOverlayActivity.url(): String {
fun Activity.setFrostTheme(themeProvider: ThemeProvider, forceTransparent: Boolean = false) {
val isTransparent =
forceTransparent || (Color.alpha(themeProvider.bgColor) != 255) || (Color.alpha(
themeProvider.headerColor
) != 255)
forceTransparent || (Color.alpha(themeProvider.bgColor) != 255) || (
Color.alpha(
themeProvider.headerColor
) != 255
)
if (themeProvider.bgColor.isColorDark) {
setTheme(if (isTransparent) R.style.FrostTheme_Transparent else R.style.FrostTheme)
} else {

View File

@ -72,7 +72,8 @@ enum class WebContextType(
OPEN_LINK(
R.string.open_link,
{ it.hasUrl },
{ c, wc, fc -> c.launchWebOverlay(wc.url!!, fc, Prefs.get()) }),
{ c, wc, fc -> c.launchWebOverlay(wc.url!!, fc, Prefs.get()) }
),
COPY_LINK(R.string.copy_link, { it.hasUrl }, { c, wc, _ -> c.copyToClipboard(wc.url) }),
COPY_TEXT(R.string.copy_text, { it.hasText }, { c, wc, _ -> c.copyToClipboard(wc.text) }),
SHARE_LINK(R.string.share_link, { it.hasUrl }, { c, wc, _ -> c.shareText(wc.url) })

View File

@ -31,20 +31,25 @@ import com.mikepenz.iconics.typeface.IIcon
import com.pitchedapps.frost.databinding.ViewBadgedIconBinding
import com.pitchedapps.frost.injectors.ThemeProvider
import com.pitchedapps.frost.prefs.Prefs
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-06-19.
*/
@AndroidEntryPoint
class BadgedIcon @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr), KoinComponent {
) : ConstraintLayout(context, attrs, defStyleAttr) {
@Inject
lateinit var prefs: Prefs
@Inject
lateinit var themeProvider: ThemeProvider
private val prefs: Prefs by inject()
private val themeProvider: ThemeProvider by inject()
private val binding: ViewBadgedIconBinding =
ViewBadgedIconBinding.inflate(LayoutInflater.from(context), this, true)
@ -54,7 +59,8 @@ class BadgedIcon @JvmOverloads constructor(
private fun ViewBadgedIconBinding.init() {
val badgeColor =
prefs.mainActivityLayout.backgroundColor(themeProvider).withAlpha(255).colorToForeground(0.2f)
prefs.mainActivityLayout.backgroundColor(themeProvider).withAlpha(255)
.colorToForeground(0.2f)
val badgeBackground =
GradientDrawable(
GradientDrawable.Orientation.BOTTOM_TOP,

View File

@ -77,7 +77,8 @@ abstract class FrostContentView<out T> @JvmOverloads constructor(
defStyleAttr: Int = 0,
defStyleRes: Int = 0
) : FrameLayout(context, attrs, defStyleAttr, defStyleRes),
FrostContentParent, KoinComponent where T : View, T : FrostContentCore {
FrostContentParent,
KoinComponent where T : View, T : FrostContentCore {
private val prefs: Prefs by inject()
private val themeProvider: ThemeProvider by inject()

View File

@ -29,9 +29,9 @@ import com.pitchedapps.frost.contracts.FrostContentParent
import com.pitchedapps.frost.fragments.RecyclerContentContract
import com.pitchedapps.frost.prefs.Prefs
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import javax.inject.Inject
/**
* Created by Allan Wang on 2017-05-29.

View File

@ -192,12 +192,12 @@ class FrostVideoViewer @JvmOverloads constructor(
fun updateLocation() {
with(binding) {
viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
video.updateLocation()
viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
video.updateLocation()
viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
}
}
@ -206,7 +206,8 @@ class FrostVideoViewer @JvmOverloads constructor(
if (video.isExpanded)
videoToolbar.fadeIn(
duration = CONTROL_ANIMATION_DURATION,
onStart = { videoToolbar.visible() })
onStart = { videoToolbar.visible() }
)
}
}

View File

@ -34,11 +34,11 @@ import com.pitchedapps.frost.prefs.Prefs
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.createFreshFile
import com.pitchedapps.frost.utils.isFacebookUrl
import java.io.File
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import java.io.File
/**
* Created by Allan Wang on 2018-01-05.

View File

@ -21,8 +21,8 @@ import android.webkit.WebResourceResponse
import android.webkit.WebView
import com.pitchedapps.frost.utils.FrostPglAdBlock
import com.pitchedapps.frost.utils.L
import java.io.ByteArrayInputStream
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import java.io.ByteArrayInputStream
/**
* Created by Allan Wang on 2017-07-13.

View File

@ -18,6 +18,12 @@ package com.pitchedapps.frost.debugger
import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.internal.COOKIE
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import org.junit.Assume.assumeTrue
import java.io.File
import java.util.zip.ZipFile
import kotlin.test.AfterTest
@ -27,12 +33,6 @@ import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlinx.coroutines.runBlocking
import okhttp3.mockwebserver.Dispatcher
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.RecordedRequest
import org.junit.Assume.assumeTrue
/**
* Created by Allan Wang on 05/01/18.
@ -247,7 +247,8 @@ class OfflineWebsiteTest {
assertEquals(5, zip.size(), "2 files expected")
zip.assertContentEquals(
"index.html", content
"index.html",
content
.replace(css1Url.toString(), "assets/a0_1.css")
.replace(css2Url.toString(), "assets/a1_2.css")
.replace(js1Url.toString(), "assets/a2_1.js.txt")

View File

@ -18,9 +18,9 @@ package com.pitchedapps.frost.facebook
import com.pitchedapps.frost.internal.authDependent
import com.pitchedapps.frost.internal.testJsoup
import kotlin.test.assertNotNull
import org.junit.BeforeClass
import org.junit.Test
import kotlin.test.assertNotNull
class FbDomTest {

View File

@ -16,9 +16,9 @@
*/
package com.pitchedapps.frost.facebook
import kotlin.test.assertEquals
import org.apache.commons.text.StringEscapeUtils
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Allan Wang on 24/12/17.

View File

@ -18,10 +18,10 @@ package com.pitchedapps.frost.facebook
import com.pitchedapps.frost.utils.isImageUrl
import com.pitchedapps.frost.utils.isIndirectImageUrl
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.junit.Test
/**
* Created by Allan Wang on 2017-07-07.

View File

@ -20,12 +20,12 @@ import com.pitchedapps.frost.internal.COOKIE
import com.pitchedapps.frost.internal.assertComponentsNotEmpty
import com.pitchedapps.frost.internal.assertDescending
import com.pitchedapps.frost.internal.authDependent
import org.junit.BeforeClass
import org.junit.Test
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import kotlin.test.fail
import org.junit.BeforeClass
import org.junit.Test
/**
* Created by Allan Wang on 24/12/17.

View File

@ -18,10 +18,10 @@ package com.pitchedapps.frost.facebook.requests
import com.pitchedapps.frost.internal.COOKIE
import com.pitchedapps.frost.internal.authDependent
import kotlin.test.assertNotNull
import kotlinx.coroutines.runBlocking
import org.junit.BeforeClass
import org.junit.Test
import kotlin.test.assertNotNull
/**
* Created by Allan Wang on 12/04/18.

View File

@ -20,6 +20,7 @@ import com.pitchedapps.frost.facebook.FB_USER_MATCHER
import com.pitchedapps.frost.facebook.FbItem
import com.pitchedapps.frost.facebook.get
import com.pitchedapps.frost.utils.frostJsoup
import org.junit.Assume
import java.io.File
import java.io.FileInputStream
import java.util.Properties
@ -27,7 +28,6 @@ import kotlin.reflect.full.starProjectedType
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import kotlin.test.fail
import org.junit.Assume
/**
* Created by Allan Wang on 21/12/17.

View File

@ -16,6 +16,11 @@
*/
package com.pitchedapps.frost.kotlin
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.rules.Timeout
import java.util.concurrent.atomic.AtomicInteger
import kotlin.test.BeforeTest
import kotlin.test.Test
@ -23,11 +28,6 @@ import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlin.test.fail
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.runBlocking
import org.junit.Rule
import org.junit.rules.Timeout
class FlyweightTest {

View File

@ -16,9 +16,9 @@
*/
package com.pitchedapps.frost.prefs
import kotlin.test.assertEquals
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Allan Wang on 2017-05-31.

View File

@ -17,10 +17,10 @@
package com.pitchedapps.frost.utils
import com.pitchedapps.frost.BuildConfig
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import org.junit.Test
class BuildUtilsTest {

View File

@ -17,13 +17,6 @@
package com.pitchedapps.frost.utils
import com.pitchedapps.frost.kotlin.Flyweight
import java.util.concurrent.Executors
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.GlobalScope
@ -39,6 +32,13 @@ import kotlinx.coroutines.joinAll
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.util.concurrent.Executors
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
/**
* Collection of tests around coroutines

View File

@ -16,8 +16,8 @@
*/
package com.pitchedapps.frost.utils
import kotlin.test.assertEquals
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Allan Wang on 2017-08-10.

View File

@ -16,8 +16,8 @@
*/
package com.pitchedapps.frost.utils
import kotlin.test.assertEquals
import org.junit.Test
import kotlin.test.assertEquals
/**
* Created by Allan Wang on 11/03/18.

View File

@ -17,10 +17,10 @@
package com.pitchedapps.frost.utils
import com.pitchedapps.frost.facebook.FACEBOOK_COM
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
import org.junit.Test
/**
* Created by Allan Wang on 2017-11-15.

View File

@ -3,7 +3,7 @@ apply plugin: "com.diffplug.spotless"
spotless {
kotlin {
target "**/*.kt"
ktlint()
ktlint("0.41.0").userData(["disabled_rules": "no-wildcard-imports"])
licenseHeaderFile '../spotless.license.kt'
trimTrailingWhitespace()
endWithNewline()