From 88b40736874a876576e1dc6c49c299fdfeb600bb Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 23 Dec 2018 20:04:08 -0500 Subject: [PATCH 1/5] Migrate to androidx (#1257) * Initial migration * Update gradle wrapper * Update iconics and revert progressanimator api * Clean up imports * Update dependencies and address some lint issues * Update constants * Remove extra import --- app/build.gradle | 13 ++++----- app/src/main/AndroidManifest.xml | 2 +- .../frost/activities/AboutActivity.kt | 14 +++++----- .../frost/activities/BaseMainActivity.kt | 16 +++++------ .../frost/activities/DebugActivity.kt | 6 ++-- .../frost/activities/ImageActivity.kt | 2 +- .../frost/activities/IntroActivity.kt | 8 +++--- .../frost/activities/LoginActivity.kt | 6 ++-- .../frost/activities/MainActivity.kt | 4 +-- .../frost/activities/SelectorActivity.kt | 8 +++--- .../frost/activities/SettingsActivity.kt | 2 +- .../frost/activities/TabCustomizerActivity.kt | 10 +++---- .../frost/activities/WebOverlayActivity.kt | 10 +++---- .../com/pitchedapps/frost/enums/FeedSort.kt | 2 +- .../com/pitchedapps/frost/enums/Support.kt | 2 +- .../com/pitchedapps/frost/enums/Theme.kt | 2 +- .../com/pitchedapps/frost/facebook/FbItem.kt | 6 ++-- .../frost/fragments/FragmentBase.kt | 4 +-- .../frost/intro/IntroMainFragments.kt | 4 +-- .../frost/services/FrostNotifications.kt | 6 ++-- .../frost/services/NotificationService.kt | 2 +- .../frost/services/NotificationUtils.kt | 8 +++--- .../frost/utils/AnimatedVectorDelegate.kt | 2 +- .../com/pitchedapps/frost/utils/Utils.kt | 10 +++---- .../pitchedapps/frost/views/AccountItem.kt | 4 +-- .../com/pitchedapps/frost/views/BadgedIcon.kt | 2 +- .../frost/views/FrostContentView.kt | 2 +- .../frost/views/FrostRecyclerView.kt | 4 +-- .../pitchedapps/frost/views/FrostVideoView.kt | 6 ++-- .../frost/views/FrostVideoViewer.kt | 2 +- .../pitchedapps/frost/views/FrostViewPager.kt | 2 +- .../com/pitchedapps/frost/views/Keywords.kt | 10 +++---- .../com/pitchedapps/frost/web/DebugWebView.kt | 2 +- .../pitchedapps/frost/web/NestedWebView.kt | 6 ++-- .../{frost_f_256.xml => frost_f_200.xml} | 4 +-- app/src/main/res/layout/activity_debug.xml | 10 +++---- app/src/main/res/layout/activity_image.xml | 6 ++-- .../res/layout/activity_image_textless.xml | 6 ++-- app/src/main/res/layout/activity_intro.xml | 8 +++--- app/src/main/res/layout/activity_invalid.xml | 4 +-- app/src/main/res/layout/activity_login.xml | 6 ++-- app/src/main/res/layout/activity_main.xml | 8 +++--- .../res/layout/activity_main_bottom_tabs.xml | 8 +++--- app/src/main/res/layout/activity_selector.xml | 8 +++--- .../res/layout/activity_tab_customizer.xml | 6 ++-- .../main/res/layout/activity_web_overlay.xml | 6 ++-- app/src/main/res/layout/iitem_menu.xml | 4 +-- .../main/res/layout/iitem_notification.xml | 4 +-- app/src/main/res/layout/intro_end.xml | 6 ++-- app/src/main/res/layout/intro_image.xml | 4 +-- app/src/main/res/layout/intro_theme.xml | 4 +-- app/src/main/res/layout/intro_welcome.xml | 6 ++-- app/src/main/res/layout/item_about_links.xml | 2 +- app/src/main/res/layout/item_keyword.xml | 2 +- app/src/main/res/layout/login_webview.xml | 6 ++-- .../res/layout/material_drawer_header.xml | 4 +-- app/src/main/res/layout/view_account.xml | 4 +-- app/src/main/res/layout/view_badged_icon.xml | 8 +++--- .../res/layout/view_content_base_recycler.xml | 4 +-- .../main/res/layout/view_content_base_web.xml | 4 +-- app/src/main/res/layout/view_keywords.xml | 8 +++--- app/src/main/res/layout/view_main_fab.xml | 2 +- .../main/res/layout/view_main_tab_layout.xml | 2 +- app/src/main/res/layout/view_main_toolbar.xml | 2 +- app/src/main/res/layout/view_video.xml | 2 +- build.gradle | 2 +- gradle.properties | 28 +++++++++++-------- gradle/wrapper/gradle-wrapper.properties | 3 +- 68 files changed, 192 insertions(+), 188 deletions(-) rename app/src/main/res/drawable/{frost_f_256.xml => frost_f_200.xml} (89%) diff --git a/app/build.gradle b/app/build.gradle index 34e57f84a..2c7c5bcc4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -23,7 +23,7 @@ android { versionCode androidGitVersion.code() versionName androidGitVersion.name() multiDexEnabled true - testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } applicationVariants.all { variant -> @@ -148,14 +148,13 @@ repositories { } dependencies { - androidTestImplementation("com.android.support.test:runner:${kau.testRunner}") { - exclude group: 'com.android.support', module: 'support-annotations' - } - - implementation "com.android.support:exifinterface:${kau.supportLibs}" + implementation 'androidx.exifinterface:exifinterface:1.0.0' androidTestImplementation kauDependency.kotlinTest - androidTestImplementation "com.android.support.test:rules:${TEST_RULE}" + androidTestImplementation kauDependency.espresso + androidTestImplementation kauDependency.testRules + androidTestImplementation kauDependency.testRunner + testImplementation kauDependency.kotlinTest testImplementation "org.jetbrains.kotlin:kotlin-reflect:${KOTLIN}" testImplementation kauDependency.junit diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index bdfb5688b..ed1975109 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -156,7 +156,7 @@ 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 2261328d9..4d333099e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt @@ -1,8 +1,8 @@ package com.pitchedapps.frost.activities -import android.support.constraint.ConstraintLayout -import android.support.constraint.ConstraintSet -import android.support.v7.widget.RecyclerView +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintSet +import androidx.recyclerview.widget.RecyclerView import android.view.View import android.view.ViewGroup import android.widget.ImageView @@ -34,7 +34,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 @@ -137,10 +137,10 @@ class AboutActivity : AboutActivityBase(null, { val size = c.dimenPixelSize(R.dimen.kau_avatar_bounds) images = arrayOf 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.Icon2.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) } + 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) 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 2fce69a81..52f61bea9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -8,14 +8,14 @@ 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 androidx.annotation.StringRes +import com.google.android.material.appbar.AppBarLayout +import androidx.coordinatorlayout.widget.CoordinatorLayout +import com.google.android.material.floatingactionbutton.FloatingActionButton +import com.google.android.material.tabs.TabLayout +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentPagerAdapter +import androidx.appcompat.widget.Toolbar import android.view.Menu import android.view.MenuItem import android.webkit.ValueCallback 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 9b1d8e79c..9a90f0903 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt @@ -5,9 +5,9 @@ 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 com.google.android.material.floatingactionbutton.FloatingActionButton +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import androidx.appcompat.widget.Toolbar import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.setIcon 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 30a771076..348b36b94 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -5,7 +5,7 @@ import android.content.res.ColorStateList import android.graphics.Color import android.os.Bundle import android.os.Environment -import android.support.design.widget.FloatingActionButton +import com.google.android.material.floatingactionbutton.FloatingActionButton import android.view.View import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.logging.KauLoggerExtension 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 4b00c242a..c41229daa 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt @@ -4,10 +4,10 @@ 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 androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter +import androidx.viewpager.widget.ViewPager import android.view.View import android.view.WindowManager import android.widget.Button 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 b5e2119f5..9c8a60aa1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -3,9 +3,9 @@ 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 androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import androidx.appcompat.widget.AppCompatTextView +import androidx.appcompat.widget.Toolbar import android.widget.ImageView import ca.allanwang.kau.utils.bindView import ca.allanwang.kau.utils.fadeIn 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 bf8120de2..2555fe5bb 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,8 @@ package com.pitchedapps.frost.activities import android.os.Bundle -import android.support.design.widget.TabLayout -import android.support.v4.view.ViewPager +import com.google.android.material.tabs.TabLayout +import androidx.viewpager.widget.ViewPager import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.views.BadgedIcon import io.reactivex.android.schedulers.AndroidSchedulers 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 58ab3dac3..514af197a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SelectorActivity.kt @@ -1,10 +1,10 @@ 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 androidx.constraintlayout.widget.ConstraintLayout +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView import android.view.View import ca.allanwang.kau.utils.bindView import com.mikepenz.fastadapter.FastAdapter 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 7561dc88d..7663b70f1 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -100,7 +100,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()) { 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 7b2cfbf22..1938add0e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt @@ -3,10 +3,10 @@ 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 com.google.android.material.floatingactionbutton.FloatingActionButton +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import androidx.recyclerview.widget.ItemTouchHelper import android.view.View import android.view.animation.AnimationUtils import android.widget.TextView @@ -50,7 +50,7 @@ class TabCustomizerActivity : BaseActivity() { toolbar.setBackgroundColor(Prefs.headerColor) - recycler.layoutManager = GridLayoutManager(this, TAB_COUNT, GridLayoutManager.VERTICAL, false) + recycler.layoutManager = GridLayoutManager(this, TAB_COUNT, RecyclerView.VERTICAL, false) recycler.adapter = adapter recycler.setHasFixedSize(true) 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 323a2eb53..6d930fff9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt @@ -5,9 +5,8 @@ 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 androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.appcompat.widget.Toolbar import android.view.Menu import android.view.MenuItem import android.webkit.ValueCallback @@ -16,6 +15,7 @@ import android.widget.FrameLayout import ca.allanwang.kau.swipe.kauSwipeOnCreate import ca.allanwang.kau.swipe.kauSwipeOnDestroy import ca.allanwang.kau.utils.* +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 @@ -168,7 +168,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() } } } @@ -248,7 +248,7 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc overlayContext?.onMenuCreate(this, menu) toolbar.tint(Prefs.iconColor) setMenuIcons(menu, Prefs.iconColor, - R.id.action_share to CommunityMaterial.Icon.cmd_share, + R.id.action_share to CommunityMaterial.Icon2.cmd_share, R.id.action_copy_link to GoogleMaterial.Icon.gmd_content_copy) return true } 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 d2de99883..d8a0f349e 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,6 @@ 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 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 ef3c88b6f..34fa4b5f8 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,7 @@ 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 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 ada0b456c..934dda07e 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,7 @@ 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 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 d6915f75b..2f0e4e227 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,6 @@ 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 @@ -25,14 +25,14 @@ enum class FbItem( 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/fragments/FragmentBase.kt b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt index cf48893c7..34e28c2e9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/fragments/FragmentBase.kt @@ -2,8 +2,8 @@ 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 com.google.android.material.floatingactionbutton.FloatingActionButton +import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup 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 39a39232a..6e9537771 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt @@ -3,8 +3,8 @@ 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 androidx.constraintlayout.widget.ConstraintLayout +import androidx.fragment.app.Fragment import android.view.LayoutInflater import android.view.View import android.view.ViewGroup 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 295dbe0c5..ededaad49 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/FrostNotifications.kt @@ -8,8 +8,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 @@ -206,7 +206,7 @@ enum class NotificationType( .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) 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 56ff4db7c..f15df482b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt @@ -2,7 +2,7 @@ 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 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 59352f8e6..707220f64 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationUtils.kt @@ -11,8 +11,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 @@ -70,8 +70,8 @@ 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 { 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 8d800e9ba..223eed3f7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt @@ -1,7 +1,7 @@ package com.pitchedapps.frost.utils import android.graphics.drawable.AnimatedVectorDrawable -import android.support.annotation.DrawableRes +import androidx.annotation.DrawableRes import android.widget.ImageView import ca.allanwang.kau.utils.drawable 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 6c78d922c..650f277bf 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -8,11 +8,10 @@ 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 androidx.annotation.StringRes +import com.google.android.material.snackbar.Snackbar +import androidx.core.content.FileProvider +import androidx.appcompat.widget.Toolbar import android.view.View import android.widget.FrameLayout import android.widget.TextView @@ -23,6 +22,7 @@ import ca.allanwang.kau.mediapicker.createPrivateMediaFile import ca.allanwang.kau.utils.* import ca.allanwang.kau.xml.showChangelog import com.afollestad.materialdialogs.MaterialDialog +import com.google.android.material.snackbar.SnackbarContentLayout import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.R import com.pitchedapps.frost.activities.* 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 7262fa172..9f6d0c065 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/AccountItem.kt @@ -1,8 +1,8 @@ package com.pitchedapps.frost.views import android.graphics.drawable.Drawable -import android.support.v7.widget.AppCompatTextView -import android.support.v7.widget.RecyclerView +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.RecyclerView import android.view.View import android.widget.ImageView import ca.allanwang.kau.iitems.KauIItem 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 60713034d..926205678 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt @@ -2,7 +2,7 @@ package com.pitchedapps.frost.views import android.content.Context import android.graphics.drawable.GradientDrawable -import android.support.constraint.ConstraintLayout +import androidx.constraintlayout.widget.ConstraintLayout import android.util.AttributeSet import android.widget.ImageView import android.widget.TextView 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 19b1176e5..c44a81883 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostContentView.kt @@ -2,7 +2,7 @@ package com.pitchedapps.frost.views import android.content.Context import android.os.Build -import android.support.v4.widget.SwipeRefreshLayout +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import android.util.AttributeSet import android.view.View import android.widget.FrameLayout 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 38b09657c..198694263 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostRecyclerView.kt @@ -1,8 +1,8 @@ package com.pitchedapps.frost.views import android.content.Context -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import android.util.AttributeSet import android.view.View import ca.allanwang.kau.utils.circularReveal 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 d7f444204..85dc7e189 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoView.kt @@ -79,7 +79,7 @@ class FrostVideoView @JvmOverloads constructor( if (!isPlaying) showControls() else viewerContract.onControlsHidden() } - }.start() + } } else { hideControls() val (scale, tX, tY) = mapBounds() @@ -90,7 +90,7 @@ class FrostVideoView @JvmOverloads constructor( withAnimator(origScale, scale) { scaleXY = it } withAnimator(origX, tX) { translationX = it } withAnimator(origY, tY) { translationY = it } - }.start() + } } } @@ -210,7 +210,7 @@ class FrostVideoView @JvmOverloads constructor( duration = FAST_ANIMATION_DURATION withAnimator(alpha, 0f) { alpha = it } withEndAction { onFinishedListener() } - }.start() + } else onFinishedListener() } 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 2d5e376df..5afb3a21a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt @@ -4,7 +4,7 @@ import android.content.Context import android.graphics.Color import android.graphics.PointF import android.net.Uri -import android.support.v7.widget.Toolbar +import androidx.appcompat.widget.Toolbar import android.util.AttributeSet import android.view.MotionEvent import android.view.View 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 8122d3628..18b7ae491 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostViewPager.kt @@ -2,7 +2,7 @@ package com.pitchedapps.frost.views import android.annotation.SuppressLint import android.content.Context -import android.support.v4.view.ViewPager +import androidx.viewpager.widget.ViewPager import android.util.AttributeSet import android.view.MotionEvent import com.pitchedapps.frost.utils.Prefs 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 8092133b4..c171ce772 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/Keywords.kt @@ -2,11 +2,11 @@ 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 androidx.constraintlayout.widget.ConstraintLayout +import androidx.appcompat.widget.AppCompatEditText +import androidx.appcompat.widget.AppCompatTextView +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import android.util.AttributeSet import android.view.View import android.widget.ImageView 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 ac62f1425..4ce6f005c 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/DebugWebView.kt @@ -4,7 +4,7 @@ import android.annotation.SuppressLint import android.content.Context import android.graphics.Bitmap import android.graphics.Color -import android.support.annotation.WorkerThread +import androidx.annotation.WorkerThread import android.util.AttributeSet import android.view.View import android.webkit.WebView 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 297c41582..760d81fc7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/NestedWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/NestedWebView.kt @@ -2,9 +2,9 @@ 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 androidx.core.view.NestedScrollingChild +import androidx.core.view.NestedScrollingChildHelper +import androidx.core.view.ViewCompat import android.util.AttributeSet import android.view.MotionEvent import android.webkit.WebView diff --git a/app/src/main/res/drawable/frost_f_256.xml b/app/src/main/res/drawable/frost_f_200.xml similarity index 89% rename from app/src/main/res/drawable/frost_f_256.xml rename to app/src/main/res/drawable/frost_f_200.xml index 220dee696..3f07c6410 100644 --- a/app/src/main/res/drawable/frost_f_256.xml +++ b/app/src/main/res/drawable/frost_f_200.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/layout/activity_debug.xml b/app/src/main/res/layout/activity_debug.xml index 42428e492..55553f42b 100644 --- a/app/src/main/res/layout/activity_debug.xml +++ b/app/src/main/res/layout/activity_debug.xml @@ -1,5 +1,5 @@ - - - - + - + diff --git a/app/src/main/res/layout/activity_image.xml b/app/src/main/res/layout/activity_image.xml index a2264b253..4e6d4ce1a 100644 --- a/app/src/main/res/layout/activity_image.xml +++ b/app/src/main/res/layout/activity_image.xml @@ -1,5 +1,5 @@ - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_image_textless.xml b/app/src/main/res/layout/activity_image_textless.xml index c5da87e68..e047b23d7 100644 --- a/app/src/main/res/layout/activity_image_textless.xml +++ b/app/src/main/res/layout/activity_image_textless.xml @@ -1,5 +1,5 @@ - @@ -19,7 +19,7 @@ android:scaleX="0.9" android:scaleY="0.9" /> - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_intro.xml b/app/src/main/res/layout/activity_intro.xml index 839e33a9a..e61a618d6 100644 --- a/app/src/main/res/layout/activity_intro.xml +++ b/app/src/main/res/layout/activity_intro.xml @@ -1,5 +1,5 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_invalid.xml b/app/src/main/res/layout/activity_invalid.xml index dba1375bd..42c16b388 100644 --- a/app/src/main/res/layout/activity_invalid.xml +++ b/app/src/main/res/layout/activity_invalid.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml index 8b3ca157e..653656a61 100644 --- a/app/src/main/res/layout/activity_login.xml +++ b/app/src/main/res/layout/activity_login.xml @@ -1,5 +1,5 @@ - - - + diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 883221d97..8fa9283fc 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,5 +1,5 @@ - - - + - + diff --git a/app/src/main/res/layout/activity_main_bottom_tabs.xml b/app/src/main/res/layout/activity_main_bottom_tabs.xml index 783aa455f..2c2527cd4 100644 --- a/app/src/main/res/layout/activity_main_bottom_tabs.xml +++ b/app/src/main/res/layout/activity_main_bottom_tabs.xml @@ -5,7 +5,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - - - + - + diff --git a/app/src/main/res/layout/activity_selector.xml b/app/src/main/res/layout/activity_selector.xml index d96257316..4bbbd8662 100644 --- a/app/src/main/res/layout/activity_selector.xml +++ b/app/src/main/res/layout/activity_selector.xml @@ -1,5 +1,5 @@ - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_tab_customizer.xml b/app/src/main/res/layout/activity_tab_customizer.xml index 8e540f116..8cf9d903b 100644 --- a/app/src/main/res/layout/activity_tab_customizer.xml +++ b/app/src/main/res/layout/activity_tab_customizer.xml @@ -16,7 +16,7 @@ android:layout_height="match_parent" android:orientation="vertical"> - @@ -36,14 +36,14 @@ - - - - - + diff --git a/app/src/main/res/layout/iitem_menu.xml b/app/src/main/res/layout/iitem_menu.xml index 3dbc7ea17..eb849cca6 100644 --- a/app/src/main/res/layout/iitem_menu.xml +++ b/app/src/main/res/layout/iitem_menu.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/iitem_notification.xml b/app/src/main/res/layout/iitem_notification.xml index 266b9dc4c..e7cdab731 100644 --- a/app/src/main/res/layout/iitem_notification.xml +++ b/app/src/main/res/layout/iitem_notification.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/intro_end.xml b/app/src/main/res/layout/intro_end.xml index 67931e43a..501cf1a99 100644 --- a/app/src/main/res/layout/intro_end.xml +++ b/app/src/main/res/layout/intro_end.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/intro_image.xml b/app/src/main/res/layout/intro_image.xml index 8bdf4c909..97a5bcae4 100644 --- a/app/src/main/res/layout/intro_image.xml +++ b/app/src/main/res/layout/intro_image.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/intro_theme.xml b/app/src/main/res/layout/intro_theme.xml index 2a8cead3c..cd0538ddf 100644 --- a/app/src/main/res/layout/intro_theme.xml +++ b/app/src/main/res/layout/intro_theme.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/intro_welcome.xml b/app/src/main/res/layout/intro_welcome.xml index b53af7552..a73657ce2 100644 --- a/app/src/main/res/layout/intro_welcome.xml +++ b/app/src/main/res/layout/intro_welcome.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/item_about_links.xml b/app/src/main/res/layout/item_about_links.xml index 09c79f377..2417c321b 100644 --- a/app/src/main/res/layout/item_about_links.xml +++ b/app/src/main/res/layout/item_about_links.xml @@ -1,7 +1,7 @@ - - - @@ -18,7 +18,7 @@ android:scaleType="centerInside" android:visibility="invisible" /> - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/material_drawer_header.xml b/app/src/main/res/layout/material_drawer_header.xml index 21cd20a17..085a18700 100644 --- a/app/src/main/res/layout/material_drawer_header.xml +++ b/app/src/main/res/layout/material_drawer_header.xml @@ -92,7 +92,7 @@ android:fontFamily="sans-serif-medium" android:lines="1" android:maxLines="1" - android:textSize="@dimen/material_drawer_account_header_text" /> + android:textSize="@dimen/material_drawer_account_header_title" /> + android:textSize="@dimen/material_drawer_account_header_subtext" /> diff --git a/app/src/main/res/layout/view_account.xml b/app/src/main/res/layout/view_account.xml index 63d3e9cdb..de8ee0a2e 100644 --- a/app/src/main/res/layout/view_account.xml +++ b/app/src/main/res/layout/view_account.xml @@ -10,11 +10,11 @@ android:layout_width="@dimen/account_image_size" android:layout_height="@dimen/account_image_size" /> - - - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/view_content_base_recycler.xml b/app/src/main/res/layout/view_content_base_recycler.xml index e1591efe0..05b142150 100644 --- a/app/src/main/res/layout/view_content_base_recycler.xml +++ b/app/src/main/res/layout/view_content_base_recycler.xml @@ -6,7 +6,7 @@ android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> - @@ -19,7 +19,7 @@ android:focusableInTouchMode="true" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - + - @@ -19,7 +19,7 @@ android:focusableInTouchMode="true" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> - + - - - - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/view_main_fab.xml b/app/src/main/res/layout/view_main_fab.xml index 7e3ec2aa8..e9fe9981a 100644 --- a/app/src/main/res/layout/view_main_fab.xml +++ b/app/src/main/res/layout/view_main_fab.xml @@ -1,5 +1,5 @@ - - - - Date: Sun, 23 Dec 2018 20:05:18 -0500 Subject: [PATCH 2/5] Update play listings (#1250) * Update play listing * Update default language * Delete fastlane --- app/src/main/play/defaultLanguage | 2 +- .../{en-CA => en-US}/listing/fulldescription | 0 .../en-US/listing}/images/featureGraphic.png | Bin .../phoneScreenshots/frost_1_themes.png | Bin .../images/phoneScreenshots/frost_2_glass.png | Bin .../frost_3_multi_accounts.png | Bin .../images/phoneScreenshots/frost_4_pip.png | Bin .../images/phoneScreenshots/frost_5_swipe.png | Bin .../phoneScreenshots/frost_6_quick_links.png | Bin .../{en-CA => en-US}/listing/shortdescription | 0 .../main/play/{en-CA => en-US}/listing/title | 0 app/src/main/play/{en-CA => en-US}/whatsnew | 0 .../es-ES/listing/images/featureGraphic.png | Bin 0 -> 8596 bytes .../phoneScreenshots/frost_1_themes.png | Bin 0 -> 41141 bytes .../images/phoneScreenshots/frost_2_glass.png | Bin 0 -> 128325 bytes .../frost_3_multi_accounts.png | Bin 0 -> 30160 bytes .../images/phoneScreenshots/frost_4_pip.png | Bin 0 -> 63637 bytes .../images/phoneScreenshots/frost_5_swipe.png | Bin 0 -> 41821 bytes .../phoneScreenshots/frost_6_quick_links.png | Bin 0 -> 25264 bytes .../android/en-CA/full_description.txt | 80 ------------------ .../android/en-CA/short_description.txt | 1 - fastlane/metadata/android/en-CA/title.txt | 1 - 22 files changed, 1 insertion(+), 83 deletions(-) rename app/src/main/play/{en-CA => en-US}/listing/fulldescription (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/featureGraphic.png (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/phoneScreenshots/frost_1_themes.png (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/phoneScreenshots/frost_2_glass.png (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/phoneScreenshots/frost_3_multi_accounts.png (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/phoneScreenshots/frost_4_pip.png (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/phoneScreenshots/frost_5_swipe.png (100%) rename {fastlane/metadata/android/en-CA => app/src/main/play/en-US/listing}/images/phoneScreenshots/frost_6_quick_links.png (100%) rename app/src/main/play/{en-CA => en-US}/listing/shortdescription (100%) rename app/src/main/play/{en-CA => en-US}/listing/title (100%) rename app/src/main/play/{en-CA => en-US}/whatsnew (100%) create mode 100644 app/src/main/play/es-ES/listing/images/featureGraphic.png create mode 100644 app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_1_themes.png create mode 100644 app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_2_glass.png create mode 100644 app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_3_multi_accounts.png create mode 100644 app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_4_pip.png create mode 100644 app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_5_swipe.png create mode 100644 app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_6_quick_links.png delete mode 100644 fastlane/metadata/android/en-CA/full_description.txt delete mode 100644 fastlane/metadata/android/en-CA/short_description.txt delete mode 100644 fastlane/metadata/android/en-CA/title.txt diff --git a/app/src/main/play/defaultLanguage b/app/src/main/play/defaultLanguage index ffdd217e4..f2b0341fe 100644 --- a/app/src/main/play/defaultLanguage +++ b/app/src/main/play/defaultLanguage @@ -1 +1 @@ -en-CA \ No newline at end of file +en-US \ No newline at end of file diff --git a/app/src/main/play/en-CA/listing/fulldescription b/app/src/main/play/en-US/listing/fulldescription similarity index 100% rename from app/src/main/play/en-CA/listing/fulldescription rename to app/src/main/play/en-US/listing/fulldescription diff --git a/fastlane/metadata/android/en-CA/images/featureGraphic.png b/app/src/main/play/en-US/listing/images/featureGraphic.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/featureGraphic.png rename to app/src/main/play/en-US/listing/images/featureGraphic.png diff --git a/fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_1_themes.png b/app/src/main/play/en-US/listing/images/phoneScreenshots/frost_1_themes.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_1_themes.png rename to app/src/main/play/en-US/listing/images/phoneScreenshots/frost_1_themes.png diff --git a/fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_2_glass.png b/app/src/main/play/en-US/listing/images/phoneScreenshots/frost_2_glass.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_2_glass.png rename to app/src/main/play/en-US/listing/images/phoneScreenshots/frost_2_glass.png diff --git a/fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_3_multi_accounts.png b/app/src/main/play/en-US/listing/images/phoneScreenshots/frost_3_multi_accounts.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_3_multi_accounts.png rename to app/src/main/play/en-US/listing/images/phoneScreenshots/frost_3_multi_accounts.png diff --git a/fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_4_pip.png b/app/src/main/play/en-US/listing/images/phoneScreenshots/frost_4_pip.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_4_pip.png rename to app/src/main/play/en-US/listing/images/phoneScreenshots/frost_4_pip.png diff --git a/fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_5_swipe.png b/app/src/main/play/en-US/listing/images/phoneScreenshots/frost_5_swipe.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_5_swipe.png rename to app/src/main/play/en-US/listing/images/phoneScreenshots/frost_5_swipe.png diff --git a/fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_6_quick_links.png b/app/src/main/play/en-US/listing/images/phoneScreenshots/frost_6_quick_links.png similarity index 100% rename from fastlane/metadata/android/en-CA/images/phoneScreenshots/frost_6_quick_links.png rename to app/src/main/play/en-US/listing/images/phoneScreenshots/frost_6_quick_links.png diff --git a/app/src/main/play/en-CA/listing/shortdescription b/app/src/main/play/en-US/listing/shortdescription similarity index 100% rename from app/src/main/play/en-CA/listing/shortdescription rename to app/src/main/play/en-US/listing/shortdescription diff --git a/app/src/main/play/en-CA/listing/title b/app/src/main/play/en-US/listing/title similarity index 100% rename from app/src/main/play/en-CA/listing/title rename to app/src/main/play/en-US/listing/title diff --git a/app/src/main/play/en-CA/whatsnew b/app/src/main/play/en-US/whatsnew similarity index 100% rename from app/src/main/play/en-CA/whatsnew rename to app/src/main/play/en-US/whatsnew diff --git a/app/src/main/play/es-ES/listing/images/featureGraphic.png b/app/src/main/play/es-ES/listing/images/featureGraphic.png new file mode 100644 index 0000000000000000000000000000000000000000..c47aa1d966ddfdc8f8fb7e7c9135830da28e5fbc GIT binary patch literal 8596 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 literal 0 HcmV?d00001 diff --git a/app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_2_glass.png b/app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_2_glass.png new file mode 100644 index 0000000000000000000000000000000000000000..4ee98308521725afbd45a79723bcc256f67c6586 GIT binary patch literal 128325 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 z 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 literal 0 HcmV?d00001 diff --git a/app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_3_multi_accounts.png b/app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_3_multi_accounts.png new file mode 100644 index 0000000000000000000000000000000000000000..11536dfef2d951a09c40cb4af0a3353e82d7b6d5 GIT binary patch literal 30160 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 Ix{eY51MtE!g#Z8m literal 0 HcmV?d00001 diff --git a/app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_6_quick_links.png b/app/src/main/play/es-ES/listing/images/phoneScreenshots/frost_6_quick_links.png new file mode 100644 index 0000000000000000000000000000000000000000..bd42e92b516431b751795e26b0a0d8a45b41ecb7 GIT binary patch literal 25264 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 literal 0 HcmV?d00001 diff --git a/fastlane/metadata/android/en-CA/full_description.txt b/fastlane/metadata/android/en-CA/full_description.txt deleted file mode 100644 index d0c3f6dc6..000000000 --- a/fastlane/metadata/android/en-CA/full_description.txt +++ /dev/null @@ -1,80 +0,0 @@ -'''Welcome to Frost for Facebook!''' - -[https://allanwang.github.io/Frost-for-Facebook/ Webpage] - -Frost is a fully functional web wrapper, with many unique and native features -such as: - -* '''True multi user interactions''' - More than just an option in a settings -menu, Frost's account switcher is right in the drawer. You are one tap away from -switching accounts, and everything refreshes on the switch so that you can view -other accounts instantaneously. Furthermore, the notification service will fetch -notifications from all accounts, and will let you know which account has the new -notification. - -* '''Better multitasking''' - Frost contains an overlaying web browser that can -be drawn on top of your foreground task. Open links and notifications with a -full screen view, then swipe away to get back to your previous task. - -* '''Contextual awareness''' - Frost integrates additional features via long -presses. Need to copy a block of text or share a link? Long press the text. Need -to zoom into an image or download it? Long press the image! - -* '''Material Design''' - Built for lollipop and up, Frost focuses strongly on -a beautiful and functional UI, and embraces material transitions and dimensions. - -* '''Complete theme engine''' - Frost contains very comprehensive themes that -customize all components of the app. Frost is also the only app to support -transparent themes. - -* '''Fully opened''' - Nothing speaks for privacy more than being open sourced. -Frost is proud to be one of those apps, and can be found on github (Link in the -app's about section) - -* '''Fixes the little things''' - Frost is community driven, and many tweaks -are added to address minor inconveniences and give a full native experience, -despite being a web app. - -Mandatory permissions used and why: - -* Internet, Network State, Wifi State - Frost fetches the pages from Facebook's -mobile website. It also needs the network state so as to limit internet usage -when you are on a metered network. - -* Receive Boot Completed - Frost notifications persist on reboot, and need this -permission to be added each time. - -* Vibrate - Needed to vibrate phone for notifications; this can be toggled in -the settings - -* Billing - For purchasing pro and unlocking all of Frost's features - -Optional permissions used and why: ''(these are only requested when they have -to be, and are disabled until then)'' - -* Read/write external storage - Needed to upload photos in a new status and save -photos when prompted - -* Fine/coarse location - Needed for the check in option if users wish to search -for their location - -* That's it! No privacy intrusion and no extra demands. - -Permissions ''NOT'' used and why: - -* Wakelock - Frost takes advantage of Android's Job Scheduler, and lets the -framework decide when to run background services. Frost therefore doesn't need -to constantly run in the background, nor does it force your phone to stay awake. - -* Retrieve running apps - Frost has no need to access external apps or see what -else is running - -* Identity - Frost manages its accounts internally and uses it solely to give -you access to your account. We don't depend on other personal information and we -don't even save your email. - -* Camera - While the camera permission can be added to allow you to directly -take photos and upload them, we've decided that it would be best to allow you to -do so externally and then share the photo with Frost - -''Frost is a third party app and is in no way affiliated with Facebook Inc.'' \ No newline at end of file diff --git a/fastlane/metadata/android/en-CA/short_description.txt b/fastlane/metadata/android/en-CA/short_description.txt deleted file mode 100644 index 5fd6d4012..000000000 --- a/fastlane/metadata/android/en-CA/short_description.txt +++ /dev/null @@ -1 +0,0 @@ -Facebook Web Wrapper \ No newline at end of file diff --git a/fastlane/metadata/android/en-CA/title.txt b/fastlane/metadata/android/en-CA/title.txt deleted file mode 100644 index a933d8450..000000000 --- a/fastlane/metadata/android/en-CA/title.txt +++ /dev/null @@ -1 +0,0 @@ -Frost for Facebook \ No newline at end of file From 9a40780c3baffcef381e4575f7c28b4b5fb4a56b Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 23 Dec 2018 20:16:20 -0500 Subject: [PATCH 3/5] Add composer to css --- app/src/main/assets/css/core/_core_bg.scss | 2 +- app/src/main/assets/css/themes/custom.css | 2 +- app/src/main/assets/css/themes/material_amoled.css | 2 +- app/src/main/assets/css/themes/material_dark.css | 2 +- app/src/main/assets/css/themes/material_glass.css | 2 +- app/src/main/assets/css/themes/material_light.css | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/src/main/assets/css/core/_core_bg.scss b/app/src/main/assets/css/core/_core_bg.scss index 75e0b5214..eba4cd10d 100644 --- a/app/src/main/assets/css/core/_core_bg.scss +++ b/app/src/main/assets/css/core/_core_bg.scss @@ -2,7 +2,7 @@ background: $background !important; } -body, :root, #root, #header, [style*="background-color"], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, +body, :root, #root, #header, #MComposer, [style*="background-color"], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i, ._6-l ._2us7, ._6-l ._6-p, ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz, ._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1, ._-j7, diff --git a/app/src/main/assets/css/themes/custom.css b/app/src/main/assets/css/themes/custom.css index df1a3908e..a64e964f7 100644 --- a/app/src/main/assets/css/themes/custom.css +++ b/app/src/main/assets/css/themes/custom.css @@ -40,7 +40,7 @@ a, background: $B$ !important; } -body, :root, #root, #header, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, +body, :root, #root, #header, #MComposer, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i, ._6-l ._2us7, ._6-l ._6-p, ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz, ._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1, ._-j7, diff --git a/app/src/main/assets/css/themes/material_amoled.css b/app/src/main/assets/css/themes/material_amoled.css index 78bd119ba..d4cf8233d 100644 --- a/app/src/main/assets/css/themes/material_amoled.css +++ b/app/src/main/assets/css/themes/material_amoled.css @@ -40,7 +40,7 @@ a, background: #000 !important; } -body, :root, #root, #header, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, +body, :root, #root, #header, #MComposer, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i, ._6-l ._2us7, ._6-l ._6-p, ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz, ._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1, ._-j7, diff --git a/app/src/main/assets/css/themes/material_dark.css b/app/src/main/assets/css/themes/material_dark.css index 179bec1ab..e13f5600c 100644 --- a/app/src/main/assets/css/themes/material_dark.css +++ b/app/src/main/assets/css/themes/material_dark.css @@ -40,7 +40,7 @@ a, background: #303030 !important; } -body, :root, #root, #header, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, +body, :root, #root, #header, #MComposer, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i, ._6-l ._2us7, ._6-l ._6-p, ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz, ._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1, ._-j7, diff --git a/app/src/main/assets/css/themes/material_glass.css b/app/src/main/assets/css/themes/material_glass.css index ad50e4945..0d4cb7262 100644 --- a/app/src/main/assets/css/themes/material_glass.css +++ b/app/src/main/assets/css/themes/material_glass.css @@ -40,7 +40,7 @@ a, background: rgba(0, 0, 0, 0.1) !important; } -body, :root, #root, #header, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, +body, :root, #root, #header, #MComposer, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i, ._6-l ._2us7, ._6-l ._6-p, ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz, ._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1, ._-j7, diff --git a/app/src/main/assets/css/themes/material_light.css b/app/src/main/assets/css/themes/material_light.css index cbc3002c3..f3c6cc922 100644 --- a/app/src/main/assets/css/themes/material_light.css +++ b/app/src/main/assets/css/themes/material_light.css @@ -40,7 +40,7 @@ a, background: #fafafa !important; } -body, :root, #root, #header, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, +body, :root, #root, #header, #MComposer, [style*=background-color], ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, .container, .subpage, ._5n_f, #static_templates, ._22_8, ._1t4h, ._uoq, ._3qdh, ._8ca, ._3h8i, ._6-l ._2us7, ._6-l ._6-p, ._333v, div.sharerSelector, ._529j, ._305j, ._1pph, ._3t_l, ._4pvz, ._1g05, .acy, ._51-g, ._533c, ._ib-, .sharerAttachmentEmpty, .sharerBottomWrapper, ._24e1, ._-j7, From c45b30e28f451699f3be828a1201260ed27e321e Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 24 Dec 2018 00:21:21 -0500 Subject: [PATCH 4/5] Update/bindview (#1258) * Update bindview for FrostVideoViewer * Remove more bindview usages * Fix compilation problems * Remove custom drawer header --- .../frost/activities/BaseMainActivity.kt | 1 - .../frost/activities/DebugActivity.kt | 34 ++--- .../frost/activities/TabCustomizerActivity.kt | 41 +++--- .../frost/intro/IntroFragmentTheme.kt | 19 ++- .../com/pitchedapps/frost/views/BadgedIcon.kt | 24 ++-- .../frost/views/FrostVideoViewer.kt | 43 +++---- .../res/layout/material_drawer_header.xml | 119 ------------------ app/src/main/res/layout/view_account.xml | 2 +- build.gradle | 1 + gradle.properties | 4 +- 10 files changed, 69 insertions(+), 219 deletions(-) delete mode 100644 app/src/main/res/layout/material_drawer_header.xml 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 52f61bea9..8f6bbacbb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseMainActivity.kt @@ -185,7 +185,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 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 9a90f0903..3acbf7b3b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/DebugActivity.kt @@ -5,25 +5,22 @@ import android.content.Context import android.content.Intent import android.content.res.ColorStateList import android.os.Bundle -import com.google.android.material.floatingactionbutton.FloatingActionButton -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import androidx.appcompat.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 -import com.pitchedapps.frost.R import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.injectors.JsActions +import com.pitchedapps.frost.R 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 +28,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 +48,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 +61,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 { emitter -> - web.evaluateJavascript(JsActions.RETURN_BODY.function) { + debug_webview.evaluateJavascript(JsActions.RETURN_BODY.function) { emitter.onSuccess(it) } }.subscribeOn(AndroidSchedulers.mainThread()) @@ -89,7 +81,7 @@ class DebugActivity : KauBaseActivity() { return@subscribe } val intent = Intent() - intent.putExtra(RESULT_URL, web.url) + intent.putExtra(RESULT_URL, debug_webview.url) intent.putExtra(RESULT_SCREENSHOT, screenshot) if (body != null) intent.putExtra(RESULT_BODY, body) @@ -107,17 +99,17 @@ 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() } 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 1938add0e..6222d98fd 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt @@ -3,23 +3,23 @@ package com.pitchedapps.frost.activities import android.app.Activity import android.content.res.ColorStateList import android.os.Bundle -import com.google.android.material.floatingactionbutton.FloatingActionButton -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import androidx.recyclerview.widget.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 com.pitchedapps.frost.R import ca.allanwang.kau.utils.withAlpha +import com.google.android.material.floatingactionbutton.FloatingActionButton import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter import com.mikepenz.fastadapter_extensions.drag.ItemTouchCallback import com.mikepenz.fastadapter_extensions.drag.SimpleDragCallback import com.mikepenz.google_material_typeface_library.GoogleMaterial -import com.pitchedapps.frost.R import com.pitchedapps.frost.dbflow.TAB_COUNT import com.pitchedapps.frost.dbflow.loadFbTabs import com.pitchedapps.frost.dbflow.save @@ -27,6 +27,7 @@ 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 kotlinx.android.synthetic.main.activity_tab_customizer.* import java.util.* /** @@ -34,13 +35,7 @@ import java.util.* */ 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() - val fabCancel: FloatingActionButton by bindView(R.id.fab_cancel) - val fabSave: FloatingActionButton by bindView(R.id.fab_save) + private val adapter = FastItemAdapter() private val wobble = lazyContext { AnimationUtils.loadAnimation(it, R.anim.rotate_delta) } @@ -48,11 +43,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, RecyclerView.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 +58,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 } 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 42630d790..3e40b6ba9 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt @@ -2,34 +2,29 @@ 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> = arrayOf(arrayOf(title), arrayOf(light, dark), arrayOf(amoled, glass)) + override fun viewArray(): Array> = 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 } 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 926205678..8093c8526 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt @@ -4,12 +4,11 @@ import android.content.Context import android.graphics.drawable.GradientDrawable import androidx.constraintlayout.widget.ConstraintLayout import android.util.AttributeSet -import android.widget.ImageView -import android.widget.TextView import ca.allanwang.kau.utils.* 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.* /** @@ -19,36 +18,33 @@ class BadgedIcon @JvmOverloads constructor( 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)) 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/FrostVideoViewer.kt b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt index 5afb3a21a..b2796999e 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt @@ -4,21 +4,18 @@ import android.content.Context import android.graphics.Color import android.graphics.PointF import android.net.Uri -import androidx.appcompat.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 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.R 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. @@ -27,12 +24,6 @@ class FrostVideoViewer @JvmOverloads constructor( 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 +50,29 @@ class FrostVideoViewer @JvmOverloads constructor( init { inflate(R.layout.view_video, true) alpha = 0f - background.setBackgroundColor( + 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, + 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 +106,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 +120,7 @@ class FrostVideoViewer @JvmOverloads constructor( override fun onVideoComplete() { video.jumpToStart() - restarter.fadeIn() + video_restart.fadeIn() } fun updateLocation() { @@ -143,12 +134,12 @@ 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() } } } diff --git a/app/src/main/res/layout/material_drawer_header.xml b/app/src/main/res/layout/material_drawer_header.xml deleted file mode 100644 index 085a18700..000000000 --- a/app/src/main/res/layout/material_drawer_header.xml +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_account.xml b/app/src/main/res/layout/view_account.xml index de8ee0a2e..1c7eea661 100644 --- a/app/src/main/res/layout/view_account.xml +++ b/app/src/main/res/layout/view_account.xml @@ -10,7 +10,7 @@ android:layout_width="@dimen/account_image_size" android:layout_height="@dimen/account_image_size" /> - diff --git a/build.gradle b/build.gradle index a163b512f..ef1dc4481 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,7 @@ buildscript { dependencies { classpath "ca.allanwang:kau:${KAU}" + classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta02' classpath "com.android.tools.build:gradle:${ANDROID_GRADLE}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${KOTLIN}" classpath "com.bugsnag:bugsnag-android-gradle-plugin:${BUGSNAG_PLUGIN}" diff --git a/gradle.properties b/gradle.properties index 6728eb08e..f708598c3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,11 +14,11 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryErro APP_ID=Frost APP_GROUP=com.pitchedapps -KAU=0d24880 +KAU=b4a2ded KOTLIN=1.3.11 # https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google -ANDROID_GRADLE=3.3.0-rc02 +ANDROID_GRADLE=3.2.1 # https://github.com/bugsnag/bugsnag-android/releases BUGSNAG=4.9.3 From 697d01882ba8b1dbb85484ba3bf6e810e32448fc Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Mon, 24 Dec 2018 01:47:03 -0500 Subject: [PATCH 5/5] Enhancement/ktlint (#1259) * Add spotless * Reformat code * Apply license header * Add remaining license headers --- app/build.gradle | 2 + .../kotlin/com/pitchedapps/frost/FrostApp.kt | 53 +++-- .../com/pitchedapps/frost/StartActivity.kt | 31 ++- .../frost/activities/AboutActivity.kt | 84 +++++--- .../frost/activities/BaseActivity.kt | 19 +- .../frost/activities/BaseMainActivity.kt | 148 +++++++++---- .../frost/activities/DebugActivity.kt | 47 +++-- .../frost/activities/ImageActivity.kt | 84 ++++++-- .../frost/activities/IntroActivity.kt | 76 +++++-- .../frost/activities/LoginActivity.kt | 118 +++++++---- .../frost/activities/MainActivity.kt | 76 ++++--- .../frost/activities/SelectorActivity.kt | 22 +- .../frost/activities/SettingsActivity.kt | 54 ++++- .../frost/activities/TabCustomizerActivity.kt | 29 ++- .../frost/activities/WebOverlayActivity.kt | 82 ++++++-- .../frost/contracts/ActivityContract.kt | 18 +- .../frost/contracts/DynamicUiContract.kt | 20 +- .../frost/contracts/FileChooser.kt | 35 +++- .../frost/contracts/FrostContentContract.kt | 21 +- .../frost/contracts/FrostObservables.kt | 19 +- .../frost/contracts/FrostThemable.kt | 25 ++- .../frost/contracts/VideoViewHolder.kt | 17 +- .../com/pitchedapps/frost/dbflow/CookiesDb.kt | 79 ++++--- .../com/pitchedapps/frost/dbflow/DbUtils.kt | 19 +- .../com/pitchedapps/frost/dbflow/FbTabsDb.kt | 18 +- .../frost/dbflow/NotificationDb.kt | 45 +++- .../frost/debugger/OfflineWebsite.kt | 65 +++--- .../com/pitchedapps/frost/enums/FeedSort.kt | 18 +- .../frost/enums/MainActivityLayout.kt | 39 +++- .../pitchedapps/frost/enums/OverlayContext.kt | 25 ++- .../com/pitchedapps/frost/enums/Support.kt | 18 +- .../com/pitchedapps/frost/enums/Theme.kt | 106 ++++++---- .../com/pitchedapps/frost/facebook/FbConst.kt | 27 ++- .../pitchedapps/frost/facebook/FbCookie.kt | 32 ++- .../com/pitchedapps/frost/facebook/FbItem.kt | 24 ++- .../com/pitchedapps/frost/facebook/FbRegex.kt | 17 +- .../frost/facebook/FbUrlFormatter.kt | 46 ++-- .../frost/facebook/parsers/FrostParser.kt | 29 ++- .../frost/facebook/parsers/MessageParser.kt | 98 +++++---- .../frost/facebook/parsers/NotifParser.kt | 94 +++++---- .../frost/facebook/parsers/SearchParser.kt | 37 +++- .../frost/facebook/requests/FbRequest.kt | 61 ++++-- .../frost/facebook/requests/Images.kt | 49 +++-- .../frost/facebook/requests/Menu.kt | 129 +++++++----- .../frost/facebook/requests/Messages.kt | 26 ++- .../frost/facebook/requests/Notifications.kt | 32 ++- .../frost/fragments/FragmentBase.kt | 93 ++++++--- .../frost/fragments/FragmentContract.kt | 27 ++- .../frost/fragments/RecyclerFragmentBase.kt | 17 +- .../frost/fragments/RecyclerFragments.kt | 34 ++- .../frost/fragments/WebFragments.kt | 18 +- .../com/pitchedapps/frost/glide/GlideUtils.kt | 30 ++- .../frost/glide/RoundCornerTransformation.kt | 36 +++- .../pitchedapps/frost/iitems/GenericIItems.kt | 53 +++-- .../com/pitchedapps/frost/iitems/MenuIItem.kt | 41 ++-- .../frost/iitems/NotificationIItem.kt | 62 ++++-- .../com/pitchedapps/frost/iitems/TabIItem.kt | 29 ++- .../pitchedapps/frost/injectors/CssAssets.kt | 48 +++-- .../pitchedapps/frost/injectors/CssHider.kt | 33 ++- .../pitchedapps/frost/injectors/JsActions.kt | 21 +- .../pitchedapps/frost/injectors/JsAssets.kt | 19 +- .../pitchedapps/frost/injectors/JsInjector.kt | 34 ++- .../frost/intro/IntroFragmentTheme.kt | 25 ++- .../frost/intro/IntroImageFragments.kt | 52 ++++- .../frost/intro/IntroMainFragments.kt | 23 +- .../com/pitchedapps/frost/rx/RxFlyweight.kt | 25 ++- .../frost/services/FrostNotifications.kt | 196 ++++++++++-------- .../frost/services/FrostRequestService.kt | 50 +++-- .../frost/services/NotificationService.kt | 55 +++-- .../frost/services/NotificationUtils.kt | 69 +++--- .../frost/services/UpdateReceiver.kt | 19 +- .../pitchedapps/frost/settings/Appearance.kt | 41 +++- .../pitchedapps/frost/settings/Behaviour.kt | 22 +- .../com/pitchedapps/frost/settings/Debug.kt | 40 ++-- .../frost/settings/Experimental.kt | 19 +- .../com/pitchedapps/frost/settings/Feed.kt | 18 +- .../com/pitchedapps/frost/settings/Network.kt | 24 ++- .../frost/settings/Notifications.kt | 72 ++++--- .../com/pitchedapps/frost/utils/AdBlocker.kt | 18 +- .../frost/utils/AnimatedVectorDelegate.kt | 62 +++--- .../com/pitchedapps/frost/utils/BuildUtils.kt | 21 +- .../com/pitchedapps/frost/utils/Const.kt | 18 +- .../com/pitchedapps/frost/utils/Downloader.kt | 43 ++-- .../com/pitchedapps/frost/utils/EnumUtils.kt | 25 ++- .../pitchedapps/frost/utils/JsoupCleaner.kt | 22 +- .../kotlin/com/pitchedapps/frost/utils/L.kt | 20 +- .../com/pitchedapps/frost/utils/Prefs.kt | 20 +- .../com/pitchedapps/frost/utils/Showcase.kt | 17 +- .../com/pitchedapps/frost/utils/Utils.kt | 139 +++++++++---- .../pitchedapps/frost/utils/WebContextMenu.kt | 22 +- .../pitchedapps/frost/views/AccountItem.kt | 69 ++++-- .../com/pitchedapps/frost/views/BadgedIcon.kt | 44 +++- .../frost/views/FrostContentView.kt | 91 +++++--- .../frost/views/FrostRecyclerView.kt | 29 ++- .../pitchedapps/frost/views/FrostVideoView.kt | 37 +++- .../frost/views/FrostVideoViewer.kt | 54 +++-- .../pitchedapps/frost/views/FrostViewPager.kt | 43 ++-- .../pitchedapps/frost/views/FrostWebView.kt | 31 ++- .../frost/views/KPrefTextSeekbar.kt | 18 +- .../com/pitchedapps/frost/views/Keywords.kt | 37 +++- .../com/pitchedapps/frost/web/DebugWebView.kt | 48 +++-- .../frost/web/FrostChromeClients.kt | 35 +++- .../com/pitchedapps/frost/web/FrostJSI.kt | 44 ++-- .../frost/web/FrostRequestInterceptor.kt | 34 ++- .../frost/web/FrostUrlOverlayValidator.kt | 38 +++- .../frost/web/FrostWebViewClients.kt | 84 +++++--- .../com/pitchedapps/frost/web/LoginWebView.kt | 36 +++- .../pitchedapps/frost/web/NestedWebView.kt | 46 +++- .../kotlin/com/pitchedapps/frost/MiscTest.kt | 32 ++- .../frost/debugger/OfflineWebsiteTest.kt | 27 ++- .../pitchedapps/frost/facebook/FbDomTest.kt | 19 +- .../pitchedapps/frost/facebook/FbRegexTest.kt | 22 +- .../pitchedapps/frost/facebook/FbUrlTest.kt | 38 ++-- .../frost/facebook/parsers/FbParseTest.kt | 22 +- .../facebook/requests/FbFullImageTest.kt | 18 +- .../frost/facebook/requests/FbRequestTest.kt | 22 +- .../frost/injectors/InjectorTest.kt | 16 ++ .../pitchedapps/frost/internal/Internal.kt | 20 +- .../frost/rx/ResettableFlyweightTest.kt | 20 +- .../pitchedapps/frost/utils/BuildUtilsTest.kt | 18 +- .../frost/utils/JsoupCleanerTest.kt | 24 ++- .../com/pitchedapps/frost/utils/PrefsTest.kt | 18 +- .../frost/utils/StringEscapeUtilsTest.kt | 18 +- .../com/pitchedapps/frost/utils/UrlTests.kt | 44 ++-- build.gradle | 1 + gradle.properties | 3 + spotless.gradle | 11 + spotless.license.kt | 16 ++ 128 files changed, 3864 insertions(+), 1348 deletions(-) create mode 100644 spotless.gradle create mode 100644 spotless.license.kt diff --git a/app/build.gradle b/app/build.gradle index 2c7c5bcc4..1b8feda78 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,6 +6,8 @@ apply plugin: 'kotlin-kapt' apply plugin: 'com.getkeepsafe.dexcount' apply plugin: 'com.gladed.androidgitversion' +apply from: '../spotless.gradle' + android { compileSdkVersion kau.targetSdk buildToolsVersion kau.buildTools diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt index c566aa052..7f3d6b62c 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 . + */ 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 034dabe22..14cc579f7 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 . + */ 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(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(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(R.id.invalid_icon) - .setIcon(GoogleMaterial.Icon.gmd_adb, -1, Color.WHITE) + .setIcon(GoogleMaterial.Icon.gmd_adb, -1, Color.WHITE) findViewById(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 4d333099e..a110071c6 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 . + */ package com.pitchedapps.frost.activities -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.constraintlayout.widget.ConstraintSet -import androidx.recyclerview.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. */ @@ -42,21 +64,21 @@ class AboutActivity : AboutActivityBase(null, { override fun getLibraries(libs: Libs): List { 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 Unit>>( - 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) } + 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 3ac8c6ce3..08b5ab0c5 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 . + */ 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 8f6bbacbb..20b5727fb 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 . + */ 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 androidx.annotation.StringRes -import com.google.android.material.appbar.AppBarLayout -import androidx.coordinatorlayout.widget.CoordinatorLayout -import com.google.android.material.floatingactionbutton.FloatingActionButton -import com.google.android.material.tabs.TabLayout -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentPagerAdapter -import androidx.appcompat.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) @@ -204,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 } @@ -225,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) } @@ -295,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 -> @@ -309,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 } @@ -332,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) @@ -340,7 +401,10 @@ abstract class BaseMainActivity : BaseActivity(), MainActivityContract, return true } - override fun openFileChooser(filePathCallback: ValueCallback?>, fileChooserParams: WebChromeClient.FileChooserParams) { + override fun openFileChooser( + filePathCallback: ValueCallback?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) { openMediaPicker(filePathCallback, fileChooserParams) } @@ -377,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() { @@ -444,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 @@ -455,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 @@ -469,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 3acbf7b3b..6257e6f16 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 . + */ package com.pitchedapps.frost.activities import android.app.Activity @@ -9,9 +25,9 @@ import ca.allanwang.kau.internal.KauBaseActivity import ca.allanwang.kau.utils.setIcon import ca.allanwang.kau.utils.visible import com.mikepenz.google_material_typeface_library.GoogleMaterial +import com.pitchedapps.frost.R import com.pitchedapps.frost.facebook.FbItem import com.pitchedapps.frost.injectors.JsActions -import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.L import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.createFreshDir @@ -73,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, debug_webview.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 { @@ -113,4 +128,4 @@ class DebugActivity : KauBaseActivity() { 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 348b36b94..83f617ba0 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 . + */ 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 com.google.android.material.floatingactionbutton.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 c41229daa..a3ab61727 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 . + */ package com.pitchedapps.frost.activities import android.animation.ValueAnimator import android.content.res.ColorStateList import android.graphics.Color import android.os.Bundle -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager -import androidx.fragment.app.FragmentPagerAdapter -import androidx.viewpager.widget.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(skip, indicator, next, - lastView?.find(R.id.intro_title), - lastView?.find(R.id.intro_desc)).forEach { + arrayOf( + 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) : FragmentPagerAdapter(fm) { + class IntroPageAdapter(fm: FragmentManager, private val fragments: List) : + 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 9c8a60aa1..8b5fe38da 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 . + */ package com.pitchedapps.frost.activities import android.graphics.drawable.Drawable import android.os.Bundle import android.os.Handler -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import android.widget.ImageView import androidx.appcompat.widget.AppCompatTextView import androidx.appcompat.widget.Toolbar -import android.widget.ImageView +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>( - 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(cookies, true) - else - launchNewTask(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(cookies, true) + else + launchNewTask(cookies, true) + }, 1000) + } + }.disposeOnDestroy() loadProfile(cookie.id) loadUsername(cookie) } - private fun loadProfile(id: Long) { profileLoader.load(profilePictureUrl(id)) - .transform(FrostGlide.roundCorner).listener(object : RequestListener { - override fun onResourceReady(resource: Drawable?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { - profileSubject.onSuccess(true) - return false - } + .transform(FrostGlide.roundCorner).listener(object : RequestListener { + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + profileSubject.onSuccess(true) + return false + } - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { - e.logFrostEvent("Profile loading exception") - profileSubject.onSuccess(false) - return false - } - }).into(profile) + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + 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 2555fe5bb..d03c6496f 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 . + */ package com.pitchedapps.frost.activities import android.os.Bundle -import com.google.android.material.tabs.TabLayout 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 514af197a..2907bac6c 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 . + */ package com.pitchedapps.frost.activities import android.os.Bundle -import androidx.constraintlayout.widget.ConstraintLayout +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 android.view.View 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 7663b70f1..370474480 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 . + */ 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. @@ -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 6222d98fd..7f6329406 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/TabCustomizerActivity.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 . + */ package com.pitchedapps.frost.activities import android.app.Activity @@ -5,21 +21,18 @@ import android.content.res.ColorStateList import android.os.Bundle 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 com.pitchedapps.frost.R import ca.allanwang.kau.utils.withAlpha -import com.google.android.material.floatingactionbutton.FloatingActionButton import com.mikepenz.fastadapter.commons.adapters.FastItemAdapter import com.mikepenz.fastadapter_extensions.drag.ItemTouchCallback import com.mikepenz.fastadapter_extensions.drag.SimpleDragCallback import com.mikepenz.google_material_typeface_library.GoogleMaterial +import com.pitchedapps.frost.R import com.pitchedapps.frost.dbflow.TAB_COUNT import com.pitchedapps.frost.dbflow.loadFbTabs import com.pitchedapps.frost.dbflow.save @@ -28,7 +41,7 @@ import com.pitchedapps.frost.iitems.TabIItem import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.setFrostColors import kotlinx.android.synthetic.main.activity_tab_customizer.* -import java.util.* +import java.util.Collections /** * Created by Allan Wang on 26/11/17. @@ -96,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 @@ -122,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 6d930fff9..b706d467a 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 . + */ 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 androidx.coordinatorlayout.widget.CoordinatorLayout -import androidx.appcompat.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 @@ -235,7 +277,10 @@ open class WebOverlayActivityBase(private val forceBasicAgent: Boolean) : BaseAc kauSwipeOnDestroy() } - override fun openFileChooser(filePathCallback: ValueCallback?>, fileChooserParams: WebChromeClient.FileChooserParams) { + override fun openFileChooser( + filePathCallback: ValueCallback?>, + 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.Icon2.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 1182e6098..2ce838713 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 . + */ 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 303c64b37..736ef72d4 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 . + */ 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 15165456a..73d5c56dc 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 . + */ 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?>, fileChooserParams: WebChromeClient.FileChooserParams) + fun openFileChooser( + filePathCallback: ValueCallback?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) } interface FileChooserContract { var filePathCallback: ValueCallback?>? - fun Activity.openMediaPicker(filePathCallback: ValueCallback?>, fileChooserParams: WebChromeClient.FileChooserParams) + fun Activity.openMediaPicker( + filePathCallback: ValueCallback?>, + fileChooserParams: WebChromeClient.FileChooserParams + ) + fun Activity.onActivityResultWeb(requestCode: Int, resultCode: Int, intent: Intent?): Boolean } @@ -30,7 +53,10 @@ class FileChooserDelegate : FileChooserContract { override var filePathCallback: ValueCallback?>? = null - override fun Activity.openMediaPicker(filePathCallback: ValueCallback?>, fileChooserParams: WebChromeClient.FileChooserParams) { + override fun Activity.openMediaPicker( + filePathCallback: ValueCallback?>, + 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 613295e6f..50c2fe778 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 . + */ 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 882b67a06..b3b93b669 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 . + */ 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 3322f62e1..93d827a6c 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 . + */ 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 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 13b6a7aa7..e749b0d38 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 . + */ 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 1fe65d5ae..db3bf9734 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 . + */ 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) -> 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 = (select from CookieModel::class).orderBy(CookieModel_Table.name, true).queryList() - +fun loadFbCookiesSync(): List = + (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 e4aef2a9b..740fef628 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 . + */ 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 List.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 827881e3f..9d330169e 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 . + */ package com.pitchedapps.frost.dbflow import com.pitchedapps.frost.facebook.FbItem @@ -39,4 +55,4 @@ fun loadFbTabs(): List { fun List.save() { database().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 b61fc2187..a054d95ec 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 . + */ 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) : AlterTableMigration(modelClass) { +class NotificationMigration2(modelClass: Class) : + AlterTableMigration(modelClass) { override fun onPreMigrate() { super.onPreMigrate() addColumn(SQLiteType.INTEGER, "epochIm") @@ -27,11 +53,14 @@ class NotificationMigration2(modelClass: Class) : 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 6298f1f9c..f5009cc55 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 . + */ package com.pitchedapps.frost.debugger import ca.allanwang.kau.logging.KauLoggerExtension @@ -32,21 +48,23 @@ import java.util.zip.ZipOutputStream * * Inspired by Save for Offline */ -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() 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 String.downloadUrl(fallback: () -> T, - action: (file: File, body: ResponseBody) -> T): T { + private inline fun 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.clean(): List = - 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 d8a0f349e..7312399ea 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/FeedSort.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/FeedSort.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 . + */ package com.pitchedapps.frost.enums import androidx.annotation.StringRes @@ -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 79b11752a..2d51b032a 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 . + */ 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 f93a22291..d529db125 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 . + */ package com.pitchedapps.frost.enums import android.content.Context @@ -52,12 +68,13 @@ enum class OverlayContext(private val menuItem: FrostMenuItem?) : EnumBundle. + */ package com.pitchedapps.frost.enums import android.content.Context @@ -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 934dda07e..345aa88eb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/enums/Theme.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 . + */ package com.pitchedapps.frost.enums import android.graphics.Color @@ -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 2b881d1c4..b6207a7b5 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 . + */ 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 ab7e165a6..c65837128 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 . + */ package com.pitchedapps.frost.facebook import android.app.Activity @@ -38,13 +54,13 @@ object FbCookie { val cookies = cookie.split(";").map { Pair(it, SingleSubject.create()) } cookies.forEach { (cookie, callback) -> setCookie(FB_URL_BASE, cookie) { callback.onSuccess(it) } } Observable.zip(cookies.map { (_, callback) -> callback.toObservable() }) {} - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { - callback?.invoke() - L.d { "Cookies set" } - L._d { cookie } - flush() - } + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { + callback?.invoke() + L.d { "Cookies set" } + L._d { cookie } + flush() + } } } } @@ -132,4 +148,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 2f0e4e227..723ed4500 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbItem.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 . + */ package com.pitchedapps.frost.facebook import androidx.annotation.StringRes @@ -15,10 +31,10 @@ 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 { ACTIVITY_LOG(R.string.activity_log, GoogleMaterial.Icon.gmd_list, "me/allactivity"), 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 9b29d009b..2c987a485 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 . + */ 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 62675df69..2c171762c 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 . + */ 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 3d5c5bce9..5709bb9f8 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 . + */ package com.pitchedapps.frost.facebook.parsers import com.pitchedapps.frost.dbflow.CookieModel @@ -54,7 +70,6 @@ interface FrostParser { * Call parsing with given data */ fun parseFromData(cookie: String?, text: String): ParseResponse? - } const val FALLBACK_TIME_MOD = 1000000 @@ -92,7 +107,7 @@ internal abstract class FrostParserBase(private val redirectToText: } final override fun parseFromUrl(cookie: String?, url: String): ParseResponse? = - parse(cookie, frostJsoup(cookie, url)) + parse(cookie, frostJsoup(cookie, url)) override fun parse(cookie: String?, document: Document): ParseResponse? { cookie ?: return null @@ -109,17 +124,17 @@ internal abstract class FrostParserBase(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 27b731bc1..f05c42e9c 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 . + */ 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 by MessageParserImpl() { fun queryUser(cookie: String?, name: String) = parseFromUrl(cookie, "${FbItem.MESSAGES.url}/?q=$name") - } -data class FrostMessages(val threads: List, - val seeMore: FrostLink?, - val extraLinks: List +data class FrostMessages( + val threads: List, + val seeMore: FrostLink?, + val extraLinks: List ) : ParseNotification { override fun toString() = StringBuilder().apply { append("FrostMessages {\n") @@ -35,19 +55,19 @@ data class FrostMessages(val threads: List, }.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, * [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(true) { @@ -92,11 +114,12 @@ private class MessageParserImpl : FrostParserBase(true) { override fun parseImpl(doc: Document): FrostMessages? { val threadList = doc.getElementById("threadlist_rows") ?: return null - val threads: List = threadList.getElementsByAttributeValueMatching("id", ".*${FB_MESSAGE_NOTIF_ID_MATCHER.pattern}.*") + val threads: List = + 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(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 8aa8e7067..b8aa899b8 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 . + */ 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 by NotifParserImpl() data class FrostNotifs( - val notifs: List, - val seeMore: FrostLink? + val notifs: List, + 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(false) { @@ -67,8 +89,8 @@ private class NotifParserImpl : FrostParserBase(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(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 d33675143..7869d8819 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 . + */ 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(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 500c41028..584107cc5 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 . + */ 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() { 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(val call: Call, private val invoke: (Call) -> T } internal inline fun 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 { val request = cookie.requestBuilder() request.builder() @@ -75,8 +98,10 @@ internal inline fun 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>.withEmptyData(vararg key: String): List lines.forEach { val text = StringEscapeUtils.unescapeEcmaScript(it) @@ -135,8 +160,10 @@ fun String.getAuth(): RequestAuth { return auth } -inline fun Array.zip(crossinline mapper: (List) -> O, - crossinline caller: (T) -> R): Single { +inline fun Array.zip( + crossinline mapper: (List) -> O, + crossinline caller: (T) -> R +): Single { 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 8eeef08dc..e0ccea815 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 . + */ 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 = 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 { } fun RequestBuilder.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 { - override fun buildLoadData(model: HdImageMaybe, - width: Int, - height: Int, - options: Options): ModelLoader.LoadData? = - if (!model.isValid) null - else ModelLoader.LoadData(ObjectKey(model), HdImageFetcher(model)) + override fun buildLoadData( + model: HdImageMaybe, + width: Int, + height: Int, + options: Options + ): ModelLoader.LoadData? = + 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 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 e83e4e43a..dcb0ce10d 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 . + */ package com.pitchedapps.frost.facebook.requests import com.fasterxml.jackson.annotation.JsonCreator @@ -19,28 +35,27 @@ import java.io.IOException fun RequestAuth.getMenuData(): FrostRequest { 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("}", "") + .substringAfter("{", "") + .substringBefore("}", "") - val doc = Jsoup.parseBodyFragment(StringEscapeUtils.unescapeEcmaScript( - StringEscapeUtils.unescapeEcmaScript(footer))) + val doc = Jsoup.parseBodyFragment( + StringEscapeUtils.unescapeEcmaScript( + StringEscapeUtils.unescapeEcmaScript(footer) + ) + ) val footerData = mutableListOf() val footerSmallData = mutableListOf() @@ -76,11 +94,14 @@ fun parseMenu(call: Call): MenuData? { } @JsonIgnoreProperties(ignoreUnknown = true) -data class MenuData(val data: List = emptyList(), - val footer: MenuFooter = MenuFooter()) { +data class MenuData( + val data: List = emptyList(), + val footer: MenuFooter = MenuFooter() +) { - @JsonCreator constructor( - @JsonProperty("data") data: List? + @JsonCreator + constructor( + @JsonProperty("data") data: List? ) : this(data ?: emptyList(), MenuFooter()) fun flatMapValid(): List { @@ -95,7 +116,6 @@ data class MenuData(val data: List = 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 = emptyList(), - val all: List = emptyList()) : MenuItemData { +data class MenuHeader( + val id: String? = null, + val header: String? = null, + val visible: List = emptyList(), + val all: List = emptyList() +) : MenuItemData { - @JsonCreator constructor( - @JsonProperty("id") id: String?, - @JsonProperty("header") header: String?, - @JsonProperty("visible") visible: List?, - @JsonProperty("all") all: List?, - @JsonProperty("fake") fake: Boolean? + @JsonCreator + constructor( + @JsonProperty("id") id: String?, + @JsonProperty("header") header: String?, + @JsonProperty("visible") visible: List?, + @JsonProperty("all") all: List?, + @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 { +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) + @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 = emptyList(), - val smallData: List = emptyList()) { +data class MenuFooter( + val data: List = emptyList(), + val smallData: List = 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 0e37a61ec..f350c547e 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 . + */ 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. + */ 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 { 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 { } fun RequestAuth.markNotificationsRead(vararg notifId: Long) = - notifId.toTypedArray().zip( - { it.all { self -> self } }, - { markNotificationRead(it).invoke() }) \ No newline at end of file + notifId.toTypedArray().zip( + { 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 34e28c2e9..98e28bd33 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 . + */ package com.pitchedapps.frost.fragments import android.content.Context import android.os.Bundle -import com.google.android.material.floatingactionbutton.FloatingActionButton -import androidx.fragment.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 6555e076a..e24e8308f 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 . + */ 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 4f9133a6f..f77f83ea4 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 . + */ package com.pitchedapps.frost.fragments import ca.allanwang.kau.adapters.fastAdapter @@ -65,7 +81,6 @@ abstract class GenericRecyclerFragment> : RecyclerFragment * Create the fast adapter to bind to the recyclerview */ open fun getAdapter(): FastAdapter> = fastAdapter(this.adapter) - } abstract class FrostParserFragment> : 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 4f597731f..ff37b66d4 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 . + */ 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 override fun getDoc(cookie: String?) = frostJsoup(cookie, "${FbItem.NOTIFICATIONS.url}?more") override fun toItems(response: ParseResponse): List = - 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>() { } } } -} \ 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 d9edda780..72367eaa4 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 . + */ 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 50d4d7b48..0c471c63a 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 . + */ package com.pitchedapps.frost.glide import android.content.Context @@ -30,11 +46,11 @@ object FrostGlide { } fun RequestBuilder.transform(vararg transformation: BitmapTransformation): RequestBuilder = - 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 5eded1598..564224ea6 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 . + */ 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 1211b7421..6eacf48ee 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 . + */ package com.pitchedapps.frost.iitems import android.content.Context @@ -32,25 +48,25 @@ interface ClickableIItemContract { companion object { fun bindEvents(adapter: IAdapter>) { 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(R.layout.iitem_header, ::ViewHolder, itemId) { +open class HeaderIItem( + val text: String?, + itemId: Int = R.layout.iitem_header +) : KauIItem(R.layout.iitem_header, ::ViewHolder, itemId) { class ViewHolder(itemView: View) : FastAdapter.ViewHolder(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(R.layout.iitem_text, ::ViewHolder, itemId), - ClickableIItemContract { +open class TextIItem( + val text: String?, + override val url: String?, + itemId: Int = R.layout.iitem_text +) : KauIItem(R.layout.iitem_text, ::ViewHolder, itemId), + ClickableIItemContract { class ViewHolder(itemView: View) : FastAdapter.ViewHolder(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 4a7356b01..651a4a2aa 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 . + */ 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(R.layout.iitem_menu, ::ViewHolder), - ClickableIItemContract { +class MenuContentIItem(val data: MenuItem) : + KauIItem(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 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 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 06bc06042..e83329558 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 . + */ 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( +class NotificationIItem(val notification: FrostNotif, val cookie: String) : + KauIItem( R.layout.iitem_notification, ::ViewHolder -) { + ) { companion object { fun bindEvents(adapter: ItemAdapter) { 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 { 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) { 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 506d1cab6..51201d091 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 . + */ 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( - R.layout.iitem_tab_preview, - { ViewHolder(it) } + R.layout.iitem_tab_preview, + { ViewHolder(it) } ), IDraggable> { override fun withIsDraggable(draggable: Boolean): TabIItem = this @@ -45,6 +65,5 @@ class TabIItem(val item: FbItem) : KauIItem( 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 033e482f0..de19f99ca 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 . + */ 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 5444fad85..7da6295f5 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 . + */ 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 1ab001536..e64d4faa1 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 . + */ 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 980481a44..0dccc751a 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 . + */ 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 acda2d9b7..8ae3a2f43 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 . + */ 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() } val disposable = Single.zip(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 3e40b6ba9..afa8df35b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.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 . + */ package com.pitchedapps.frost.intro import android.os.Bundle @@ -17,7 +33,11 @@ class IntroFragmentTheme : BaseIntroFragment(R.layout.intro_theme) { val themeList get() = listOf(intro_theme_light, intro_theme_dark, intro_theme_amoled, intro_theme_glass) - override fun viewArray(): Array> = arrayOf(arrayOf(title), arrayOf(intro_theme_light, intro_theme_dark), arrayOf(intro_theme_amoled, intro_theme_glass)) + override fun viewArray(): Array> = 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) @@ -40,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 c0ccd649b..1fd8c76ea 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 . + */ 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 6e9537771..a4f9e1931 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 . + */ package com.pitchedapps.frost.intro import android.annotation.SuppressLint import android.content.res.ColorStateList import android.os.Bundle -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.fragment.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 e8373dd64..25f6d6aa9 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 . + */ package com.pitchedapps.frost.rx import io.reactivex.Single @@ -72,9 +88,9 @@ abstract class RxFlyweight { * you likely won't have a need for flyweights */ protected open fun createNewSource(input: T): Single = - 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 { 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 ededaad49..ee515a55b 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 . + */ package com.pitchedapps.frost.services import android.app.Notification @@ -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, - 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, + 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,12 +224,12 @@ 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(NotificationCompat.GROUP_ALERT_CHILDREN) @@ -211,31 +237,33 @@ enum class NotificationType( 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(NOTIFICATION_PERIODIC_JOB, minutes) + scheduleJob(NOTIFICATION_PERIODIC_JOB, minutes) const val NOTIFICATION_JOB_NOW = 6 fun Context.fetchNotifications(): Boolean = - fetchJob(NOTIFICATION_JOB_NOW) \ No newline at end of file + fetchJob(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 b2ccaea24..22acc9fb1 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 . + */ package com.pitchedapps.frost.services import android.app.job.JobInfo @@ -37,10 +53,10 @@ private enum class FrostRequestCommands : EnumBundle { } 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 @@ -58,7 +74,6 @@ private enum class FrostRequestCommands : EnumBundle { abstract fun propagate(bundle: BaseBundle): BaseBundle.() -> Unit companion object : EnumCompanion("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 f15df482b..4ede5163b 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.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 . + */ package com.pitchedapps.frost.services import android.app.job.JobParameters @@ -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 707220f64..20a497e3c 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 . + */ package com.pitchedapps.frost.services import android.app.Notification @@ -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) NotificationCompat.GROUP_ALERT_CHILDREN - else NotificationCompat.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 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 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 59df9ed78..2d86f3b99 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 . + */ 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 9253d9261..538e20f11 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 . + */ 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 02a86e588..10fa5c990 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 . + */ 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 91dac2427..4b538e877 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 . + */ 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 fe95e7f12..e0d314a85 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 . + */ 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 402322ad3..ff0badf03 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 . + */ 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 b5515a52d..a1ec33e65 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 . + */ 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 1f9411e4a..0200f1092 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 . + */ 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.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 1bb0449b5..61a90024d 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 . + */ 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 223eed3f7..c9e64eb37 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 . + */ package com.pitchedapps.frost.utils import android.graphics.drawable.AnimatedVectorDrawable -import androidx.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 c9a2f2850..33da56f2b 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 . + */ package com.pitchedapps.frost.utils object BuildUtils { @@ -18,8 +34,7 @@ object BuildUtils { } fun getAllStages(): Array = - 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 0cb57ed50..3c76759c4 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 . + */ 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 16b1d1499..f4baa2426 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 . + */ 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 Stack Overflow */ -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 2a562ba22..b6d9b8338 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 . + */ package com.pitchedapps.frost.utils import android.content.Intent @@ -39,12 +55,12 @@ interface EnumBundleCompanion> { operator fun get(bundle: BaseBundle?) = get(bundle?.getString(argTag)) operator fun get(intent: Intent?) = get(intent?.getStringExtra(argTag)) - } open class EnumCompanion>( - final override val argTag: String, - final override val values: Array) : EnumBundleCompanion { + final override val argTag: String, + final override val values: Array +) : EnumBundleCompanion { final override val valueMap: Map = values.map { it.name to it }.toMap() @@ -53,5 +69,4 @@ open class EnumCompanion>( 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 da8672f44..c783a8423 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 . + */ 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 bee2f49bc..8364c34e5 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 . + */ 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 9f068a58e..303142afb 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 . + */ 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 cafba223d..270160189 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 . + */ 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 650f277bf..56c1d6d9b 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 . + */ 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 androidx.annotation.StringRes -import com.google.android.material.snackbar.Snackbar -import androidx.core.content.FileProvider -import androidx.appcompat.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 Context.launchNewTask(cookieList: ArrayList = arrayListOf(), clearStack: Boolean = false) { +inline fun Context.launchNewTask( + cookieList: ArrayList = arrayListOf(), + clearStack: Boolean = false +) { startActivity(clearStack, intentBuilder = { putParcelableArrayListExtra(EXTRA_COOKIES, cookieList) }) @@ -81,8 +126,10 @@ fun Context.launchWebOverlay(url: String) = launchWebOverlayImpl(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(intentBuilder = { @@ -174,7 +221,6 @@ inline fun Activity.setFrostColors(builder: ActivityThemeUtils.() -> Unit) { themer.theme(this) } - fun frostEvent(name: String, vararg events: Pair) { // 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) + 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(@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() -} +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 dc2d75494..62330e4d5 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 . + */ 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 9f6d0c065..d7a7de0eb 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 . + */ package com.pitchedapps.frost.views import android.graphics.drawable.Drawable -import androidx.appcompat.widget.AppCompatTextView -import androidx.recyclerview.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 -(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) { super.bindView(viewHolder, payloads) @@ -33,20 +53,37 @@ class AccountItem(val cookie: CookieModel?) : KauIItem { - override fun onResourceReady(resource: Drawable?, model: Any?, target: Target?, dataSource: DataSource?, isFirstResource: Boolean): Boolean { - text.fadeIn() - return false - } + .transform(FrostGlide.roundCorner).listener(object : RequestListener { + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + text.fadeIn() + return false + } - override fun onLoadFailed(e: GlideException?, model: Any?, target: Target?, isFirstResource: Boolean): Boolean { - text.fadeIn() - return false - } - }).into(image) + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + 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. + */ package com.pitchedapps.frost.views import android.content.Context import android.graphics.drawable.GradientDrawable -import androidx.constraintlayout.widget.ConstraintLayout import android.util.AttributeSet -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) { 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() badge_text.background = badgeBackground badge_text.setTextColor(Prefs.mainActivityLayout.iconColor()) @@ -30,7 +53,13 @@ class BadgedIcon @JvmOverloads constructor( var iicon: IIcon? = null set(value) { field = value - badge_image.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) { @@ -46,5 +75,4 @@ class BadgedIcon @JvmOverloads constructor( 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 c44a81883..d17a424ce 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 . + */ package com.pitchedapps.frost.views import android.content.Context import android.os.Build -import androidx.swiperefreshlayout.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(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(context, attrs, defStyleAttr, defStyleRes) { override val layoutRes: Int = R.layout.view_content_base_recycler - } abstract class FrostContentView @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 @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 @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 198694263..2b9e8f9c2 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 . + */ package com.pitchedapps.frost.views import android.content.Context -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.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 85dc7e189..6ee34a2ba 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 . + */ 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) { /** @@ -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() } @@ -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 b2796999e..c25359406 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/FrostVideoViewer.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 . + */ package com.pitchedapps.frost.views import android.content.Context @@ -8,11 +24,22 @@ import android.util.AttributeSet import android.view.MotionEvent import android.view.ViewTreeObserver import android.widget.FrameLayout -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.utils.L 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.* @@ -21,7 +48,9 @@ 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 { companion object { @@ -51,16 +80,18 @@ class FrostVideoViewer @JvmOverloads constructor( inflate(R.layout.view_video, true) alpha = 0f video_background.setBackgroundColor( - if (!Prefs.blackMediaBg && Prefs.bgColor.isColorDark) - Prefs.bgColor.withMinAlpha(200) - else - Color.BLACK) + if (!Prefs.blackMediaBg && Prefs.bgColor.isColorDark) + Prefs.bgColor.withMinAlpha(200) + else + Color.BLACK + ) video.setViewerContract(this) video.pause() 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 + 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 ) video_toolbar.setOnMenuItemClickListener { when (it.itemId) { @@ -141,7 +172,6 @@ class FrostVideoViewer @JvmOverloads constructor( if (!video_toolbar.isGone) video_toolbar.fadeOut(duration = CONTROL_ANIMATION_DURATION) { video_toolbar.gone() } } - } interface FrostVideoViewerContract : VideoControlsVisibilityListener { @@ -171,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 18b7ae491..bf2f771de 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 . + */ package com.pitchedapps.frost.views import android.annotation.SuppressLint import android.content.Context -import androidx.viewpager.widget.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 8230c3388..b15ad5cf1 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 . + */ 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 14f77e72f..7f0d792ad 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 . + */ 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 c171ce772..e63fcc21a 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 . + */ package com.pitchedapps.frost.views import android.content.Context import android.graphics.drawable.Drawable -import androidx.constraintlayout.widget.ConstraintLayout -import androidx.appcompat.widget.AppCompatEditText -import androidx.appcompat.widget.AppCompatTextView -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.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() { - 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, 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. + */ package com.pitchedapps.frost.web import android.annotation.SuppressLint import android.content.Context import android.graphics.Bitmap import android.graphics.Color -import androidx.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 3c3c063af..12df80009 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 . + */ 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?>, fileChooserParams: FileChooserParams): Boolean { + override fun onShowFileChooser( + webView: WebView, + filePathCallback: ValueCallback?>, + 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 564b0e049..2afb28c95 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 . + */ 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 4e4df027c..bd696b026 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 . + */ 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 b83002a3e..e2d294f7b 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 . + */ 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 = - 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 8824e6353..d75f03bb7 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 . + */ 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 1f22f3038..392cb353c 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 . + */ 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 760d81fc7..6e7fc0b6a 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 . + */ package com.pitchedapps.frost.web import android.annotation.SuppressLint import android.content.Context -import androidx.core.view.NestedScrollingChild -import androidx.core.view.NestedScrollingChildHelper -import androidx.core.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) +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt index d730b933d..20610b2aa 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/MiscTest.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 . + */ package com.pitchedapps.frost import com.pitchedapps.frost.facebook.requests.zip @@ -19,12 +35,14 @@ class MiscTest { val now = System.currentTimeMillis() val base = 1 val data: LongArray = (0..15).map { Math.random() + base } - .toTypedArray().zip(List::toLongArray) { - Thread.sleep((it * 1000).toLong()) - System.currentTimeMillis() - now - }.blockingGet() + .toTypedArray().zip(List::toLongArray) { + Thread.sleep((it * 1000).toLong()) + System.currentTimeMillis() - now + }.blockingGet() println(data.contentToString()) - assertTrue(data.all { it >= base * 1000 && it < base * 1000 * 5 }, - "zip did not seem to work on different threads") + assertTrue( + data.all { it >= base * 1000 && it < base * 1000 * 5 }, + "zip did not seem to work on different threads" + ) } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/debugger/OfflineWebsiteTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/debugger/OfflineWebsiteTest.kt index e30ec1744..f7dad4d38 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/debugger/OfflineWebsiteTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/debugger/OfflineWebsiteTest.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 . + */ package com.pitchedapps.frost.debugger import com.pitchedapps.frost.facebook.FB_URL_BASE @@ -16,11 +32,10 @@ class OfflineWebsiteTest { val countdown = CountDownLatch(1) val buildPath = if (File(".").parentFile?.name == "app") "build/offline_test" else "app/build/offline_test" OfflineWebsite(FB_URL_BASE, COOKIE, baseDir = File(buildPath)) - .loadAndZip("test") { - println("Outcome $it") - countdown.countDown() - } + .loadAndZip("test") { + println("Outcome $it") + countdown.countDown() + } countdown.await() } - -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbDomTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbDomTest.kt index ce7489077..9472adfe1 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbDomTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbDomTest.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 . + */ package com.pitchedapps.frost.facebook import com.pitchedapps.frost.internal.authDependent @@ -22,5 +38,4 @@ class FbDomTest { assertNotNull(doc.getElementById("header")) assertNotNull(doc.getElementById("mJewelNav")) } - -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbRegexTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbRegexTest.kt index 088534663..f872cfc73 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbRegexTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbRegexTest.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 . + */ package com.pitchedapps.frost.facebook import org.apache.commons.text.StringEscapeUtils @@ -18,7 +34,8 @@ class FbRegexTest { @Test fun fbDtsgRegex() { val fb_dtsg = "readme" - val input = "data-sigil=\"mbasic_inline_feed_composer\">\u003Cinput type=\"hidden\" name=\"fb_dtsg\" value=\"$fb_dtsg\" autocomplete=\"off\" \\/>\u003Cinput type=\"hidden\" name=\"privacyx\" value=\"12345\"" + val input = + "data-sigil=\"mbasic_inline_feed_composer\">\u003Cinput type=\"hidden\" name=\"fb_dtsg\" value=\"$fb_dtsg\" autocomplete=\"off\" \\/>\u003Cinput type=\"hidden\" name=\"privacyx\" value=\"12345\"" assertEquals(fb_dtsg, FB_DTSG_MATCHER.find(input)[1]) } @@ -56,5 +73,4 @@ class FbRegexTest { val img = "https://scontent-yyz1-1.xx.fbcdn.net/v/t31.0-8/fr/cp0/e15/q65/89056_${id}_98239_o.jpg" assertEquals(id, FB_IMAGE_ID_MATCHER.find(img)[1]?.toLongOrNull()) } - -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbUrlTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbUrlTest.kt index beda26ef2..3bd59fd31 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbUrlTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/FbUrlTest.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 . + */ package com.pitchedapps.frost.facebook import com.pitchedapps.frost.utils.isImageUrl @@ -7,7 +23,6 @@ import kotlin.test.assertEquals import kotlin.test.assertFalse import kotlin.test.assertTrue - /** * Created by Allan Wang on 2017-07-07. */ @@ -63,16 +78,17 @@ class FbUrlTest { @Test fun video() { //note that the video numbers have been changed to maintain privacy - val url = "/video_redirect/?src=https%3A%2F%2Fvideo-yyz1-1.xx.fbcdn.net%2Fv%2Ft42.1790-2%2F2349078999904_n.mp4%3Fefg%3DeyJ87J9%26oh%3Df5777784%26oe%3D56FD4&source=media_collage&id=1735049&refid=8&_ft_=qid.6484464%3Amf_story_key.-43172431214%3Atop_level_post_id.102773&__tn__=FEH-R" - val expected = "https://video-yyz1-1.xx.fbcdn.net/v/t42.1790-2/2349078999904_n.mp4?efg=eyJ87J9&oh=f5777784&oe=56FD4&source=media_collage&id=1735049&_ft_=qid.6484464:mf_story_key.-43172431214:top_level_post_id.102773&__tn__=FEH-R" + val url = + "/video_redirect/?src=https%3A%2F%2Fvideo-yyz1-1.xx.fbcdn.net%2Fv%2Ft42.1790-2%2F2349078999904_n.mp4%3Fefg%3DeyJ87J9%26oh%3Df5777784%26oe%3D56FD4&source=media_collage&id=1735049&refid=8&_ft_=qid.6484464%3Amf_story_key.-43172431214%3Atop_level_post_id.102773&__tn__=FEH-R" + val expected = + "https://video-yyz1-1.xx.fbcdn.net/v/t42.1790-2/2349078999904_n.mp4?efg=eyJ87J9&oh=f5777784&oe=56FD4&source=media_collage&id=1735049&_ft_=qid.6484464:mf_story_key.-43172431214:top_level_post_id.102773&__tn__=FEH-R" assertFbFormat(expected, url) } - @Test fun image() { arrayOf( - "https://scontent-yyz1-1.xx.fbcdn.net/v/t1.0-9/fr/cp0/e15/q65/229_546131_836546862_n.jpg?efg=e343J9&oh=d4245b1&oe=5453" + "https://scontent-yyz1-1.xx.fbcdn.net/v/t1.0-9/fr/cp0/e15/q65/229_546131_836546862_n.jpg?efg=e343J9&oh=d4245b1&oe=5453" // "/photo/view_full_size/?fbid=1523&ref_component=mbasic_photo_permalink&ref_page=%2Fwap%2Fphoto.php&refid=153&_ft_=...", // "#!/photo/view_full_size/?fbid=1523&ref_component=mbasic_photo_permalink&ref_page=%2Fwap%2Fphoto.php&refid=153&_ft_=..." ).forEach { @@ -83,7 +99,7 @@ class FbUrlTest { @Test fun indirectImage() { arrayOf( - "#!/photo/view_full_size/?fbid=107368839645039" + "#!/photo/view_full_size/?fbid=107368839645039" ).forEach { assertTrue(it.isIndirectImageUrl, "Failed to match indirect image for $it") } @@ -92,13 +108,12 @@ class FbUrlTest { @Test fun antiImageRegex() { arrayOf( - "http...fbcdn.net...mp4", - "/photo/...png", - "https://www.google.ca" + "http...fbcdn.net...mp4", + "/photo/...png", + "https://www.google.ca" ).forEach { assertFalse(it.isImageUrl, "Should not have matched image for $it") } - } @Test @@ -112,5 +127,4 @@ class FbUrlTest { // val urlBase = "photo/view_full_size/?fbid=1234&ref_component=mbasic_photo_permalink&ref_page=%2Fwap%2Fphoto.php&refid=13&_ft_=qid.1234%3Amf_story_key.1234%3Atop_level_post_id" // assertFbFormat("$FB_URL_BASE$urlBase", "#!/$urlBase") // } - -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/parsers/FbParseTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/parsers/FbParseTest.kt index 3307c72e6..075f045e5 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/parsers/FbParseTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/parsers/FbParseTest.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 . + */ package com.pitchedapps.frost.facebook.parsers import com.pitchedapps.frost.internal.COOKIE @@ -24,11 +40,11 @@ class FbParseTest { } private inline fun FrostParser.test(action: T.() -> Unit = {}) = - parse(COOKIE).test(url, action) + parse(COOKIE).test(url, action) private inline fun ParseResponse?.test(url: String, action: T.() -> Unit = {}) { val response = this - ?: fail("${T::class.simpleName} parser returned null for $url") + ?: fail("${T::class.simpleName} parser returned null for $url") println(response) response.data.action() } @@ -58,4 +74,4 @@ class FbParseTest { } notifs.map(FrostNotif::time).assertDescending("notif time values") } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbFullImageTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbFullImageTest.kt index c4e51d41b..4eb90d743 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbFullImageTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbFullImageTest.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 . + */ package com.pitchedapps.frost.facebook.requests import com.pitchedapps.frost.internal.COOKIE @@ -26,4 +42,4 @@ class FbFullImageTest { assertNotNull(result) println(result) } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt index c5fc8e8e8..3a7abec45 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/facebook/requests/FbRequestTest.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 . + */ package com.pitchedapps.frost.facebook.requests import com.fasterxml.jackson.databind.ObjectMapper @@ -8,7 +24,11 @@ import com.pitchedapps.frost.internal.authDependent import okhttp3.Call import org.junit.BeforeClass import org.junit.Test -import kotlin.test.* +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue +import kotlin.test.fail /** * Created by Allan Wang on 21/12/17. diff --git a/app/src/test/kotlin/com/pitchedapps/frost/injectors/InjectorTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/injectors/InjectorTest.kt index 76b37afe8..f38f03bb8 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/injectors/InjectorTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/injectors/InjectorTest.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 . + */ package com.pitchedapps.frost.injectors import org.junit.Test diff --git a/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt b/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt index 81175b193..061e7c38f 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/internal/Internal.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 . + */ package com.pitchedapps.frost.internal import com.pitchedapps.frost.facebook.FB_USER_MATCHER @@ -11,7 +27,7 @@ import org.junit.Assume import org.junit.Test import java.io.File import java.io.FileInputStream -import java.util.* +import java.util.Properties import java.util.concurrent.TimeUnit import kotlin.reflect.full.starProjectedType import kotlin.test.assertEquals @@ -111,4 +127,4 @@ class InternalTest { } catch (e: Exception) { // pass } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/rx/ResettableFlyweightTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/rx/ResettableFlyweightTest.kt index a520e9e3e..26a5a8de5 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/rx/ResettableFlyweightTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/rx/ResettableFlyweightTest.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 . + */ package com.pitchedapps.frost.rx import com.pitchedapps.frost.internal.concurrentTest @@ -54,6 +70,4 @@ class ResettableFlyweightTest { } } } - - -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/BuildUtilsTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/BuildUtilsTest.kt index 92bd5bec3..b3d44d690 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/BuildUtilsTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/BuildUtilsTest.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 . + */ package com.pitchedapps.frost.utils import com.pitchedapps.frost.BuildConfig @@ -19,4 +35,4 @@ class BuildUtilsTest { fun androidTests() { assertNotNull(BuildUtils.match(BuildConfig.VERSION_NAME)) } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/JsoupCleanerTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/JsoupCleanerTest.kt index 4ec09ea69..72cca836f 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/JsoupCleanerTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/JsoupCleanerTest.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 . + */ package com.pitchedapps.frost.utils import org.junit.Test @@ -47,10 +63,10 @@ class JsoupCleanerTest { @Test fun kau() { - val html = """
KAU

An extensive collection of Kotlin Android Utils

KAUclose
  • Huge package of one line extension functions
  • Custom UI views
  • Adapter items and animators
  • SearchView
  • Custom delegates
""" - val expected = """
""" + val html = + """
KAU

An extensive collection of Kotlin Android Utils

KAUclose
  • Huge package of one line extension functions
  • Custom UI views
  • Adapter items and animators
  • SearchView
  • Custom delegates
""" + val expected = + """
""" html.assertCleanHtml(expected) } - } - diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt index 56ec4c02f..088a7fbef 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/PrefsTest.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 . + */ package com.pitchedapps.frost.utils import org.junit.Before @@ -38,4 +54,4 @@ class PrefsTest { test = 3L assertEquals(3L, file) } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/StringEscapeUtilsTest.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/StringEscapeUtilsTest.kt index 86bd4ce50..f5ea56aed 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/StringEscapeUtilsTest.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/StringEscapeUtilsTest.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 . + */ package com.pitchedapps.frost.utils import org.junit.Test @@ -13,4 +29,4 @@ class StringEscapeUtilsTest { val escaped = "\\u003Chead> color=\\\"#3b5998\\\"" assertEquals(" color=\"#3b5998\"", escaped.unescapeHtml()) } -} \ No newline at end of file +} diff --git a/app/src/test/kotlin/com/pitchedapps/frost/utils/UrlTests.kt b/app/src/test/kotlin/com/pitchedapps/frost/utils/UrlTests.kt index 109387a02..44e8377a8 100644 --- a/app/src/test/kotlin/com/pitchedapps/frost/utils/UrlTests.kt +++ b/app/src/test/kotlin/com/pitchedapps/frost/utils/UrlTests.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 . + */ package com.pitchedapps.frost.utils import com.pitchedapps.frost.facebook.FACEBOOK_COM @@ -17,19 +33,21 @@ class UrlTests { fun independence() { mapOf( - GOOGLE to true, - FACEBOOK_COM to true, - "#!/photos/viewer/?photoset_token=pcb.1234" to false, - "#test-id" to false, - "#" to false, - "#!" to false, - "#!/" to false, - "#!/events/permalink/going/?event_id=" to false, - "/this/is/valid" to true, - "#!/facebook/segment" to true + GOOGLE to true, + FACEBOOK_COM to true, + "#!/photos/viewer/?photoset_token=pcb.1234" to false, + "#test-id" to false, + "#" to false, + "#!" to false, + "#!/" to false, + "#!/events/permalink/going/?event_id=" to false, + "/this/is/valid" to true, + "#!/facebook/segment" to true ).forEach { (url, valid) -> - assertEquals(valid, url.isIndependent, - "Independence test failed for $url; should be $valid") + assertEquals( + valid, url.isIndependent, + "Independence test failed for $url; should be $valid" + ) } } @@ -38,4 +56,4 @@ class UrlTests { assertFalse(GOOGLE.isFacebookUrl, "google") assertTrue(FACEBOOK_COM.isFacebookUrl, "facebook") } -} \ No newline at end of file +} diff --git a/build.gradle b/build.gradle index ef1dc4481..64e324d21 100644 --- a/build.gradle +++ b/build.gradle @@ -12,6 +12,7 @@ buildscript { classpath "com.android.tools.build:gradle:${ANDROID_GRADLE}" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${KOTLIN}" classpath "com.bugsnag:bugsnag-android-gradle-plugin:${BUGSNAG_PLUGIN}" + classpath "com.diffplug.spotless:spotless-plugin-gradle:${SPOTLESS}" classpath "com.getkeepsafe.dexcount:dexcount-gradle-plugin:${DEX_PLUGIN}" classpath "gradle.plugin.com.gladed.gradle.androidgitversion:gradle-android-git-version:${GIT_PLUGIN}" } diff --git a/gradle.properties b/gradle.properties index f708598c3..1af549445 100644 --- a/gradle.properties +++ b/gradle.properties @@ -20,6 +20,9 @@ KOTLIN=1.3.11 # https://mvnrepository.com/artifact/com.android.tools.build/gradle?repo=google ANDROID_GRADLE=3.2.1 +# https://github.com/diffplug/spotless/blob/master/plugin-gradle/CHANGES.md +SPOTLESS=3.17.0 + # https://github.com/bugsnag/bugsnag-android/releases BUGSNAG=4.9.3 # https://github.com/bugsnag/bugsnag-android-gradle-plugin/releases diff --git a/spotless.gradle b/spotless.gradle new file mode 100644 index 000000000..22dba3a82 --- /dev/null +++ b/spotless.gradle @@ -0,0 +1,11 @@ +apply plugin: "com.diffplug.gradle.spotless" + +spotless { + kotlin { + target "**/*.kt" + ktlint() + licenseHeaderFile '../spotless.license.kt' + trimTrailingWhitespace() + endWithNewline() + } +} \ No newline at end of file diff --git a/spotless.license.kt b/spotless.license.kt new file mode 100644 index 000000000..35d16571d --- /dev/null +++ b/spotless.license.kt @@ -0,0 +1,16 @@ +/* + * Copyright $YEAR 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 . + */ \ No newline at end of file