1
0
mirror of https://github.com/AllanWang/Frost-for-Facebook.git synced 2024-11-10 04:52:38 +01:00

Add keys and header reload

This commit is contained in:
Allan Wang 2017-06-23 21:53:50 -07:00
parent 8c1ff3e546
commit 0aac77d2bb
13 changed files with 214 additions and 49 deletions

5
.gitignore vendored
View File

@ -7,8 +7,5 @@
/build
/captures
.externalNativeBuild
/app/src/main/res/values/strings_facebook.xml
/app/src/main/kotlin/com/pitchedapps/frost/facebook/Private.kt
*.min.css
.sass-cache/
PrivConstants.kt
.sass-cache/

View File

@ -15,6 +15,7 @@ import android.support.v4.view.ViewPager
import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
import ca.allanwang.kau.changelog.showChangelog
import ca.allanwang.kau.utils.*
import co.zsmb.materialdrawerkt.builders.Builder
import co.zsmb.materialdrawerkt.builders.accountHeader
@ -36,7 +37,6 @@ import com.pitchedapps.frost.facebook.FbCookie.switchUser
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
import com.pitchedapps.frost.fragments.WebFragment
import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.views.BadgedIcon
import io.reactivex.android.schedulers.AndroidSchedulers
@ -61,14 +61,20 @@ class MainActivity : BaseActivity() {
companion object {
const val FRAGMENT_REFRESH = 99
/*
* Possible responses from the SettingsActivity
* after the configurations have changed
*/
const val REQUEST_RESTART = 90909
const val REQUEST_REFRESH = 80808
const val REQUEST_NAV = 10101
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (BuildConfig.VERSION_CODE > Prefs.versionCode) {
Prefs.versionCode = BuildConfig.VERSION_CODE
showChangelog(R.xml.changelog, { theme() })
showChangelog(R.xml.changelog, Prefs.textColor) { theme() }
}
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
@ -129,12 +135,12 @@ class MainActivity : BaseActivity() {
})
headerBadgeObservable.throttleFirst(15, TimeUnit.SECONDS).subscribeOn(Schedulers.newThread())
.map { Jsoup.parse(it) }
.filter { it.select("[data-sigil=\"count\"]").size >= 0 } //ensure headers exist
.filter { it.select("[data-sigil=count]").size >= 0 } //ensure headers exist
.map {
val feed = it.select("[data-sigil*=\"feed\"] [data-sigil=\"count\"]")
val requests = it.select("[data-sigil*=\"requests\"] [data-sigil=\"count\"]")
val messages = it.select("[data-sigil*=\"messages\"] [data-sigil=\"count\"]")
val notifications = it.select("[data-sigil*=\"notifications\"] [data-sigil=\"count\"]")
val feed = it.select("[data-sigil*=feed] [data-sigil=count]")
val requests = it.select("[data-sigil*=requests] [data-sigil=count]")
val messages = it.select("[data-sigil*=messages] [data-sigil=count]")
val notifications = it.select("[data-sigil*=notifications] [data-sigil=count]")
return@map arrayOf(feed, requests, messages, notifications).map { it?.getOrNull(0)?.ownText() }
}
.observeOn(AndroidSchedulers.mainThread())
@ -303,8 +309,10 @@ class MainActivity : BaseActivity() {
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == REQUEST_RESTART) {
restart()
when (requestCode) {
REQUEST_RESTART -> restart()
REQUEST_REFRESH -> webFragmentObservable.onNext(FRAGMENT_REFRESH)
REQUEST_NAV -> frostNavigationBar()
}
}

View File

@ -3,17 +3,22 @@ package com.pitchedapps.frost
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import ca.allanwang.kau.changelog.showChangelog
import ca.allanwang.kau.email.sendEmail
import ca.allanwang.kau.kpref.CoreAttributeContract
import ca.allanwang.kau.kpref.KPrefActivity
import ca.allanwang.kau.kpref.KPrefAdapterBuilder
import ca.allanwang.kau.kpref.items.KPrefColorPicker
import ca.allanwang.kau.kpref.items.KPrefItemBase
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.facebook.FeedSort
import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.iab.openPlayPurchase
import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import com.pitchedapps.frost.utils.iab.openPlayProPurchase
import com.pitchedapps.frost.views.Keywords
@ -32,27 +37,39 @@ class SettingsActivity : KPrefActivity() {
descRes = R.string.appearance_desc
iicon = GoogleMaterial.Icon.gmd_palette
}
subItems(R.string.newsfeed, subPrefsFeed()) {
descRes = R.string.newsfeed_desc
iicon = CommunityMaterial.Icon.cmd_newspaper
}
subItems(R.string.notifications, subPrefsNotifications()) {
descRes = R.string.notifications_desc
iicon = GoogleMaterial.Icon.gmd_notifications
}
if (BuildConfig.DEBUG) {
checkbox(R.string.custom_pro, { Prefs.debugPro }, { Prefs.debugPro = it })
}
}
fun subPrefsAppearance(): KPrefAdapterBuilder.() -> Unit = {
header(R.string.base_customization)
header(R.string.theme_customization)
text(R.string.theme, { Prefs.theme }, { Prefs.theme = it }) {
onClick = {
_, _, item ->
this@SettingsActivity.materialDialogThemed {
title(R.string.theme)
items(Theme.values().map { this@SettingsActivity.string(it.textRes) })
items(Theme.values()
.map { if (it == Theme.CUSTOM && !IS_FROST_PRO) R.string.custom_pro else it.textRes }
.map { this@SettingsActivity.string(it) })
itemsCallbackSingleChoice(item.pref, {
_, _, which, text ->
if (item.pref != which) {
if (which == Theme.CUSTOM.ordinal) {
this@SettingsActivity.openPlayPurchase("asdf", 9)
if (which == Theme.CUSTOM.ordinal && !IS_FROST_PRO) {
this@SettingsActivity.openPlayProPurchase(9)
return@itemsCallbackSingleChoice true
}
item.pref = which
shouldRestartMain()
@ -68,8 +85,7 @@ class SettingsActivity : KPrefActivity() {
true
}
textGetter = {
this@SettingsActivity.string(if (it == Theme.CUSTOM.ordinal)
R.string.kau_custom else Theme(it).textRes)
this@SettingsActivity.string(Theme(it).textRes)
}
}
@ -83,21 +99,33 @@ class SettingsActivity : KPrefActivity() {
CssAssets.CUSTOM.injector = null
}
colorPicker(R.string.text_color, { Prefs.customTextColor }, { Prefs.customTextColor = it; reload(); invalidateCustomTheme() }) {
colorPicker(R.string.text_color, { Prefs.customTextColor }, {
Prefs.customTextColor = it
reload()
invalidateCustomTheme()
shouldRestartMain()
}) {
dependsOnCustom()
allowCustomAlpha = false
}
colorPicker(R.string.background_color, { Prefs.customBackgroundColor },
{ Prefs.customBackgroundColor = it; bgCanvas.ripple(it, duration = 500L); invalidateCustomTheme() }) {
colorPicker(R.string.background_color, { Prefs.customBackgroundColor }, {
Prefs.customBackgroundColor = it
bgCanvas.ripple(it, duration = 500L)
invalidateCustomTheme()
setFrostTheme(true)
shouldRestartMain()
}) {
dependsOnCustom()
allowCustomAlpha = true
}
colorPicker(R.string.header_color, { Prefs.customHeaderColor }, {
Prefs.customHeaderColor = it
this@SettingsActivity.navigationBarColor = it
if (Prefs.tintNavBar) this@SettingsActivity.frostNavigationBar()
toolbarCanvas.ripple(it, RippleCanvas.MIDDLE, RippleCanvas.END, duration = 500L)
reload()
shouldRestartMain()
}) {
dependsOnCustom()
allowCustomAlpha = true
@ -106,32 +134,82 @@ class SettingsActivity : KPrefActivity() {
colorPicker(R.string.icon_color, { Prefs.customIconColor }, {
Prefs.customIconColor = it
invalidateOptionsMenu()
shouldRestartMain()
}) {
dependsOnCustom()
allowCustomAlpha = false
}
checkbox(R.string.rounded_icons, { Prefs.showRoundedIcons }, { Prefs.showRoundedIcons = it })
header(R.string.global_customization)
checkbox(R.string.rounded_icons, { Prefs.showRoundedIcons }, {
Prefs.showRoundedIcons = it
setResult(MainActivity.REQUEST_REFRESH)
}) {
descRes = R.string.rounded_icons_desc
}
checkbox(R.string.fancy_animations, { Prefs.animate }, { Prefs.animate = it; animate = it }) {
descRes = R.string.fancy_animations_desc
}
header(R.string.feed_customization)
checkbox(R.string.tint_nav, { Prefs.tintNavBar }, {
Prefs.tintNavBar = it
this@SettingsActivity.frostNavigationBar()
setResult(MainActivity.REQUEST_NAV)
}) {
descRes = R.string.tint_nav_desc
}
}
checkbox(R.string.suggested_friends, { Prefs.showSuggestedFriends }, { Prefs.showSuggestedFriends = it }) {
fun KPrefItemBase.BaseContract<*>.dependsOnPro() {
onDisabledClick = { _, _, _ -> openPlayProPurchase(0); true }
enabler = { IS_FROST_PRO }
}
fun subPrefsFeed(): KPrefAdapterBuilder.() -> Unit = {
text(R.string.newsfeed_sort, { Prefs.feedSort }, { Prefs.feedSort = it }) {
descRes = R.string.newsfeed_sort_desc
onClick = {
_, _, item ->
this@SettingsActivity.materialDialogThemed {
title(R.string.newsfeed_sort)
items(FeedSort.values().map { this@SettingsActivity.string(it.textRes) })
itemsCallbackSingleChoice(item.pref, {
_, _, which, text ->
if (item.pref != which) {
item.pref = which
shouldRestartMain()
}
true
})
}
true
}
textGetter = { string(FeedSort(it).textRes) }
}
checkbox(R.string.suggested_friends, { Prefs.showSuggestedFriends }, {
Prefs.showSuggestedFriends = it
setResult(MainActivity.REQUEST_REFRESH)
}) {
descRes = R.string.suggested_friends_desc
dependsOnPro()
}
checkbox(R.string.facebook_ads, { Prefs.showFacebookAds }, { Prefs.showFacebookAds = it }) {
checkbox(R.string.facebook_ads, { Prefs.showFacebookAds }, {
Prefs.showFacebookAds = it
setResult(MainActivity.REQUEST_REFRESH)
}) {
descRes = R.string.facebook_ads_desc
dependsOnPro()
}
}
fun subPrefsNotifications(): KPrefAdapterBuilder.() -> Unit = {
text(R.string.notification_frequency, { Prefs.notificationFreq }, { Prefs.notificationFreq = it; reloadByTitle(R.string.notification_frequency) }) {
text(R.string.notification_frequency, { Prefs.notificationFreq }, { Prefs.notificationFreq = it }) {
val options = longArrayOf(-1, 15, 30, 60, 120, 180, 300, 1440, 2880)
val texts = options.map { this@SettingsActivity.minuteToText(it) }
onClick = {
@ -140,7 +218,7 @@ class SettingsActivity : KPrefActivity() {
title(R.string.notification_frequency)
items(texts)
itemsCallbackSingleChoice(options.indexOf(item.pref), {
_, _, which, text ->
_, _, which, _ ->
item.pref = options[which]
this@SettingsActivity.scheduleNotifications(item.pref)
true
@ -151,7 +229,7 @@ class SettingsActivity : KPrefActivity() {
textGetter = { this@SettingsActivity.minuteToText(it) }
}
text<String?>(R.string.notification_keywords, { null }, { }) {
plainText(R.string.notification_keywords) {
descRes = R.string.notification_keywords_desc
onClick = {
_, _, _ ->
@ -184,7 +262,7 @@ class SettingsActivity : KPrefActivity() {
else bgCanvas.set(Prefs.bgColor)
if (animate) toolbarCanvas.ripple(Prefs.headerColor, RippleCanvas.MIDDLE, RippleCanvas.END)
else toolbarCanvas.set(Prefs.headerColor)
this.navigationBarColor = Prefs.headerColor
frostNavigationBar()
}
override fun onBackPressed() {
@ -208,7 +286,7 @@ class SettingsActivity : KPrefActivity() {
R.id.action_email -> sendEmail(R.string.dev_email, R.string.frost_feedback) {
addItem("Random Frost ID", Prefs.frostId)
}
R.id.action_changelog -> showChangelog(R.xml.changelog, { theme() })
R.id.action_changelog -> showChangelog(R.xml.changelog, Prefs.textColor) { theme() }
else -> return super.onOptionsItemSelected(item)
}
return true

View File

@ -0,0 +1,18 @@
package com.pitchedapps.frost.facebook
import android.support.annotation.StringRes
import com.pitchedapps.frost.R
/**
* Created by Allan Wang on 2017-06-23.
*/
enum class FeedSort(@StringRes val textRes: Int) {
DEFAULT(R.string.kau_default),
MOST_RECENT(R.string.most_recent),
TOP(R.string.top_stories);
companion object {
val values = values() //save one instance
operator fun invoke(index: Int) = values[index]
}
}

View File

@ -9,6 +9,8 @@ import android.view.ViewGroup
import ca.allanwang.kau.utils.withBundle
import com.pitchedapps.frost.MainActivity
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.FeedSort
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.web.FrostWebView
import com.pitchedapps.frost.web.FrostWebViewCore
import io.reactivex.android.schedulers.AndroidSchedulers
@ -29,7 +31,15 @@ class WebFragment : Fragment() {
operator fun invoke(data: FbTab, position: Int) = WebFragment().withBundle {
putString(ARG_URL, data.url)
putInt(ARG_POSITION, position)
putSerializable(ARG_URL_ENUM, data)
putSerializable(ARG_URL_ENUM, when (data) {
//If is feed, check if sorting method is specified
FbTab.FEED -> when (FeedSort(Prefs.feedSort)) {
FeedSort.DEFAULT -> data
FeedSort.MOST_RECENT -> FbTab.FEED_MOST_RECENT
FeedSort.TOP -> FbTab.FEED_TOP_STORIES
}
else -> data
})
}
}

View File

@ -6,6 +6,7 @@ import ca.allanwang.kau.kpref.StringSet
import ca.allanwang.kau.kpref.kpref
import ca.allanwang.kau.utils.isColorVisibleOn
import ca.allanwang.kau.utils.lazyResettable
import com.pitchedapps.frost.facebook.FeedSort
import com.pitchedapps.frost.injectors.InjectorContract
/**
@ -23,11 +24,11 @@ object Prefs : KPref() {
var theme: Int by kpref("theme", 0, postSetter = { _: Int -> loader.invalidate() })
var customTextColor: Int by kpref("color_text", Color.BLACK)
var customTextColor: Int by kpref("color_text", Color.WHITE)
var customBackgroundColor: Int by kpref("color_bg", 0xfffafafa.toInt())
var customBackgroundColor: Int by kpref("color_bg", 0xff37474f.toInt())
var customHeaderColor: Int by kpref("color_header", 0xff3b5998.toInt())
var customHeaderColor: Int by kpref("color_header", 0xff039be5.toInt())
var customIconColor: Int by kpref("color_icons", Color.WHITE)
@ -69,6 +70,10 @@ object Prefs : KPref() {
val frostId: String
get() = "${installDate}-${identifier}"
var tintNavBar: Boolean by kpref("tint_nav_bar", true)
var feedSort: Int by kpref("feed_sort", FeedSort.DEFAULT.ordinal)
var showRoundedIcons: Boolean by kpref("rounded_icons", true)
var showSuggestedFriends: Boolean by kpref("suggested_friends_feed", true)
@ -81,4 +86,8 @@ object Prefs : KPref() {
//check if this is the first time launching the web overlay; show snackbar if true
var firstWebOverlay: Boolean by kpref("first_web_overlay", true)
var previouslyPro: Boolean by kpref("previously_pro", false)
var debugPro: Boolean by kpref("debug_pro", false)
}

View File

@ -1,6 +1,7 @@
package com.pitchedapps.frost.utils
import android.graphics.Color
import android.support.annotation.StringRes
import com.pitchedapps.frost.R
import com.pitchedapps.frost.injectors.CssAssets
import com.pitchedapps.frost.injectors.InjectorContract
@ -9,7 +10,7 @@ import com.pitchedapps.frost.injectors.JsActions
/**
* Created by Allan Wang on 2017-06-14.
*/
enum class Theme(val textRes: Int, val injector: InjectorContract,
enum class Theme(@StringRes val textRes: Int, val injector: InjectorContract,
private val textColorGetter: () -> Int, private val backgroundColorGetter: () -> Int,
private val headerColorGetter: () -> Int, private val iconColorGetter: () -> Int) {
DEFAULT(R.string.kau_default, JsActions.EMPTY, { Color.BLACK }, { 0xfffafafa.toInt() }, { 0xff3b5998.toInt() }, { Color.WHITE }),

View File

@ -163,4 +163,8 @@ fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {})
}
show()
}
}
fun Activity.frostNavigationBar() {
navigationBarColor = if (Prefs.tintNavBar) Prefs.headerColor else Color.BLACK
}

View File

@ -7,10 +7,7 @@ import ca.allanwang.kau.utils.startPlayStoreLink
import com.crashlytics.android.answers.PurchaseEvent
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostAnswers
import com.pitchedapps.frost.utils.frostAnswersCustom
import com.pitchedapps.frost.utils.materialDialogThemed
import com.pitchedapps.frost.utils.*
import org.jetbrains.anko.doAsync
/**
@ -38,8 +35,10 @@ object IAB {
}
}
val Context.isFrostPro: Boolean
get() = BuildConfig.DEBUG || isFromGooglePlay
private const val FROST_PRO = "frost_pro"
val IS_FROST_PRO: Boolean
get() = (BuildConfig.DEBUG && Prefs.debugPro) || (IAB.helper?.queryInventory()?.getSkuDetails(FROST_PRO) != null)
private fun Context.checkFromPlay(): Boolean {
val isPlay = isFromGooglePlay
@ -53,7 +52,7 @@ private fun Context.checkFromPlay(): Boolean {
return isPlay
}
fun Activity.openPlayProPurchase(code: Int) = openPlayPurchase("frost_pro", code)
fun Activity.openPlayProPurchase(code: Int) = openPlayPurchase(FROST_PRO, code)
fun Activity.openPlayPurchase(key: String, code: Int) {
if (!checkFromPlay()) return

View File

@ -0,0 +1,33 @@
package com.pitchedapps.frost.utils.iab
/**
* Created by Allan Wang on 2017-06-23.
*
* NOTE
*
* Since this is an open source project and all other components are essentially public,
* I have decided to add the keys here too;
* they can be reverse engineered relatively easily since they are constants anyways.
* This is the public billing key from the play store
*/
private const val play_key_1 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgyTZS"
private const val play_key_2 = "K9Bd3ALpr9KJUsVGczP9CcPelWkdnJfNrrzu1EztJyrHRsGQ4"
private const val play_key_3 = "QVWY9NZwc6Nrk9qdJlEdr8AJAxJ+JiwUqsj3/TxxUYm/G7q8Z"
private const val play_key_4 = "7zo8jSkYZyzqwoAl2PDx2kleI4sZLkhCRLyE6dGQEZQmvJ6kk"
private const val play_key_5 = "W12Gz3FagAM5luRGsoWZj40pJItUrGJA9euMWq4rMhVZv4mVk"
private const val play_key_6 = "KFJB9/vhF/XGz7txpYlFxMESzXuKsbEDKmKCHzvySLq8Ki4N9"
private const val play_key_7 = "DzbgUiw+VzA2KpSVp66JH3GEU8egO8i9SvAWeCPikuolooRVh"
private const val play_key_8 = "jwfBV7gDxZztoLuvmQU6kXvCwRnRa+mkfUnBKKLkH1QIDAQAB"
internal val PUBLIC_BILLING_KEY: String by lazy {
StringBuilder()
.append(play_key_1)
.append(play_key_2)
.append(play_key_3)
.append(play_key_4)
.append(play_key_5)
.append(play_key_6)
.append(play_key_7)
.append(play_key_8)
.toString()
}

View File

@ -40,7 +40,7 @@
<string name="custom_pro">Custom [Pro]</string>
<string name="uh_oh">Uh Oh</string>
<string name="play_store_not_found">This app doesn\'t seem to be installed from the Play Store. Please reinstall if this is an issue.</string>
<string name="play_store_not_found">This is a pro feature, but this app doesn\'t seem to be installed from the Play Store. Please reinstall if this is an issue.</string>
<string name="play_store_billing_error">Something went wrong. Please try again later.</string>
<string name="play_thank_you">Thank you!</string>
<string name="play_purchased_pro">Thank you for your support! Enjoy the pro version.</string>

View File

@ -4,6 +4,8 @@
<string name="appearance_desc">Theme, Items to display, etc</string>
<string name="notifications_desc">Frequency, filters, etc</string>
<string name="newsfeed">News Feed</string>
<string name="newsfeed_desc">Define what items appear in the newsfeed</string>
<!--themes-->
<string name="theme">Theme</string>
@ -13,8 +15,12 @@
<string name="icon_color">Icon Color</string>
<string name="rounded_icons">Rounded Icons</string>
<string name="base_customization">Base Customization</string>
<string name="rounded_icons_desc">Profile photos and group conversation icons will be rounded</string>
<string name="theme_customization">Theme Customization</string>
<string name="global_customization">Global Customization</string>
<string name="feed_customization">Feed Customization</string>
<string name="newsfeed_sort">Newsfeed Order</string>
<string name="newsfeed_sort_desc">Defines the order in which the posts are shown</string>
<string name="suggested_friends">Suggested Friends</string>
<string name="suggested_friends_desc">Show "People You May Know" in the feed</string>
<string name="facebook_ads">Facebook Ads</string>
@ -29,5 +35,7 @@
<string name="fancy_animations">Fancy Animations</string>
<string name="fancy_animations_desc">Reveal webviews using ripples and animate transitions</string>
<string name="tint_nav">Tint Nav Bar</string>
<string name="tint_nav_desc">Navigation bar will be the same color as the header</string>
</resources>

View File

@ -19,7 +19,7 @@ BUILD_TOOLS=26.0.0
VERSION_CODE=5
VERSION_NAME=0.5
KAU=d6b4ebb938
KAU=9e31fdd4f1
MATERIAL_DRAWER=5.9.2
MATERIAL_DRAWER_KT=1.0.2
IICON_GOOGLE=3.0.1.0