diff options
Diffstat (limited to 'app/src/main/kotlin/com')
107 files changed, 3591 insertions, 1398 deletions
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt index c566aa05..7f3d6b62 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost import android.app.Activity @@ -21,7 +37,11 @@ import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.glide.GlideApp import com.pitchedapps.frost.services.scheduleNotifications import com.pitchedapps.frost.services.setupNotificationChannels -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.BuildUtils +import com.pitchedapps.frost.utils.FrostPglAdBlock +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.Showcase import com.raizlabs.android.dbflow.config.DatabaseConfig import com.raizlabs.android.dbflow.config.FlowConfig import com.raizlabs.android.dbflow.config.FlowManager @@ -30,10 +50,9 @@ import io.reactivex.exceptions.UndeliverableException import io.reactivex.plugins.RxJavaPlugins import java.net.SocketTimeoutException import java.net.UnknownHostException -import java.util.* +import java.util.Random import kotlin.reflect.KClass - /** * Created by Allan Wang on 2017-05-28. */ @@ -46,10 +65,12 @@ class FrostApp : Application() { // lateinit var refWatcher: RefWatcher private fun FlowConfig.Builder.withDatabase(name: String, klass: KClass<*>) = - addDatabaseConfig(DatabaseConfig.builder(klass.java) - .databaseName(name) - .modelNotifier(ContentResolverNotifier("${BuildConfig.APPLICATION_ID}.dbflow.provider")) - .build()) + addDatabaseConfig( + DatabaseConfig.builder(klass.java) + .databaseName(name) + .modelNotifier(ContentResolverNotifier("${BuildConfig.APPLICATION_ID}.dbflow.provider")) + .build() + ) override fun onCreate() { if (!buildIsLollipopAndUp) { // not supported @@ -57,11 +78,13 @@ class FrostApp : Application() { return } - FlowManager.init(FlowConfig.Builder(this) + FlowManager.init( + FlowConfig.Builder(this) .withDatabase(CookiesDb.NAME, CookiesDb::class) .withDatabase(FbTabsDb.NAME, FbTabsDb::class) .withDatabase(NotificationDb.NAME, NotificationDb::class) - .build()) + .build() + ) Showcase.initialize(this, "${BuildConfig.APPLICATION_ID}.showcase") Prefs.initialize(this, "${BuildConfig.APPLICATION_ID}.prefs") // if (LeakCanary.isInAnalyzerProcess(this)) return @@ -95,9 +118,11 @@ class FrostApp : Application() { val c = imageView.context val request = GlideApp.with(c) val old = request.load(uri).apply(RequestOptions().placeholder(placeholder)) - request.load(uri).apply(RequestOptions() - .signature(ApplicationVersionSignature.obtain(c))) - .thumbnail(old).into(imageView) + request.load(uri).apply( + RequestOptions() + .signature(ApplicationVersionSignature.obtain(c)) + ) + .thumbnail(old).into(imageView) } }) if (BuildConfig.DEBUG) @@ -127,7 +152,6 @@ class FrostApp : Application() { L.e(it) { "RxJava error" } } } - } private fun initBugsnag() { @@ -136,7 +160,7 @@ class FrostApp : Application() { Bugsnag.disableExceptionHandler() if (!BuildConfig.APPLICATION_ID.startsWith("com.pitchedapps.frost")) return val version = BuildUtils.match(BuildConfig.VERSION_NAME) - ?: return L.d { "Bugsnag disabled for ${BuildConfig.VERSION_NAME}" } + ?: return L.d { "Bugsnag disabled for ${BuildConfig.VERSION_NAME}" } Bugsnag.enableExceptionHandler() Bugsnag.setNotifyReleaseStages(*BuildUtils.getAllStages()) Bugsnag.setAppVersion(version.versionName) @@ -157,5 +181,4 @@ class FrostApp : Application() { } } } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt index 034dabe2..14cc579f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost import android.content.Intent @@ -21,7 +37,8 @@ import com.pitchedapps.frost.utils.EXTRA_COOKIES import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.launchNewTask -import java.util.* +import java.util.ArrayList +import java.util.IllegalFormatException /** * Created by Allan Wang on 2017-05-28. @@ -46,7 +63,8 @@ class StartActivity : KauBaseActivity() { if (Prefs.userId != -1L) 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 + flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or + Intent.FLAG_ACTIVITY_SINGLE_TOP }) else launchNewTask<SelectorActivity>(cookies) @@ -57,11 +75,10 @@ class StartActivity : KauBaseActivity() { } catch (e: Exception) { showInvalidWebView() } - } private fun showInvalidWebView() = - showInvalidView(R.string.error_webview) + showInvalidView(R.string.error_webview) private fun showInvalidSdkView() { val text = try { @@ -73,12 +90,12 @@ class StartActivity : KauBaseActivity() { } private fun showInvalidView(textRes: Int) = - showInvalidView(string(textRes)) + showInvalidView(string(textRes)) private fun showInvalidView(text: String) { setContentView(R.layout.activity_invalid) findViewById<ImageView>(R.id.invalid_icon) - .setIcon(GoogleMaterial.Icon.gmd_adb, -1, Color.WHITE) + .setIcon(GoogleMaterial.Icon.gmd_adb, -1, Color.WHITE) findViewById<TextView>(R.id.invalid_text).text = text } -}
\ No newline at end of file +} 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 2261328d..a110071c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt @@ -1,17 +1,40 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities -import android.support.constraint.ConstraintLayout -import android.support.constraint.ConstraintSet -import android.support.v7.widget.RecyclerView import android.view.View import android.view.ViewGroup import android.widget.ImageView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.recyclerview.widget.RecyclerView import ca.allanwang.kau.about.AboutActivityBase 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.utils.* +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.dimenPixelSize +import ca.allanwang.kau.utils.resolveDrawable +import ca.allanwang.kau.utils.startLink +import ca.allanwang.kau.utils.string +import ca.allanwang.kau.utils.toDrawable +import ca.allanwang.kau.utils.toast +import ca.allanwang.kau.utils.withMinAlpha import com.mikepenz.aboutlibraries.Libs import com.mikepenz.aboutlibraries.entity.Library import com.mikepenz.aboutlibraries.entity.License @@ -25,7 +48,6 @@ import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs - /** * Created by Allan Wang on 2017-06-26. */ @@ -34,7 +56,7 @@ class AboutActivity : AboutActivityBase(null, { accentColor = Prefs.accentColor backgroundColor = Prefs.bgColor.withMinAlpha(200) cutoutForeground = Prefs.accentColor - cutoutDrawableRes = R.drawable.frost_f_256 + cutoutDrawableRes = R.drawable.frost_f_200 faqPageTitleRes = R.string.faq_title faqXmlRes = R.xml.frost_faq faqParseNewLine = false @@ -42,21 +64,21 @@ class AboutActivity : AboutActivityBase(null, { override fun getLibraries(libs: Libs): List<Library> { val include = arrayOf( - "AboutLibraries", - "AndroidIconics", - "androidin_appbillingv3", - "androidslidinguppanel", - "Crashlytics", - "dbflow", - "fastadapter", - "glide", - "Jsoup", - "kau", - "kotterknife", - "materialdialogs", - "materialdrawer", - "rxjava", - "subsamplingscaleimageview" + "AboutLibraries", + "AndroidIconics", + "androidin_appbillingv3", + "androidslidinguppanel", + "Crashlytics", + "dbflow", + "fastadapter", + "glide", + "Jsoup", + "kau", + "kotterknife", + "materialdialogs", + "materialdrawer", + "rxjava", + "subsamplingscaleimageview" ) val l = libs.prepareLibraries(this, include, null, false, true, true) @@ -136,11 +158,11 @@ class AboutActivity : AboutActivityBase(null, { val c = itemView.context val size = c.dimenPixelSize(R.dimen.kau_avatar_bounds) images = arrayOf<Pair<IIcon, () -> Unit>>( - GoogleMaterial.Icon.gmd_arrow_downward to { c.startLink(R.string.github_downloads_url) }, - CommunityMaterial.Icon.cmd_reddit to { c.startLink(R.string.reddit_url) }, - CommunityMaterial.Icon.cmd_github_circle to { c.startLink(R.string.github_url) }, - CommunityMaterial.Icon.cmd_slack to { c.startLink(R.string.slack_url) }, - CommunityMaterial.Icon.cmd_xda to { c.startLink(R.string.xda_url) } + GoogleMaterial.Icon.gmd_arrow_downward to { c.startLink(R.string.github_downloads_url) }, + CommunityMaterial.Icon2.cmd_reddit to { c.startLink(R.string.reddit_url) }, + CommunityMaterial.Icon.cmd_github_circle to { c.startLink(R.string.github_url) }, + CommunityMaterial.Icon2.cmd_slack to { c.startLink(R.string.slack_url) }, + CommunityMaterial.Icon2.cmd_xda to { c.startLink(R.string.xda_url) } ).mapIndexed { i, (icon, onClick) -> ImageView(c).apply { layoutParams = ViewGroup.LayoutParams(size, size) @@ -154,10 +176,16 @@ class AboutActivity : AboutActivityBase(null, { } val set = ConstraintSet() set.clone(container) - set.createHorizontalChain(ConstraintSet.PARENT_ID, ConstraintSet.LEFT, ConstraintSet.PARENT_ID, ConstraintSet.RIGHT, - images.map { it.id }.toIntArray(), null, ConstraintSet.CHAIN_SPREAD_INSIDE) + set.createHorizontalChain(ConstraintSet.PARENT_ID, + ConstraintSet.LEFT, + ConstraintSet.PARENT_ID, + ConstraintSet.RIGHT, + images.map { it.id }.toIntArray(), + null, + ConstraintSet.CHAIN_SPREAD_INSIDE + ) set.applyTo(container) } } } -}
\ No newline at end of file +} 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 3ac8c6ce..08b5ab0c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.content.res.Configuration @@ -80,7 +96,6 @@ abstract class BaseActivity : KauBaseActivity() { //// disposeNetworkConnectivity() // } - override fun onStop() { if (this is VideoViewHolder) videoOnStop() super.onStop() @@ -90,4 +105,4 @@ abstract class BaseActivity : KauBaseActivity() { super.onConfigurationChanged(newConfig) if (this is VideoViewHolder) videoViewer?.updateLocation() } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt index 2fce69a8..20b5727f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.annotation.SuppressLint @@ -8,25 +24,31 @@ import android.graphics.PointF import android.graphics.drawable.ColorDrawable import android.net.Uri import android.os.Bundle -import android.support.annotation.StringRes -import android.support.design.widget.AppBarLayout -import android.support.design.widget.CoordinatorLayout -import android.support.design.widget.FloatingActionButton -import android.support.design.widget.TabLayout -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentPagerAdapter -import android.support.v7.widget.Toolbar import android.view.Menu import android.view.MenuItem import android.webkit.ValueCallback import android.webkit.WebChromeClient import android.webkit.WebView import android.widget.FrameLayout +import androidx.annotation.StringRes +import androidx.appcompat.widget.Toolbar +import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentPagerAdapter import ca.allanwang.kau.searchview.SearchItem import ca.allanwang.kau.searchview.SearchView import ca.allanwang.kau.searchview.SearchViewHolder import ca.allanwang.kau.searchview.bindSearchView -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.fadeScaleTransition +import ca.allanwang.kau.utils.restart +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.setMenuIcons +import ca.allanwang.kau.utils.showIf +import ca.allanwang.kau.utils.string +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.toast +import ca.allanwang.kau.utils.withMinAlpha import co.zsmb.materialdrawerkt.builders.Builder import co.zsmb.materialdrawerkt.builders.accountHeader import co.zsmb.materialdrawerkt.builders.drawer @@ -35,6 +57,9 @@ import co.zsmb.materialdrawerkt.draweritems.badgeable.secondaryItem import co.zsmb.materialdrawerkt.draweritems.divider import co.zsmb.materialdrawerkt.draweritems.profile.profile import co.zsmb.materialdrawerkt.draweritems.profile.profileSetting +import com.google.android.material.appbar.AppBarLayout +import com.google.android.material.floatingactionbutton.FloatingActionButton +import com.google.android.material.tabs.TabLayout import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.IconicsDrawable import com.mikepenz.iconics.typeface.IIcon @@ -57,7 +82,26 @@ import com.pitchedapps.frost.facebook.parsers.SearchParser import com.pitchedapps.frost.facebook.profilePictureUrl import com.pitchedapps.frost.fragments.BaseFragment import com.pitchedapps.frost.fragments.WebFragment -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.ACTIVITY_SETTINGS +import com.pitchedapps.frost.utils.EXTRA_COOKIES +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.MAIN_TIMEOUT_DURATION +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.REQUEST_NAV +import com.pitchedapps.frost.utils.REQUEST_REFRESH +import com.pitchedapps.frost.utils.REQUEST_RESTART +import com.pitchedapps.frost.utils.REQUEST_RESTART_APPLICATION +import com.pitchedapps.frost.utils.REQUEST_SEARCH +import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM +import com.pitchedapps.frost.utils.cookies +import com.pitchedapps.frost.utils.frostChangelog +import com.pitchedapps.frost.utils.frostEvent +import com.pitchedapps.frost.utils.frostNavigationBar +import com.pitchedapps.frost.utils.launchLogin +import com.pitchedapps.frost.utils.launchNewTask +import com.pitchedapps.frost.utils.launchWebOverlay +import com.pitchedapps.frost.utils.materialDialogThemed +import com.pitchedapps.frost.utils.setFrostColors import com.pitchedapps.frost.views.BadgedIcon import com.pitchedapps.frost.views.FrostVideoViewer import com.pitchedapps.frost.views.FrostViewPager @@ -68,8 +112,8 @@ import com.pitchedapps.frost.views.FrostViewPager * Most of the logic that is unrelated to handling fragments */ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, - FileChooserContract by FileChooserDelegate(), - VideoViewHolder, SearchViewHolder { + FileChooserContract by FileChooserDelegate(), + VideoViewHolder, SearchViewHolder { protected lateinit var adapter: SectionsPagerAdapter override val frameWrapper: FrameLayout by bindView(R.id.frame_wrapper) @@ -111,12 +155,14 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, Prefs.versionCode = BuildConfig.VERSION_CODE if (!BuildConfig.DEBUG) { frostChangelog() - frostEvent("Version", - "Version code" to BuildConfig.VERSION_CODE, - "Prev version code" to Prefs.prevVersionCode, - "Version name" to BuildConfig.VERSION_NAME, - "Build type" to BuildConfig.BUILD_TYPE, - "Frost id" to Prefs.frostId) + frostEvent( + "Version", + "Version code" to BuildConfig.VERSION_CODE, + "Prev version code" to Prefs.prevVersionCode, + "Version name" to BuildConfig.VERSION_NAME, + "Build type" to BuildConfig.BUILD_TYPE, + "Frost id" to Prefs.frostId + ) } } setupDrawer(savedInstanceState) @@ -185,7 +231,6 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, translucentStatusBar = false sliderBackgroundColor = navBg drawerHeader = accountHeader { - customViewRes = R.layout.material_drawer_header textColor = Prefs.iconColor.toLong() backgroundDrawable = ColorDrawable(navHeader) selectionSecondLineShown = false @@ -205,7 +250,9 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, identifier = -2L } profileSetting(nameRes = R.string.kau_add_account) { - iconDrawable = IconicsDrawable(this@BaseMainActivity, GoogleMaterial.Icon.gmd_add).actionBar().paddingDp(5).color(Prefs.textColor) + iconDrawable = + IconicsDrawable(this@BaseMainActivity, GoogleMaterial.Icon.gmd_add).actionBar().paddingDp(5) + .color(Prefs.textColor) textColor = Prefs.textColor.toLong() identifier = -3L } @@ -226,8 +273,12 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, } else { materialDialogThemed { title(R.string.kau_logout) - content(String.format(string(R.string.kau_logout_confirm_as_x), currentCookie.name - ?: Prefs.userId.toString())) + content( + String.format( + string(R.string.kau_logout_confirm_as_x), currentCookie.name + ?: Prefs.userId.toString() + ) + ) positiveText(R.string.kau_yes) negativeText(R.string.kau_no) onPositive { _, _ -> FbCookie.logout(this@BaseMainActivity) } @@ -296,9 +347,11 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_main, menu) toolbar.tint(Prefs.iconColor) - setMenuIcons(menu, Prefs.iconColor, - R.id.action_settings to GoogleMaterial.Icon.gmd_settings, - R.id.action_search to GoogleMaterial.Icon.gmd_search) + setMenuIcons( + menu, Prefs.iconColor, + R.id.action_settings to GoogleMaterial.Icon.gmd_settings, + R.id.action_search to GoogleMaterial.Icon.gmd_search + ) searchViewBindIfNull { bindSearchView(menu, R.id.action_search, Prefs.iconColor) { textCallback = { query, searchView -> @@ -310,7 +363,13 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, if (data != null) { val items = data.mapTo(mutableListOf(), FrostSearch::toSearchItem) if (items.isNotEmpty()) - items.add(SearchItem("${FbItem._SEARCH.url}?q=$query", string(R.string.show_all_results), iicon = null)) + items.add( + SearchItem( + "${FbItem._SEARCH.url}?q=$query", + string(R.string.show_all_results), + iicon = null + ) + ) searchViewCache[query] = items searchView.results = items } @@ -333,7 +392,8 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, R.id.action_settings -> { val intent = Intent(this, SettingsActivity::class.java) intent.putParcelableArrayListExtra(EXTRA_COOKIES, cookies()) - val bundle = ActivityOptions.makeCustomAnimation(this, R.anim.kau_slide_in_right, R.anim.kau_fade_out).toBundle() + val bundle = + ActivityOptions.makeCustomAnimation(this, R.anim.kau_slide_in_right, R.anim.kau_fade_out).toBundle() startActivityForResult(intent, ACTIVITY_SETTINGS, bundle) } else -> return super.onOptionsItemSelected(item) @@ -341,7 +401,10 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, return true } - override fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) { + override fun openFileChooser( + filePathCallback: ValueCallback<Array<Uri>?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) { openMediaPicker(filePathCallback, fileChooserParams) } @@ -378,8 +441,10 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, override fun onRestoreInstanceState(savedInstanceState: Bundle) { super.onRestoreInstanceState(savedInstanceState) adapter.forcedFallbacks.clear() - adapter.forcedFallbacks.addAll(savedInstanceState.getStringArrayList(STATE_FORCE_FALLBACK) - ?: emptyList()) + adapter.forcedFallbacks.addAll( + savedInstanceState.getStringArrayList(STATE_FORCE_FALLBACK) + ?: emptyList() + ) } override fun onResume() { @@ -445,10 +510,12 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, override fun getItem(position: Int): Fragment { val item = pages[position] - return BaseFragment(item.fragmentCreator, - forcedFallbacks.contains(item.name), - item, - position) + return BaseFragment( + item.fragmentCreator, + forcedFallbacks.contains(item.name), + item, + position + ) } override fun getCount() = pages.size @@ -456,12 +523,12 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, override fun getPageTitle(position: Int): CharSequence = getString(pages[position].titleId) override fun getItemPosition(fragment: Any) = - if (fragment !is BaseFragment) - POSITION_UNCHANGED - else if (fragment is WebFragment || fragment.valid) - POSITION_UNCHANGED - else - POSITION_NONE + if (fragment !is BaseFragment) + POSITION_UNCHANGED + else if (fragment is WebFragment || fragment.valid) + POSITION_UNCHANGED + else + POSITION_NONE } override val lowerVideoPadding: PointF @@ -470,4 +537,4 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, PointF(0f, toolbar.height.toFloat()) else PointF(0f, 0f) -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt index 9b1d8e79..6257e6f1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.app.Activity @@ -5,11 +21,7 @@ import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.os.Bundle -import android.support.design.widget.FloatingActionButton -import android.support.v4.widget.SwipeRefreshLayout -import android.support.v7.widget.Toolbar import ca.allanwang.kau.internal.KauBaseActivity -import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.visible import com.mikepenz.google_material_typeface_library.GoogleMaterial @@ -20,10 +32,11 @@ import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.createFreshDir import com.pitchedapps.frost.utils.setFrostColors -import com.pitchedapps.frost.web.DebugWebView import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import kotlinx.android.synthetic.main.activity_debug.* +import kotlinx.android.synthetic.main.view_main_fab.* import java.io.File /** @@ -31,11 +44,6 @@ import java.io.File */ class DebugActivity : KauBaseActivity() { - private val toolbar: Toolbar by bindView(R.id.toolbar) - private val web: DebugWebView by bindView(R.id.debug_webview) - private val swipeRefresh: SwipeRefreshLayout by bindView(R.id.swipe_refresh) - private val fab: FloatingActionButton by bindView(R.id.fab) - companion object { const val RESULT_URL = "extra_result_url" const val RESULT_SCREENSHOT = "extra_result_screenshot" @@ -56,10 +64,10 @@ class DebugActivity : KauBaseActivity() { setFrostColors { toolbar(toolbar) } - web.loadUrl(FbItem.FEED.url) - web.onPageFinished = { swipeRefresh.isRefreshing = false } + debug_webview.loadUrl(FbItem.FEED.url) + debug_webview.onPageFinished = { swipe_refresh.isRefreshing = false } - swipeRefresh.setOnRefreshListener(web::reload) + swipe_refresh.setOnRefreshListener(debug_webview::reload) fab.visible().setIcon(GoogleMaterial.Icon.gmd_bug_report, Prefs.iconColor) fab.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) @@ -69,10 +77,10 @@ class DebugActivity : KauBaseActivity() { val parent = baseDir(this) parent.createFreshDir() val rxScreenshot = Single.fromCallable { - web.getScreenshot(File(parent, "screenshot.png")) + debug_webview.getScreenshot(File(parent, "screenshot.png")) }.subscribeOn(Schedulers.io()) val rxBody = Single.create<String> { emitter -> - web.evaluateJavascript(JsActions.RETURN_BODY.function) { + debug_webview.evaluateJavascript(JsActions.RETURN_BODY.function) { emitter.onSuccess(it) } }.subscribeOn(AndroidSchedulers.mainThread()) @@ -81,23 +89,22 @@ class DebugActivity : KauBaseActivity() { val body = it[1] as? String screenshot to body }.observeOn(AndroidSchedulers.mainThread()) - .subscribe { (screenshot, body), err -> - if (err != null) { - L.e { "DebugActivity error ${err.message}" } - setResult(Activity.RESULT_CANCELED) - finish() - return@subscribe - } - val intent = Intent() - intent.putExtra(RESULT_URL, web.url) - intent.putExtra(RESULT_SCREENSHOT, screenshot) - if (body != null) - intent.putExtra(RESULT_BODY, body) - setResult(Activity.RESULT_OK, intent) + .subscribe { (screenshot, body), err -> + if (err != null) { + L.e { "DebugActivity error ${err.message}" } + setResult(Activity.RESULT_CANCELED) finish() + return@subscribe } + val intent = Intent() + intent.putExtra(RESULT_URL, debug_webview.url) + intent.putExtra(RESULT_SCREENSHOT, screenshot) + if (body != null) + intent.putExtra(RESULT_BODY, body) + setResult(Activity.RESULT_OK, intent) + finish() + } } - } override fun onSupportNavigateUp(): Boolean { @@ -107,18 +114,18 @@ class DebugActivity : KauBaseActivity() { override fun onResume() { super.onResume() - web.resumeTimers() + debug_webview.resumeTimers() } override fun onPause() { - web.pauseTimers() + debug_webview.pauseTimers() super.onPause() } override fun onBackPressed() { - if (web.canGoBack()) - web.goBack() + if (debug_webview.canGoBack()) + debug_webview.goBack() else super.onBackPressed() } -}
\ 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 30a77107..83f617ba 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.content.Intent @@ -5,16 +21,25 @@ import android.content.res.ColorStateList import android.graphics.Color import android.os.Bundle import android.os.Environment -import android.support.design.widget.FloatingActionButton import android.view.View import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.logging.KauLoggerExtension import ca.allanwang.kau.mediapicker.scanMedia import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE import ca.allanwang.kau.permissions.kauRequestPermissions -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.colorToForeground +import ca.allanwang.kau.utils.fadeOut +import ca.allanwang.kau.utils.fadeScaleTransition +import ca.allanwang.kau.utils.isHidden +import ca.allanwang.kau.utils.scaleXY +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.use +import ca.allanwang.kau.utils.withAlpha +import ca.allanwang.kau.utils.withMinAlpha import com.davemorrissey.labs.subscaleview.ImageSource import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon import com.pitchedapps.frost.R @@ -23,7 +48,19 @@ import com.pitchedapps.frost.facebook.get import com.pitchedapps.frost.facebook.requests.call import com.pitchedapps.frost.facebook.requests.getFullSizedImageUrl import com.pitchedapps.frost.facebook.requests.requestBuilder -import com.pitchedapps.frost.utils.* +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.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.createFreshFile +import com.pitchedapps.frost.utils.frostSnackbar +import com.pitchedapps.frost.utils.frostUriFromFile +import com.pitchedapps.frost.utils.isIndirectImageUrl +import com.pitchedapps.frost.utils.logFrostEvent +import com.pitchedapps.frost.utils.materialDialogThemed +import com.pitchedapps.frost.utils.sendFrostEmail +import com.pitchedapps.frost.utils.setFrostColors import com.sothree.slidinguppanel.SlidingUpPanelLayout import kotlinx.android.synthetic.main.activity_image.* import okhttp3.Response @@ -34,7 +71,8 @@ import java.io.File import java.io.FileFilter import java.io.IOException import java.text.SimpleDateFormat -import java.util.* +import java.util.Date +import java.util.Locale /** * Created by Allan Wang on 2017-07-15. @@ -94,8 +132,10 @@ class ImageActivity : KauBaseActivity() { // a unique image identifier based on the id (if it exists), and its hash private val imageHash: String by lazy { - "${Math.abs(FB_IMAGE_ID_MATCHER.find(imageUrl)[1]?.hashCode() - ?: 0)}_${Math.abs(imageUrl.hashCode())}" + "${Math.abs( + FB_IMAGE_ID_MATCHER.find(imageUrl)[1]?.hashCode() + ?: 0 + )}_${Math.abs(imageUrl.hashCode())}" } override fun onCreate(savedInstanceState: Bundle?) { @@ -105,11 +145,15 @@ class ImageActivity : KauBaseActivity() { L.v { "Displaying image $imageUrl" } val layout = if (!imageText.isNullOrBlank()) R.layout.activity_image else R.layout.activity_image_textless setContentView(layout) - image_container.setBackgroundColor(if (Prefs.blackMediaBg) Color.BLACK - else Prefs.bgColor.withMinAlpha(222)) + image_container.setBackgroundColor( + if (Prefs.blackMediaBg) Color.BLACK + else Prefs.bgColor.withMinAlpha(222) + ) image_text?.setTextColor(if (Prefs.blackMediaBg) Color.WHITE else Prefs.textColor) - image_text?.setBackgroundColor((if (Prefs.blackMediaBg) Color.BLACK else Prefs.bgColor) - .colorToForeground(0.2f).withAlpha(255)) + image_text?.setBackgroundColor( + (if (Prefs.blackMediaBg) Color.BLACK else Prefs.bgColor) + .colorToForeground(0.2f).withAlpha(255) + ) image_text?.text = imageText image_progress.tint(if (Prefs.blackMediaBg) Color.WHITE else Prefs.accentColor) image_panel?.addPanelSlideListener(object : SlidingUpPanelLayout.SimplePanelSlideListener() { @@ -208,16 +252,15 @@ class ImageActivity : KauBaseActivity() { } private fun getImageResponse(): Response = cookie.requestBuilder() - .url(trueImageUrl) - .get() - .call() - .execute() - + .url(trueImageUrl) + .get() + .call() + .execute() @Throws(IOException::class) private fun downloadImageTo(file: File) { val body = getImageResponse().body() - ?: throw IOException("Failed to retrieve image body") + ?: throw IOException("Failed to retrieve image body") body.byteStream().use { input -> file.outputStream().use { output -> input.copyTo(output) @@ -272,7 +315,11 @@ class ImageActivity : KauBaseActivity() { } } -internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconColor, val backgroundTint: Int = Int.MAX_VALUE) { +internal enum class FabStates( + val iicon: IIcon, + val iconColor: Int = Prefs.iconColor, + val backgroundTint: Int = Int.MAX_VALUE +) { ERROR(GoogleMaterial.Icon.gmd_error, Color.WHITE, Color.RED) { override fun onClick(activity: ImageActivity) { activity.materialDialogThemed { @@ -334,5 +381,4 @@ internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconC } abstract fun onClick(activity: ImageActivity) - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt index 4b00c242..a3ab6172 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt @@ -1,31 +1,60 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.animation.ValueAnimator import android.content.res.ColorStateList import android.graphics.Color import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentManager -import android.support.v4.app.FragmentPagerAdapter -import android.support.v4.view.ViewPager import android.view.View import android.view.WindowManager import android.widget.Button import android.widget.ImageButton import android.widget.ImageView +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import androidx.viewpager.widget.ViewPager import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.ui.views.RippleCanvas import ca.allanwang.kau.ui.widgets.InkPageIndicator -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.blendWith +import ca.allanwang.kau.utils.color +import ca.allanwang.kau.utils.fadeScaleTransition +import ca.allanwang.kau.utils.navigationBarColor +import ca.allanwang.kau.utils.postDelayed +import ca.allanwang.kau.utils.scaleXY +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.statusBarColor import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.pitchedapps.frost.R -import com.pitchedapps.frost.intro.* +import com.pitchedapps.frost.intro.BaseIntroFragment +import com.pitchedapps.frost.intro.IntroAccountFragment +import com.pitchedapps.frost.intro.IntroFragmentEnd +import com.pitchedapps.frost.intro.IntroFragmentTheme +import com.pitchedapps.frost.intro.IntroFragmentWelcome +import com.pitchedapps.frost.intro.IntroTabContextFragment +import com.pitchedapps.frost.intro.IntroTabTouchFragment import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.cookies import com.pitchedapps.frost.utils.launchNewTask import org.jetbrains.anko.find - /** * Created by Allan Wang on 2017-07-25. * @@ -43,12 +72,12 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On private var barHasNext = true val fragments = listOf( - IntroFragmentWelcome(), - IntroFragmentTheme(), - IntroAccountFragment(), - IntroTabTouchFragment(), - IntroTabContextFragment(), - IntroFragmentEnd() + IntroFragmentWelcome(), + IntroFragmentTheme(), + IntroAccountFragment(), + IntroTabTouchFragment(), + IntroTabContextFragment(), + IntroFragmentEnd() ) override fun onCreate(savedInstanceState: Bundle?) { @@ -97,7 +126,6 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On page.alpha = 1f page.translationX = 0f } - } fun finish(x: Float, y: Float) { @@ -107,9 +135,11 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On postDelayed(1000) { finish() } } val lastView: View? = fragments.last().view - arrayOf<View?>(skip, indicator, next, - lastView?.find(R.id.intro_title), - lastView?.find(R.id.intro_desc)).forEach { + arrayOf<View?>( + skip, indicator, next, + lastView?.find(R.id.intro_title), + lastView?.find(R.id.intro_desc) + ).forEach { it?.animate()?.alpha(0f)?.setDuration(600)?.start() } if (Prefs.textColor != Color.WHITE) { @@ -147,7 +177,6 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On } override fun onPageScrollStateChanged(state: Int) { - } override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { @@ -162,16 +191,19 @@ class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.On if (barHasNext == hasNext) return barHasNext = hasNext next.fadeScaleTransition { - setIcon(if (barHasNext) GoogleMaterial.Icon.gmd_navigate_next else GoogleMaterial.Icon.gmd_done, color = Prefs.textColor) + setIcon( + if (barHasNext) GoogleMaterial.Icon.gmd_navigate_next else GoogleMaterial.Icon.gmd_done, + color = Prefs.textColor + ) } skip.animate().scaleXY(if (barHasNext) 1f else 0f) } - class IntroPageAdapter(fm: FragmentManager, private val fragments: List<BaseIntroFragment>) : FragmentPagerAdapter(fm) { + class IntroPageAdapter(fm: FragmentManager, private val fragments: List<BaseIntroFragment>) : + FragmentPagerAdapter(fm) { override fun getItem(position: Int): Fragment = fragments[position] override fun getCount(): Int = fragments.size } - -}
\ No newline at end of file +} 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 b5e2119f..8b5fe38d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -1,12 +1,28 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.graphics.drawable.Drawable import android.os.Bundle import android.os.Handler -import android.support.v4.widget.SwipeRefreshLayout -import android.support.v7.widget.AppCompatTextView -import android.support.v7.widget.Toolbar import android.widget.ImageView +import androidx.appcompat.widget.AppCompatTextView +import androidx.appcompat.widget.Toolbar +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.fadeIn import ca.allanwang.kau.utils.fadeOut @@ -24,14 +40,18 @@ import com.pitchedapps.frost.facebook.profilePictureUrl import com.pitchedapps.frost.glide.FrostGlide import com.pitchedapps.frost.glide.GlideApp import com.pitchedapps.frost.glide.transform -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Showcase +import com.pitchedapps.frost.utils.frostEvent +import com.pitchedapps.frost.utils.launchNewTask +import com.pitchedapps.frost.utils.logFrostEvent +import com.pitchedapps.frost.utils.setFrostColors import com.pitchedapps.frost.web.LoginWebView import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.functions.BiFunction import io.reactivex.subjects.SingleSubject - /** * Created by Allan Wang on 2017-06-01. */ @@ -78,51 +98,62 @@ class LoginActivity : BaseActivity() { private fun loadInfo(cookie: CookieModel) { refresh = true Single.zip<Boolean, String, Pair<Boolean, String>>( - profileSubject, - usernameSubject, - BiFunction(::Pair)) - .observeOn(AndroidSchedulers.mainThread()).subscribe { (foundImage, name) -> - refresh = false - if (!foundImage) { - L.e { "Could not get profile photo; Invalid userId?" } - L._i { cookie } - } - textview.text = String.format(getString(R.string.welcome), name) - textview.fadeIn() - frostEvent("Login", "success" to true) - /* - * The user may have logged into an account that is already in the database - * We will let the db handle duplicates and load it now after the new account has been saved - */ - loadFbCookiesAsync { - val cookies = ArrayList(it) - Handler().postDelayed({ - if (Showcase.intro) - launchNewTask<IntroActivity>(cookies, true) - else - launchNewTask<MainActivity>(cookies, true) - }, 1000) - } - }.disposeOnDestroy() + profileSubject, + usernameSubject, + BiFunction(::Pair) + ) + .observeOn(AndroidSchedulers.mainThread()).subscribe { (foundImage, name) -> + refresh = false + if (!foundImage) { + L.e { "Could not get profile photo; Invalid userId?" } + L._i { cookie } + } + textview.text = String.format(getString(R.string.welcome), name) + textview.fadeIn() + frostEvent("Login", "success" to true) + /* + * The user may have logged into an account that is already in the database + * We will let the db handle duplicates and load it now after the new account has been saved + */ + loadFbCookiesAsync { + val cookies = ArrayList(it) + Handler().postDelayed({ + if (Showcase.intro) + launchNewTask<IntroActivity>(cookies, true) + else + launchNewTask<MainActivity>(cookies, true) + }, 1000) + } + }.disposeOnDestroy() loadProfile(cookie.id) loadUsername(cookie) } - private fun loadProfile(id: Long) { profileLoader.load(profilePictureUrl(id)) - .transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> { - override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { - profileSubject.onSuccess(true) - return false - } - - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean { - e.logFrostEvent("Profile loading exception") - profileSubject.onSuccess(false) - return false - } - }).into(profile) + .transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> { + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target<Drawable>?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + profileSubject.onSuccess(true) + return false + } + + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target<Drawable>?, + isFirstResource: Boolean + ): Boolean { + e.logFrostEvent("Profile loading exception") + profileSubject.onSuccess(false) + return false + } + }).into(profile) } private fun loadUsername(cookie: CookieModel) { @@ -146,5 +177,4 @@ class LoginActivity : BaseActivity() { web.pauseTimers() super.onPause() } - -}
\ 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 bf8120de..d03c6496 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt @@ -1,8 +1,24 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.os.Bundle -import android.support.design.widget.TabLayout -import android.support.v4.view.ViewPager +import androidx.viewpager.widget.ViewPager +import com.google.android.material.tabs.TabLayout import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.views.BadgedIcon import io.reactivex.android.schedulers.AndroidSchedulers @@ -36,19 +52,19 @@ class MainActivity : BaseMainActivity() { super.onPageScrolled(position, positionOffset, positionOffsetPixels) val delta = positionOffset * (255 - 128).toFloat() tabsForEachView { tabPosition, view -> - view.setAllAlpha(when (tabPosition) { - position -> 255.0f - delta - position + 1 -> 128.0f + delta - else -> 128f - }) + view.setAllAlpha( + when (tabPosition) { + position -> 255.0f - delta + position + 1 -> 128.0f + delta + else -> 128f + } + ) } } }) viewPager.post { fragmentSubject.onNext(0); lastPosition = 0 } //trigger hook so title is set - } - private fun setupTabs() { viewPager.addOnPageChangeListener(TabLayout.TabLayoutOnPageChangeListener(tabs)) tabs.addOnTabSelectedListener(object : TabLayout.ViewPagerOnTabSelectedListener(viewPager) { @@ -63,31 +79,31 @@ class MainActivity : BaseMainActivity() { } }) headerBadgeObservable.throttleFirst(15, TimeUnit.SECONDS) - .subscribeOn(Schedulers.newThread()) - .map { Jsoup.parse(it) } - .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]") - return@map arrayOf(feed, requests, messages, notifications).map { e -> e?.getOrNull(0)?.ownText() } - } - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { (feed, requests, messages, notifications) -> - tabsForEachView { _, view -> - when (view.iicon) { - FbItem.FEED.icon -> view.badgeText = feed - FbItem.FRIENDS.icon -> view.badgeText = requests - FbItem.MESSAGES.icon -> view.badgeText = messages - FbItem.NOTIFICATIONS.icon -> view.badgeText = notifications - } + .subscribeOn(Schedulers.newThread()) + .map { Jsoup.parse(it) } + .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]") + return@map arrayOf(feed, requests, messages, notifications).map { e -> e?.getOrNull(0)?.ownText() } + } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { (feed, requests, messages, notifications) -> + tabsForEachView { _, view -> + when (view.iicon) { + FbItem.FEED.icon -> view.badgeText = feed + FbItem.FRIENDS.icon -> view.badgeText = requests + FbItem.MESSAGES.icon -> view.badgeText = messages + FbItem.NOTIFICATIONS.icon -> view.badgeText = notifications } - }.disposeOnDestroy() + } + }.disposeOnDestroy() adapter.pages.forEach { tabs.addTab(tabs.newTab() - .setCustomView(BadgedIcon(this).apply { iicon = it.icon })) + .setCustomView(BadgedIcon(this).apply { iicon = it.icon }) + ) } } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt index 58ab3dac..2907bac6 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt @@ -1,11 +1,27 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.os.Bundle -import android.support.constraint.ConstraintLayout -import android.support.v7.widget.AppCompatTextView -import android.support.v7.widget.GridLayoutManager -import android.support.v7.widget.RecyclerView import android.view.View +import androidx.appcompat.widget.AppCompatTextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import ca.allanwang.kau.utils.bindView import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter @@ -47,4 +63,4 @@ class SelectorActivity : BaseActivity() { background(container) } } -}
\ No newline at end of file +} 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 7561dc88..37047448 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.annotation.SuppressLint @@ -12,14 +28,33 @@ 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.ui.views.RippleCanvas -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.finishSlideOut +import ca.allanwang.kau.utils.setMenuIcons +import ca.allanwang.kau.utils.startActivityForResult +import ca.allanwang.kau.utils.startLink +import ca.allanwang.kau.utils.string +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.withSceneTransitionAnimation import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.pitchedapps.frost.R import com.pitchedapps.frost.enums.Support -import com.pitchedapps.frost.settings.* -import com.pitchedapps.frost.utils.* - +import com.pitchedapps.frost.settings.getAppearancePrefs +import com.pitchedapps.frost.settings.getBehaviourPrefs +import com.pitchedapps.frost.settings.getDebugPrefs +import com.pitchedapps.frost.settings.getExperimentalPrefs +import com.pitchedapps.frost.settings.getFeedPrefs +import com.pitchedapps.frost.settings.getNotificationPrefs +import com.pitchedapps.frost.settings.sendDebug +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.REQUEST_RESTART +import com.pitchedapps.frost.utils.cookies +import com.pitchedapps.frost.utils.frostChangelog +import com.pitchedapps.frost.utils.frostNavigationBar +import com.pitchedapps.frost.utils.launchNewTask +import com.pitchedapps.frost.utils.materialDialogThemed +import com.pitchedapps.frost.utils.setFrostTheme /** * Created by Allan Wang on 2017-06-06. @@ -100,7 +135,7 @@ class SettingsActivity : KPrefActivity() { subItems(R.string.newsfeed, getFeedPrefs()) { descRes = R.string.newsfeed_desc - iicon = CommunityMaterial.Icon.cmd_newspaper + iicon = CommunityMaterial.Icon2.cmd_newspaper } subItems(R.string.notifications, getNotificationPrefs()) { @@ -146,7 +181,6 @@ class SettingsActivity : KPrefActivity() { iicon = CommunityMaterial.Icon.cmd_android_debug_bridge visible = { Prefs.debugSettings } } - } fun shouldRestartMain() { @@ -179,9 +213,11 @@ class SettingsActivity : KPrefActivity() { override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_settings, menu) toolbar.tint(Prefs.iconColor) - setMenuIcons(menu, Prefs.iconColor, - R.id.action_email to GoogleMaterial.Icon.gmd_email, - R.id.action_changelog to GoogleMaterial.Icon.gmd_info) + setMenuIcons( + menu, Prefs.iconColor, + R.id.action_email to GoogleMaterial.Icon.gmd_email, + R.id.action_changelog to GoogleMaterial.Icon.gmd_info + ) return true } @@ -201,4 +237,4 @@ class SettingsActivity : KPrefActivity() { fun setFrostResult(flag: Int) { resultFlag = resultFlag or flag } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt index 7b2cfbf2..7f632940 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt @@ -1,17 +1,30 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.app.Activity import android.content.res.ColorStateList import android.os.Bundle -import android.support.design.widget.FloatingActionButton -import android.support.v7.widget.GridLayoutManager -import android.support.v7.widget.RecyclerView -import android.support.v7.widget.helper.ItemTouchHelper import android.view.View import android.view.animation.AnimationUtils -import android.widget.TextView +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView import ca.allanwang.kau.kotlin.lazyContext -import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.scaleXY import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.withAlpha @@ -27,20 +40,15 @@ import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.iitems.TabIItem import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.setFrostColors -import java.util.* +import kotlinx.android.synthetic.main.activity_tab_customizer.* +import java.util.Collections /** * Created by Allan Wang on 26/11/17. */ class TabCustomizerActivity : BaseActivity() { - val toolbar: View by bindView(R.id.pseudo_toolbar) - val recycler: RecyclerView by bindView(R.id.tab_recycler) - val instructions: TextView by bindView(R.id.instructions) - val divider: View by bindView(R.id.divider) - val adapter = FastItemAdapter<TabIItem>() - val fabCancel: FloatingActionButton by bindView(R.id.fab_cancel) - val fabSave: FloatingActionButton by bindView(R.id.fab_save) + private val adapter = FastItemAdapter<TabIItem>() private val wobble = lazyContext { AnimationUtils.loadAnimation(it, R.anim.rotate_delta) } @@ -48,11 +56,11 @@ class TabCustomizerActivity : BaseActivity() { super.onCreate(savedInstanceState) setContentView(R.layout.activity_tab_customizer) - toolbar.setBackgroundColor(Prefs.headerColor) + pseudo_toolbar.setBackgroundColor(Prefs.headerColor) - recycler.layoutManager = GridLayoutManager(this, TAB_COUNT, GridLayoutManager.VERTICAL, false) - recycler.adapter = adapter - recycler.setHasFixedSize(true) + tab_recycler.layoutManager = GridLayoutManager(this, TAB_COUNT, RecyclerView.VERTICAL, false) + tab_recycler.adapter = adapter + tab_recycler.setHasFixedSize(true) divider.setBackgroundColor(Prefs.textColor.withAlpha(30)) instructions.setTextColor(Prefs.textColor) @@ -63,22 +71,22 @@ class TabCustomizerActivity : BaseActivity() { tabs.addAll(remaining) adapter.add(tabs.map(::TabIItem)) - bindSwapper(adapter, recycler) + bindSwapper(adapter, tab_recycler) adapter.withOnClickListener { view, _, _, _ -> view!!.wobble(); true } setResult(Activity.RESULT_CANCELED) - fabSave.setIcon(GoogleMaterial.Icon.gmd_check, Prefs.iconColor) - fabSave.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) - fabSave.setOnClickListener { + fab_save.setIcon(GoogleMaterial.Icon.gmd_check, Prefs.iconColor) + fab_save.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) + fab_save.setOnClickListener { adapter.adapterItems.subList(0, TAB_COUNT).map(TabIItem::item).save() setResult(Activity.RESULT_OK) finish() } - fabCancel.setIcon(GoogleMaterial.Icon.gmd_close, Prefs.iconColor) - fabCancel.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) - fabCancel.setOnClickListener { finish() } + fab_cancel.setIcon(GoogleMaterial.Icon.gmd_close, Prefs.iconColor) + fab_cancel.backgroundTintList = ColorStateList.valueOf(Prefs.accentColor) + fab_cancel.setOnClickListener { finish() } setFrostColors { themeWindow = true } @@ -101,9 +109,9 @@ class TabCustomizerActivity : BaseActivity() { override fun itemTouchDropped(oldPosition: Int, newPosition: Int) = Unit } - private class TabDragCallback( - directions: Int, itemTouchCallback: ItemTouchCallback + directions: Int, + itemTouchCallback: ItemTouchCallback ) : SimpleDragCallback(directions, itemTouchCallback) { private var draggingView: TabIItem.ViewHolder? = null @@ -127,7 +135,5 @@ class TabCustomizerActivity : BaseActivity() { } } } - } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt index 323a2eb5..b706d467 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.activities import android.annotation.SuppressLint @@ -5,25 +21,52 @@ import android.content.Intent import android.graphics.PointF import android.net.Uri import android.os.Bundle -import android.support.design.widget.CoordinatorLayout -import android.support.design.widget.Snackbar -import android.support.v7.widget.Toolbar import android.view.Menu import android.view.MenuItem import android.webkit.ValueCallback import android.webkit.WebChromeClient import android.widget.FrameLayout +import androidx.appcompat.widget.Toolbar +import androidx.coordinatorlayout.widget.CoordinatorLayout import ca.allanwang.kau.swipe.kauSwipeOnCreate import ca.allanwang.kau.swipe.kauSwipeOnDestroy -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.copyToClipboard +import ca.allanwang.kau.utils.darken +import ca.allanwang.kau.utils.dpToPx +import ca.allanwang.kau.utils.finishSlideOut +import ca.allanwang.kau.utils.navigationBarColor +import ca.allanwang.kau.utils.setMenuIcons +import ca.allanwang.kau.utils.shareText +import ca.allanwang.kau.utils.statusBarColor +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.toDrawable +import ca.allanwang.kau.utils.toast +import ca.allanwang.kau.utils.withAlpha +import com.google.android.material.snackbar.BaseTransientBottomBar import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.pitchedapps.frost.R -import com.pitchedapps.frost.contracts.* +import com.pitchedapps.frost.contracts.ActivityContract +import com.pitchedapps.frost.contracts.FileChooserContract +import com.pitchedapps.frost.contracts.FileChooserDelegate +import com.pitchedapps.frost.contracts.FrostContentContainer +import com.pitchedapps.frost.contracts.VideoViewHolder import com.pitchedapps.frost.enums.OverlayContext -import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.facebook.FB_URL_BASE +import com.pitchedapps.frost.facebook.FbCookie +import com.pitchedapps.frost.facebook.FbItem +import com.pitchedapps.frost.facebook.USER_AGENT_BASIC +import com.pitchedapps.frost.facebook.formattedFbUrl import com.pitchedapps.frost.services.FrostRunnable -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.ARG_URL +import com.pitchedapps.frost.utils.ARG_USER_ID +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.Showcase +import com.pitchedapps.frost.utils.frostSnackbar +import com.pitchedapps.frost.utils.materialDialogThemed +import com.pitchedapps.frost.utils.setFrostColors import com.pitchedapps.frost.views.FrostContentWeb import com.pitchedapps.frost.views.FrostVideoViewer import com.pitchedapps.frost.views.FrostWebView @@ -31,7 +74,6 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import okhttp3.HttpUrl - /** * Created by Allan Wang on 2017-06-01. * @@ -103,8 +145,8 @@ class WebOverlayActivity : WebOverlayActivityBase(false) @SuppressLint("Registered") open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseActivity(), - ActivityContract, FrostContentContainer, - VideoViewHolder, FileChooserContract by FileChooserDelegate() { + 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) @@ -156,9 +198,9 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc content.bind(this) content.titleObservable - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { toolbar.title = it } - .disposeOnDestroy() + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { toolbar.title = it } + .disposeOnDestroy() with(web) { if (forceBasicAgent) //todo check; the webview already adds it dynamically @@ -168,7 +210,7 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc else reloadBase(true) if (Showcase.firstWebOverlay) { coordinator.frostSnackbar(R.string.web_overlay_swipe_hint) { - duration = Snackbar.LENGTH_INDEFINITE + duration = BaseTransientBottomBar.LENGTH_INDEFINITE setAction(R.string.kau_got_it) { _ -> this.dismiss() } } } @@ -235,7 +277,10 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc kauSwipeOnDestroy() } - override fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) { + override fun openFileChooser( + filePathCallback: ValueCallback<Array<Uri>?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) { openMediaPicker(filePathCallback, fileChooserParams) } @@ -247,9 +292,11 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc menuInflater.inflate(R.menu.menu_web, menu) overlayContext?.onMenuCreate(this, menu) toolbar.tint(Prefs.iconColor) - setMenuIcons(menu, Prefs.iconColor, - R.id.action_share to CommunityMaterial.Icon.cmd_share, - R.id.action_copy_link to GoogleMaterial.Icon.gmd_content_copy) + setMenuIcons( + menu, Prefs.iconColor, + R.id.action_share to CommunityMaterial.Icon2.cmd_share, + R.id.action_copy_link to GoogleMaterial.Icon.gmd_content_copy + ) return true } @@ -270,5 +317,4 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc */ override var videoViewer: FrostVideoViewer? = null override val lowerVideoPadding: PointF = PointF(0f, 0f) - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/ActivityContract.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/ActivityContract.kt index 1182e609..2ce83871 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/ActivityContract.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/ActivityContract.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts import com.mikepenz.iconics.typeface.IIcon @@ -25,4 +41,4 @@ interface MainActivityContract : ActivityContract, MainFabContract { interface MainFabContract { fun showFab(iicon: IIcon, clickEvent: () -> Unit) fun hideFab() -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/DynamicUiContract.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/DynamicUiContract.kt index 303c64b3..736ef72d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/DynamicUiContract.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/DynamicUiContract.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts /** @@ -21,10 +37,8 @@ interface DynamicUiContract { */ fun reloadTextSize() - /** * Change text size without propagation */ fun reloadTextSizeSelf() - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt index 15165456..73d5c56d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts import android.app.Activity @@ -17,12 +33,19 @@ import com.pitchedapps.frost.utils.L const val MEDIA_CHOOSER_RESULT = 67 interface FileChooserActivityContract { - fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) + fun openFileChooser( + filePathCallback: ValueCallback<Array<Uri>?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) } interface FileChooserContract { var filePathCallback: ValueCallback<Array<Uri>?>? - fun Activity.openMediaPicker(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) + fun Activity.openMediaPicker( + filePathCallback: ValueCallback<Array<Uri>?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) + fun Activity.onActivityResultWeb(requestCode: Int, resultCode: Int, intent: Intent?): Boolean } @@ -30,7 +53,10 @@ class FileChooserDelegate : FileChooserContract { override var filePathCallback: ValueCallback<Array<Uri>?>? = null - override fun Activity.openMediaPicker(filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: WebChromeClient.FileChooserParams) { + override fun Activity.openMediaPicker( + filePathCallback: ValueCallback<Array<Uri>?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) { kauRequestPermissions(PERMISSION_WRITE_EXTERNAL_STORAGE) { granted, _ -> if (!granted) { filePathCallback.onReceiveValue(null) @@ -52,5 +78,4 @@ class FileChooserDelegate : FileChooserContract { filePathCallback = null return true } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt index 613295e6..50c2fe77 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostContentContract.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts import android.view.View @@ -23,7 +39,6 @@ interface FrostContentContainer { * Update toolbar title */ fun setTitle(title: String) - } /** @@ -84,7 +99,6 @@ interface FrostContentParent : DynamicUiContract { * For those cases, we will return false to stop it */ fun registerTransition(urlChanged: Boolean, animate: Boolean): Boolean - } /** @@ -147,5 +161,4 @@ interface FrostContentCore : DynamicUiContract { * Signal destruction to release some content manually */ fun destroy() - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostObservables.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostObservables.kt index 882b67a0..b3b93b66 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostObservables.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostObservables.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts import io.reactivex.subjects.BehaviorSubject @@ -27,5 +43,4 @@ interface FrostObservables { other.progressObservable = progressObservable other.titleObservable = titleObservable } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostThemable.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostThemable.kt index 3322f62e..93d827a6 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostThemable.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FrostThemable.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts import android.view.View @@ -18,12 +34,11 @@ interface FrostThemable { fun reloadTheme() fun setTextColors(color: Int, vararg textViews: TextView?) = - themeViews(color, *textViews) { setTextColor(it) } + themeViews(color, *textViews) { setTextColor(it) } fun setBackgrounds(color: Int, vararg views: View?) = - themeViews(color, *views) { setBackgroundColor(it) } + themeViews(color, *views) { setBackgroundColor(it) } fun <T : View> themeViews(color: Int, vararg views: T?, action: T.(Int) -> Unit) = - views.filterNotNull().forEach { it.action(color) } - -}
\ No newline at end of file + views.filterNotNull().forEach { it.action(color) } +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/contracts/VideoViewHolder.kt b/app/src/main/kotlin/com/pitchedapps/frost/contracts/VideoViewHolder.kt index 13b6a7aa..e749b0d3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/VideoViewHolder.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/VideoViewHolder.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.contracts import android.app.Activity @@ -49,5 +65,4 @@ interface FrameWrapper { setContentView(R.layout.activity_frame_wrapper) frameWrapper.inflate(layoutRes, true) } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt index 1fe65d5a..db3bf973 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/CookiesDb.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.dbflow import android.os.Parcel @@ -11,7 +27,13 @@ import com.raizlabs.android.dbflow.annotation.ConflictAction import com.raizlabs.android.dbflow.annotation.Database import com.raizlabs.android.dbflow.annotation.PrimaryKey import com.raizlabs.android.dbflow.annotation.Table -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.kotlinextensions.async +import com.raizlabs.android.dbflow.kotlinextensions.delete +import com.raizlabs.android.dbflow.kotlinextensions.eq +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.where import com.raizlabs.android.dbflow.structure.BaseModel import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers @@ -30,7 +52,8 @@ object CookiesDb { @PaperParcel @Table(database = CookiesDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE) -data class CookieModel(@PrimaryKey var id: Long = -1L, var name: String? = null, var cookie: String? = null) : BaseModel(), Parcelable { +data class CookieModel(@PrimaryKey var id: Long = -1L, var name: String? = null, var cookie: String? = null) : + BaseModel(), Parcelable { companion object { @JvmField val CREATOR = PaperParcelCookieModel.CREATOR @@ -40,18 +63,22 @@ data class CookieModel(@PrimaryKey var id: Long = -1L, var name: String? = null, override fun writeToParcel(dest: Parcel, flags: Int) = PaperParcelCookieModel.writeToParcel(this, dest, flags) } -fun loadFbCookie(id: Long): CookieModel? = (select from CookieModel::class where (CookieModel_Table.id eq id)).querySingle() -fun loadFbCookie(name: String): CookieModel? = (select from CookieModel::class where (CookieModel_Table.name eq name)).querySingle() +fun loadFbCookie(id: Long): CookieModel? = + (select from CookieModel::class where (CookieModel_Table.id eq id)).querySingle() + +fun loadFbCookie(name: String): CookieModel? = + (select from CookieModel::class where (CookieModel_Table.name eq name)).querySingle() /** * Loads cookies sorted by name */ fun loadFbCookiesAsync(callback: (cookies: List<CookieModel>) -> Unit) { - (select from CookieModel::class).orderBy(CookieModel_Table.name, true).async().queryListResultCallback { _, tResult -> callback(tResult) }.execute() + (select from CookieModel::class).orderBy(CookieModel_Table.name, true).async() + .queryListResultCallback { _, tResult -> callback(tResult) }.execute() } -fun loadFbCookiesSync(): List<CookieModel> = (select from CookieModel::class).orderBy(CookieModel_Table.name, true).queryList() - +fun loadFbCookiesSync(): List<CookieModel> = + (select from CookieModel::class).orderBy(CookieModel_Table.name, true).queryList() inline fun saveFbCookie(cookie: CookieModel, crossinline callback: (() -> Unit) = {}) { cookie.async save { @@ -69,24 +96,24 @@ fun removeCookie(id: Long) { } inline fun CookieModel.fetchUsername(crossinline callback: (String) -> Unit): Disposable = - ReactiveNetwork.checkInternetConnectivity().subscribeOn(Schedulers.io()).subscribe { yes, _ -> - if (!yes) return@subscribe callback("") - var result = "" - try { - result = frostJsoup(cookie, FbItem.PROFILE.url).title() - L.d { "Fetch username found" } - } catch (e: Exception) { - if (e !is UnknownHostException) - e.logFrostEvent("Fetch username failed") - } finally { - if (result.isBlank() && (name?.isNotBlank() == true)) { - callback(name!!) - return@subscribe - } - if (name != result) { - name = result - saveFbCookie(this@fetchUsername) - } - callback(result) + ReactiveNetwork.checkInternetConnectivity().subscribeOn(Schedulers.io()).subscribe { yes, _ -> + if (!yes) return@subscribe callback("") + var result = "" + try { + result = frostJsoup(cookie, FbItem.PROFILE.url).title() + L.d { "Fetch username found" } + } catch (e: Exception) { + if (e !is UnknownHostException) + e.logFrostEvent("Fetch username failed") + } finally { + if (result.isBlank() && (name?.isNotBlank() == true)) { + callback(name!!) + return@subscribe } + if (name != result) { + name = result + saveFbCookie(this@fetchUsername) + } + callback(result) } + } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt index e4aef2a9..740fef62 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/DbUtils.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.dbflow import android.content.Context @@ -14,11 +30,10 @@ object DbUtils { fun db(name: String) = FlowManager.getDatabase(name) fun dbName(name: String) = "$name.db" fun deleteDatabase(c: Context, name: String) = c.deleteDatabase(dbName(name)) - } inline fun <reified T : Any> List<T>.replace(dbName: String) { L.d { "Replacing $dbName.db" } DbUtils.db(dbName).reset() FastStoreModelTransaction.saveBuilder(FlowManager.getModelAdapter(T::class.java)).addAll(this).build() -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt index 827881e3..9d330169 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/FbTabsDb.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.dbflow import com.pitchedapps.frost.facebook.FbItem @@ -39,4 +55,4 @@ fun loadFbTabs(): List<FbItem> { fun List<FbItem>.save() { database<FbTabsDb>().beginTransactionAsync(mapIndexed(::FbTabModel).fastSave().build()).execute() -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt index b61fc218..a054d95e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt @@ -1,8 +1,33 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.dbflow import com.pitchedapps.frost.utils.L -import com.raizlabs.android.dbflow.annotation.* -import com.raizlabs.android.dbflow.kotlinextensions.* +import com.raizlabs.android.dbflow.annotation.ConflictAction +import com.raizlabs.android.dbflow.annotation.Database +import com.raizlabs.android.dbflow.annotation.Migration +import com.raizlabs.android.dbflow.annotation.PrimaryKey +import com.raizlabs.android.dbflow.annotation.Table +import com.raizlabs.android.dbflow.kotlinextensions.async +import com.raizlabs.android.dbflow.kotlinextensions.eq +import com.raizlabs.android.dbflow.kotlinextensions.from +import com.raizlabs.android.dbflow.kotlinextensions.save +import com.raizlabs.android.dbflow.kotlinextensions.select +import com.raizlabs.android.dbflow.kotlinextensions.where import com.raizlabs.android.dbflow.sql.SQLiteType import com.raizlabs.android.dbflow.sql.migration.AlterTableMigration import com.raizlabs.android.dbflow.structure.BaseModel @@ -18,7 +43,8 @@ object NotificationDb { } @Migration(version = 2, database = NotificationDb::class) -class NotificationMigration2(modelClass: Class<NotificationModel>) : AlterTableMigration<NotificationModel>(modelClass) { +class NotificationMigration2(modelClass: Class<NotificationModel>) : + AlterTableMigration<NotificationModel>(modelClass) { override fun onPreMigrate() { super.onPreMigrate() addColumn(SQLiteType.INTEGER, "epochIm") @@ -27,11 +53,14 @@ class NotificationMigration2(modelClass: Class<NotificationModel>) : AlterTableM } @Table(database = NotificationDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE) -data class NotificationModel(@PrimaryKey var id: Long = -1L, - var epoch: Long = -1L, - var epochIm: Long = -1L) : BaseModel() +data class NotificationModel( + @PrimaryKey var id: Long = -1L, + var epoch: Long = -1L, + var epochIm: Long = -1L +) : BaseModel() -fun lastNotificationTime(id: Long): NotificationModel = (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle() +fun lastNotificationTime(id: Long): NotificationModel = + (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle() ?: NotificationModel(id = id) fun saveNotificationTime(notificationModel: NotificationModel, callback: (() -> Unit)? = null) { @@ -40,4 +69,4 @@ fun saveNotificationTime(notificationModel: NotificationModel, callback: (() -> L._d { notificationModel } callback?.invoke() } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt b/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt index 6298f1f9..f5009cc5 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/debugger/OfflineWebsite.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.debugger import ca.allanwang.kau.logging.KauLoggerExtension @@ -32,21 +48,23 @@ import java.util.zip.ZipOutputStream * * Inspired by <a href="https://github.com/JonasCz/save-for-offline">Save for Offline</a> */ -class OfflineWebsite(private val url: String, - private val cookie: String = "", - baseUrl: String? = null, - private val html: String? = null, - /** - * Directory that holds all the files - */ - val baseDir: File, - private val userAgent: String = USER_AGENT_BASIC) { +class OfflineWebsite( + private val url: String, + private val cookie: String = "", + baseUrl: String? = null, + private val html: String? = null, + /** + * Directory that holds all the files + */ + val baseDir: File, + private val userAgent: String = USER_AGENT_BASIC +) { /** * Supplied url without the queries */ private val baseUrl = (baseUrl ?: url.substringBefore("?") - .substringBefore(".com")).trim('/') + .substringBefore(".com")).trim('/') private val mainFile = File(baseDir, "index.html") private val assetDir = File(baseDir, "assets") @@ -67,11 +85,11 @@ class OfflineWebsite(private val url: String, private val cssQueue = mutableSetOf<String>() private fun request(url: String) = Request.Builder() - .header("Cookie", cookie) - .header("User-Agent", userAgent) - .url(url) - .get() - .call() + .header("Cookie", cookie) + .header("User-Agent", userAgent) + .url(url) + .get() + .call() private val compositeDisposable = CompositeDisposable() @@ -94,7 +112,6 @@ class OfflineWebsite(private val url: String, return callback(false) } - if (!assetDir.createFreshDir()) { L.e { "Could not create ${assetDir.absolutePath}" } return callback(false) @@ -245,8 +262,10 @@ class OfflineWebsite(private val url: String, } }) - private inline fun <T> String.downloadUrl(fallback: () -> T, - action: (file: File, body: ResponseBody) -> T): T { + private inline fun <T> String.downloadUrl( + fallback: () -> T, + action: (file: File, body: ResponseBody) -> T + ): T { val file = File(assetDir, fileName()) if (!file.createNewFile()) { @@ -289,11 +308,10 @@ class OfflineWebsite(private val url: String, if (mapped != null) return mapped val candidate = substringBefore("?").trim('/') - .substringAfterLast("/").shorten() + .substringAfterLast("/").shorten() val index = atomicInt.getAndIncrement() - var newUrl = "a${index}_$candidate" /** @@ -308,10 +326,10 @@ class OfflineWebsite(private val url: String, } private fun String.shorten() = - if (length <= 10) this else substring(length - 10) + if (length <= 10) this else substring(length - 10) private fun Set<String>.clean(): List<String> = - filter(String::isNotBlank).filter { it.startsWith("http") } + filter(String::isNotBlank).filter { it.startsWith("http") } private fun reset() { cancelled = false @@ -326,5 +344,4 @@ class OfflineWebsite(private val url: String, compositeDisposable.dispose() L.v { "Request cancelled" } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/FeedSort.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/FeedSort.kt index d2de9988..7312399e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/FeedSort.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/FeedSort.kt @@ -1,6 +1,22 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.enums -import android.support.annotation.StringRes +import androidx.annotation.StringRes import com.pitchedapps.frost.R import com.pitchedapps.frost.facebook.FbItem @@ -16,4 +32,4 @@ enum class FeedSort(@StringRes val textRes: Int, val item: FbItem) { val values = values() //save one instance operator fun invoke(index: Int) = values[index] } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt index 79b11752..2d51b032 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/MainActivityLayout.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.enums import com.pitchedapps.frost.R @@ -7,23 +23,24 @@ import com.pitchedapps.frost.utils.Prefs * Created by Allan Wang on 2017-08-19. */ enum class MainActivityLayout( - val titleRes: Int, - val layoutRes: Int, - val backgroundColor: () -> Int, - val iconColor: () -> Int) { + val titleRes: Int, + val layoutRes: Int, + val backgroundColor: () -> Int, + val iconColor: () -> Int +) { TOP_BAR(R.string.top_bar, - R.layout.activity_main, - { Prefs.headerColor }, - { Prefs.iconColor }), + R.layout.activity_main, + { Prefs.headerColor }, + { Prefs.iconColor }), BOTTOM_BAR(R.string.bottom_bar, - R.layout.activity_main_bottom_tabs, - { Prefs.bgColor }, - { Prefs.textColor }); + R.layout.activity_main_bottom_tabs, + { Prefs.bgColor }, + { Prefs.textColor }); companion object { val values = values() //save one instance operator fun invoke(index: Int) = values[index] } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/OverlayContext.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/OverlayContext.kt index f93a2229..d529db12 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/OverlayContext.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/OverlayContext.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.enums import android.content.Context @@ -52,12 +68,13 @@ enum class OverlayContext(private val menuItem: FrostMenuItem?) : EnumBundle<Ove * Frame for an injectable menu item */ class FrostMenuItem( - val id: Int, - val fbItem: FbItem, - val showAsAction: Int = MenuItem.SHOW_AS_ACTION_IF_ROOM) { + val id: Int, + val fbItem: FbItem, + val showAsAction: Int = MenuItem.SHOW_AS_ACTION_IF_ROOM +) { fun addToMenu(context: Context, menu: Menu, index: Int) { val item = menu.add(Menu.NONE, id, index, fbItem.titleId) item.icon = fbItem.icon.toDrawable(context, 18) item.setShowAsAction(showAsAction) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/Support.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/Support.kt index ef3c88b6..23ea5a8f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/Support.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/Support.kt @@ -1,7 +1,23 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.enums import android.content.Context -import android.support.annotation.StringRes +import androidx.annotation.StringRes import ca.allanwang.kau.utils.string import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.sendFrostEmail @@ -21,4 +37,4 @@ enum class Support(@StringRes val title: Int) { } } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt b/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt index ada0b456..345aa88e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt @@ -1,7 +1,23 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.enums import android.graphics.Color -import android.support.annotation.StringRes +import androidx.annotation.StringRes import com.pitchedapps.frost.R import com.pitchedapps.frost.injectors.CssAssets import com.pitchedapps.frost.injectors.InjectorContract @@ -14,61 +30,63 @@ import com.pitchedapps.frost.utils.Prefs const val FACEBOOK_BLUE = 0xff3b5998.toInt() const val BLUE_LIGHT = 0xff5d86dd.toInt() -enum class Theme(@StringRes val textRes: Int, - val injector: InjectorContract, - private val textColorGetter: () -> Int, - private val accentColorGetter: () -> Int, - private val backgroundColorGetter: () -> Int, - private val headerColorGetter: () -> Int, - private val iconColorGetter: () -> Int) { +enum class Theme( + @StringRes val textRes: Int, + val injector: InjectorContract, + private val textColorGetter: () -> Int, + private val accentColorGetter: () -> Int, + private val backgroundColorGetter: () -> Int, + private val headerColorGetter: () -> Int, + private val iconColorGetter: () -> Int +) { DEFAULT(R.string.kau_default, - JsActions.EMPTY, - { 0xde000000.toInt() }, - { FACEBOOK_BLUE }, - { 0xfffafafa.toInt() }, - { FACEBOOK_BLUE }, - { Color.WHITE }), + JsActions.EMPTY, + { 0xde000000.toInt() }, + { FACEBOOK_BLUE }, + { 0xfffafafa.toInt() }, + { FACEBOOK_BLUE }, + { Color.WHITE }), LIGHT(R.string.kau_light, - CssAssets.MATERIAL_LIGHT, - { 0xde000000.toInt() }, - { FACEBOOK_BLUE }, - { 0xfffafafa.toInt() }, - { FACEBOOK_BLUE }, - { Color.WHITE }), + CssAssets.MATERIAL_LIGHT, + { 0xde000000.toInt() }, + { FACEBOOK_BLUE }, + { 0xfffafafa.toInt() }, + { FACEBOOK_BLUE }, + { Color.WHITE }), DARK(R.string.kau_dark, - CssAssets.MATERIAL_DARK, - { Color.WHITE }, - { BLUE_LIGHT }, - { 0xff303030.toInt() }, - { 0xff2e4b86.toInt() }, - { Color.WHITE }), + CssAssets.MATERIAL_DARK, + { Color.WHITE }, + { BLUE_LIGHT }, + { 0xff303030.toInt() }, + { 0xff2e4b86.toInt() }, + { Color.WHITE }), AMOLED(R.string.kau_amoled, - CssAssets.MATERIAL_AMOLED, - { Color.WHITE }, - { BLUE_LIGHT }, - { Color.BLACK }, - { Color.BLACK }, - { Color.WHITE }), + CssAssets.MATERIAL_AMOLED, + { Color.WHITE }, + { BLUE_LIGHT }, + { Color.BLACK }, + { Color.BLACK }, + { Color.WHITE }), GLASS(R.string.kau_glass, - CssAssets.MATERIAL_GLASS, - { Color.WHITE }, - { BLUE_LIGHT }, - { 0x80000000.toInt() }, - { 0xb3000000.toInt() }, - { Color.WHITE }), + CssAssets.MATERIAL_GLASS, + { Color.WHITE }, + { BLUE_LIGHT }, + { 0x80000000.toInt() }, + { 0xb3000000.toInt() }, + { Color.WHITE }), CUSTOM(R.string.kau_custom, - CssAssets.CUSTOM, - { Prefs.customTextColor }, - { Prefs.customAccentColor }, - { Prefs.customBackgroundColor }, - { Prefs.customHeaderColor }, - { Prefs.customIconColor }); + CssAssets.CUSTOM, + { Prefs.customTextColor }, + { Prefs.customAccentColor }, + { Prefs.customBackgroundColor }, + { Prefs.customHeaderColor }, + { Prefs.customIconColor }); val textColor: Int get() = textColorGetter() @@ -89,4 +107,4 @@ enum class Theme(@StringRes val textRes: Int, val values = values() //save one instance operator fun invoke(index: Int) = values[index] } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt index 2b881d1c..b6207a7b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbConst.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook /** @@ -12,9 +28,12 @@ fun profilePictureUrl(id: Long) = "https://graph.facebook.com/$id/picture?type=l const val FB_LOGIN_URL = "${FB_URL_BASE}login" const val FB_HOME_URL = "${FB_URL_BASE}home.php" -const val USER_AGENT_FULL = "Mozilla/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-G900T Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.6 Chrome/28.0.1500.94 Mobile Safari/537.36" -const val USER_AGENT_BASIC_OLD = "Mozilla/5.0 (Linux; Android 6.0) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.1.0.4633 Mobile Safari/537.10+" -const val USER_AGENT_MESSENGER = "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" +const val USER_AGENT_FULL = + "Mozilla/5.0 (Linux; Android 4.4.2; en-us; SAMSUNG SM-G900T Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.6 Chrome/28.0.1500.94 Mobile Safari/537.36" +const val USER_AGENT_BASIC_OLD = + "Mozilla/5.0 (Linux; Android 6.0) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.1.0.4633 Mobile Safari/537.10+" +const val USER_AGENT_MESSENGER = + "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36" const val USER_AGENT_BASIC = USER_AGENT_MESSENGER /** @@ -27,4 +46,4 @@ const val WEB_LOAD_DELAY = 50L * Note that transitions are also called from onFinish, so this value * will never make a load slower than it is */ -const val WEB_COMMIT_LOAD_DELAY = 200L
\ No newline at end of file +const val WEB_COMMIT_LOAD_DELAY = 200L diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt index d54c82bc..c7931e53 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbCookie.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook import android.app.Activity @@ -166,4 +182,4 @@ object FbCookie { } } else callback() } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt index d6915f75..723ed450 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt @@ -1,6 +1,22 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook -import android.support.annotation.StringRes +import androidx.annotation.StringRes import com.mikepenz.community_material_typeface_library.CommunityMaterial import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.mikepenz.iconics.typeface.IIcon @@ -15,24 +31,24 @@ import com.pitchedapps.frost.utils.EnumBundleCompanion import com.pitchedapps.frost.utils.EnumCompanion enum class FbItem( - @StringRes val titleId: Int, - val icon: IIcon, - relativeUrl: String, - val fragmentCreator: () -> BaseFragment = ::WebFragment + @StringRes val titleId: Int, + val icon: IIcon, + relativeUrl: String, + val fragmentCreator: () -> BaseFragment = ::WebFragment ) : EnumBundle<FbItem> { ACTIVITY_LOG(R.string.activity_log, GoogleMaterial.Icon.gmd_list, "me/allactivity"), BIRTHDAYS(R.string.birthdays, GoogleMaterial.Icon.gmd_cake, "events/birthdays"), CHAT(R.string.chat, GoogleMaterial.Icon.gmd_chat, "buddylist"), EVENTS(R.string.events, GoogleMaterial.Icon.gmd_event_note, "events/upcoming"), - FEED(R.string.feed, CommunityMaterial.Icon.cmd_newspaper, ""), + FEED(R.string.feed, CommunityMaterial.Icon2.cmd_newspaper, ""), FEED_MOST_RECENT(R.string.most_recent, GoogleMaterial.Icon.gmd_history, "home.php?sk=h_chr"), FEED_TOP_STORIES(R.string.top_stories, GoogleMaterial.Icon.gmd_star, "home.php?sk=h_nor"), FRIENDS(R.string.friends, GoogleMaterial.Icon.gmd_person_add, "friends/center/requests"), GROUPS(R.string.groups, GoogleMaterial.Icon.gmd_group, "groups"), MENU(R.string.menu, GoogleMaterial.Icon.gmd_menu, "settings", ::MenuFragment), MESSAGES(R.string.messages, MaterialDesignIconic.Icon.gmi_comments, "messages"), - NOTES(R.string.notes, CommunityMaterial.Icon.cmd_note, "notes"), + NOTES(R.string.notes, CommunityMaterial.Icon2.cmd_note, "notes"), NOTIFICATIONS(R.string.notifications, MaterialDesignIconic.Icon.gmi_globe, "notifications", ::NotificationFragment), ON_THIS_DAY(R.string.on_this_day, GoogleMaterial.Icon.gmd_today, "onthisday"), PAGES(R.string.pages, GoogleMaterial.Icon.gmd_flag, "pages"), diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt index 9b29d009..2c987a48 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbRegex.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook /** @@ -29,4 +45,3 @@ val FB_IMAGE_ID_MATCHER: Regex = Regex("fbcdn.*?/[0-9]+_([0-9]+)_") val FB_REDIRECT_URL_MATCHER: Regex = Regex("url=(.*?fbcdn.*?)\"") operator fun MatchResult?.get(groupIndex: Int) = this?.groupValues?.get(groupIndex) - diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt index 62675df6..2c171762 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook import com.pitchedapps.frost.utils.L @@ -91,13 +107,13 @@ class FbUrlFormatter(url: String) { * That shouldn't break anything */ val discardable = arrayOf( - "http://lm.facebook.com/l.php?u=", - "https://lm.facebook.com/l.php?u=", - "http://m.facebook.com/l.php?u=", - "https://m.facebook.com/l.php?u=", - "http://touch.facebook.com/l.php?u=", - "https://touch.facebook.com/l.php?u=", - VIDEO_REDIRECT + "http://lm.facebook.com/l.php?u=", + "https://lm.facebook.com/l.php?u=", + "http://m.facebook.com/l.php?u=", + "https://m.facebook.com/l.php?u=", + "http://touch.facebook.com/l.php?u=", + "https://touch.facebook.com/l.php?u=", + VIDEO_REDIRECT ) /** @@ -108,13 +124,13 @@ class FbUrlFormatter(url: String) { val discardableQueries = arrayOf("ref", "refid", "SharedWith") val converter = listOf( - "\\3C " to "%3C", "\\3E " to "%3E", "\\23 " to "%23", "\\25 " to "%25", - "\\7B " to "%7B", "\\7D " to "%7D", "\\7C " to "%7C", "\\5C " to "%5C", - "\\5E " to "%5E", "\\7E " to "%7E", "\\5B " to "%5B", "\\5D " to "%5D", - "\\60 " to "%60", "\\3B " to "%3B", "\\2F " to "%2F", "\\3F " to "%3F", - "\\3A " to "%3A", "\\40 " to "%40", "\\3D " to "%3D", "\\26 " to "%26", - "\\24 " to "%24", "\\2B " to "%2B", "\\22 " to "%22", "\\2C " to "%2C", - "\\20 " to "%20" + "\\3C " to "%3C", "\\3E " to "%3E", "\\23 " to "%23", "\\25 " to "%25", + "\\7B " to "%7B", "\\7D " to "%7D", "\\7C " to "%7C", "\\5C " to "%5C", + "\\5E " to "%5E", "\\7E " to "%7E", "\\5B " to "%5B", "\\5D " to "%5D", + "\\60 " to "%60", "\\3B " to "%3B", "\\2F " to "%2F", "\\3F " to "%3F", + "\\3A " to "%3A", "\\40 " to "%40", "\\3D " to "%3D", "\\26 " to "%26", + "\\24 " to "%24", "\\2B " to "%2B", "\\22 " to "%22", "\\2C " to "%2C", + "\\20 " to "%20" ) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt index 3d5c5bce..5709bb9f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/FrostParser.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.parsers import com.pitchedapps.frost.dbflow.CookieModel @@ -54,7 +70,6 @@ interface FrostParser<out T : Any> { * Call parsing with given data */ fun parseFromData(cookie: String?, text: String): ParseResponse<T>? - } const val FALLBACK_TIME_MOD = 1000000 @@ -92,7 +107,7 @@ internal abstract class FrostParserBase<out T : Any>(private val redirectToText: } final override fun parseFromUrl(cookie: String?, url: String): ParseResponse<T>? = - parse(cookie, frostJsoup(cookie, url)) + parse(cookie, frostJsoup(cookie, url)) override fun parse(cookie: String?, document: Document): ParseResponse<T>? { cookie ?: return null @@ -109,17 +124,17 @@ internal abstract class FrostParserBase<out T : Any>(private val redirectToText: * Returns the formatted url, or an empty string if nothing was found */ protected fun Element.getInnerImgStyle(): String? = - select("i.img[style*=url]").getStyleUrl() + select("i.img[style*=url]").getStyleUrl() protected fun Elements.getStyleUrl(): String? = - FB_CSS_URL_MATCHER.find(attr("style"))[1]?.formattedFbUrl + FB_CSS_URL_MATCHER.find(attr("style"))[1]?.formattedFbUrl protected open fun textToDoc(text: String): Document? = - if (!redirectToText) Jsoup.parse(text) - else throw RuntimeException("${this::class.java.simpleName} requires text redirect but did not implement textToDoc") + if (!redirectToText) Jsoup.parse(text) + else throw RuntimeException("${this::class.java.simpleName} requires text redirect but did not implement textToDoc") protected fun parseLink(element: Element?): FrostLink? { val a = element?.getElementsByTag("a")?.first() ?: return null return FrostLink(a.text(), a.attr("href")) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/MessageParser.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/MessageParser.kt index 27b731bc..f05c42e9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/MessageParser.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/MessageParser.kt @@ -1,7 +1,27 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.parsers import com.pitchedapps.frost.dbflow.CookieModel -import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.facebook.FB_EPOCH_MATCHER +import com.pitchedapps.frost.facebook.FB_MESSAGE_NOTIF_ID_MATCHER +import com.pitchedapps.frost.facebook.FbItem +import com.pitchedapps.frost.facebook.formattedFbUrl +import com.pitchedapps.frost.facebook.get import com.pitchedapps.frost.services.NotificationContent import com.pitchedapps.frost.utils.L import org.apache.commons.text.StringEscapeUtils @@ -19,12 +39,12 @@ import org.jsoup.nodes.Element object MessageParser : FrostParser<FrostMessages> by MessageParserImpl() { fun queryUser(cookie: String?, name: String) = parseFromUrl(cookie, "${FbItem.MESSAGES.url}/?q=$name") - } -data class FrostMessages(val threads: List<FrostThread>, - val seeMore: FrostLink?, - val extraLinks: List<FrostLink> +data class FrostMessages( + val threads: List<FrostThread>, + val seeMore: FrostLink?, + val extraLinks: List<FrostLink> ) : ParseNotification { override fun toString() = StringBuilder().apply { append("FrostMessages {\n") @@ -35,19 +55,19 @@ data class FrostMessages(val threads: List<FrostThread>, }.toString() override fun getUnreadNotifications(data: CookieModel) = - threads.asSequence().filter(FrostThread::unread).map { - with(it) { - NotificationContent( - data = data, - id = id, - href = url, - title = title, - text = content ?: "", - timestamp = time, - profileUrl = img - ) - } - }.toList() + threads.asSequence().filter(FrostThread::unread).map { + with(it) { + NotificationContent( + data = data, + id = id, + href = url, + title = title, + text = content ?: "", + timestamp = time, + profileUrl = img + ) + } + }.toList() } /** @@ -58,14 +78,16 @@ data class FrostMessages(val threads: List<FrostThread>, * [unread] true if image is unread, false otherwise * [content] optional string for thread */ -data class FrostThread(val id: Long, - val img: String?, - val title: String, - val time: Long, - val url: String, - val unread: Boolean, - val content: String?, - val contentImgUrl: String?) +data class FrostThread( + val id: Long, + val img: String?, + val title: String, + val time: Long, + val url: String, + val unread: Boolean, + val content: String?, + val contentImgUrl: String? +) private class MessageParserImpl : FrostParserBase<FrostMessages>(true) { @@ -92,11 +114,12 @@ private class MessageParserImpl : FrostParserBase<FrostMessages>(true) { override fun parseImpl(doc: Document): FrostMessages? { val threadList = doc.getElementById("threadlist_rows") ?: return null - val threads: List<FrostThread> = threadList.getElementsByAttributeValueMatching("id", ".*${FB_MESSAGE_NOTIF_ID_MATCHER.pattern}.*") + val threads: List<FrostThread> = + threadList.getElementsByAttributeValueMatching("id", ".*${FB_MESSAGE_NOTIF_ID_MATCHER.pattern}.*") .mapNotNull(this::parseMessage) val seeMore = parseLink(doc.getElementById("see_older_threads")) val extraLinks = threadList.nextElementSibling().select("a") - .mapNotNull(this::parseLink) + .mapNotNull(this::parseLink) return FrostMessages(threads, seeMore, extraLinks) } @@ -106,21 +129,20 @@ private class MessageParserImpl : FrostParserBase<FrostMessages>(true) { val epoch = FB_EPOCH_MATCHER.find(abbr.attr("data-store"))[1]?.toLongOrNull() ?: -1L //fetch id val id = FB_MESSAGE_NOTIF_ID_MATCHER.find(element.id())[1]?.toLongOrNull() - ?: System.currentTimeMillis() % FALLBACK_TIME_MOD + ?: System.currentTimeMillis() % FALLBACK_TIME_MOD val snippet = element.select("span.snippet").firstOrNull() val content = snippet?.text()?.trim() val contentImg = snippet?.select("i[style*=url]")?.getStyleUrl() val img = element.getInnerImgStyle() return FrostThread( - id = id, - img = img, - title = a.text(), - time = epoch, - url = a.attr("href").formattedFbUrl, - unread = !element.hasClass("acw"), - content = content, - contentImgUrl = contentImg + id = id, + img = img, + title = a.text(), + time = epoch, + url = a.attr("href").formattedFbUrl, + unread = !element.hasClass("acw"), + content = content, + contentImgUrl = contentImg ) } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/NotifParser.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/NotifParser.kt index 8aa8e706..b8aa899b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/NotifParser.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/NotifParser.kt @@ -1,7 +1,27 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.parsers import com.pitchedapps.frost.dbflow.CookieModel -import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.facebook.FB_EPOCH_MATCHER +import com.pitchedapps.frost.facebook.FB_NOTIF_ID_MATCHER +import com.pitchedapps.frost.facebook.FbItem +import com.pitchedapps.frost.facebook.formattedFbUrl +import com.pitchedapps.frost.facebook.get import com.pitchedapps.frost.services.NotificationContent import org.jsoup.nodes.Document import org.jsoup.nodes.Element @@ -13,8 +33,8 @@ import org.jsoup.nodes.Element object NotifParser : FrostParser<FrostNotifs> by NotifParserImpl() data class FrostNotifs( - val notifs: List<FrostNotif>, - val seeMore: FrostLink? + val notifs: List<FrostNotif>, + val seeMore: FrostLink? ) : ParseNotification { override fun toString() = StringBuilder().apply { append("FrostNotifs {\n") @@ -24,19 +44,19 @@ data class FrostNotifs( }.toString() override fun getUnreadNotifications(data: CookieModel) = - notifs.asSequence().filter(FrostNotif::unread).map { - with(it) { - NotificationContent( - data = data, - id = id, - href = url, - title = null, - text = content, - timestamp = time, - profileUrl = img - ) - } - }.toList() + notifs.asSequence().filter(FrostNotif::unread).map { + with(it) { + NotificationContent( + data = data, + id = id, + href = url, + title = null, + text = content, + timestamp = time, + profileUrl = img + ) + } + }.toList() } /** @@ -49,14 +69,16 @@ data class FrostNotifs( * [timeString] text version of time from Facebook * [thumbnailUrl] optional thumbnail url if existent */ -data class FrostNotif(val id: Long, - val img: String?, - val time: Long, - val url: String, - val unread: Boolean, - val content: String, - val timeString: String, - val thumbnailUrl: String?) +data class FrostNotif( + val id: Long, + val img: String?, + val time: Long, + val url: String, + val unread: Boolean, + val content: String, + val timeString: String, + val thumbnailUrl: String? +) private class NotifParserImpl : FrostParserBase<FrostNotifs>(false) { @@ -67,8 +89,8 @@ private class NotifParserImpl : FrostParserBase<FrostNotifs>(false) { override fun parseImpl(doc: Document): FrostNotifs? { val notificationList = doc.getElementById("notifications_list") ?: return null val notifications = notificationList - .getElementsByAttributeValueMatching("id", ".*${FB_NOTIF_ID_MATCHER.pattern}.*") - .mapNotNull(this::parseNotif) + .getElementsByAttributeValueMatching("id", ".*${FB_NOTIF_ID_MATCHER.pattern}.*") + .mapNotNull(this::parseNotif) val seeMore = parseLink(doc.getElementsByAttributeValue("href", "/notifications.php?more").first()) return FrostNotifs(notifications, seeMore) } @@ -79,22 +101,20 @@ private class NotifParserImpl : FrostParserBase<FrostNotifs>(false) { val epoch = FB_EPOCH_MATCHER.find(abbr.attr("data-store"))[1]?.toLongOrNull() ?: -1L //fetch id val id = FB_NOTIF_ID_MATCHER.find(element.id())[1]?.toLongOrNull() - ?: System.currentTimeMillis() % FALLBACK_TIME_MOD + ?: System.currentTimeMillis() % FALLBACK_TIME_MOD val img = element.getInnerImgStyle() val timeString = abbr.text() val content = a.text().replace("\u00a0", " ").removeSuffix(timeString).trim() //remove val thumbnail = element.selectFirst("img.thumbnail")?.attr("src") return FrostNotif( - id = id, - img = img, - time = epoch, - url = a.attr("href").formattedFbUrl, - unread = !element.hasClass("acw"), - content = content, - timeString = timeString, - thumbnailUrl = if (thumbnail?.isNotEmpty() == true) thumbnail else null + id = id, + img = img, + time = epoch, + url = a.attr("href").formattedFbUrl, + unread = !element.hasClass("acw"), + content = content, + timeString = timeString, + thumbnailUrl = if (thumbnail?.isNotEmpty() == true) thumbnail else null ) } - - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/SearchParser.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/SearchParser.kt index d3367514..7869d881 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/SearchParser.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/parsers/SearchParser.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.parsers import ca.allanwang.kau.searchview.SearchItem @@ -46,9 +62,9 @@ data class FrostSearch(val href: String, val title: String, val description: Str companion object { fun create(href: String, title: String, description: String?) = FrostSearch( - with(href.indexOf("?")) { if (this == -1) href else href.substring(0, this) }, - title.format(), - description?.format() + with(href.indexOf("?")) { if (this == -1) href else href.substring(0, this) }, + title.format(), + description?.format() ) } } @@ -61,17 +77,18 @@ private class SearchParserImpl : FrostParserBase<FrostSearches>(false) { override fun parseImpl(doc: Document): FrostSearches? { val container: Element = doc.getElementById("BrowseResultsContainer") - ?: doc.getElementById("root") - ?: return null + ?: doc.getElementById("root") + ?: return null /** * * Removed [data-store*=result_id] */ return FrostSearches(container.select("a.touchable[href]").filter(Element::hasText).map { - FrostSearch.create(it.attr("href").formattedFbUrl, - it.select("._uoi").first()?.text() ?: "", - it.select("._1tcc").first()?.text()) + FrostSearch.create( + it.attr("href").formattedFbUrl, + it.select("._uoi").first()?.text() ?: "", + it.select("._1tcc").first()?.text() + ) }.filter { it.title.isNotBlank() }) } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt index 500c4102..584107cc 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/FbRequest.kt @@ -1,7 +1,29 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.requests import com.pitchedapps.frost.BuildConfig -import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.facebook.FB_DTSG_MATCHER +import com.pitchedapps.frost.facebook.FB_JSON_URL_MATCHER +import com.pitchedapps.frost.facebook.FB_REV_MATCHER +import com.pitchedapps.frost.facebook.FB_URL_BASE +import com.pitchedapps.frost.facebook.FB_USER_MATCHER +import com.pitchedapps.frost.facebook.USER_AGENT_BASIC +import com.pitchedapps.frost.facebook.get import com.pitchedapps.frost.rx.RxFlyweight import com.pitchedapps.frost.utils.L import io.reactivex.Single @@ -21,10 +43,9 @@ private class RxAuth : RxFlyweight<String, Long, RequestAuth>() { override fun call(input: String) = input.getAuth() override fun validate(input: String, cond: Long) = - System.currentTimeMillis() - cond < 3600000 // valid for an hour + System.currentTimeMillis() - cond < 3600000 // valid for an hour override fun cache(input: String) = System.currentTimeMillis() - } private val auth = RxAuth() @@ -48,10 +69,12 @@ fun String?.fbRequest(fail: () -> Unit = {}, action: RequestAuth.() -> Unit) { /** * Underlying container for all fb requests */ -data class RequestAuth(val userId: Long = -1, - val cookie: String = "", - val fb_dtsg: String = "", - val rev: String = "") { +data class RequestAuth( + val userId: Long = -1, + val cookie: String = "", + val fb_dtsg: String = "", + val rev: String = "" +) { val isComplete get() = userId > 0 && cookie.isNotEmpty() && fb_dtsg.isNotEmpty() && rev.isNotEmpty() } @@ -64,8 +87,8 @@ class FrostRequest<out T : Any?>(val call: Call, private val invoke: (Call) -> T } internal inline fun <T : Any?> RequestAuth.frostRequest( - noinline invoke: (Call) -> T, - builder: Request.Builder.() -> Request.Builder // to ensure we don't do anything extra at the end + noinline invoke: (Call) -> T, + builder: Request.Builder.() -> Request.Builder // to ensure we don't do anything extra at the end ): FrostRequest<T> { val request = cookie.requestBuilder() request.builder() @@ -75,8 +98,10 @@ internal inline fun <T : Any?> RequestAuth.frostRequest( val httpClient: OkHttpClient by lazy { val builder = OkHttpClient.Builder() if (BuildConfig.DEBUG) - builder.addInterceptor(HttpLoggingInterceptor() - .setLevel(HttpLoggingInterceptor.Level.BASIC)) + builder.addInterceptor( + HttpLoggingInterceptor() + .setLevel(HttpLoggingInterceptor.Level.BASIC) + ) builder.build() } @@ -97,7 +122,7 @@ internal fun List<Pair<String, Any?>>.withEmptyData(vararg key: String): List<Pa internal fun String?.requestBuilder(): Request.Builder { val builder = Request.Builder() - .header("User-Agent", USER_AGENT_BASIC) + .header("User-Agent", USER_AGENT_BASIC) if (this != null) builder.header("Cookie", this) // .cacheControl(CacheControl.FORCE_NETWORK) @@ -112,9 +137,9 @@ fun String.getAuth(): RequestAuth { val id = FB_USER_MATCHER.find(this)[1]?.toLong() ?: return auth auth = auth.copy(userId = id) val call = this.requestBuilder() - .url(FB_URL_BASE) - .get() - .call() + .url(FB_URL_BASE) + .get() + .call() call.execute().body()?.charStream()?.useLines { lines -> lines.forEach { val text = StringEscapeUtils.unescapeEcmaScript(it) @@ -135,8 +160,10 @@ fun String.getAuth(): RequestAuth { return auth } -inline fun <T, reified R : Any, O> Array<T>.zip(crossinline mapper: (List<R>) -> O, - crossinline caller: (T) -> R): Single<O> { +inline fun <T, reified R : Any, O> Array<T>.zip( + crossinline mapper: (List<R>) -> O, + crossinline caller: (T) -> R +): Single<O> { if (isEmpty()) return Single.just(mapper(emptyList())) val singles = map { Single.fromCallable { caller(it) }.subscribeOn(Schedulers.io()) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt index 8eeef08d..e0ccea81 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Images.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.requests import com.bumptech.glide.Priority @@ -11,7 +27,11 @@ import com.bumptech.glide.load.model.MultiModelLoaderFactory import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.request.target.Target import com.bumptech.glide.signature.ObjectKey -import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.facebook.FB_IMAGE_ID_MATCHER +import com.pitchedapps.frost.facebook.FB_REDIRECT_URL_MATCHER +import com.pitchedapps.frost.facebook.FB_URL_BASE +import com.pitchedapps.frost.facebook.formattedFbUrl +import com.pitchedapps.frost.facebook.get import io.reactivex.Maybe import okhttp3.Call import okhttp3.Request @@ -33,9 +53,9 @@ val test: () -> InputStream? = { null } */ fun String.getFullSizedImageUrl(url: String): Maybe<String?> = Maybe.fromCallable { val redirect = requestBuilder().url(url).get().call() - .execute().body()?.string() ?: return@fromCallable null + .execute().body()?.string() ?: return@fromCallable null return@fromCallable FB_REDIRECT_URL_MATCHER.find(redirect)[1]?.formattedFbUrl - ?: return@fromCallable null + ?: return@fromCallable null }.onErrorComplete() /** @@ -51,7 +71,6 @@ data class HdImageMaybe(val url: String, val cookie: String) { val isValid: Boolean by lazy { id != -1L && cookie.isNotBlank() } - } /* @@ -69,18 +88,20 @@ class HdImageLoadingFactory : ModelLoaderFactory<HdImageMaybe, InputStream> { } fun <T> RequestBuilder<T>.loadWithPotentialHd(model: HdImageMaybe) = - thumbnail(clone().load(model.url)) - .load(model) - .apply(RequestOptions().override(Target.SIZE_ORIGINAL)) + thumbnail(clone().load(model.url)) + .load(model) + .apply(RequestOptions().override(Target.SIZE_ORIGINAL)) class HdImageLoading : ModelLoader<HdImageMaybe, InputStream> { - override fun buildLoadData(model: HdImageMaybe, - width: Int, - height: Int, - options: Options): ModelLoader.LoadData<InputStream>? = - if (!model.isValid) null - else ModelLoader.LoadData(ObjectKey(model), HdImageFetcher(model)) + override fun buildLoadData( + model: HdImageMaybe, + width: Int, + height: Int, + options: Options + ): ModelLoader.LoadData<InputStream>? = + if (!model.isValid) null + else ModelLoader.LoadData(ObjectKey(model), HdImageFetcher(model)) override fun handles(model: HdImageMaybe) = model.isValid } @@ -105,7 +126,7 @@ class HdImageFetcher(private val model: HdImageMaybe) : DataFetcher<InputStream> model.cookie.fbRequest(fail = { callback.fail("Invalid auth") }) { if (cancelled) return@fbRequest callback.fail("Cancelled") val url = getFullSizedImage(model.id).invoke() - ?: return@fbRequest callback.fail("Null url") + ?: return@fbRequest callback.fail("Null url") if (cancelled) return@fbRequest callback.fail("Cancelled") if (!url.contains("png") && !url.contains("jpg")) return@fbRequest callback.fail("Invalid format") urlCall = Request.Builder().url(url).get().call() diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Menu.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Menu.kt index e83e4e43..dcb0ce10 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Menu.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Menu.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.requests import com.fasterxml.jackson.annotation.JsonCreator @@ -19,28 +35,27 @@ import java.io.IOException fun RequestAuth.getMenuData(): FrostRequest<MenuData?> { val body = listOf( - "fb_dtsg" to fb_dtsg, - "__user" to userId + "fb_dtsg" to fb_dtsg, + "__user" to userId ).withEmptyData("m_sess", "__dyn", "__req", "__ajax__") return frostRequest(::parseMenu) { url("${FB_URL_BASE}bookmarks/flyout/body/?id=u_0_2") post(body.toForm()) } - } fun parseMenu(call: Call): MenuData? { val fullString = call.execute().body()?.string() ?: return null var jsonString = fullString.substringAfter("bookmarkGroups", "") - .substringAfter("[", "") + .substringAfter("[", "") if (jsonString.isBlank()) return null jsonString = "{ \"data\" : [${StringEscapeUtils.unescapeEcmaScript(jsonString)}" val mapper = ObjectMapper() - .disable(MapperFeature.AUTO_DETECT_SETTERS) + .disable(MapperFeature.AUTO_DETECT_SETTERS) return try { val data = mapper.readValue(jsonString, MenuData::class.java) @@ -48,11 +63,14 @@ fun parseMenu(call: Call): MenuData? { // parse footer content val footer = fullString.substringAfter("footerMarkup", "") - .substringAfter("{", "") - .substringBefore("}", "") - - val doc = Jsoup.parseBodyFragment(StringEscapeUtils.unescapeEcmaScript( - StringEscapeUtils.unescapeEcmaScript(footer))) + .substringAfter("{", "") + .substringBefore("}", "") + + val doc = Jsoup.parseBodyFragment( + StringEscapeUtils.unescapeEcmaScript( + StringEscapeUtils.unescapeEcmaScript(footer) + ) + ) val footerData = mutableListOf<MenuFooterItem>() val footerSmallData = mutableListOf<MenuFooterItem>() @@ -76,11 +94,14 @@ fun parseMenu(call: Call): MenuData? { } @JsonIgnoreProperties(ignoreUnknown = true) -data class MenuData(val data: List<MenuHeader> = emptyList(), - val footer: MenuFooter = MenuFooter()) { - - @JsonCreator constructor( - @JsonProperty("data") data: List<MenuHeader>? +data class MenuData( + val data: List<MenuHeader> = emptyList(), + val footer: MenuFooter = MenuFooter() +) { + + @JsonCreator + constructor( + @JsonProperty("data") data: List<MenuHeader>? ) : this(data ?: emptyList(), MenuFooter()) fun flatMapValid(): List<MenuItemData> { @@ -95,7 +116,6 @@ data class MenuData(val data: List<MenuHeader> = emptyList(), return items } - } interface MenuItemData { @@ -103,17 +123,20 @@ interface MenuItemData { } @JsonIgnoreProperties(ignoreUnknown = true) -data class MenuHeader(val id: String? = null, - val header: String? = null, - val visible: List<MenuItem> = emptyList(), - val all: List<MenuItem> = emptyList()) : MenuItemData { - - @JsonCreator constructor( - @JsonProperty("id") id: String?, - @JsonProperty("header") header: String?, - @JsonProperty("visible") visible: List<MenuItem>?, - @JsonProperty("all") all: List<MenuItem>?, - @JsonProperty("fake") fake: Boolean? +data class MenuHeader( + val id: String? = null, + val header: String? = null, + val visible: List<MenuItem> = emptyList(), + val all: List<MenuItem> = emptyList() +) : MenuItemData { + + @JsonCreator + constructor( + @JsonProperty("id") id: String?, + @JsonProperty("header") header: String?, + @JsonProperty("visible") visible: List<MenuItem>?, + @JsonProperty("all") all: List<MenuItem>?, + @JsonProperty("fake") fake: Boolean? ) : this(id, header, visible ?: emptyList(), all ?: emptyList()) override val isValid: Boolean @@ -121,41 +144,49 @@ data class MenuHeader(val id: String? = null, } @JsonIgnoreProperties(ignoreUnknown = true) -data class MenuItem(val id: String? = null, - val name: String? = null, - val pic: String? = null, - val url: String? = null, - val badge: String? = null, - val countDetails: String? = null) : MenuItemData { - - @JsonCreator constructor( - @JsonProperty("id") id: String?, - @JsonProperty("name") name: String?, - @JsonProperty("pic") pic: String?, - @JsonProperty("url") url: String?, - @JsonProperty("count") badge: String?, - @JsonProperty("count_details") countDetails: String?, - @JsonProperty("fake") fake: Boolean? - ) : this(id, name, pic?.formattedFbUrl, - url?.formattedFbUrl, - if (badge == "0") null else badge, - countDetails) +data class MenuItem( + val id: String? = null, + val name: String? = null, + val pic: String? = null, + val url: String? = null, + val badge: String? = null, + val countDetails: String? = null +) : MenuItemData { + + @JsonCreator + constructor( + @JsonProperty("id") id: String?, + @JsonProperty("name") name: String?, + @JsonProperty("pic") pic: String?, + @JsonProperty("url") url: String?, + @JsonProperty("count") badge: String?, + @JsonProperty("count_details") countDetails: String?, + @JsonProperty("fake") fake: Boolean? + ) : this( + id, name, pic?.formattedFbUrl, + url?.formattedFbUrl, + if (badge == "0") null else badge, + countDetails + ) override val isValid: Boolean get() = !name.isNullOrBlank() && !url.isNullOrBlank() } -data class MenuFooter(val data: List<MenuFooterItem> = emptyList(), - val smallData: List<MenuFooterItem> = emptyList()) { +data class MenuFooter( + val data: List<MenuFooterItem> = emptyList(), + val smallData: List<MenuFooterItem> = emptyList() +) { val hasContent get() = data.isNotEmpty() || smallData.isNotEmpty() - } -data class MenuFooterItem(val name: String? = null, - val url: String? = null, - val isSmall: Boolean = false) : MenuItemData { +data class MenuFooterItem( + val name: String? = null, + val url: String? = null, + val isSmall: Boolean = false +) : MenuItemData { override val isValid: Boolean get() = name != null && url != null -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt index 0e37a61e..f350c547 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Messages.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.requests import com.pitchedapps.frost.facebook.FB_URL_BASE @@ -10,10 +26,10 @@ fun RequestAuth.sendMessage(group: String, content: String): FrostRequest<Boolea // todo test more; only tested against tids=cid... val body = listOf( - "tids" to group, - "body" to content, - "fb_dtsg" to fb_dtsg, - "__user" to userId + "tids" to group, + "body" to content, + "fb_dtsg" to fb_dtsg, + "__user" to userId ).withEmptyData("m_sess", "__dyn", "__req", "__ajax__") return frostRequest(::validateMessage) { @@ -29,4 +45,4 @@ private fun validateMessage(call: Call): Boolean { val body = call.execute().body() ?: return false // todo return true -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Notifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Notifications.kt index 0d3926dc..43815b67 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Notifications.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/requests/Notifications.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.facebook.requests import com.pitchedapps.frost.facebook.FB_URL_BASE @@ -8,11 +24,11 @@ import com.pitchedapps.frost.facebook.FB_URL_BASE fun RequestAuth.markNotificationRead(notifId: Long): FrostRequest<Boolean> { val body = listOf( - "click_type" to "notification_click", - "id" to notifId, - "target_id" to "null", - "fb_dtsg" to fb_dtsg, - "__user" to userId + "click_type" to "notification_click", + "id" to notifId, + "target_id" to "null", + "fb_dtsg" to fb_dtsg, + "__user" to userId ).withEmptyData("m_sess", "__dyn", "__req", "__ajax__") return frostRequest(::executeForNoError) { @@ -22,6 +38,6 @@ fun RequestAuth.markNotificationRead(notifId: Long): FrostRequest<Boolean> { } fun RequestAuth.markNotificationsRead(vararg notifId: Long) = - notifId.toTypedArray().zip<Long, Boolean, Boolean>( - { it.all { self -> self } }, - { markNotificationRead(it).invoke() })
\ No newline at end of file + notifId.toTypedArray().zip<Long, Boolean, Boolean>( + { it.all { self -> self } }, + { markNotificationRead(it).invoke() }) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt index cf48893c..98e28bd3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt @@ -1,15 +1,31 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.fragments import android.content.Context import android.os.Bundle -import android.support.design.widget.FloatingActionButton -import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.fragment.app.Fragment import ca.allanwang.kau.utils.fadeScaleTransition import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.withArguments +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.mikepenz.iconics.typeface.IIcon import com.pitchedapps.frost.contracts.DynamicUiContract import com.pitchedapps.frost.contracts.FrostContentParent @@ -17,7 +33,12 @@ import com.pitchedapps.frost.contracts.MainActivityContract import com.pitchedapps.frost.contracts.MainFabContract import com.pitchedapps.frost.enums.FeedSort import com.pitchedapps.frost.facebook.FbItem -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.ARG_URL +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.REQUEST_REFRESH +import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM +import com.pitchedapps.frost.utils.frostEvent import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable @@ -33,12 +54,17 @@ abstract class BaseFragment : Fragment(), FragmentContract, DynamicUiContract { private const val ARG_POSITION = "arg_position" private const val ARG_VALID = "arg_valid" - internal operator fun invoke(base: () -> BaseFragment, useFallback: Boolean, data: FbItem, position: Int): BaseFragment { + internal operator fun invoke( + base: () -> BaseFragment, + useFallback: Boolean, + data: FbItem, + position: Int + ): BaseFragment { val fragment = if (!useFallback) base() else WebFragment() val d = if (data == FbItem.FEED) FeedSort(Prefs.feedSort).item else data fragment.withArguments( - ARG_URL to d.url, - ARG_POSITION to position + ARG_URL to d.url, + ARG_POSITION to position ) d.put(fragment.arguments!!) return fragment @@ -55,8 +81,10 @@ abstract class BaseFragment : Fragment(), FragmentContract, DynamicUiContract { if (value || this is WebFragment) return arguments!!.putBoolean(ARG_VALID, value) L.e { "Invalidating position $position" } - frostEvent("Native Fallback", - "Item" to baseEnum.name) + frostEvent( + "Native Fallback", + "Item" to baseEnum.name + ) (context as MainActivityContract).reloadFragment(this) } @@ -75,10 +103,14 @@ abstract class BaseFragment : Fragment(), FragmentContract, DynamicUiContract { throw IllegalArgumentException("${this::class.java.simpleName} is not attached to a context implementing MainActivityContract") } - final override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + final override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { val view = inflater.inflate(layoutRes, container, false) - val content = view as? FrostContentParent - ?: throw IllegalArgumentException("layoutRes for fragment must return view implementing FrostContentParent") + val content = view as? FrostContentParent + ?: throw IllegalArgumentException("layoutRes for fragment must return view implementing FrostContentParent") this.content = content content.bind(this) return view @@ -113,28 +145,28 @@ abstract class BaseFragment : Fragment(), FragmentContract, DynamicUiContract { } override fun attachMainObservable(contract: MainActivityContract): Disposable = - contract.fragmentSubject.observeOn(AndroidSchedulers.mainThread()).subscribe { - when (it) { - REQUEST_REFRESH -> { - core?.apply { - clearHistory() - firstLoad = true - firstLoadRequest() - } - } - position -> { - contract.setTitle(baseEnum.titleId) - updateFab(contract) - core?.active = true - } - -(position + 1) -> { - core?.active = false - } - REQUEST_TEXT_ZOOM -> { - reloadTextSize() + contract.fragmentSubject.observeOn(AndroidSchedulers.mainThread()).subscribe { + when (it) { + REQUEST_REFRESH -> { + core?.apply { + clearHistory() + firstLoad = true + firstLoadRequest() } } + position -> { + contract.setTitle(baseEnum.titleId) + updateFab(contract) + core?.active = true + } + -(position + 1) -> { + core?.active = false + } + REQUEST_TEXT_ZOOM -> { + reloadTextSize() + } } + } override fun updateFab(contract: MainFabContract) { contract.hideFab() // default @@ -197,4 +229,3 @@ abstract class BaseFragment : Fragment(), FragmentContract, DynamicUiContract { override fun onTabClick(): Unit = content?.core?.onTabClicked() ?: Unit } - diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentContract.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentContract.kt index 6555e076..e24e8308 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentContract.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentContract.kt @@ -1,6 +1,26 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.fragments -import com.pitchedapps.frost.contracts.* +import com.pitchedapps.frost.contracts.FrostContentContainer +import com.pitchedapps.frost.contracts.FrostContentCore +import com.pitchedapps.frost.contracts.FrostContentParent +import com.pitchedapps.frost.contracts.MainActivityContract +import com.pitchedapps.frost.contracts.MainFabContract import com.pitchedapps.frost.views.FrostRecyclerView import io.reactivex.disposables.Disposable @@ -74,8 +94,6 @@ interface FragmentContract : FrostContentContainer { fun onBackPressed(): Boolean fun onTabClick() - - } interface RecyclerContentContract { @@ -88,5 +106,4 @@ interface RecyclerContentContract { * Callback returns [true] for success, [false] otherwise */ fun reload(progress: (Int) -> Unit, callback: (Boolean) -> Unit) - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragmentBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragmentBase.kt index 4f9133a6..f77f83ea 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragmentBase.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragmentBase.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.fragments import ca.allanwang.kau.adapters.fastAdapter @@ -65,7 +81,6 @@ abstract class GenericRecyclerFragment<T, Item : IItem<*, *>> : RecyclerFragment * Create the fast adapter to bind to the recyclerview */ open fun getAdapter(): FastAdapter<IItem<*, *>> = fastAdapter(this.adapter) - } abstract class FrostParserFragment<T : Any, Item : IItem<*, *>> : RecyclerFragment() { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragments.kt index 4f597731..ff37b66d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragments.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/RecyclerFragments.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.fragments import com.mikepenz.fastadapter.IItem @@ -6,8 +22,18 @@ import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.parsers.FrostNotifs import com.pitchedapps.frost.facebook.parsers.NotifParser import com.pitchedapps.frost.facebook.parsers.ParseResponse -import com.pitchedapps.frost.facebook.requests.* -import com.pitchedapps.frost.iitems.* +import com.pitchedapps.frost.facebook.requests.MenuFooterItem +import com.pitchedapps.frost.facebook.requests.MenuHeader +import com.pitchedapps.frost.facebook.requests.MenuItem +import com.pitchedapps.frost.facebook.requests.MenuItemData +import com.pitchedapps.frost.facebook.requests.fbRequest +import com.pitchedapps.frost.facebook.requests.getMenuData +import com.pitchedapps.frost.iitems.ClickableIItemContract +import com.pitchedapps.frost.iitems.MenuContentIItem +import com.pitchedapps.frost.iitems.MenuFooterIItem +import com.pitchedapps.frost.iitems.MenuFooterSmallIItem +import com.pitchedapps.frost.iitems.MenuHeaderIItem +import com.pitchedapps.frost.iitems.NotificationIItem import com.pitchedapps.frost.utils.frostJsoup import com.pitchedapps.frost.views.FrostRecyclerView import org.jetbrains.anko.doAsync @@ -23,7 +49,7 @@ class NotificationFragment : FrostParserFragment<FrostNotifs, NotificationIItem> override fun getDoc(cookie: String?) = frostJsoup(cookie, "${FbItem.NOTIFICATIONS.url}?more") override fun toItems(response: ParseResponse<FrostNotifs>): List<NotificationIItem> = - response.data.notifs.map { NotificationIItem(it, response.cookie) } + response.data.notifs.map { NotificationIItem(it, response.cookie) } override fun bindImpl(recyclerView: FrostRecyclerView) { NotificationIItem.bindEvents(adapter) @@ -61,4 +87,4 @@ class MenuFragment : GenericRecyclerFragment<MenuItemData, IItem<*, *>>() { } } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt index d9edda78..72367eaa 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/WebFragments.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.fragments import android.webkit.WebView @@ -43,4 +59,4 @@ class WebFragment : BaseFragment() { } super.updateFab(contract) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt index 50d4d7b4..0c471c63 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/glide/GlideUtils.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.glide import android.content.Context @@ -30,11 +46,11 @@ object FrostGlide { } fun <T> RequestBuilder<T>.transform(vararg transformation: BitmapTransformation): RequestBuilder<T> = - when (transformation.size) { - 0 -> this - 1 -> apply(RequestOptions.bitmapTransform(transformation[0])) - else -> apply(RequestOptions.bitmapTransform(MultiTransformation(*transformation))) - } + when (transformation.size) { + 0 -> this + 1 -> apply(RequestOptions.bitmapTransform(transformation[0])) + else -> apply(RequestOptions.bitmapTransform(MultiTransformation(*transformation))) + } @GlideModule class FrostGlideModule : AppGlideModule() { @@ -48,7 +64,7 @@ class FrostGlideModule : AppGlideModule() { } private fun getFrostHttpClient(): OkHttpClient = - OkHttpClient.Builder().addInterceptor(FrostCookieInterceptor()).build() + OkHttpClient.Builder().addInterceptor(FrostCookieInterceptor()).build() class FrostCookieInterceptor : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { @@ -58,4 +74,4 @@ class FrostCookieInterceptor : Interceptor { val request = origRequest.newBuilder().addHeader("Cookie", cookie).build() return chain.proceed(request) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/glide/RoundCornerTransformation.kt b/app/src/main/kotlin/com/pitchedapps/frost/glide/RoundCornerTransformation.kt index 5eded159..564224ea 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/glide/RoundCornerTransformation.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/glide/RoundCornerTransformation.kt @@ -1,12 +1,32 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.glide -import android.graphics.* +import android.graphics.Bitmap +import android.graphics.BitmapShader +import android.graphics.Canvas +import android.graphics.Paint +import android.graphics.RectF +import android.graphics.Shader import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool import com.bumptech.glide.load.resource.bitmap.BitmapTransformation import com.pitchedapps.frost.utils.Prefs import java.security.MessageDigest - /** * Created by Allan Wang on 27/12/17. */ @@ -25,17 +45,17 @@ class RoundCornerTransformation : BitmapTransformation() { bitmap.setHasAlpha(true) val radius = Math.min(width, height).toFloat() / - (if (Prefs.showRoundedIcons) 2f else 10f) + (if (Prefs.showRoundedIcons) 2f else 10f) val canvas = Canvas(bitmap) val paint = Paint() paint.isAntiAlias = true paint.shader = BitmapShader(toTransform, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP) - canvas.drawRoundRect(RectF(0f, 0f, width.toFloat(), height.toFloat()), - radius, radius, paint) + canvas.drawRoundRect( + RectF(0f, 0f, width.toFloat(), height.toFloat()), + radius, radius, paint + ) return bitmap } - - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt index 1211b742..6eacf48e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/GenericIItems.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.iitems import android.content.Context @@ -32,25 +48,25 @@ interface ClickableIItemContract { companion object { fun bindEvents(adapter: IAdapter<IItem<*, *>>) { adapter.fastAdapter.withSelectable(false) - .withOnClickListener { v, _, item, _ -> - if (item is ClickableIItemContract) { - item.click(v!!.context) - true - } else - false - } + .withOnClickListener { v, _, item, _ -> + if (item is ClickableIItemContract) { + item.click(v!!.context) + true + } else + false + } } } - } /** * Generic header item * Not clickable with an accent color */ -open class HeaderIItem(val text: String?, - itemId: Int = R.layout.iitem_header) - : KauIItem<HeaderIItem, HeaderIItem.ViewHolder>(R.layout.iitem_header, ::ViewHolder, itemId) { +open class HeaderIItem( + val text: String?, + itemId: Int = R.layout.iitem_header +) : KauIItem<HeaderIItem, HeaderIItem.ViewHolder>(R.layout.iitem_header, ::ViewHolder, itemId) { class ViewHolder(itemView: View) : FastAdapter.ViewHolder<HeaderIItem>(itemView) { @@ -66,18 +82,18 @@ open class HeaderIItem(val text: String?, text.text = null } } - } /** * Generic text item * Clickable with text color */ -open class TextIItem(val text: String?, - override val url: String?, - itemId: Int = R.layout.iitem_text) - : KauIItem<TextIItem, TextIItem.ViewHolder>(R.layout.iitem_text, ::ViewHolder, itemId), - ClickableIItemContract { +open class TextIItem( + val text: String?, + override val url: String?, + itemId: Int = R.layout.iitem_text +) : KauIItem<TextIItem, TextIItem.ViewHolder>(R.layout.iitem_text, ::ViewHolder, itemId), + ClickableIItemContract { class ViewHolder(itemView: View) : FastAdapter.ViewHolder<TextIItem>(itemView) { @@ -93,5 +109,4 @@ open class TextIItem(val text: String?, text.text = null } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/MenuIItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/MenuIItem.kt index 4a7356b0..651a4a2a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/MenuIItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/MenuIItem.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.iitems import android.view.View @@ -21,9 +37,9 @@ import com.pitchedapps.frost.utils.Prefs /** * Created by Allan Wang on 30/12/17. */ -class MenuContentIItem(val data: MenuItem) - : KauIItem<MenuContentIItem, MenuContentIItem.ViewHolder>(R.layout.iitem_menu, ::ViewHolder), - ClickableIItemContract { +class MenuContentIItem(val data: MenuItem) : + KauIItem<MenuContentIItem, MenuContentIItem.ViewHolder>(R.layout.iitem_menu, ::ViewHolder), + ClickableIItemContract { override val url: String? get() = data.url @@ -42,9 +58,9 @@ class MenuContentIItem(val data: MenuItem) val iconUrl = item.data.pic if (iconUrl != null) GlideApp.with(itemView) - .load(iconUrl) - .transform(FrostGlide.roundCorner) - .into(icon.visible()) + .load(iconUrl) + .transform(FrostGlide.roundCorner) + .into(icon.visible()) else icon.gone() content.text = item.data.name @@ -59,12 +75,11 @@ class MenuContentIItem(val data: MenuItem) } } -class MenuHeaderIItem(val data: MenuHeader) : HeaderIItem(data.header, - itemId = R.id.item_menu_header) - -class MenuFooterIItem(val data: MenuFooterItem) - : TextIItem(data.name, data.url, R.id.item_menu_footer) +class MenuHeaderIItem(val data: MenuHeader) : HeaderIItem( + data.header, + itemId = R.id.item_menu_header +) -class MenuFooterSmallIItem(val data: MenuFooterItem) - : TextIItem(data.name, data.url, R.id.item_menu_footer_small) +class MenuFooterIItem(val data: MenuFooterItem) : TextIItem(data.name, data.url, R.id.item_menu_footer) +class MenuFooterSmallIItem(val data: MenuFooterItem) : TextIItem(data.name, data.url, R.id.item_menu_footer_small) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt index 06bc0604..e8332955 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/NotificationIItem.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.iitems import android.view.View @@ -26,23 +42,24 @@ import com.pitchedapps.frost.utils.launchWebOverlay /** * Created by Allan Wang on 27/12/17. */ -class NotificationIItem(val notification: FrostNotif, val cookie: String) : KauIItem<NotificationIItem, NotificationIItem.ViewHolder>( +class NotificationIItem(val notification: FrostNotif, val cookie: String) : + KauIItem<NotificationIItem, NotificationIItem.ViewHolder>( R.layout.iitem_notification, ::ViewHolder -) { + ) { companion object { fun bindEvents(adapter: ItemAdapter<NotificationIItem>) { adapter.fastAdapter.withSelectable(false) - .withOnClickListener { v, _, item, position -> - val notif = item.notification - if (notif.unread) { - FrostRunnable.markNotificationRead(v!!.context, notif.id, item.cookie) - adapter.set(position, NotificationIItem(notif.copy(unread = false), item.cookie)) - } - // TODO temp fix. If url is dependent, we cannot load it directly - v!!.context.launchWebOverlay(if (notif.url.isIndependent) notif.url else FbItem.NOTIFICATIONS.url) - true + .withOnClickListener { v, _, item, position -> + val notif = item.notification + if (notif.unread) { + FrostRunnable.markNotificationRead(v!!.context, notif.id, item.cookie) + adapter.set(position, NotificationIItem(notif.copy(unread = false), item.cookie)) } + // TODO temp fix. If url is dependent, we cannot load it directly + v!!.context.launchWebOverlay(if (notif.url.isIndependent) notif.url else FbItem.NOTIFICATIONS.url) + true + } } //todo see if necessary @@ -52,12 +69,17 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) : KauI private class Diff : DiffCallback<NotificationIItem> { override fun areItemsTheSame(oldItem: NotificationIItem, newItem: NotificationIItem) = - oldItem.notification.id == newItem.notification.id + oldItem.notification.id == newItem.notification.id override fun areContentsTheSame(oldItem: NotificationIItem, newItem: NotificationIItem) = - oldItem.notification == newItem.notification + oldItem.notification == newItem.notification - override fun getChangePayload(oldItem: NotificationIItem, oldItemPosition: Int, newItem: NotificationIItem, newItemPosition: Int): Any? { + override fun getChangePayload( + oldItem: NotificationIItem, + oldItemPosition: Int, + newItem: NotificationIItem, + newItemPosition: Int + ): Any? { return newItem } } @@ -75,15 +97,17 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) : KauI override fun bindView(item: NotificationIItem, payloads: MutableList<Any>) { val notif = item.notification - frame.background = createSimpleRippleDrawable(Prefs.textColor, - Prefs.nativeBgColor(notif.unread)) + frame.background = createSimpleRippleDrawable( + Prefs.textColor, + Prefs.nativeBgColor(notif.unread) + ) content.setTextColor(Prefs.textColor) date.setTextColor(Prefs.textColor.withAlpha(150)) val glide = glide glide.load(notif.img) - .transform(FrostGlide.roundCorner) - .into(avatar) + .transform(FrostGlide.roundCorner) + .into(avatar) if (notif.thumbnailUrl != null) glide.load(notif.thumbnailUrl).into(thumbnail.visible()) @@ -101,4 +125,4 @@ class NotificationIItem(val notification: FrostNotif, val cookie: String) : KauI date.text = null } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt index 506d1cab..51201d09 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/iitems/TabIItem.kt @@ -1,10 +1,30 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.iitems import android.view.View import android.widget.ImageView import android.widget.TextView import ca.allanwang.kau.iitems.KauIItem -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.invisible +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.visible +import ca.allanwang.kau.utils.withAlpha import com.mikepenz.fastadapter.FastAdapter import com.mikepenz.fastadapter.IItem import com.mikepenz.fastadapter_extensions.drag.IDraggable @@ -16,8 +36,8 @@ import com.pitchedapps.frost.utils.Prefs * Created by Allan Wang on 26/11/17. */ class TabIItem(val item: FbItem) : KauIItem<TabIItem, TabIItem.ViewHolder>( - R.layout.iitem_tab_preview, - { ViewHolder(it) } + R.layout.iitem_tab_preview, + { ViewHolder(it) } ), IDraggable<TabIItem, IItem<*, *>> { override fun withIsDraggable(draggable: Boolean): TabIItem = this @@ -45,6 +65,5 @@ class TabIItem(val item: FbItem) : KauIItem<TabIItem, TabIItem.ViewHolder>( image.setImageDrawable(null) text.visible().text = null } - } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt index 033e482f..de19f99c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt @@ -1,14 +1,35 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.injectors import android.graphics.Color import android.webkit.WebView import ca.allanwang.kau.kotlin.lazyContext -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.adjustAlpha +import ca.allanwang.kau.utils.colorToBackground +import ca.allanwang.kau.utils.colorToForeground +import ca.allanwang.kau.utils.toRgbaString +import ca.allanwang.kau.utils.use +import ca.allanwang.kau.utils.withAlpha import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import java.io.BufferedReader import java.io.FileNotFoundException -import java.util.* +import java.util.Locale /** * Created by Allan Wang on 2017-05-31. @@ -32,17 +53,17 @@ enum class CssAssets(val folder: String = "themes") : InjectorContract { val bb = Prefs.bgColor.colorToForeground(0.35f) content = content - .replace("\$T\$", Prefs.textColor.toRgbaString()) - .replace("\$TT\$", Prefs.textColor.colorToBackground(0.05f).toRgbaString()) - .replace("\$A\$", Prefs.accentColor.toRgbaString()) - .replace("\$B\$", Prefs.bgColor.toRgbaString()) - .replace("\$BT\$", bt) - .replace("\$BBT\$", bb.withAlpha(51).toRgbaString()) - .replace("\$O\$", Prefs.bgColor.withAlpha(255).toRgbaString()) - .replace("\$OO\$", bb.withAlpha(255).toRgbaString()) - .replace("\$D\$", Prefs.textColor.adjustAlpha(0.3f).toRgbaString()) - .replace("\$TI\$", bb.withAlpha(60).toRgbaString()) - .replace("\$C\$", bt) + .replace("\$T\$", Prefs.textColor.toRgbaString()) + .replace("\$TT\$", Prefs.textColor.colorToBackground(0.05f).toRgbaString()) + .replace("\$A\$", Prefs.accentColor.toRgbaString()) + .replace("\$B\$", Prefs.bgColor.toRgbaString()) + .replace("\$BT\$", bt) + .replace("\$BBT\$", bb.withAlpha(51).toRgbaString()) + .replace("\$O\$", Prefs.bgColor.withAlpha(255).toRgbaString()) + .replace("\$OO\$", bb.withAlpha(255).toRgbaString()) + .replace("\$D\$", Prefs.textColor.adjustAlpha(0.3f).toRgbaString()) + .replace("\$TI\$", bb.withAlpha(60).toRgbaString()) + .replace("\$C\$", bt) } JsBuilder().css(content).build() } catch (e: FileNotFoundException) { @@ -58,5 +79,4 @@ enum class CssAssets(val folder: String = "themes") : InjectorContract { fun reset() { injector.invalidate() } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt index 5444fad8..7da6295f 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssHider.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.injectors import android.webkit.WebView @@ -9,10 +25,14 @@ import android.webkit.WebView */ enum class CssHider(vararg val items: String) : InjectorContract { CORE("[data-sigil=m_login_upsell]", "[role=progressbar]"), - HEADER("#header", "#mJewelNav", "[data-sigil=MTopBlueBarHeader]", - "#header-notices", "[data-sigil*=m-promo-jewel-header]"), - ADS("article[data-xt*=sponsor]", - "article[data-store*=sponsor]"), + HEADER( + "#header", "#mJewelNav", "[data-sigil=MTopBlueBarHeader]", + "#header-notices", "[data-sigil*=m-promo-jewel-header]" + ), + ADS( + "article[data-xt*=sponsor]", + "article[data-store*=sponsor]" + ), PEOPLE_YOU_MAY_KNOW("article._d2r"), SUGGESTED_GROUPS("article[data-ft*=\"ei\":]"), COMPOSER("#MComposer"), @@ -22,11 +42,10 @@ enum class CssHider(vararg val items: String) : InjectorContract { val injector: JsInjector by lazy { JsBuilder().css("${items.joinToString(separator = ",")}{display:none !important}") - .single(name).build() + .single(name).build() } override fun inject(webView: WebView, callback: (() -> Unit)?) { injector.inject(webView, callback) } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt index 1ab00153..e64d4faa 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.injectors import android.webkit.WebView @@ -27,10 +43,9 @@ enum class JsActions(body: String) : InjectorContract { val function = "(function(){$body})();" override fun inject(webView: WebView, callback: (() -> Unit)?) = - JsInjector(function).inject(webView, callback) - + JsInjector(function).inject(webView, callback) } @Suppress("NOTHING_TO_INLINE") private inline fun clickBySelector(selector: String): String = - """document.querySelector("$selector").click()"""
\ No newline at end of file + """document.querySelector("$selector").click()""" diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt index 980481a4..0dccc751 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.injectors import android.webkit.WebView @@ -5,7 +21,7 @@ import ca.allanwang.kau.kotlin.lazyContext import com.pitchedapps.frost.utils.L import java.io.BufferedReader import java.io.FileNotFoundException -import java.util.* +import java.util.Locale /** * Created by Allan Wang on 2017-05-31. @@ -31,5 +47,4 @@ enum class JsAssets : InjectorContract { override fun inject(webView: WebView, callback: (() -> Unit)?) { injector(webView.context).inject(webView, callback) } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt index acda2d9b..8ae3a2f4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsInjector.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.injectors import android.webkit.WebView @@ -8,7 +24,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.disposables.Disposable import io.reactivex.subjects.SingleSubject import org.apache.commons.text.StringEscapeUtils -import java.util.* +import java.util.Locale class JsBuilder { private val css = StringBuilder() @@ -90,10 +106,10 @@ fun WebView.jsInject(vararg injectors: InjectorContract, callback: ((Int) -> Uni } val observables = Array(validInjectors.size) { SingleSubject.create<Unit>() } val disposable = Single.zip<Unit, Int>(observables.asList()) { it.size } - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { res, _ -> - callback(res) - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { res, _ -> + callback(res) + } (0 until validInjectors.size).forEach { i -> validInjectors[i].inject(this) { observables[i].onSuccess(Unit) @@ -102,8 +118,10 @@ fun WebView.jsInject(vararg injectors: InjectorContract, callback: ((Int) -> Uni return disposable } -fun FrostWebViewClient.jsInject(vararg injectors: InjectorContract, - callback: ((Int) -> Unit)? = null) = web.jsInject(*injectors, callback = callback) +fun FrostWebViewClient.jsInject( + vararg injectors: InjectorContract, + callback: ((Int) -> Unit)? = null +) = web.jsInject(*injectors, callback = callback) /** * Wrapper class to convert a function into an injector @@ -112,4 +130,4 @@ class JsInjector(val function: String) : InjectorContract { override fun inject(webView: WebView, callback: (() -> Unit)?) { webView.evaluateJavascript(function) { callback?.invoke() } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt index 42630d79..afa8df35 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt @@ -1,35 +1,50 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.intro import android.os.Bundle import android.view.View -import ca.allanwang.kau.utils.bindViewResettable import ca.allanwang.kau.utils.scaleXY import com.pitchedapps.frost.R import com.pitchedapps.frost.activities.IntroActivity import com.pitchedapps.frost.enums.Theme import com.pitchedapps.frost.utils.Prefs +import kotlinx.android.synthetic.main.intro_theme.* /** * Created by Allan Wang on 2017-07-28. */ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) { - val light: View by bindViewResettable(R.id.intro_theme_light) - val dark: View by bindViewResettable(R.id.intro_theme_dark) - val amoled: View by bindViewResettable(R.id.intro_theme_amoled) - val glass: View by bindViewResettable(R.id.intro_theme_glass) - val themeList - get() = listOf(light, dark, amoled, glass) + get() = listOf(intro_theme_light, intro_theme_dark, intro_theme_amoled, intro_theme_glass) - override fun viewArray(): Array<Array<out View>> = arrayOf(arrayOf(title), arrayOf(light, dark), arrayOf(amoled, glass)) + override fun viewArray(): Array<Array<out View>> = arrayOf( + arrayOf(title), + arrayOf(intro_theme_light, intro_theme_dark), + arrayOf(intro_theme_amoled, intro_theme_glass) + ) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - light.setThemeClick(Theme.LIGHT) - dark.setThemeClick(Theme.DARK) - amoled.setThemeClick(Theme.AMOLED) - glass.setThemeClick(Theme.GLASS) + intro_theme_light.setThemeClick(Theme.LIGHT) + intro_theme_dark.setThemeClick(Theme.DARK) + intro_theme_amoled.setThemeClick(Theme.AMOLED) + intro_theme_glass.setThemeClick(Theme.GLASS) val currentTheme = Prefs.theme - 1 if (currentTheme in 0..3) themeList.forEachIndexed { index, v -> v.scaleXY = if (index == currentTheme) 1.6f else 0.8f } @@ -45,5 +60,4 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) { themeList.forEach { it.animate().scaleXY(if (it == this) 1.6f else 0.8f).start() } } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt index c0ccd649..1fd8c76e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.intro import android.graphics.drawable.Drawable @@ -5,7 +21,12 @@ import android.graphics.drawable.LayerDrawable import android.os.Bundle import android.view.View import android.widget.ImageView -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.bindViewResettable +import ca.allanwang.kau.utils.colorToForeground +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.visible +import ca.allanwang.kau.utils.withAlpha import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.Prefs @@ -15,9 +36,9 @@ import com.pitchedapps.frost.utils.launchTabCustomizerActivity * Created by Allan Wang on 2017-07-28. */ abstract class BaseImageIntroFragment( - val titleRes: Int, - val imageRes: Int, - val descRes: Int + val titleRes: Int, + val imageRes: Int, + val descRes: Int ) : BaseIntroFragment(R.layout.intro_image) { val imageDrawable: LayerDrawable by lazyResettableRegistered { image.drawable as LayerDrawable } @@ -68,7 +89,7 @@ abstract class BaseImageIntroFragment( } class IntroAccountFragment : BaseImageIntroFragment( - R.string.intro_multiple_accounts, R.drawable.intro_phone_nav, R.string.intro_multiple_accounts_desc + R.string.intro_multiple_accounts, R.drawable.intro_phone_nav, R.string.intro_multiple_accounts_desc ) { override fun themeFragmentImpl() { @@ -85,7 +106,7 @@ class IntroAccountFragment : BaseImageIntroFragment( } class IntroTabTouchFragment : BaseImageIntroFragment( - R.string.intro_easy_navigation, R.drawable.intro_phone_tab, R.string.intro_easy_navigation_desc + R.string.intro_easy_navigation, R.drawable.intro_phone_tab, R.string.intro_easy_navigation_desc ) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -98,14 +119,20 @@ class IntroTabTouchFragment : BaseImageIntroFragment( override fun themeFragmentImpl() { super.themeFragmentImpl() - themeImageComponent(Prefs.iconColor, R.id.intro_phone_icon_1, R.id.intro_phone_icon_2, R.id.intro_phone_icon_3, R.id.intro_phone_icon_4) + themeImageComponent( + Prefs.iconColor, + R.id.intro_phone_icon_1, + R.id.intro_phone_icon_2, + R.id.intro_phone_icon_3, + R.id.intro_phone_icon_4 + ) themeImageComponent(Prefs.headerColor, R.id.intro_phone_tab) themeImageComponent(Prefs.textColor.withAlpha(80), R.id.intro_phone_icon_ripple) } } class IntroTabContextFragment : BaseImageIntroFragment( - R.string.intro_context_aware, R.drawable.intro_phone_long_press, R.string.intro_context_aware_desc + R.string.intro_context_aware, R.drawable.intro_phone_long_press, R.string.intro_context_aware_desc ) { override fun themeFragmentImpl() { @@ -115,11 +142,16 @@ class IntroTabContextFragment : BaseImageIntroFragment( themeImageComponent(Prefs.bgColor.colorToForeground(0.2f), R.id.intro_phone_like, R.id.intro_phone_share) themeImageComponent(Prefs.bgColor.colorToForeground(0.3f), R.id.intro_phone_comment) themeImageComponent(Prefs.bgColor.colorToForeground(0.1f), R.id.intro_phone_card_1, R.id.intro_phone_card_2) - themeImageComponent(Prefs.textColor, R.id.intro_phone_image_indicator, R.id.intro_phone_comment_indicator, R.id.intro_phone_card_indicator) + themeImageComponent( + Prefs.textColor, + R.id.intro_phone_image_indicator, + R.id.intro_phone_comment_indicator, + R.id.intro_phone_card_indicator + ) } override fun onPageScrolledImpl(positionOffset: Float) { super.onPageScrolledImpl(positionOffset) lastImageFragmentTransition(positionOffset) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt index 39a39232..a4f9e193 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt @@ -1,15 +1,31 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.intro import android.annotation.SuppressLint import android.content.res.ColorStateList import android.os.Bundle -import android.support.constraint.ConstraintLayout -import android.support.v4.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.ImageView import android.widget.TextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.fragment.app.Fragment import ca.allanwang.kau.kotlin.LazyResettableRegistry import ca.allanwang.kau.utils.Kotterknife import ca.allanwang.kau.utils.bindViewResettable @@ -99,7 +115,6 @@ abstract class BaseIntroFragment(val layoutRes: Int) : Fragment() { } protected open fun onPageSelectedImpl() { - } } @@ -131,4 +146,4 @@ class IntroFragmentEnd : BaseIntroFragment(R.layout.intro_end) { (activity as IntroActivity).finish(event.x, event.y) } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/rx/RxFlyweight.kt b/app/src/main/kotlin/com/pitchedapps/frost/rx/RxFlyweight.kt index e8373dd6..25f6d6aa 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/rx/RxFlyweight.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/rx/RxFlyweight.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.rx import io.reactivex.Single @@ -72,9 +88,9 @@ abstract class RxFlyweight<in T : Any, C : Any, R : Any> { * you likely won't have a need for flyweights */ protected open fun createNewSource(input: T): Single<R> = - Single.fromCallable { call(input) } - .timeout(15, TimeUnit.SECONDS) - .subscribeOn(Schedulers.io()) + Single.fromCallable { call(input) } + .timeout(15, TimeUnit.SECONDS) + .subscribeOn(Schedulers.io()) fun reset() { synchronized(lock) { @@ -82,5 +98,4 @@ abstract class RxFlyweight<in T : Any, C : Any, R : Any> { conditionals.clear() } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt index 295dbe0c..ee515a55 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.services import android.app.Notification @@ -8,8 +24,8 @@ import android.net.Uri import android.os.BaseBundle import android.os.Build import android.os.Bundle -import android.support.v4.app.NotificationCompat -import android.support.v4.app.NotificationManagerCompat +import androidx.core.app.NotificationCompat +import androidx.core.app.NotificationManagerCompat import ca.allanwang.kau.utils.dpToPx import ca.allanwang.kau.utils.string import com.pitchedapps.frost.BuildConfig @@ -26,8 +42,12 @@ import com.pitchedapps.frost.facebook.parsers.NotifParser import com.pitchedapps.frost.facebook.parsers.ParseNotification import com.pitchedapps.frost.glide.FrostGlide import com.pitchedapps.frost.glide.GlideApp -import com.pitchedapps.frost.utils.* -import java.util.* +import com.pitchedapps.frost.utils.ARG_USER_ID +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.frostEvent +import com.pitchedapps.frost.utils.isIndependent +import java.util.Locale /** * Created by Allan Wang on 2017-07-08. @@ -40,33 +60,38 @@ private val _40_DP = 40.dpToPx * Enum to handle notification creations */ enum class NotificationType( - private val channelId: String, - private val overlayContext: OverlayContext, - private val fbItem: FbItem, - private val parser: FrostParser<ParseNotification>, - private val getTime: (notif: NotificationModel) -> Long, - private val putTime: (notif: NotificationModel, time: Long) -> NotificationModel, - private val ringtone: () -> String) { + private val channelId: String, + private val overlayContext: OverlayContext, + private val fbItem: FbItem, + private val parser: FrostParser<ParseNotification>, + private val getTime: (notif: NotificationModel) -> Long, + private val putTime: (notif: NotificationModel, time: Long) -> NotificationModel, + private val ringtone: () -> String +) { - GENERAL(NOTIF_CHANNEL_GENERAL, - OverlayContext.NOTIFICATION, - FbItem.NOTIFICATIONS, - NotifParser, - NotificationModel::epoch, - { notif, time -> notif.copy(epoch = time) }, - Prefs::notificationRingtone) { + GENERAL( + NOTIF_CHANNEL_GENERAL, + OverlayContext.NOTIFICATION, + FbItem.NOTIFICATIONS, + NotifParser, + NotificationModel::epoch, + { notif, time -> notif.copy(epoch = time) }, + Prefs::notificationRingtone + ) { override fun bindRequest(content: NotificationContent, cookie: String) = - FrostRunnable.prepareMarkNotificationRead(content.id, cookie) + FrostRunnable.prepareMarkNotificationRead(content.id, cookie) }, - MESSAGE(NOTIF_CHANNEL_MESSAGES, - OverlayContext.MESSAGE, - FbItem.MESSAGES, - MessageParser, - NotificationModel::epochIm, - { notif, time -> notif.copy(epochIm = time) }, - Prefs::messageRingtone); + MESSAGE( + NOTIF_CHANNEL_MESSAGES, + OverlayContext.MESSAGE, + FbItem.MESSAGES, + MessageParser, + NotificationModel::epochIm, + { notif, time -> notif.copy(epochIm = time) }, + Prefs::messageRingtone + ); private val groupPrefix = "frost_${name.toLowerCase(Locale.CANADA)}" @@ -133,13 +158,15 @@ enum class NotificationType( } fun debugNotification(context: Context, data: CookieModel) { - val content = NotificationContent(data, - System.currentTimeMillis(), - "https://github.com/AllanWang/Frost-for-Facebook", - "Debug Notif", - "Test 123", - System.currentTimeMillis() / 1000, - "https://www.iconexperience.com/_img/v_collection_png/256x256/shadow/dog.png") + val content = NotificationContent( + data, + System.currentTimeMillis(), + "https://github.com/AllanWang/Frost-for-Facebook", + "Debug Notif", + "Test 123", + System.currentTimeMillis() / 1000, + "https://www.iconexperience.com/_img/v_collection_png/256x256/shadow/dog.png" + ) createNotification(context, content).notify(context) } @@ -147,44 +174,43 @@ enum class NotificationType( * Create and submit a new notification with the given [content] */ private fun createNotification(context: Context, content: NotificationContent): FrostNotification = - with(content) { - val intent = Intent(context, FrostWebActivity::class.java) - // TODO temp fix; we will show notification page for dependent urls. We can trigger a click next time - intent.data = Uri.parse(if (href.isIndependent) href else FbItem.NOTIFICATIONS.url) - intent.putExtra(ARG_USER_ID, data.id) - overlayContext.put(intent) - bindRequest(intent, content, data.cookie) + with(content) { + val intent = Intent(context, FrostWebActivity::class.java) + // TODO temp fix; we will show notification page for dependent urls. We can trigger a click next time + intent.data = Uri.parse(if (href.isIndependent) href else FbItem.NOTIFICATIONS.url) + intent.putExtra(ARG_USER_ID, data.id) + overlayContext.put(intent) + bindRequest(intent, content, data.cookie) - val group = "${groupPrefix}_${data.id}" - val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) - val notifBuilder = context.frostNotification(channelId) - .setContentTitle(title ?: context.string(R.string.frost_name)) - .setContentText(text) - .setContentIntent(pendingIntent) - .setCategory(Notification.CATEGORY_SOCIAL) - .setSubText(data.name) - .setGroup(group) + val group = "${groupPrefix}_${data.id}" + val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) + val notifBuilder = context.frostNotification(channelId) + .setContentTitle(title ?: context.string(R.string.frost_name)) + .setContentText(text) + .setContentIntent(pendingIntent) + .setCategory(Notification.CATEGORY_SOCIAL) + .setSubText(data.name) + .setGroup(group) - if (timestamp != -1L) notifBuilder.setWhen(timestamp * 1000) - L.v { "Notif load $content" } + if (timestamp != -1L) notifBuilder.setWhen(timestamp * 1000) + L.v { "Notif load $content" } - if (profileUrl != null) { - try { - val profileImg = GlideApp.with(context) - .asBitmap() - .load(profileUrl) - .transform(FrostGlide.circleCrop) - .submit(_40_DP, _40_DP) - .get() - notifBuilder.setLargeIcon(profileImg) - } catch (e: Exception) { - L.e { "Failed to get image $profileUrl" } - } + if (profileUrl != null) { + try { + val profileImg = GlideApp.with(context) + .asBitmap() + .load(profileUrl) + .transform(FrostGlide.circleCrop) + .submit(_40_DP, _40_DP) + .get() + notifBuilder.setLargeIcon(profileImg) + } catch (e: Exception) { + L.e { "Failed to get image $profileUrl" } } - - FrostNotification(group, notifId, notifBuilder) } + FrostNotification(group, notifId, notifBuilder) + } /** * Create a summary notification to wrap the previous ones @@ -198,44 +224,46 @@ enum class NotificationType( val group = "${groupPrefix}_$userId" val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) val notifBuilder = context.frostNotification(channelId) - .setContentTitle(context.string(R.string.frost_name)) - .setContentText("$count ${context.string(fbItem.titleId)}") - .setGroup(group) - .setGroupSummary(true) - .setContentIntent(pendingIntent) - .setCategory(Notification.CATEGORY_SOCIAL) + .setContentTitle(context.string(R.string.frost_name)) + .setContentText("$count ${context.string(fbItem.titleId)}") + .setGroup(group) + .setGroupSummary(true) + .setContentIntent(pendingIntent) + .setCategory(Notification.CATEGORY_SOCIAL) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - notifBuilder.setGroupAlertBehavior(Notification.GROUP_ALERT_CHILDREN) + notifBuilder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_CHILDREN) } return FrostNotification(group, 1, notifBuilder) } - } /** * Notification data holder */ -data class NotificationContent(val data: CookieModel, - val id: Long, - val href: String, - val title: String? = null, // defaults to frost title - val text: String, - val timestamp: Long, - val profileUrl: String?) { +data class NotificationContent( + val data: CookieModel, + val id: Long, + val href: String, + val title: String? = null, // defaults to frost title + val text: String, + val timestamp: Long, + val profileUrl: String? +) { val notifId = Math.abs(id.toInt()) - } /** * Wrapper for a complete notification builder and identifier * which can be immediately notified when given a [Context] */ -data class FrostNotification(private val tag: String, - private val id: Int, - val notif: NotificationCompat.Builder) { +data class FrostNotification( + private val tag: String, + private val id: Int, + val notif: NotificationCompat.Builder +) { fun withAlert(enable: Boolean, ringtone: String): FrostNotification { notif.setFrostAlert(enable, ringtone) @@ -243,15 +271,15 @@ data class FrostNotification(private val tag: String, } fun notify(context: Context) = - NotificationManagerCompat.from(context).notify(tag, id, notif.build()) + NotificationManagerCompat.from(context).notify(tag, id, notif.build()) } const val NOTIFICATION_PERIODIC_JOB = 7 fun Context.scheduleNotifications(minutes: Long): Boolean = - scheduleJob<NotificationService>(NOTIFICATION_PERIODIC_JOB, minutes) + scheduleJob<NotificationService>(NOTIFICATION_PERIODIC_JOB, minutes) const val NOTIFICATION_JOB_NOW = 6 fun Context.fetchNotifications(): Boolean = - fetchJob<NotificationService>(NOTIFICATION_JOB_NOW)
\ No newline at end of file + fetchJob<NotificationService>(NOTIFICATION_JOB_NOW) diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt index b2ccaea2..22acc9fb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostRequestService.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.services import android.app.job.JobInfo @@ -37,10 +53,10 @@ private enum class FrostRequestCommands : EnumBundle<FrostRequestCommands> { } override fun propagate(bundle: BaseBundle) = - FrostRunnable.prepareMarkNotificationRead( - bundle.getLong(ARG_0), - bundle.getCookie()) - + FrostRunnable.prepareMarkNotificationRead( + bundle.getLong(ARG_0), + bundle.getCookie() + ) }; override val bundleContract: EnumBundleCompanion<FrostRequestCommands> @@ -58,7 +74,6 @@ private enum class FrostRequestCommands : EnumBundle<FrostRequestCommands> { abstract fun propagate(bundle: BaseBundle): BaseBundle.() -> Unit companion object : EnumCompanion<FrostRequestCommands>("frost_arg_commands", values()) - } private const val ARG_COMMAND = "frost_request_command" @@ -99,8 +114,10 @@ object FrostRunnable { L.d { "Invalid notification id $id for marking as read" } return false } - return schedule(context, FrostRequestCommands.NOTIF_READ, - prepareMarkNotificationRead(id, cookie)) + return schedule( + context, FrostRequestCommands.NOTIF_READ, + prepareMarkNotificationRead(id, cookie) + ) } fun propagate(context: Context, intent: Intent?) { @@ -112,9 +129,11 @@ object FrostRunnable { schedule(context, command, builder) } - private fun schedule(context: Context, - command: FrostRequestCommands, - bundleBuilder: PersistableBundle.() -> Unit): Boolean { + private fun schedule( + context: Context, + command: FrostRequestCommands, + bundleBuilder: PersistableBundle.() -> Unit + ): Boolean { val scheduler = context.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val serviceComponent = ComponentName(context, FrostRequestService::class.java) val bundle = PersistableBundle() @@ -127,10 +146,10 @@ object FrostRunnable { } val builder = JobInfo.Builder(JOB_REQUEST_BASE + command.ordinal, serviceComponent) - .setMinimumLatency(0L) - .setExtras(bundle) - .setOverrideDeadline(2000L) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setMinimumLatency(0L) + .setExtras(bundle) + .setOverrideDeadline(2000L) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) val result = scheduler.schedule(builder.build()) if (result <= 0) { L.eThrow("FrostRequestService scheduler failed for ${command.name}") @@ -139,7 +158,6 @@ object FrostRunnable { L.d { "Scheduled ${command.name}" } return true } - } class FrostRequestService : JobService() { @@ -183,4 +201,4 @@ class FrostRequestService : JobService() { } return true } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt index 56ff4db7..4ede5163 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt @@ -1,8 +1,24 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.services import android.app.job.JobParameters import android.app.job.JobService -import android.support.v4.app.NotificationManagerCompat +import androidx.core.app.NotificationManagerCompat import ca.allanwang.kau.utils.string import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.R @@ -31,10 +47,12 @@ class NotificationService : JobService() { override fun onStopJob(params: JobParameters?): Boolean { val time = System.currentTimeMillis() - startTime L.d { "Notification service has finished abruptly in $time ms" } - frostEvent("NotificationTime", - "Type" to "Service force stop", - "IM Included" to Prefs.notificationsInstantMessages, - "Duration" to time) + frostEvent( + "NotificationTime", + "Type" to "Service force stop", + "IM Included" to Prefs.notificationsInstantMessages, + "Duration" to time + ) future?.cancel(true) future = null return false @@ -43,10 +61,12 @@ class NotificationService : JobService() { fun finish(params: JobParameters?) { val time = System.currentTimeMillis() - startTime L.i { "Notification service has finished in $time ms" } - frostEvent("NotificationTime", - "Type" to "Service", - "IM Included" to Prefs.notificationsInstantMessages, - "Duration" to time) + frostEvent( + "NotificationTime", + "Type" to "Service", + "IM Included" to Prefs.notificationsInstantMessages, + "Duration" to time + ) jobFinished(params, false) future?.cancel(true) future = null @@ -61,11 +81,13 @@ class NotificationService : JobService() { var notifCount = 0 cookies.forEach { val current = it.id == currentId - if (Prefs.notificationsGeneral - && (current || Prefs.notificationAllAccounts)) + if (Prefs.notificationsGeneral && + (current || Prefs.notificationAllAccounts) + ) notifCount += fetch(jobId, NotificationType.GENERAL, it) - if (Prefs.notificationsInstantMessages - && (current || Prefs.notificationsImAllAccounts)) + if (Prefs.notificationsInstantMessages && + (current || Prefs.notificationsImAllAccounts) + ) notifCount += fetch(jobId, NotificationType.MESSAGE, it) } @@ -99,10 +121,9 @@ class NotificationService : JobService() { private fun generalNotification(id: Int, textRes: Int, withDefaults: Boolean) { val notifBuilder = frostNotification(NOTIF_CHANNEL_GENERAL) - .setFrostAlert(withDefaults, Prefs.notificationRingtone) - .setContentTitle(string(R.string.frost_name)) - .setContentText(string(textRes)) + .setFrostAlert(withDefaults, Prefs.notificationRingtone) + .setContentTitle(string(R.string.frost_name)) + .setContentText(string(textRes)) NotificationManagerCompat.from(this).notify(id, notifBuilder.build()) } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt index 59352f8e..20a497e3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.services import android.app.Notification @@ -11,8 +27,8 @@ import android.content.Context import android.net.Uri import android.os.Build import android.os.PersistableBundle -import android.support.annotation.RequiresApi -import android.support.v4.app.NotificationCompat +import androidx.annotation.RequiresApi +import androidx.core.app.NotificationCompat import ca.allanwang.kau.utils.color import ca.allanwang.kau.utils.string import com.pitchedapps.frost.R @@ -31,11 +47,11 @@ fun setupNotificationChannels(c: Context) { val appName = c.string(R.string.frost_name) val msg = c.string(R.string.messages) manager.notificationChannels - .filter { - it.id != NOTIF_CHANNEL_GENERAL - && it.id != NOTIF_CHANNEL_MESSAGES - } - .forEach { manager.deleteNotificationChannel(it.id) } + .filter { + it.id != NOTIF_CHANNEL_GENERAL && + it.id != NOTIF_CHANNEL_MESSAGES + } + .forEach { manager.deleteNotificationChannel(it.id) } manager.createNotificationChannel(NOTIF_CHANNEL_GENERAL, appName) manager.createNotificationChannel(NOTIF_CHANNEL_MESSAGES, "$appName: $msg") L.d { "Created notification channels: ${manager.notificationChannels.size} channels, ${manager.notificationChannelGroups.size} groups" } @@ -43,8 +59,10 @@ fun setupNotificationChannels(c: Context) { @RequiresApi(Build.VERSION_CODES.O) private fun NotificationManager.createNotificationChannel(id: String, name: String): NotificationChannel { - val channel = NotificationChannel(id, - name, NotificationManager.IMPORTANCE_DEFAULT) + val channel = NotificationChannel( + id, + name, NotificationManager.IMPORTANCE_DEFAULT + ) channel.enableLights(true) channel.lightColor = Prefs.accentColor channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC @@ -53,14 +71,14 @@ private fun NotificationManager.createNotificationChannel(id: String, name: Stri } fun Context.frostNotification(id: String) = - NotificationCompat.Builder(this, id) - .apply { - setSmallIcon(R.drawable.frost_f_24) - setAutoCancel(true) - setOnlyAlertOnce(true) - setStyle(NotificationCompat.BigTextStyle()) - color = color(R.color.frost_notification_accent) - } + NotificationCompat.Builder(this, id) + .apply { + setSmallIcon(R.drawable.frost_f_24) + setAutoCancel(true) + setOnlyAlertOnce(true) + setStyle(NotificationCompat.BigTextStyle()) + color = color(R.color.frost_notification_accent) + } /** * Dictates whether a notification should have sound/vibration/lights or not @@ -70,8 +88,9 @@ fun Context.frostNotification(id: String) = fun NotificationCompat.Builder.setFrostAlert(enable: Boolean, ringtone: String): NotificationCompat.Builder { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { setGroupAlertBehavior( - if (enable) Notification.GROUP_ALERT_CHILDREN - else Notification.GROUP_ALERT_SUMMARY) + if (enable) NotificationCompat.GROUP_ALERT_CHILDREN + else NotificationCompat.GROUP_ALERT_SUMMARY + ) } else if (!enable) { setDefaults(0) } else { @@ -111,10 +130,10 @@ inline fun <reified T : JobService> Context.scheduleJob(id: Int, minutes: Long): if (minutes < 0L) return true val serviceComponent = ComponentName(this, T::class.java) val builder = JobInfo.Builder(id, serviceComponent) - .setPeriodic(minutes * 60000) - .setExtras(id) - .setPersisted(true) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) //TODO add options + .setPeriodic(minutes * 60000) + .setExtras(id) + .setPersisted(true) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) //TODO add options val result = scheduler.schedule(builder.build()) if (result <= 0) { L.eThrow("${T::class.java.simpleName} scheduler failed") @@ -130,10 +149,10 @@ inline fun <reified T : JobService> Context.fetchJob(id: Int): Boolean { val scheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler val serviceComponent = ComponentName(this, T::class.java) val builder = JobInfo.Builder(id, serviceComponent) - .setMinimumLatency(0L) - .setExtras(id) - .setOverrideDeadline(2000L) - .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) + .setMinimumLatency(0L) + .setExtras(id) + .setOverrideDeadline(2000L) + .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) val result = scheduler.schedule(builder.build()) if (result <= 0) { L.eThrow("${T::class.java.simpleName} instant scheduler failed") diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/UpdateReceiver.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/UpdateReceiver.kt index 59df9ed7..2d86f3b9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/UpdateReceiver.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/UpdateReceiver.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.services import android.content.BroadcastReceiver @@ -18,5 +34,4 @@ class UpdateReceiver : BroadcastReceiver() { L.d { "Frost has updated" } context.scheduleNotifications(Prefs.notificationFreq) //Update notifications } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt index 9253d926..538e20f1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder @@ -10,7 +26,16 @@ import com.pitchedapps.frost.activities.SettingsActivity import com.pitchedapps.frost.enums.MainActivityLayout import com.pitchedapps.frost.enums.Theme import com.pitchedapps.frost.injectors.CssAssets -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.REQUEST_NAV +import com.pitchedapps.frost.utils.REQUEST_REFRESH +import com.pitchedapps.frost.utils.REQUEST_TEXT_ZOOM +import com.pitchedapps.frost.utils.frostEvent +import com.pitchedapps.frost.utils.frostNavigationBar +import com.pitchedapps.frost.utils.frostSnackbar +import com.pitchedapps.frost.utils.launchTabCustomizerActivity +import com.pitchedapps.frost.utils.materialDialogThemed +import com.pitchedapps.frost.utils.setFrostTheme import com.pitchedapps.frost.views.KPrefTextSeekbar /** @@ -74,7 +99,6 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = { allowCustomAlpha = false } - colorPicker(R.string.background_color, Prefs::customBackgroundColor, { Prefs.customBackgroundColor = it bgCanvas.ripple(it, duration = 500L) @@ -146,17 +170,20 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = { descRes = R.string.tint_nav_desc } - list.add(KPrefTextSeekbar( + list.add( + KPrefTextSeekbar( KPrefSeekbar.KPrefSeekbarBuilder( - globalOptions, - R.string.web_text_scaling, Prefs::webTextScaling) { + globalOptions, + R.string.web_text_scaling, Prefs::webTextScaling + ) { Prefs.webTextScaling = it setFrostResult(REQUEST_TEXT_ZOOM) - })) + }) + ) checkbox(R.string.enforce_black_media_bg, Prefs::blackMediaBg, { Prefs.blackMediaBg = it }) { descRes = R.string.enforce_black_media_bg_desc } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt index 02a86e58..10fa5c99 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Behaviour.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder @@ -15,7 +31,10 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = { descRes = R.string.fancy_animations_desc } - checkbox(R.string.overlay_swipe, Prefs::overlayEnabled, { Prefs.overlayEnabled = it; setFrostResult(REQUEST_REFRESH) }) { + checkbox( + R.string.overlay_swipe, + Prefs::overlayEnabled, + { Prefs.overlayEnabled = it; setFrostResult(REQUEST_REFRESH) }) { descRes = R.string.overlay_swipe_desc } @@ -46,5 +65,4 @@ fun SettingsActivity.getBehaviourPrefs(): KPrefAdapterBuilder.() -> Unit = { checkbox(R.string.analytics, Prefs::analytics, { Prefs.analytics = it }) { descRes = R.string.analytics_desc } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt index 91dac242..4b538e87 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Debug.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import android.content.Context @@ -77,25 +93,26 @@ fun SettingsActivity.getDebugPrefs(): KPrefAdapterBuilder.() -> Unit = { } } } - } } } private fun Context.createEmail(parser: FrostParser<*>, content: Any?) = - sendFrostEmail("${string(R.string.debug_report)}: ${parser::class.java.simpleName}") { - addItem("Url", parser.url) - addItem("Contents", "$content") - } + sendFrostEmail("${string(R.string.debug_report)}: ${parser::class.java.simpleName}") { + addItem("Url", parser.url) + addItem("Contents", "$content") + } private const val ZIP_NAME = "debug" fun SettingsActivity.sendDebug(url: String, html: String?) { - val downloader = OfflineWebsite(url, FbCookie.webCookie ?: "", - baseUrl = FB_URL_BASE, - html = html, - baseDir = DebugActivity.baseDir(this)) + val downloader = OfflineWebsite( + url, FbCookie.webCookie ?: "", + baseUrl = FB_URL_BASE, + html = html, + baseDir = DebugActivity.baseDir(this) + ) val md = materialDialog { title(R.string.parsing_data) @@ -114,7 +131,8 @@ fun SettingsActivity.sendDebug(url: String, html: String?) { it.dismiss() if (success) { val zipUri = it.context.frostUriFromFile( - File(downloader.baseDir, "$ZIP_NAME.zip")) + File(downloader.baseDir, "$ZIP_NAME.zip") + ) L.i { "Sending debug zip with uri $zipUri" } sendFrostEmail(R.string.debug_report_email_title) { addItem("Url", url) @@ -128,7 +146,5 @@ fun SettingsActivity.sendDebug(url: String, html: String?) { } } } - } - } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt index fe95e7f1..e0d314a8 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import android.util.Log @@ -24,7 +40,6 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = { // Experimental content starts here ------------------ - // Experimental content ends here -------------------- checkbox(R.string.verbose_logging, Prefs::verboseLogging, { @@ -41,4 +56,4 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = { finish() } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt index 402322ad..ff0badf0 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Feed.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder @@ -66,4 +82,4 @@ fun SettingsActivity.getFeedPrefs(): KPrefAdapterBuilder.() -> Unit = { }) { descRes = R.string.facebook_ads_desc } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt index b5515a52..a1ec33e6 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Network.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder @@ -10,8 +26,10 @@ import com.pitchedapps.frost.utils.Prefs */ fun SettingsActivity.getNetworkPrefs(): KPrefAdapterBuilder.() -> Unit = { - checkbox(R.string.network_media_on_metered, { !Prefs.loadMediaOnMeteredNetwork }, { Prefs.loadMediaOnMeteredNetwork = !it }) { + checkbox( + R.string.network_media_on_metered, + { !Prefs.loadMediaOnMeteredNetwork }, + { Prefs.loadMediaOnMeteredNetwork = !it }) { descRes = R.string.network_media_on_metered_desc } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt index 1f9411e4..0200f109 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Notifications.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.settings import android.annotation.SuppressLint @@ -22,7 +38,6 @@ import com.pitchedapps.frost.utils.frostSnackbar import com.pitchedapps.frost.utils.materialDialogThemed import com.pitchedapps.frost.views.Keywords - /** * Created by Allan Wang on 2017-06-29. */ @@ -66,33 +81,33 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = { } 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) - }) { + { + 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 }) { + { Prefs.notificationAllAccounts = it }) { descRes = R.string.notification_general_all_accounts_desc enabler = Prefs::notificationsGeneral } 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) - }) { + { + 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 }) { + { Prefs.notificationsImAllAccounts = it }) { descRes = R.string.notification_messages_all_accounts_desc enabler = Prefs::notificationsInstantMessages } @@ -102,15 +117,17 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = { descRes = R.string.notification_channel_desc onClick = { val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS) - .putExtra(Settings.EXTRA_APP_PACKAGE, packageName) + .putExtra(Settings.EXTRA_APP_PACKAGE, packageName) startActivity(intent) } } } else { checkbox(R.string.notification_sound, Prefs::notificationSound, { Prefs.notificationSound = it - reloadByTitle(R.string.notification_ringtone, - R.string.message_ringtone) + reloadByTitle( + R.string.notification_ringtone, + R.string.message_ringtone + ) }) fun KPrefText.KPrefTextContract<String>.ringtone(code: Int) { @@ -118,8 +135,8 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = { textGetter = { if (it.isBlank()) string(R.string.kau_default) else RingtoneManager.getRingtone(this@getNotificationPrefs, Uri.parse(it)) - ?.getTitle(this@getNotificationPrefs) - ?: "---" //todo figure out why this happens + ?.getTitle(this@getNotificationPrefs) + ?: "---" //todo figure out why this happens } onClick = { val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { @@ -135,20 +152,20 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = { } text(R.string.notification_ringtone, Prefs::notificationRingtone, - { Prefs.notificationRingtone = it }) { + { Prefs.notificationRingtone = it }) { ringtone(SettingsActivity.REQUEST_NOTIFICATION_RINGTONE) } text(R.string.message_ringtone, Prefs::messageRingtone, - { Prefs.messageRingtone = it }) { + { Prefs.messageRingtone = it }) { ringtone(SettingsActivity.REQUEST_MESSAGE_RINGTONE) } checkbox(R.string.notification_vibrate, Prefs::notificationVibrate, - { Prefs.notificationVibrate = it }) + { Prefs.notificationVibrate = it }) checkbox(R.string.notification_lights, Prefs::notificationLights, - { Prefs.notificationLights = it }) + { Prefs.notificationLights = it }) } if (BuildConfig.DEBUG) { @@ -165,10 +182,9 @@ fun SettingsActivity.getNotificationPrefs(): KPrefAdapterBuilder.() -> Unit = { descRes = R.string.notification_fetch_now_desc onClick = { val text = - if (fetchNotifications()) R.string.notification_fetch_success - else R.string.notification_fetch_fail + if (fetchNotifications()) R.string.notification_fetch_success + else R.string.notification_fetch_fail frostSnackbar(text) } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/AdBlocker.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/AdBlocker.kt index 1bb0449b..61a90024 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/AdBlocker.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/AdBlocker.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.content.Context @@ -45,4 +61,4 @@ open class AdBlocker(val assetPath: String) { if (host.contains(host)) return true return isAdHost(host.substring(index + 1)) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt index 8d800e9b..c9e64eb3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt @@ -1,8 +1,24 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.graphics.drawable.AnimatedVectorDrawable -import android.support.annotation.DrawableRes import android.widget.ImageView +import androidx.annotation.DrawableRes import ca.allanwang.kau.utils.drawable /** @@ -23,23 +39,23 @@ interface AnimatedVectorContract { } class AnimatedVectorDelegate( - /** - * The res for the starting resource; must have parent tag animated-vector - */ - @param:DrawableRes val avdStart: Int, - /** - * The res for the ending resource; must have parent tag animated-vector - */ - @param:DrawableRes val avdEnd: Int, - /** - * The delegate will automatically set the start resource when bound - * If [emitOnBind] is true, it will also trigger the listener - */ - val emitOnBind: Boolean = true, - /** - * The optional listener that will be triggered every time the avd is switched by the delegate - */ - override var animatedVectorListener: ((avd: AnimatedVectorDrawable, forwards: Boolean) -> Unit)? = null + /** + * The res for the starting resource; must have parent tag animated-vector + */ + @param:DrawableRes val avdStart: Int, + /** + * The res for the ending resource; must have parent tag animated-vector + */ + @param:DrawableRes val avdEnd: Int, + /** + * The delegate will automatically set the start resource when bound + * If [emitOnBind] is true, it will also trigger the listener + */ + val emitOnBind: Boolean = true, + /** + * The optional listener that will be triggered every time the avd is switched by the delegate + */ + override var animatedVectorListener: ((avd: AnimatedVectorDrawable, forwards: Boolean) -> Unit)? = null ) : AnimatedVectorContract { lateinit var view: ImageView @@ -55,9 +71,9 @@ class AnimatedVectorDelegate( override fun bind(view: ImageView) { this.view = view view.context.drawable(avdStart) as? AnimatedVectorDrawable - ?: throw IllegalArgumentException("AnimatedVectorDelegate has a starting drawable that isn't an avd") + ?: throw IllegalArgumentException("AnimatedVectorDelegate has a starting drawable that isn't an avd") view.context.drawable(avdEnd) as? AnimatedVectorDrawable - ?: throw IllegalArgumentException("AnimatedVectorDelegate has an ending drawable that isn't an avd") + ?: throw IllegalArgumentException("AnimatedVectorDelegate has an ending drawable that isn't an avd") view.setImageResource(avdStart) if (emitOnBind) animatedVectorListener?.invoke(avd!!, false) } @@ -70,15 +86,11 @@ class AnimatedVectorDelegate( private fun animateImpl(toStart: Boolean) { if ((atStart == toStart)) return L.d { "AVD already at ${if (toStart) "start" else "end"}" } - if (avd == null) return L.d { "AVD null resource" }//no longer using animated vector; do not modify + if (avd == null) return L.d { "AVD null resource" } //no longer using animated vector; do not modify avd?.stop() view.setImageResource(if (toStart) avdEnd else avdStart) animatedVectorListener?.invoke(avd!!, !toStart) atStart = toStart avd?.start() } - } - - - diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/BuildUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/BuildUtils.kt index c9a2f285..33da56f2 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/BuildUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/BuildUtils.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils object BuildUtils { @@ -18,8 +34,7 @@ object BuildUtils { } fun getAllStages(): Array<String> = - arrayOf(BUILD_PRODUCTION, BUILD_TEST, BUILD_GITHUB, BUILD_RELEASE, BUILD_UNNAMED) + arrayOf(BUILD_PRODUCTION, BUILD_TEST, BUILD_GITHUB, BUILD_RELEASE, BUILD_UNNAMED) fun getStage(build: String): String = build.takeIf { it in getAllStages() } ?: BUILD_UNNAMED - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt index 0cb57ed5..3c76759c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Const.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils /** @@ -15,4 +31,4 @@ const val REQUEST_TEXT_ZOOM = 1 shl 14 const val REQUEST_NAV = 1 shl 15 const val REQUEST_SEARCH = 1 shl 16 -const val MAIN_TIMEOUT_DURATION = 30 * 60 * 1000 // 30 min
\ No newline at end of file +const val MAIN_TIMEOUT_DURATION = 30 * 60 * 1000 // 30 min diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt index 16b1d149..f4baa242 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Downloader.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.app.DownloadManager @@ -16,26 +32,29 @@ import com.pitchedapps.frost.R import com.pitchedapps.frost.dbflow.loadFbCookie import com.pitchedapps.frost.facebook.USER_AGENT_BASIC - /** * Created by Allan Wang on 2017-08-04. * * With reference to <a href="https://stackoverflow.com/questions/33434532/android-webview-download-files-like-browsers-do">Stack Overflow</a> */ -fun Context.frostDownload(url: String?, - userAgent: String = USER_AGENT_BASIC, - contentDisposition: String? = null, - mimeType: String? = null, - contentLength: Long = 0L) { +fun Context.frostDownload( + url: String?, + userAgent: String = USER_AGENT_BASIC, + contentDisposition: String? = null, + mimeType: String? = null, + contentLength: Long = 0L +) { url ?: return frostDownload(Uri.parse(url), userAgent, contentDisposition, mimeType, contentLength) } -fun Context.frostDownload(uri: Uri?, - userAgent: String = USER_AGENT_BASIC, - contentDisposition: String? = null, - mimeType: String? = null, - contentLength: Long = 0L) { +fun Context.frostDownload( + uri: Uri?, + userAgent: String = USER_AGENT_BASIC, + contentDisposition: String? = null, + mimeType: String? = null, + contentLength: Long = 0L +) { uri ?: return L.d { "Received download request" } if (uri.scheme != "http" && uri.scheme != "https") { @@ -75,4 +94,4 @@ fun Context.frostDownload(uri: Uri?, } } -private const val DOWNLOAD_MANAGER_PACKAGE = "com.android.providers.downloads"
\ No newline at end of file +private const val DOWNLOAD_MANAGER_PACKAGE = "com.android.providers.downloads" diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/EnumUtils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/EnumUtils.kt index 2a562ba2..b6d9b833 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/EnumUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/EnumUtils.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.content.Intent @@ -39,12 +55,12 @@ interface EnumBundleCompanion<E : Enum<E>> { operator fun get(bundle: BaseBundle?) = get(bundle?.getString(argTag)) operator fun get(intent: Intent?) = get(intent?.getStringExtra(argTag)) - } open class EnumCompanion<E : Enum<E>>( - final override val argTag: String, - final override val values: Array<E>) : EnumBundleCompanion<E> { + final override val argTag: String, + final override val values: Array<E> +) : EnumBundleCompanion<E> { final override val valueMap: Map<String, E> = values.map { it.name to it }.toMap() @@ -53,5 +69,4 @@ open class EnumCompanion<E : Enum<E>>( final override fun get(bundle: BaseBundle?) = super.get(bundle) final override fun get(intent: Intent?) = super.get(intent) - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt index da8672f4..c783a842 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/JsoupCleaner.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import org.jsoup.Jsoup @@ -21,8 +37,10 @@ internal fun String.cleanJsoup(): String = Jsoup.clean(this, PrivacyWhitelist()) class PrivacyWhitelist : Whitelist() { val blacklistAttrs = arrayOf("style", "aria-label", "rel") - val blacklistTags = arrayOf("body", "html", "head", "i", "b", "u", "style", "script", - "br", "p", "span", "ul", "ol", "li") + val blacklistTags = arrayOf( + "body", "html", "head", "i", "b", "u", "style", "script", + "br", "p", "span", "ul", "ol", "li" + ) override fun isSafeAttribute(tagName: String, el: Element, attr: Attribute): Boolean { val key = attr.key diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt index bee2f49b..8364c34e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/L.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.util.Log @@ -5,7 +21,6 @@ import ca.allanwang.kau.logging.KauLogger import com.bugsnag.android.Bugsnag import com.pitchedapps.frost.BuildConfig - /** * Created by Allan Wang on 2017-05-28. * @@ -45,5 +60,4 @@ object L : KauLogger("Frost", { Bugsnag.notify(t) } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt index 9f068a58..303142af 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.graphics.Color @@ -71,8 +87,8 @@ object Prefs : KPref() { get() = Prefs.bgColor.withAlpha(30) fun nativeBgColor(unread: Boolean) = Prefs.bgColor - .colorToForeground(if (unread) 0.7f else 0.0f) - .withAlpha(30) + .colorToForeground(if (unread) 0.7f else 0.0f) + .withAlpha(30) val bgColor: Int get() = t.bgColor diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt index cafba223..27016018 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import ca.allanwang.kau.kpref.KPref @@ -21,4 +37,3 @@ object Showcase : KPref() { override fun deleteKeys() = arrayOf("shown_release") } - diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt index 6c78d922..56c1d6d9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.annotation.SuppressLint @@ -8,33 +24,59 @@ import android.content.Intent import android.graphics.Color import android.graphics.drawable.ColorDrawable import android.net.Uri -import android.support.annotation.StringRes -import android.support.design.widget.Snackbar -import android.support.design.widget.SnackbarContentLayout -import android.support.v4.content.FileProvider -import android.support.v7.widget.Toolbar import android.view.View import android.widget.FrameLayout import android.widget.TextView +import androidx.annotation.StringRes +import androidx.appcompat.widget.Toolbar +import androidx.core.content.FileProvider import ca.allanwang.kau.email.EmailBuilder import ca.allanwang.kau.email.sendEmail import ca.allanwang.kau.mediapicker.createMediaFile import ca.allanwang.kau.mediapicker.createPrivateMediaFile -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.adjustAlpha +import ca.allanwang.kau.utils.colorToForeground +import ca.allanwang.kau.utils.darken +import ca.allanwang.kau.utils.isColorDark +import ca.allanwang.kau.utils.lighten +import ca.allanwang.kau.utils.navigationBarColor +import ca.allanwang.kau.utils.snackbar +import ca.allanwang.kau.utils.startActivity +import ca.allanwang.kau.utils.startActivityForResult +import ca.allanwang.kau.utils.statusBarColor +import ca.allanwang.kau.utils.string +import ca.allanwang.kau.utils.with +import ca.allanwang.kau.utils.withAlpha +import ca.allanwang.kau.utils.withMinAlpha import ca.allanwang.kau.xml.showChangelog import com.afollestad.materialdialogs.MaterialDialog +import com.google.android.material.snackbar.Snackbar +import com.google.android.material.snackbar.SnackbarContentLayout import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.R -import com.pitchedapps.frost.activities.* +import com.pitchedapps.frost.activities.ImageActivity +import com.pitchedapps.frost.activities.LoginActivity +import com.pitchedapps.frost.activities.SelectorActivity +import com.pitchedapps.frost.activities.SettingsActivity +import com.pitchedapps.frost.activities.TabCustomizerActivity +import com.pitchedapps.frost.activities.WebOverlayActivity +import com.pitchedapps.frost.activities.WebOverlayActivityBase +import com.pitchedapps.frost.activities.WebOverlayBasicActivity import com.pitchedapps.frost.dbflow.CookieModel -import com.pitchedapps.frost.facebook.* +import com.pitchedapps.frost.facebook.FACEBOOK_COM +import com.pitchedapps.frost.facebook.FBCDN_NET +import com.pitchedapps.frost.facebook.FbCookie +import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.FbUrlFormatter.Companion.VIDEO_REDIRECT +import com.pitchedapps.frost.facebook.USER_AGENT_BASIC +import com.pitchedapps.frost.facebook.formattedFbUrl import org.apache.commons.text.StringEscapeUtils import org.jsoup.Jsoup import org.jsoup.nodes.Element import java.io.File import java.io.IOException -import java.util.* +import java.util.ArrayList +import java.util.Locale /** * Created by Allan Wang on 2017-06-03. @@ -46,7 +88,10 @@ const val ARG_IMAGE_URL = "arg_image_url" const val ARG_TEXT = "arg_text" const val ARG_COOKIE = "arg_cookie" -inline fun <reified T : Activity> Context.launchNewTask(cookieList: ArrayList<CookieModel> = arrayListOf(), clearStack: Boolean = false) { +inline fun <reified T : Activity> Context.launchNewTask( + cookieList: ArrayList<CookieModel> = arrayListOf(), + clearStack: Boolean = false +) { startActivity<T>(clearStack, intentBuilder = { putParcelableArrayListExtra(EXTRA_COOKIES, cookieList) }) @@ -81,8 +126,10 @@ fun Context.launchWebOverlay(url: String) = launchWebOverlayImpl<WebOverlayActiv fun Context.launchWebOverlayBasic(url: String) = launchWebOverlayImpl<WebOverlayBasicActivity>(url) -private fun Context.fadeBundle() = ActivityOptions.makeCustomAnimation(this, - android.R.anim.fade_in, android.R.anim.fade_out).toBundle() +private fun Context.fadeBundle() = ActivityOptions.makeCustomAnimation( + this, + android.R.anim.fade_in, android.R.anim.fade_out +).toBundle() fun Context.launchImageActivity(imageUrl: String, text: String? = null, cookie: String? = null) { startActivity<ImageActivity>(intentBuilder = { @@ -174,7 +221,6 @@ inline fun Activity.setFrostColors(builder: ActivityThemeUtils.() -> Unit) { themer.theme(this) } - fun frostEvent(name: String, vararg events: Pair<String, Any>) { // todo bind L.v { "Event: $name ${events.joinToString(", ")}" } @@ -189,9 +235,11 @@ fun Throwable?.logFrostEvent(text: String) { frostEvent("Errors", "text" to text, "message" to (this?.message ?: "NA")) } -fun Activity.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {}) = snackbar(text, Snackbar.LENGTH_LONG, frostSnackbar(builder)) +fun Activity.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {}) = + snackbar(text, Snackbar.LENGTH_LONG, frostSnackbar(builder)) -fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {}) = snackbar(text, Snackbar.LENGTH_LONG, frostSnackbar(builder)) +fun View.frostSnackbar(@StringRes text: Int, builder: Snackbar.() -> Unit = {}) = + snackbar(text, Snackbar.LENGTH_LONG, frostSnackbar(builder)) @SuppressLint("RestrictedApi") private inline fun frostSnackbar(crossinline builder: Snackbar.() -> Unit): Snackbar.() -> Unit = { @@ -240,7 +288,7 @@ inline val String?.isFacebookUrl */ inline val String.isVideoUrl get() = startsWith(VIDEO_REDIRECT) || - (startsWith("https://video-") && contains(FBCDN_NET)) + (startsWith("https://video-") && contains(FBCDN_NET)) /** * [true] if url directly leads to a usable image @@ -271,22 +319,22 @@ inline val String?.isIndependent: Boolean } val dependentSegments = arrayOf( - "photoset_token", "direct_action_execute", "messages/?pageNum", "sharer.php", - "events/permalink", "events/feed/watch", - /* - * Add new members to groups - */ - "madminpanel", - /** - * Editing images - */ - "/confirmation/?", - /* - * Facebook messages have the following cases for the tid query - * mid* or id* for newer threads, which can be launched in new windows - * or a hash for old threads, which must be loaded on old threads - */ - "messages/read/?tid=id", "messages/read/?tid=mid" + "photoset_token", "direct_action_execute", "messages/?pageNum", "sharer.php", + "events/permalink", "events/feed/watch", + /* + * Add new members to groups + */ + "madminpanel", + /** + * Editing images + */ + "/confirmation/?", + /* + * Facebook messages have the following cases for the tid query + * mid* or id* for newer threads, which can be launched in new windows + * or a hash for old threads, which must be loaded on old threads + */ + "messages/read/?tid=id", "messages/read/?tid=mid" ) inline val String?.isExplicitIntent @@ -297,16 +345,20 @@ fun Context.frostChangelog() = showChangelog(R.xml.frost_changelog, Prefs.textCo } fun Context.frostUriFromFile(file: File): Uri = - FileProvider.getUriForFile(this, - BuildConfig.APPLICATION_ID + ".provider", - file) - -inline fun Context.sendFrostEmail(@StringRes subjectId: Int, crossinline builder: EmailBuilder.() -> Unit) = sendFrostEmail(string(subjectId), builder) - -inline fun Context.sendFrostEmail(subjectId: String, crossinline builder: EmailBuilder.() -> Unit) = sendEmail(string(R.string.dev_email), subjectId) { - builder() - addFrostDetails() -} + FileProvider.getUriForFile( + this, + BuildConfig.APPLICATION_ID + ".provider", + file + ) + +inline fun Context.sendFrostEmail(@StringRes subjectId: Int, crossinline builder: EmailBuilder.() -> Unit) = + sendFrostEmail(string(subjectId), builder) + +inline fun Context.sendFrostEmail(subjectId: String, crossinline builder: EmailBuilder.() -> Unit) = + sendEmail(string(R.string.dev_email), subjectId) { + builder() + addFrostDetails() + } fun EmailBuilder.addFrostDetails() { addItem("Prev version", Prefs.prevVersionCode.toString()) @@ -318,7 +370,8 @@ fun EmailBuilder.addFrostDetails() { fun frostJsoup(url: String) = frostJsoup(FbCookie.webCookie, url) -fun frostJsoup(cookie: String?, url: String) = Jsoup.connect(url).cookie(FACEBOOK_COM, cookie).userAgent(USER_AGENT_BASIC).get()!! +fun frostJsoup(cookie: String?, url: String) = + Jsoup.connect(url).cookie(FACEBOOK_COM, cookie).userAgent(USER_AGENT_BASIC).get()!! fun Element.first(vararg select: String): Element? { select.forEach { @@ -346,6 +399,6 @@ fun File.createFreshDir(): Boolean { } fun String.unescapeHtml(): String = - StringEscapeUtils.unescapeXml(this) - .replace("\\u003C", "<") - .replace("\\\"", "\"") + StringEscapeUtils.unescapeXml(this) + .replace("\\u003C", "<") + .replace("\\\"", "\"") diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt index dc2d7549..62330e4d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.utils import android.content.Context @@ -41,7 +57,9 @@ class WebContext(val unformattedUrl: String, val text: String?) { enum class WebContextType(val textId: Int, val onClick: (c: Context, wc: WebContext) -> Unit) { OPEN_LINK(R.string.open_link, { c, wc -> c.launchWebOverlay(wc.unformattedUrl) }), COPY_LINK(R.string.copy_link, { c, wc -> c.copyToClipboard(wc.url) }), - COPY_TEXT(R.string.copy_text, { c, wc -> if (wc.text != null) c.copyToClipboard(wc.text) else c.toast(R.string.no_text) }), + COPY_TEXT( + R.string.copy_text, + { c, wc -> if (wc.text != null) c.copyToClipboard(wc.text) else c.toast(R.string.no_text) }), SHARE_LINK(R.string.share_link, { c, wc -> c.shareText(wc.url) }), DEBUG_LINK(R.string.debug_link, { c, wc -> c.materialDialogThemed { @@ -63,4 +81,4 @@ enum class WebContextType(val textId: Int, val onClick: (c: Context, wc: WebCont val values = values() operator fun get(index: Int) = values[index] } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt index 7262fa17..d7a7de0e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt @@ -1,12 +1,32 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.graphics.drawable.Drawable -import android.support.v7.widget.AppCompatTextView -import android.support.v7.widget.RecyclerView import android.view.View import android.widget.ImageView +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.RecyclerView import ca.allanwang.kau.iitems.KauIItem -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.fadeIn +import ca.allanwang.kau.utils.invisible +import ca.allanwang.kau.utils.toDrawable +import ca.allanwang.kau.utils.visible import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.RequestListener @@ -23,7 +43,7 @@ import com.pitchedapps.frost.utils.Prefs * Created by Allan Wang on 2017-06-05. */ class AccountItem(val cookie: CookieModel?) : KauIItem<AccountItem, AccountItem.ViewHolder> -(R.layout.view_account, { ViewHolder(it) }, R.id.item_account) { + (R.layout.view_account, { ViewHolder(it) }, R.id.item_account) { override fun bindView(viewHolder: ViewHolder, payloads: MutableList<Any>) { super.bindView(viewHolder, payloads) @@ -33,20 +53,37 @@ class AccountItem(val cookie: CookieModel?) : KauIItem<AccountItem, AccountItem. if (cookie != null) { text.text = cookie.name GlideApp.with(itemView).load(profilePictureUrl(cookie.id)) - .transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> { - override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { - text.fadeIn() - return false - } + .transform(FrostGlide.roundCorner).listener(object : RequestListener<Drawable> { + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target<Drawable>?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + text.fadeIn() + return false + } - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean { - text.fadeIn() - return false - } - }).into(image) + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target<Drawable>?, + isFirstResource: Boolean + ): Boolean { + text.fadeIn() + return false + } + }).into(image) } else { text.visible() - image.setImageDrawable(GoogleMaterial.Icon.gmd_add_circle_outline.toDrawable(itemView.context, 100, Prefs.textColor)) + image.setImageDrawable( + GoogleMaterial.Icon.gmd_add_circle_outline.toDrawable( + itemView.context, + 100, + Prefs.textColor + ) + ) text.text = itemView.context.getString(R.string.kau_add_account) } } @@ -64,4 +101,4 @@ class AccountItem(val cookie: CookieModel?) : KauIItem<AccountItem, AccountItem. val image: ImageView by bindView(R.id.account_image) val text: AppCompatTextView by bindView(R.id.account_text) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt index 60713034..51a7a8e9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt @@ -1,54 +1,78 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.content.Context import android.graphics.drawable.GradientDrawable -import android.support.constraint.ConstraintLayout import android.util.AttributeSet -import android.widget.ImageView -import android.widget.TextView -import ca.allanwang.kau.utils.* +import androidx.constraintlayout.widget.ConstraintLayout +import ca.allanwang.kau.utils.colorToForeground +import ca.allanwang.kau.utils.dpToPx +import ca.allanwang.kau.utils.gone +import ca.allanwang.kau.utils.toDrawable +import ca.allanwang.kau.utils.visible +import ca.allanwang.kau.utils.withAlpha import com.mikepenz.iconics.typeface.IIcon import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.Prefs - +import kotlinx.android.synthetic.main.view_badged_icon.view.* /** * Created by Allan Wang on 2017-06-19. */ class BadgedIcon @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { - val badgeTextView: TextView by bindView(R.id.badge_text) - val badgeImage: ImageView by bindView(R.id.badge_image) - init { inflate(context, R.layout.view_badged_icon, this) val badgeColor = Prefs.mainActivityLayout.backgroundColor().withAlpha(255).colorToForeground(0.2f) - val badgeBackground = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(badgeColor, badgeColor)) + val badgeBackground = + GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(badgeColor, badgeColor)) badgeBackground.cornerRadius = 13.dpToPx.toFloat() - badgeTextView.background = badgeBackground - badgeTextView.setTextColor(Prefs.mainActivityLayout.iconColor()) + badge_text.background = badgeBackground + badge_text.setTextColor(Prefs.mainActivityLayout.iconColor()) } var iicon: IIcon? = null set(value) { field = value - badgeImage.setImageDrawable(value?.toDrawable(context, sizeDp = 20, color = Prefs.mainActivityLayout.iconColor())) + badge_image.setImageDrawable( + value?.toDrawable( + context, + sizeDp = 20, + color = Prefs.mainActivityLayout.iconColor() + ) + ) } fun setAllAlpha(alpha: Float) { //badgeTextView.setTextColor(Prefs.textColor.withAlpha(alpha.toInt())) - badgeImage.drawable.alpha = alpha.toInt() + badge_image.drawable.alpha = alpha.toInt() } var badgeText: String? - get() = badgeTextView.text.toString() + get() = badge_text.text.toString() set(value) { - if (badgeTextView.text == value) return - badgeTextView.text = value - if (value != null && value != "0") badgeTextView.visible() - else badgeTextView.gone() + if (badge_text.text == value) return + badge_text.text = value + if (value != null && value != "0") badge_text.visible() + else badge_text.gone() } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt index 19b1176e..d17a424c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt @@ -1,13 +1,36 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.content.Context import android.os.Build -import android.support.v4.widget.SwipeRefreshLayout import android.util.AttributeSet import android.view.View import android.widget.FrameLayout import android.widget.ProgressBar -import ca.allanwang.kau.utils.* +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import ca.allanwang.kau.utils.bindView +import ca.allanwang.kau.utils.circularReveal +import ca.allanwang.kau.utils.fadeIn +import ca.allanwang.kau.utils.fadeOut +import ca.allanwang.kau.utils.invisibleIf +import ca.allanwang.kau.utils.isVisible +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.withAlpha import com.pitchedapps.frost.R import com.pitchedapps.frost.contracts.FrostContentContainer import com.pitchedapps.frost.contracts.FrostContentCore @@ -24,25 +47,32 @@ import io.reactivex.subjects.BehaviorSubject import io.reactivex.subjects.PublishSubject class FrostContentWeb @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 ) : FrostContentView<FrostWebView>(context, attrs, defStyleAttr, defStyleRes) { override val layoutRes: Int = R.layout.view_content_base_web - } class FrostContentRecycler @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 ) : FrostContentView<FrostRecyclerView>(context, attrs, defStyleAttr, defStyleRes) { override val layoutRes: Int = R.layout.view_content_base_recycler - } abstract class FrostContentView<out T> @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, defStyleRes: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr, defStyleRes), - FrostContentParent where T : View, T : FrostContentCore { + FrostContentParent where T : View, T : FrostContentCore { private val refresh: SwipeRefreshLayout by bindView(R.id.content_refresh) private val progress: ProgressBar by bindView(R.id.content_progress) @@ -88,15 +118,14 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( }.addTo(compositeDisposable) refreshObservable - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - refresh.isRefreshing = it - refresh.isEnabled = true - }.addTo(compositeDisposable) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + refresh.isRefreshing = it + refresh.isEnabled = true + }.addTo(compositeDisposable) refresh.setOnRefreshListener { coreView.reload(true) } reloadThemeSelf() - } override fun bind(container: FrostContentContainer) { @@ -151,24 +180,24 @@ abstract class FrostContentView<out T> @JvmOverloads constructor( var loading = dispose != null dispose?.dispose() dispose = refreshObservable - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - if (it) { - loading = true - transitionStart = System.currentTimeMillis() - clearAnimation() - if (isVisible) - fadeOut(duration = 200L) - } else if (loading) { - loading = false - if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY) - else fadeIn(duration = 200L, offset = WEB_LOAD_DELAY) - L.v { "Transition loaded in ${System.currentTimeMillis() - transitionStart} ms" } - dispose?.dispose() - dispose = null - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + if (it) { + loading = true + transitionStart = System.currentTimeMillis() + clearAnimation() + if (isVisible) + fadeOut(duration = 200L) + } else if (loading) { + loading = false + if (animate && Prefs.animate) circularReveal(offset = WEB_LOAD_DELAY) + else fadeIn(duration = 200L, offset = WEB_LOAD_DELAY) + L.v { "Transition loaded in ${System.currentTimeMillis() - transitionStart} ms" } + dispose?.dispose() + dispose = null } + } } return true } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt index 38b09657..2b9e8f9c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt @@ -1,10 +1,26 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.content.Context -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.util.AttributeSet import android.view.View +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import ca.allanwang.kau.utils.circularReveal import ca.allanwang.kau.utils.fadeOut import com.pitchedapps.frost.contracts.FrostContentContainer @@ -18,9 +34,11 @@ import com.pitchedapps.frost.utils.Prefs * */ class FrostRecyclerView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : RecyclerView(context, attrs, defStyleAttr), - FrostContentCore { + FrostContentCore { override fun reload(animate: Boolean) = reloadBase(animate) @@ -102,5 +120,4 @@ class FrostRecyclerView @JvmOverloads constructor( override fun reloadTextSizeSelf() { // todo } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt index d7f44420..6ee34a2b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.annotation.SuppressLint @@ -27,7 +43,9 @@ import com.pitchedapps.frost.utils.Prefs * Parent must have layout with both height & width as match_parent */ class FrostVideoView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : VideoView(context, attrs, defStyleAttr) { /** @@ -79,7 +97,7 @@ class FrostVideoView @JvmOverloads constructor( if (!isPlaying) showControls() else viewerContract.onControlsHidden() } - }.start() + } } else { hideControls() val (scale, tX, tY) = mapBounds() @@ -90,7 +108,7 @@ class FrostVideoView @JvmOverloads constructor( withAnimator(origScale, scale) { scaleXY = it } withAnimator(origX, tX) { translationX = it } withAnimator(origY, tY) { translationY = it } - }.start() + } } } @@ -105,7 +123,10 @@ class FrostVideoView @JvmOverloads constructor( videoDimensions.set(dimen, dimen) } val portrait = height > width - val scale = Math.min(height / (if (portrait) 4f else 2.3f) / videoDimensions.y, width / (if (portrait) 2.3f else 4f) / videoDimensions.x) + val scale = Math.min( + height / (if (portrait) 4f else 2.3f) / videoDimensions.y, + width / (if (portrait) 2.3f else 4f) / videoDimensions.x + ) val desiredHeight = scale * videoDimensions.y val desiredWidth = scale * videoDimensions.x val padding = containerContract.lowerVideoPadding @@ -151,8 +172,8 @@ class FrostVideoView @JvmOverloads constructor( /** * Only remap if not expanded and if dimensions have changed */ - val shouldRemap = !isExpanded - && (videoDimensions.x != ratio * intrinsicWidth || videoDimensions.y != ratio * intrinsicHeight) + val shouldRemap = !isExpanded && + (videoDimensions.x != ratio * intrinsicWidth || videoDimensions.y != ratio * intrinsicHeight) videoDimensions.set(ratio * intrinsicWidth, ratio * intrinsicHeight) if (shouldRemap) updateLocation() } @@ -210,7 +231,7 @@ class FrostVideoView @JvmOverloads constructor( duration = FAST_ANIMATION_DURATION withAnimator(alpha, 0f) { alpha = it } withEndAction { onFinishedListener() } - }.start() + } else onFinishedListener() } @@ -226,7 +247,8 @@ class FrostVideoView @JvmOverloads constructor( * ------------------------------------------------------------------- */ - private inner class FrameTouchListener(context: Context) : GestureDetector.SimpleOnGestureListener(), View.OnTouchListener { + private inner class FrameTouchListener(context: Context) : GestureDetector.SimpleOnGestureListener(), + View.OnTouchListener { private val gestureDetector: GestureDetector = GestureDetector(context, this) @@ -252,7 +274,8 @@ class FrostVideoView @JvmOverloads constructor( /** * Monitors the view click events to show and hide the video controls if they have been specified. */ - private inner class VideoTouchListener(context: Context) : GestureDetector.SimpleOnGestureListener(), View.OnTouchListener { + private inner class VideoTouchListener(context: Context) : GestureDetector.SimpleOnGestureListener(), + View.OnTouchListener { private val gestureDetector: GestureDetector = GestureDetector(context, this) private val downLoc = PointF() @@ -315,4 +338,4 @@ class FrostVideoView @JvmOverloads constructor( return true } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt index 2d5e376d..c2535940 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt @@ -1,38 +1,58 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.content.Context import android.graphics.Color import android.graphics.PointF import android.net.Uri -import android.support.v7.widget.Toolbar import android.util.AttributeSet import android.view.MotionEvent -import android.view.View -import android.view.ViewGroup import android.view.ViewTreeObserver import android.widget.FrameLayout -import android.widget.ImageView -import ca.allanwang.kau.utils.* +import ca.allanwang.kau.utils.fadeIn +import ca.allanwang.kau.utils.fadeOut +import ca.allanwang.kau.utils.gone +import ca.allanwang.kau.utils.goneIf +import ca.allanwang.kau.utils.inflate +import ca.allanwang.kau.utils.isColorDark +import ca.allanwang.kau.utils.isGone +import ca.allanwang.kau.utils.isVisible +import ca.allanwang.kau.utils.setIcon +import ca.allanwang.kau.utils.setMenuIcons +import ca.allanwang.kau.utils.visible +import ca.allanwang.kau.utils.withMinAlpha import com.devbrackets.android.exomedia.listener.VideoControlsVisibilityListener import com.mikepenz.google_material_typeface_library.GoogleMaterial import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.frostDownload +import kotlinx.android.synthetic.main.view_video.view.* /** * Created by Allan Wang on 2017-10-13. */ class FrostVideoViewer @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : FrameLayout(context, attrs, defStyleAttr), FrostVideoViewerContract { - val container: ViewGroup by bindView(R.id.video_container) - val toolbar: Toolbar by bindView(R.id.video_toolbar) - val background: View by bindView(R.id.video_background) - val video: FrostVideoView by bindView(R.id.video) - val restarter: ImageView by bindView(R.id.video_restart) - companion object { /** * Matches VideoControls.CONTROL_VISIBILITY_ANIMATION_LENGTH @@ -59,29 +79,31 @@ class FrostVideoViewer @JvmOverloads constructor( init { inflate(R.layout.view_video, true) alpha = 0f - background.setBackgroundColor( - if (!Prefs.blackMediaBg && Prefs.bgColor.isColorDark) - Prefs.bgColor.withMinAlpha(200) - else - Color.BLACK) + video_background.setBackgroundColor( + if (!Prefs.blackMediaBg && Prefs.bgColor.isColorDark) + Prefs.bgColor.withMinAlpha(200) + else + Color.BLACK + ) video.setViewerContract(this) video.pause() - toolbar.inflateMenu(R.menu.menu_video) - context.setMenuIcons(toolbar.menu, Prefs.iconColor, - R.id.action_pip to GoogleMaterial.Icon.gmd_picture_in_picture_alt, - R.id.action_download to GoogleMaterial.Icon.gmd_file_download + video_toolbar.inflateMenu(R.menu.menu_video) + context.setMenuIcons( + video_toolbar.menu, Prefs.iconColor, + R.id.action_pip to GoogleMaterial.Icon.gmd_picture_in_picture_alt, + R.id.action_download to GoogleMaterial.Icon.gmd_file_download ) - toolbar.setOnMenuItemClickListener { + video_toolbar.setOnMenuItemClickListener { when (it.itemId) { R.id.action_pip -> video.isExpanded = false R.id.action_download -> context.frostDownload(video.videoUri) } true } - restarter.gone().setIcon(GoogleMaterial.Icon.gmd_replay, 64) - restarter.setOnClickListener { + video_restart.gone().setIcon(GoogleMaterial.Icon.gmd_replay, 64) + video_restart.setOnClickListener { video.restart() - restarter.fadeOut { restarter.gone() } + video_restart.fadeOut { video_restart.gone() } } } @@ -115,13 +137,13 @@ class FrostVideoViewer @JvmOverloads constructor( */ override fun onExpand(progress: Float) { - toolbar.goneIf(progress == 0f).alpha = progress - background.alpha = progress + video_toolbar.goneIf(progress == 0f).alpha = progress + video_background.alpha = progress } override fun onSingleTapConfirmed(event: MotionEvent): Boolean { - if (restarter.isVisible) { - restarter.performClick() + if (video_restart.isVisible) { + video_restart.performClick() return true } return false @@ -129,7 +151,7 @@ class FrostVideoViewer @JvmOverloads constructor( override fun onVideoComplete() { video.jumpToStart() - restarter.fadeIn() + video_restart.fadeIn() } fun updateLocation() { @@ -143,14 +165,13 @@ class FrostVideoViewer @JvmOverloads constructor( override fun onControlsShown() { if (video.isExpanded) - toolbar.fadeIn(duration = CONTROL_ANIMATION_DURATION, onStart = { toolbar.visible() }) + video_toolbar.fadeIn(duration = CONTROL_ANIMATION_DURATION, onStart = { video_toolbar.visible() }) } override fun onControlsHidden() { - if (!toolbar.isGone) - toolbar.fadeOut(duration = CONTROL_ANIMATION_DURATION) { toolbar.gone() } + if (!video_toolbar.isGone) + video_toolbar.fadeOut(duration = CONTROL_ANIMATION_DURATION) { video_toolbar.gone() } } - } interface FrostVideoViewerContract : VideoControlsVisibilityListener { @@ -180,4 +201,4 @@ interface FrostVideoContainerContract { * Called once the video has stopped & should be removed */ fun onVideoFinished() -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt index 8122d362..bf2f771d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt @@ -1,10 +1,26 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.annotation.SuppressLint import android.content.Context -import android.support.v4.view.ViewPager import android.util.AttributeSet import android.view.MotionEvent +import androidx.viewpager.widget.ViewPager import com.pitchedapps.frost.utils.Prefs /** @@ -12,21 +28,22 @@ import com.pitchedapps.frost.utils.Prefs * * Basic override to allow us to control swiping */ -class FrostViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : ViewPager(context, attrs) { +class FrostViewPager @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) : + ViewPager(context, attrs) { var enableSwipe = true override fun onInterceptTouchEvent(ev: MotionEvent?) = - try { - Prefs.viewpagerSwipe && enableSwipe && super.onInterceptTouchEvent(ev) - } catch (e: IllegalArgumentException) { - false - } + try { + Prefs.viewpagerSwipe && enableSwipe && super.onInterceptTouchEvent(ev) + } catch (e: IllegalArgumentException) { + false + } @SuppressLint("ClickableViewAccessibility") override fun onTouchEvent(ev: MotionEvent?): Boolean = - try { - Prefs.viewpagerSwipe && enableSwipe && super.onTouchEvent(ev) - } catch (e: IllegalArgumentException) { - false - } -}
\ No newline at end of file + try { + Prefs.viewpagerSwipe && enableSwipe && super.onTouchEvent(ev) + } catch (e: IllegalArgumentException) { + false + } +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt index 8230c338..b15ad5cf 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostWebView.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.animation.ValueAnimator @@ -16,16 +32,22 @@ import com.pitchedapps.frost.facebook.USER_AGENT_BASIC import com.pitchedapps.frost.fragments.WebFragment import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.frostDownload -import com.pitchedapps.frost.web.* +import com.pitchedapps.frost.web.FrostChromeClient +import com.pitchedapps.frost.web.FrostJSI +import com.pitchedapps.frost.web.FrostWebViewClient +import com.pitchedapps.frost.web.NestedWebView +import com.pitchedapps.frost.web.shouldUseBasicAgent /** * Created by Allan Wang on 2017-05-29. * */ class FrostWebView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : NestedWebView(context, attrs, defStyleAttr), - FrostContentCore { + FrostContentCore { override fun reload(animate: Boolean) { if (parent.registerTransition(false, animate)) @@ -59,7 +81,6 @@ class FrostWebView @JvmOverloads constructor( return this } - /** * Wrapper to the main userAgentString to cache it. * This decouples it from the UiThread @@ -168,4 +189,4 @@ class FrostWebView @JvmOverloads constructor( super.destroy() } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt index 14f77e72..7f0d792a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/KPrefTextSeekbar.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.annotation.SuppressLint @@ -43,4 +59,4 @@ class KPrefTextSeekbar(builder: KPrefSeekbarContract) : KPrefSeekbar(builder) { holder.desc?.setTextSize(TypedValue.COMPLEX_UNIT_PX, descOriginalSize) super.unbindView(holder) } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt index 8092133b..e63fcc21 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt @@ -1,15 +1,31 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.views import android.content.Context import android.graphics.drawable.Drawable -import android.support.constraint.ConstraintLayout -import android.support.v7.widget.AppCompatEditText -import android.support.v7.widget.AppCompatTextView -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.util.AttributeSet import android.view.View import android.widget.ImageView +import androidx.appcompat.widget.AppCompatEditText +import androidx.appcompat.widget.AppCompatTextView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.string import ca.allanwang.kau.utils.tint @@ -23,12 +39,13 @@ import com.mikepenz.iconics.typeface.IIcon import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.Prefs - /** * Created by Allan Wang on 2017-06-19. */ class Keywords @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { val editText: AppCompatEditText by bindView(R.id.edit_text) @@ -51,7 +68,8 @@ class Keywords @JvmOverloads constructor( recycler.layoutManager = LinearLayoutManager(context) recycler.adapter = adapter adapter.withEventHook(object : ClickEventHook<KeywordItem>() { - override fun onBind(viewHolder: RecyclerView.ViewHolder): View? = (viewHolder as? KeywordItem.ViewHolder)?.delete + override fun onBind(viewHolder: RecyclerView.ViewHolder): View? = + (viewHolder as? KeywordItem.ViewHolder)?.delete override fun onClick(v: View, position: Int, fastAdapter: FastAdapter<KeywordItem>, item: KeywordItem) { adapter.remove(position) @@ -62,7 +80,6 @@ class Keywords @JvmOverloads constructor( fun save() { Prefs.notificationKeywords = adapter.adapterItems.mapTo(mutableSetOf()) { it.keyword } } - } private fun IIcon.keywordDrawable(context: Context): Drawable = toDrawable(context, 20, Prefs.textColor) @@ -94,4 +111,4 @@ class KeywordItem(val keyword: String) : AbstractItem<KeywordItem, KeywordItem.V delete.setImageDrawable(GoogleMaterial.Icon.gmd_delete.keywordDrawable(itemView.context)) } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt index ac62f142..bb196221 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt @@ -1,13 +1,29 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.annotation.SuppressLint import android.content.Context import android.graphics.Bitmap import android.graphics.Color -import android.support.annotation.WorkerThread import android.util.AttributeSet import android.view.View import android.webkit.WebView +import androidx.annotation.WorkerThread import com.pitchedapps.frost.facebook.USER_AGENT_BASIC import com.pitchedapps.frost.injectors.CssAssets import com.pitchedapps.frost.injectors.CssHider @@ -25,7 +41,9 @@ import java.io.File * A barebone webview with a refresh listener */ class DebugWebView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : WebView(context, attrs, defStyleAttr) { var onPageFinished: (String?) -> Unit = {} @@ -71,25 +89,27 @@ class DebugWebView @JvmOverloads constructor( private fun injectBackgroundColor() { setBackgroundColor( - if (url.isFacebookUrl) Prefs.bgColor.withAlpha(255) - else Color.WHITE) + if (url.isFacebookUrl) Prefs.bgColor.withAlpha(255) + else Color.WHITE + ) } - override fun onPageCommitVisible(view: WebView, url: String?) { super.onPageCommitVisible(view, url) injectBackgroundColor() if (url.isFacebookUrl) view.jsInject( - CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons), + CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons), // CssHider.CORE, - CssHider.COMPOSER.maybe(!Prefs.showComposer), - CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends), - CssHider.SUGGESTED_GROUPS.maybe(!Prefs.showSuggestedGroups), - Prefs.themeInjector, - CssHider.NON_RECENT.maybe((url?.contains("?sk=h_chr") ?: false) - && Prefs.aggressiveRecents)) + CssHider.COMPOSER.maybe(!Prefs.showComposer), + CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends), + CssHider.SUGGESTED_GROUPS.maybe(!Prefs.showSuggestedGroups), + Prefs.themeInjector, + CssHider.NON_RECENT.maybe( + (url?.contains("?sk=h_chr") ?: false) && + Prefs.aggressiveRecents + ) + ) } } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt index 3c3c063a..12df8000 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt @@ -1,7 +1,27 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.net.Uri -import android.webkit.* +import android.webkit.ConsoleMessage +import android.webkit.GeolocationPermissions +import android.webkit.ValueCallback +import android.webkit.WebChromeClient +import android.webkit.WebView import ca.allanwang.kau.permissions.PERMISSION_ACCESS_FINE_LOCATION import ca.allanwang.kau.permissions.kauRequestPermissions import com.pitchedapps.frost.R @@ -12,7 +32,6 @@ import com.pitchedapps.frost.views.FrostWebView import io.reactivex.subjects.BehaviorSubject import io.reactivex.subjects.Subject - /** * Created by Allan Wang on 2017-05-31. * @@ -45,9 +64,13 @@ class FrostChromeClient(web: FrostWebView) : WebChromeClient() { progress.onNext(newProgress) } - override fun onShowFileChooser(webView: WebView, filePathCallback: ValueCallback<Array<Uri>?>, fileChooserParams: FileChooserParams): Boolean { + override fun onShowFileChooser( + webView: WebView, + filePathCallback: ValueCallback<Array<Uri>?>, + fileChooserParams: FileChooserParams + ): Boolean { activity?.openFileChooser(filePathCallback, fileChooserParams) - ?: webView.frostSnackbar(R.string.file_chooser_not_found) + ?: webView.frostSnackbar(R.string.file_chooser_not_found) return activity != null } @@ -58,6 +81,4 @@ class FrostChromeClient(web: FrostWebView) : WebChromeClient() { callback(origin, granted, true) } } - - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt index 564b0e04..2afb28c9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.webkit.JavascriptInterface @@ -5,11 +21,16 @@ import com.pitchedapps.frost.activities.MainActivity import com.pitchedapps.frost.contracts.MainActivityContract import com.pitchedapps.frost.contracts.VideoViewHolder import com.pitchedapps.frost.facebook.FbCookie -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.WebContext +import com.pitchedapps.frost.utils.cookies +import com.pitchedapps.frost.utils.isIndependent +import com.pitchedapps.frost.utils.launchImageActivity +import com.pitchedapps.frost.utils.showWebContextMenu import com.pitchedapps.frost.views.FrostWebView import io.reactivex.subjects.Subject - /** * Created by Allan Wang on 2017-06-01. */ @@ -31,15 +52,15 @@ class FrostJSI(val web: FrostWebView) { @JavascriptInterface fun loadVideo(url: String?, isGif: Boolean): Boolean = - if (url != null && Prefs.enablePip) { - web.post { - (context as? VideoViewHolder)?.showVideo(url, isGif) - ?: L.e { "Could not load video; contract not implemented" } - } - true - } else { - false + if (url != null && Prefs.enablePip) { + web.post { + (context as? VideoViewHolder)?.showVideo(url, isGif) + ?: L.e { "Could not load video; contract not implemented" } } + true + } else { + false + } @JavascriptInterface fun reloadBaseUrl(animate: Boolean) { @@ -113,5 +134,4 @@ class FrostJSI(val web: FrostWebView) { html ?: return header?.onNext(html) } - -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt index 4e4df027..bd696b02 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.webkit.WebResourceRequest @@ -8,14 +24,19 @@ import com.pitchedapps.frost.utils.L import okhttp3.HttpUrl import java.io.ByteArrayInputStream - /** * Created by Allan Wang on 2017-07-13. * * Handler to decide when a request should be done by us * This is the crux of Frost's optimizations for the web browser */ -private val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) } +private val blankResource: WebResourceResponse by lazy { + WebResourceResponse( + "text/plain", + "utf-8", + ByteArrayInputStream("".toByteArray()) + ) +} fun WebView.shouldFrostInterceptRequest(request: WebResourceRequest): WebResourceResponse? { val requestUrl = request.url?.toString() ?: return null @@ -46,12 +67,13 @@ val WebResourceRequest.isMedia: Boolean * Generic filter passthrough * If Resource is already nonnull, pass it, otherwise check if filter is met and override the response accordingly */ -fun WebResourceResponse?.filter(request: WebResourceRequest, filter: (url: String) -> Boolean) = filter(request.query { filter(it) }) +fun WebResourceResponse?.filter(request: WebResourceRequest, filter: (url: String) -> Boolean) = + filter(request.query { filter(it) }) fun WebResourceResponse?.filter(filter: Boolean): WebResourceResponse? = this - ?: if (filter) blankResource else null + ?: if (filter) blankResource else null -fun WebResourceResponse?.filterCss(request: WebResourceRequest): WebResourceResponse? = filter(request) { it.endsWith(".css") } +fun WebResourceResponse?.filterCss(request: WebResourceRequest): WebResourceResponse? = + filter(request) { it.endsWith(".css") } fun WebResourceResponse?.filterImage(request: WebResourceRequest): WebResourceResponse? = filter(request.isImage) - diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt index b83002a3..e2d294f7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import com.pitchedapps.frost.activities.WebOverlayActivity @@ -8,7 +24,15 @@ import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.USER_AGENT_BASIC import com.pitchedapps.frost.facebook.formattedFbUrl -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.isImageUrl +import com.pitchedapps.frost.utils.isIndependent +import com.pitchedapps.frost.utils.isIndirectImageUrl +import com.pitchedapps.frost.utils.isVideoUrl +import com.pitchedapps.frost.utils.launchImageActivity +import com.pitchedapps.frost.utils.launchWebOverlay +import com.pitchedapps.frost.utils.launchWebOverlayBasic import com.pitchedapps.frost.views.FrostWebView import org.jetbrains.anko.runOnUiThread @@ -77,14 +101,14 @@ fun FrostWebView.requestWebOverlay(url: String): Boolean { * If the url contains any one of the whitelist segments, switch to the chat overlay */ val messageWhitelist: Set<String> = - setOf(FbItem.MESSAGES, FbItem.CHAT, FbItem.FEED_MOST_RECENT, FbItem.FEED_TOP_STORIES) - .mapTo(mutableSetOf(), FbItem::url) + setOf(FbItem.MESSAGES, FbItem.CHAT, FbItem.FEED_MOST_RECENT, FbItem.FEED_TOP_STORIES) + .mapTo(mutableSetOf(), FbItem::url) val String.shouldUseBasicAgent: Boolean get() { - if (contains("story.php")) // do not use basic for comment section + if (contains("story.php")) // do not use basic for comment section return false - if (contains("/events/")) // do not use for events (namely the map) + if (contains("/events/")) // do not use for events (namely the map) return false - return true // use for everything else - }
\ No newline at end of file + return true // use for everything else + } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt index 8824e635..d75f03bb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.graphics.Bitmap @@ -10,8 +26,19 @@ import com.pitchedapps.frost.facebook.FB_URL_BASE import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.facebook.formattedFbUrl -import com.pitchedapps.frost.injectors.* -import com.pitchedapps.frost.utils.* +import com.pitchedapps.frost.injectors.CssAssets +import com.pitchedapps.frost.injectors.CssHider +import com.pitchedapps.frost.injectors.JsActions +import com.pitchedapps.frost.injectors.JsAssets +import com.pitchedapps.frost.injectors.jsInject +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import com.pitchedapps.frost.utils.isExplicitIntent +import com.pitchedapps.frost.utils.isFacebookUrl +import com.pitchedapps.frost.utils.isImageUrl +import com.pitchedapps.frost.utils.isIndirectImageUrl +import com.pitchedapps.frost.utils.launchImageActivity +import com.pitchedapps.frost.utils.resolveActivityForUri import com.pitchedapps.frost.views.FrostWebView import io.reactivex.subjects.Subject import org.jetbrains.anko.withAlpha @@ -28,8 +55,8 @@ import org.jetbrains.anko.withAlpha */ open class BaseWebViewClient : WebViewClient() { - override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? = view.shouldFrostInterceptRequest(request) - + override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? = + view.shouldFrostInterceptRequest(request) } /** @@ -51,11 +78,11 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() { private fun injectBackgroundColor() { web.setBackgroundColor( - when { - isMain -> Color.TRANSPARENT - web.url.isFacebookUrl -> Prefs.bgColor.withAlpha(255) - else -> Color.WHITE - } + when { + isMain -> Color.TRANSPARENT + web.url.isFacebookUrl -> Prefs.bgColor.withAlpha(255) + else -> Color.WHITE + } ) } @@ -64,21 +91,24 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() { injectBackgroundColor() if (url.isFacebookUrl) view.jsInject( - CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons), + CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons), // CssHider.CORE, - CssHider.HEADER, - CssHider.COMPOSER.maybe(!Prefs.showComposer), - CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends), - CssHider.SUGGESTED_GROUPS.maybe(!Prefs.showSuggestedGroups), - Prefs.themeInjector, - CssHider.NON_RECENT.maybe((web.url?.contains("?sk=h_chr") ?: false) - && Prefs.aggressiveRecents), - JsAssets.DOCUMENT_WATCHER, - JsAssets.CLICK_A, - CssHider.ADS.maybe(!Prefs.showFacebookAds), - JsAssets.CONTEXT_A, + CssHider.HEADER, + CssHider.COMPOSER.maybe(!Prefs.showComposer), + CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends), + CssHider.SUGGESTED_GROUPS.maybe(!Prefs.showSuggestedGroups), + Prefs.themeInjector, + CssHider.NON_RECENT.maybe( + (web.url?.contains("?sk=h_chr") ?: false) && + Prefs.aggressiveRecents + ), + JsAssets.DOCUMENT_WATCHER, + JsAssets.CLICK_A, + CssHider.ADS.maybe(!Prefs.showFacebookAds), + JsAssets.CONTEXT_A, // JsAssets.HEADER_HIDER, - JsAssets.MEDIA) + JsAssets.MEDIA + ) else refresh.onNext(false) } @@ -104,9 +134,10 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() { refresh.onNext(false) injectBackgroundColor() web.jsInject( - JsActions.LOGIN_CHECK, - JsAssets.TEXTAREA_LISTENER, - JsAssets.HEADER_BADGES.maybe(isMain)) + JsActions.LOGIN_CHECK, + JsAssets.TEXTAREA_LISTENER, + JsAssets.HEADER_BADGES.maybe(isMain) + ) } open fun handleHtml(html: String?) { @@ -151,7 +182,6 @@ open class FrostWebViewClient(val web: FrostWebView) : BaseWebViewClient() { if (Prefs.linksInDefaultApp && view.context.resolveActivityForUri(request.url)) return true return super.shouldOverrideUrlLoading(view, request) } - } private const val EMIT_THEME = 0b1 @@ -189,4 +219,4 @@ class FrostWebViewClientMenu(web: FrostWebView) : FrostWebViewClient(web) { v { "Should inject ${url.shouldInjectMenu}" } if (!url.shouldInjectMenu) injectAndFinish() } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt index 1f22f303..392cb353 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.annotation.SuppressLint @@ -5,7 +21,11 @@ import android.content.Context import android.graphics.Color import android.util.AttributeSet import android.view.View -import android.webkit.* +import android.webkit.ConsoleMessage +import android.webkit.CookieManager +import android.webkit.WebChromeClient +import android.webkit.WebResourceRequest +import android.webkit.WebView import ca.allanwang.kau.utils.fadeIn import ca.allanwang.kau.utils.isVisible import com.pitchedapps.frost.dbflow.CookieModel @@ -26,7 +46,9 @@ import org.jetbrains.anko.uiThread * Created by Allan Wang on 2017-05-29. */ class LoginWebView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : WebView(context, attrs, defStyleAttr) { private lateinit var loginCallback: (CookieModel) -> Unit @@ -73,9 +95,11 @@ class LoginWebView @JvmOverloads constructor( L.d { "Login page commit visible" } view.setBackgroundColor(Color.TRANSPARENT) if (url.isFacebookUrl) - view.jsInject(JsAssets.HEADER_HIDER, - CssHider.CORE, - Prefs.themeInjector) + view.jsInject( + JsAssets.HEADER_HIDER, + CssHider.CORE, + Prefs.themeInjector + ) } override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { @@ -97,4 +121,4 @@ class LoginWebView @JvmOverloads constructor( progressCallback(newProgress) } } -}
\ No newline at end of file +} diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/NestedWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/NestedWebView.kt index 297c4158..6e7fc0b6 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/NestedWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/NestedWebView.kt @@ -1,14 +1,29 @@ +/* + * Copyright 2018 Allan Wang + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ package com.pitchedapps.frost.web import android.annotation.SuppressLint import android.content.Context -import android.support.v4.view.NestedScrollingChild -import android.support.v4.view.NestedScrollingChildHelper -import android.support.v4.view.ViewCompat import android.util.AttributeSet import android.view.MotionEvent import android.webkit.WebView - +import androidx.core.view.NestedScrollingChild +import androidx.core.view.NestedScrollingChildHelper +import androidx.core.view.ViewCompat /** * Created by Allan Wang on 20/12/17. @@ -16,7 +31,9 @@ import android.webkit.WebView * Webview extension that handles nested scrolls */ open class NestedWebView @JvmOverloads constructor( - context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 ) : WebView(context, attrs, defStyleAttr), NestedScrollingChild { private lateinit var childHelper: NestedScrollingChildHelper @@ -99,11 +116,20 @@ open class NestedWebView @JvmOverloads constructor( final override fun hasNestedScrollingParent() = childHelper.hasNestedScrollingParent() - final override fun dispatchNestedScroll(dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int, dyUnconsumed: Int, offsetInWindow: IntArray?) = childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow) + final override fun dispatchNestedScroll( + dxConsumed: Int, + dyConsumed: Int, + dxUnconsumed: Int, + dyUnconsumed: Int, + offsetInWindow: IntArray? + ) = childHelper.dispatchNestedScroll(dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, offsetInWindow) - final override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?) = childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow) + final override fun dispatchNestedPreScroll(dx: Int, dy: Int, consumed: IntArray?, offsetInWindow: IntArray?) = + childHelper.dispatchNestedPreScroll(dx, dy, consumed, offsetInWindow) - final override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean) = childHelper.dispatchNestedFling(velocityX, velocityY, consumed) + final override fun dispatchNestedFling(velocityX: Float, velocityY: Float, consumed: Boolean) = + childHelper.dispatchNestedFling(velocityX, velocityY, consumed) - final override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float) = childHelper.dispatchNestedPreFling(velocityX, velocityY) -}
\ No newline at end of file + final override fun dispatchNestedPreFling(velocityX: Float, velocityY: Float) = + childHelper.dispatchNestedPreFling(velocityX, velocityY) +} |