From 5d9a3fd7fb8f2f9d0f592c89446824980c9841c6 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 14 Aug 2017 20:48:39 -0700 Subject: v1.4.5 (#174) * Update/kau (#125) * Update logger * Clean imports and bring back reactive libs * Update dependencies and make billing async * Misc (#128) * Update null * Attempt to improve transparent theme backgrounds * Update menu * Move injections to visible method and reduce offset * Update searchview and logging * Clean temp strings and add network states * Move console blacklist to web state * Change some logs to info * Move glide loader to onCreate (#135) * Remove commit number increments (#139) * Fix/misc (#140) * Add canadian locale to toLowerCase * Add try catch to JsAssets * Disable error throwing for bad search subject * Log more throwables quietly * Check internet connection before fetching username * Remove name check in frost notifications * Add activity lifecycle logger * Add rxjava to lib showcase * Move network checker to io thread (#150) * Update dependency * Blank * Feature/jsoup debugger (#152) * Create debugger * Update debugger content * Create debugging logic * Finalize and test debugger * Add reload listener * Fix/pro crash without play store (#155) * Update changelog * Check if iab service exists * Add checker before launching play store request * Separate strings * Enhancement/message notifications (#157) * Map message notifs to the headless html extractor * Update strings * Bring im notifs out of alpha * Update changelog * Remove confirmation dialog (#159) * Separate message notifications and add click intents (#171) * Separate message notifications and add click intent for group notifications * Add comments and finalize * Feature/scroll down on message thread (#172) * Add hook for scroll * Update changelog * Add custom navdrawer layout (#173) * Add faq for auto play * Update changelog * Fix page banner bg (#163) --- .../pitchedapps/frost/activities/AboutActivity.kt | 32 ++++++++--- .../pitchedapps/frost/activities/BaseActivity.kt | 43 ++++++++++++++ .../pitchedapps/frost/activities/ImageActivity.kt | 12 ++-- .../pitchedapps/frost/activities/LoginActivity.kt | 19 +++---- .../pitchedapps/frost/activities/MainActivity.kt | 65 ++++++++++------------ .../frost/activities/SettingsActivity.kt | 23 +++++--- 6 files changed, 121 insertions(+), 73 deletions(-) (limited to 'app/src/main/kotlin/com/pitchedapps/frost/activities') diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt index fbcd12cc..670e8669 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt @@ -1,10 +1,8 @@ package com.pitchedapps.frost.activities -import android.os.Bundle import android.support.constraint.ConstraintLayout import android.support.constraint.ConstraintSet import android.support.v7.widget.RecyclerView -import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView @@ -13,8 +11,6 @@ import ca.allanwang.kau.about.LibraryIItem import ca.allanwang.kau.adapters.FastItemThemedAdapter import ca.allanwang.kau.adapters.ThemableIItem import ca.allanwang.kau.adapters.ThemableIItemDelegate -import ca.allanwang.kau.animators.FadeScaleAnimatorAdd -import ca.allanwang.kau.animators.KauAnimator import ca.allanwang.kau.utils.* import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.entity.Library @@ -26,10 +22,8 @@ import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.R +import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs -import org.jetbrains.anko.doAsync -import org.jetbrains.anko.uiThread -import java.security.InvalidParameterException /** @@ -41,6 +35,7 @@ class AboutActivity : AboutActivityBase(null, { backgroundColor = Prefs.bgColor.withMinAlpha(200) cutoutForeground = if (0xff3b5998.toInt().isColorVisibleOn(Prefs.bgColor)) 0xff3b5998.toInt() else Prefs.accentColor cutoutDrawableRes = R.drawable.frost_f_256 + faqPageTitleRes = R.string.faq_title faqXmlRes = R.xml.frost_faq faqParseNewLine = false }) { @@ -60,6 +55,7 @@ class AboutActivity : AboutActivityBase(null, { "kotterknife", "materialdialogs", "materialdrawer", + "rxjava", "subsamplingscaleimageview" ) @@ -68,6 +64,9 @@ class AboutActivity : AboutActivityBase(null, { return l } + var lastClick = -1L + var clickCount = 0 + override fun postInflateMainPage(adapter: FastItemThemedAdapter>) { /** * Frost may not be a library but we're conveying the same info @@ -85,7 +84,22 @@ class AboutActivity : AboutActivityBase(null, { } } adapter.add(LibraryIItem(frost)).add(AboutLinks()) - + adapter.withOnClickListener { _, _, item, _ -> + if (item is LibraryIItem) { + val now = System.currentTimeMillis() + if (now - lastClick > 500) + clickCount = 0 + else + clickCount++ + lastClick = now + if (clickCount == 7 && !Prefs.debugSettings) { + Prefs.debugSettings = true + L.d("Debugging section enabled") + toast(R.string.debug_toast_enabled) + } + } + false + } } class AboutLinks : AbstractItem(), ThemableIItem by ThemableIItemDelegate() { @@ -128,7 +142,7 @@ class AboutActivity : AboutActivityBase(null, { setImageDrawable(icon.toDrawable(context, 32)) scaleType = ImageView.ScaleType.CENTER background = context.resolveDrawable(android.R.attr.selectableItemBackgroundBorderless) - setOnClickListener({ onClick() }) + setOnClickListener { onClick() } container.addView(this) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt index 77a20d04..c7ca5ec7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt @@ -2,10 +2,16 @@ package com.pitchedapps.frost.activities import android.os.Bundle import ca.allanwang.kau.internal.KauBaseActivity +import com.github.pwittchen.reactivenetwork.library.rx2.Connectivity +import com.github.pwittchen.reactivenetwork.library.rx2.ReactiveNetwork import com.pitchedapps.frost.R +import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.materialDialogThemed import com.pitchedapps.frost.utils.setFrostTheme +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable +import io.reactivex.schedulers.Schedulers /** * Created by Allan Wang on 2017-06-12. @@ -29,4 +35,41 @@ abstract class BaseActivity : KauBaseActivity() { setFrostTheme() } + private var networkDisposable: Disposable? = null + private var networkConsumer: ((Connectivity) -> Unit)? = null + + fun setNetworkObserver(consumer: (connectivity: Connectivity) -> Unit) { + this.networkConsumer = consumer + } + + fun observeNetworkConnectivity() { + val consumer = networkConsumer ?: return + networkDisposable = ReactiveNetwork.observeNetworkConnectivity(applicationContext) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + connectivity: Connectivity -> + connectivity.apply { + L.d("Network connectivity changed: isAvailable: $isAvailable isRoaming: $isRoaming") + consumer(connectivity) + } + } + } + + fun disposeNetworkConnectivity() { + if (!(networkDisposable?.isDisposed ?: true)) + networkDisposable?.dispose() + networkDisposable = null + } + + override fun onResume() { + super.onResume() + disposeNetworkConnectivity() + observeNetworkConnectivity() + } + + override fun onPause() { + super.onPause() + disposeNetworkConnectivity() + } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt index 6a39b269..31479d54 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -7,7 +7,6 @@ import android.graphics.Color import android.graphics.drawable.Drawable import android.net.Uri import android.os.Bundle -import android.os.Environment import android.support.design.widget.FloatingActionButton import android.support.v4.content.FileProvider import android.view.View @@ -34,11 +33,8 @@ import com.pitchedapps.frost.utils.* import com.sothree.slidinguppanel.SlidingUpPanelLayout import org.jetbrains.anko.doAsync import org.jetbrains.anko.uiThread -import timber.log.Timber import java.io.File import java.io.IOException -import java.text.SimpleDateFormat -import java.util.* /** * Created by Allan Wang on 2017-07-15. @@ -99,8 +95,8 @@ class ImageActivity : KauBaseActivity() { }) fab.setOnClickListener { fabAction.onClick(this) } photo.setOnImageEventListener(object : SubsamplingScaleImageView.DefaultOnImageEventListener() { - override fun onImageLoadError(e: Exception) { - L.e(e, "Image load error") + override fun onImageLoadError(e: Exception?) { + e.logFrostAnswers("Image load error") imageCallback(null, false) } }) @@ -155,7 +151,7 @@ class ImageActivity : KauBaseActivity() { callback(null) } else { tempFilePath = photoFile.absolutePath - Timber.d("Temp image path $tempFilePath") + L.d("Temp image path $tempFilePath") // File created; proceed with request val photoURI = FileProvider.getUriForFile(this, BuildConfig.APPLICATION_ID + ".provider", @@ -252,7 +248,7 @@ internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconC } activity.startActivity(intent) } catch (e: Exception) { - L.e(e, "Image share failed"); + e.logFrostAnswers("Image share failed") activity.snackbar(R.string.image_share_failed) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt index 47c286fa..67f07635 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -12,6 +12,7 @@ import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.fadeIn import ca.allanwang.kau.utils.fadeOut import com.bumptech.glide.Glide +import com.bumptech.glide.RequestManager import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.RequestListener @@ -44,6 +45,7 @@ class LoginActivity : BaseActivity() { val profileObservable = SingleSubject.create() val usernameObservable = SingleSubject.create() + lateinit var profileLoader: RequestManager // Helper to set and enable swipeRefresh var refresh: Boolean @@ -68,6 +70,7 @@ class LoginActivity : BaseActivity() { loadInfo(cookie) }) } + profileLoader = Glide.with(profile) } fun loadInfo(cookie: CookieModel) { @@ -78,8 +81,8 @@ class LoginActivity : BaseActivity() { (foundImage, name) -> refresh = false if (!foundImage) { - L.eThrow("Could not get profile photo; Invalid userId?") - L.i("-\t$cookie") + L.e("Could not get profile photo; Invalid userId?") + L.i(null, cookie.toString()) } textview.text = String.format(getString(R.string.welcome), name) textview.fadeIn() @@ -102,14 +105,14 @@ class LoginActivity : BaseActivity() { fun loadProfile(id: Long) { - Glide.with(profile).load(PROFILE_PICTURE_URL(id)).withRoundIcon().listener(object : RequestListener { + profileLoader.load(PROFILE_PICTURE_URL(id)).withRoundIcon().listener(object : RequestListener { override fun onResourceReady(resource: Drawable?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { profileObservable.onSuccess(true) return false } override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { - if (e != null) L.e(e, "Profile loading exception") + e.logFrostAnswers( "Profile loading exception") profileObservable.onSuccess(false) return false } @@ -119,12 +122,4 @@ class LoginActivity : BaseActivity() { fun loadUsername(cookie: CookieModel) { cookie.fetchUsername { usernameObservable.onSuccess(it) } } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - if (requestCode == 999) { - L.d("Result found for activity with result $resultCode") - L.d("Intent data ${data?.extras.toString()}") - } else - super.onActivityResult(requestCode, resultCode, data) - } } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt index e8148b55..759be983 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt @@ -50,7 +50,7 @@ import com.pitchedapps.frost.dbflow.loadFbCookie import com.pitchedapps.frost.dbflow.loadFbTabs import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.facebook.FbCookie.switchUser -import com.pitchedapps.frost.facebook.FbTab +import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL import com.pitchedapps.frost.fragments.WebFragment import com.pitchedapps.frost.utils.* @@ -60,6 +60,7 @@ import com.pitchedapps.frost.utils.iab.IS_FROST_PRO import com.pitchedapps.frost.views.BadgedIcon import com.pitchedapps.frost.views.FrostViewPager import com.pitchedapps.frost.web.SearchWebView +import com.pitchedapps.frost.web.shouldLoadImages import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers @@ -160,14 +161,10 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, // } setFrostColors(toolbar, themeWindow = false, headers = arrayOf(tabs, appBar), backgrounds = arrayOf(viewPager)) onCreateBilling() - if (Prefs.installDate < 1501454310304 && Showcase.intro) - materialDialogThemed { - title(R.string.intro_title) - content(R.string.intro_desc) - positiveText(R.string.kau_yes) - negativeText(R.string.kau_no) - onPositive { _, _ -> launchIntroActivity(cookies()) } - } + setNetworkObserver { + connectivity -> + shouldLoadImages = !connectivity.isRoaming + } } fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) { @@ -206,10 +203,10 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, tabsForEachView { _, view -> when (view.iicon) { - FbTab.FEED.icon -> view.badgeText = feed - FbTab.FRIENDS.icon -> view.badgeText = requests - FbTab.MESSAGES.icon -> view.badgeText = messages - FbTab.NOTIFICATIONS.icon -> view.badgeText = notifications + FbItem.FEED.icon -> view.badgeText = feed + FbItem.FRIENDS.icon -> view.badgeText = requests + FbItem.MESSAGES.icon -> view.badgeText = messages + FbItem.NOTIFICATIONS.icon -> view.badgeText = notifications } } } @@ -230,10 +227,10 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, translucentStatusBar = false sliderBackgroundColor = navBg drawerHeader = accountHeader { + customViewRes = R.layout.material_drawer_header textColor = Prefs.iconColor.toLong() backgroundDrawable = ColorDrawable(navHeader) selectionSecondLineShown = false - paddingBelow = false cookies().forEach { (id, name) -> profile(name = name ?: "") { iconUrl = PROFILE_PICTURE_URL(id) @@ -261,7 +258,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, identifier = -4L } onProfileChanged { _, profile, current -> - if (current) launchWebOverlay(FbTab.PROFILE.url) + if (current) launchWebOverlay(FbItem.PROFILE.url) else when (profile.identifier) { -2L -> { val currentCookie = loadFbCookie(Prefs.userId) @@ -295,25 +292,25 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, } } drawerHeader.setActiveProfile(Prefs.userId) - primaryFrostItem(FbTab.FEED_MOST_RECENT) - primaryFrostItem(FbTab.FEED_TOP_STORIES) - primaryFrostItem(FbTab.ACTIVITY_LOG) + primaryFrostItem(FbItem.FEED_MOST_RECENT) + primaryFrostItem(FbItem.FEED_TOP_STORIES) + primaryFrostItem(FbItem.ACTIVITY_LOG) divider() - primaryFrostItem(FbTab.PHOTOS) - primaryFrostItem(FbTab.GROUPS) - primaryFrostItem(FbTab.FRIENDS) - primaryFrostItem(FbTab.PAGES) + primaryFrostItem(FbItem.PHOTOS) + primaryFrostItem(FbItem.GROUPS) + primaryFrostItem(FbItem.FRIENDS) + primaryFrostItem(FbItem.PAGES) divider() - primaryFrostItem(FbTab.EVENTS) - primaryFrostItem(FbTab.BIRTHDAYS) - primaryFrostItem(FbTab.ON_THIS_DAY) + primaryFrostItem(FbItem.EVENTS) + primaryFrostItem(FbItem.BIRTHDAYS) + primaryFrostItem(FbItem.ON_THIS_DAY) divider() - primaryFrostItem(FbTab.NOTES) - primaryFrostItem(FbTab.SAVED) + primaryFrostItem(FbItem.NOTES) + primaryFrostItem(FbItem.SAVED) } } - fun Builder.primaryFrostItem(item: FbTab) = this.primaryItem(item.titleId) { + fun Builder.primaryFrostItem(item: FbItem) = this.primaryItem(item.titleId) { iicon = item.icon iconColor = Prefs.textColor.toLong() textColor = Prefs.textColor.toLong() @@ -349,6 +346,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, override fun searchOverlayDispose() { hiddenSearchView?.dispose() hiddenSearchView = null + searchView?.unBind { launchWebOverlay(FbItem.SEARCH.url); true } searchView = null } @@ -369,10 +367,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, if (Prefs.searchBar) { if (firstLoadFinished && hiddenSearchView == null) hiddenSearchView = SearchWebView(this, this) if (searchView == null) searchView = bindSearchView(menu, R.id.action_search, Prefs.iconColor) { - textObserver = { - observable, _ -> - observable.observeOn(AndroidSchedulers.mainThread()).subscribe { hiddenSearchView?.query(it) } - } + textCallback = { query, _ -> runOnUiThread { hiddenSearchView?.query(query) } } foregroundColor = Prefs.textColor backgroundColor = Prefs.bgColor.withMinAlpha(200) openListener = { hiddenSearchView?.pauseLoad = false } @@ -380,8 +375,8 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, onItemClick = { _, key, _, _ -> launchWebOverlay(key) } } } else { - searchOverlayDispose() - menu.findItem(R.id.action_search).setOnMenuItemClickListener { _ -> launchWebOverlay(FbTab.SEARCH.url); true } + if (searchView != null) searchOverlayDispose() + else menu.findItem(R.id.action_search).setOnMenuItemClickListener { _ -> launchWebOverlay(FbItem.SEARCH.url); true } } return true } @@ -461,7 +456,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, val currentFragment get() = supportFragmentManager.findFragmentByTag("android:switcher:${R.id.container}:${viewPager.currentItem}") as WebFragment - inner class SectionsPagerAdapter(fm: FragmentManager, val pages: List) : FragmentPagerAdapter(fm) { + inner class SectionsPagerAdapter(fm: FragmentManager, val pages: List) : FragmentPagerAdapter(fm) { override fun getItem(position: Int): Fragment { val fragment = WebFragment(pages[position], position) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt index 7cbbe4df..196aa461 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -6,16 +6,12 @@ import android.content.Intent import android.os.Bundle import android.view.Menu import android.view.MenuItem -import ca.allanwang.kau.about.kauLaunchAbout import ca.allanwang.kau.kpref.activity.CoreAttributeContract import ca.allanwang.kau.kpref.activity.KPrefActivity import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder import ca.allanwang.kau.kpref.activity.items.KPrefItemBase import ca.allanwang.kau.ui.views.RippleCanvas -import ca.allanwang.kau.utils.finishSlideOut -import ca.allanwang.kau.utils.setMenuIcons -import ca.allanwang.kau.utils.string -import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.* import ca.allanwang.kau.xml.showChangelog import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial @@ -38,7 +34,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { if (!onActivityResultBilling(requestCode, resultCode, data)) super.onActivityResult(requestCode, resultCode, data) - adapter.notifyDataSetChanged() + reloadList() } override fun kPrefCoreAttributes(): CoreAttributeContract.() -> Unit = { @@ -67,6 +63,11 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { iicon = GoogleMaterial.Icon.gmd_notifications } + subItems(R.string.network, getNetworkPrefs()) { + descRes = R.string.network_desc + iicon = GoogleMaterial.Icon.gmd_network_cell + } + subItems(R.string.experimental, getExperimentalPrefs()) { descRes = R.string.experimental_desc iicon = CommunityMaterial.Icon.cmd_flask_outline @@ -81,7 +82,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { plainText(R.string.about_frost) { descRes = R.string.about_frost_desc iicon = GoogleMaterial.Icon.gmd_info - onClick = { _, _, _ -> kauLaunchAbout(AboutActivity::class.java); true } + onClick = { _, _, _ -> startActivityForResult(AboutActivity::class.java, 9, true); true } } plainText(R.string.replay_intro) { @@ -89,6 +90,12 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { onClick = { _, _, _ -> launchIntroActivity(cookies()); true } } + subItems(R.string.debug_frost, getDebugPrefs()) { + descRes = R.string.debug_frost_desc + iicon = CommunityMaterial.Icon.cmd_android_debug_bridge + visible = { Prefs.debugSettings } + } + if (BuildConfig.DEBUG) { checkbox(R.string.custom_pro, { Prefs.debugPro }, { Prefs.debugPro = it }) } @@ -130,8 +137,6 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_settings, menu) toolbar.tint(Prefs.iconColor) - toolbarTitle.textColor = Prefs.iconColor - toolbarTitle.invalidate() setMenuIcons(menu, Prefs.iconColor, R.id.action_email to GoogleMaterial.Icon.gmd_email, R.id.action_changelog to GoogleMaterial.Icon.gmd_info) -- cgit v1.2.3