From 14185936f46160997ef9eaae92cb3c8eacae93c5 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 30 Jul 2017 15:57:27 -0700 Subject: [PATCH] Intro (#100) * Create base activity * Created some testers * Update theme and fix mess up * Update theme and replace paint * WIP intro drawables * Create intro screens * Clear unnecessary dependencies * Finalize intro panels * Clean up intro * Attack intro to settings * Fix lint * Finalize intro --- app/build.gradle | 3 +- app/src/main/AndroidManifest.xml | 4 +- app/src/main/assets/css/core/_base.scss | 42 +++-- app/src/main/assets/css/core/_colors.scss | 1 + app/src/main/assets/css/core/main.compact.css | 22 ++- app/src/main/assets/css/core/main.scss | 23 ++- .../main/assets/css/themes/custom.compact.css | 22 ++- app/src/main/assets/css/themes/custom.scss | 1 + .../frost/activities/BaseActivity.kt | 2 + .../frost/activities/ImageActivity.kt | 14 +- .../frost/activities/IntroActivity.kt | 169 ++++++++++++++++++ .../frost/activities/LoginActivity.kt | 3 +- .../frost/activities/MainActivity.kt | 10 ++ .../frost/activities/SettingsActivity.kt | 9 +- .../pitchedapps/frost/injectors/CssAssets.kt | 1 + .../frost/intro/IntroFragmentTheme.kt | 51 ++++++ .../frost/intro/IntroImageFragments.kt | 112 ++++++++++++ .../frost/intro/IntroMainFragments.kt | 135 ++++++++++++++ .../frost/utils/AnimatedVectorDelegate.kt | 82 +++++++++ .../com/pitchedapps/frost/utils/Showcase.kt | 2 + .../com/pitchedapps/frost/utils/Utils.kt | 10 +- .../pitchedapps/frost/utils/iab/IABBinder.kt | 26 +-- .../pitchedapps/frost/utils/iab/IABDialogs.kt | 6 +- .../com/pitchedapps/frost/views/BadgedIcon.kt | 2 + .../main/res/drawable/intro_phone_case.xml | 47 +++++ .../res/drawable/intro_phone_long_press.xml | 109 +++++++++++ app/src/main/res/drawable/intro_phone_nav.xml | 49 +++++ .../main/res/drawable/intro_phone_screen.xml | 12 ++ app/src/main/res/drawable/intro_phone_tab.xml | 73 ++++++++ .../res/layout/activity_image_textless.xml | 2 +- app/src/main/res/layout/activity_intro.xml | 63 +++++++ app/src/main/res/layout/activity_main.xml | 2 +- app/src/main/res/layout/activity_selector.xml | 10 +- app/src/main/res/layout/intro_end.xml | 44 +++++ app/src/main/res/layout/intro_image.xml | 45 +++++ app/src/main/res/layout/intro_theme.xml | 78 ++++++++ app/src/main/res/layout/intro_welcome.xml | 43 +++++ app/src/main/res/layout/view_account.xml | 2 +- app/src/main/res/values/dimens.xml | 10 +- app/src/main/res/values/ids.xml | 6 + app/src/main/res/values/strings_intro.xml | 17 ++ app/src/main/res/values/strings_libs.xml | 26 --- app/src/main/res/values/strings_preferences | 1 + app/src/main/res/values/strings_temp.xml | 6 + app/src/main/res/values/styles.xml | 26 +++ gradle.properties | 2 +- 46 files changed, 1334 insertions(+), 91 deletions(-) create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt create mode 100644 app/src/main/res/drawable/intro_phone_case.xml create mode 100644 app/src/main/res/drawable/intro_phone_long_press.xml create mode 100644 app/src/main/res/drawable/intro_phone_nav.xml create mode 100644 app/src/main/res/drawable/intro_phone_screen.xml create mode 100644 app/src/main/res/drawable/intro_phone_tab.xml create mode 100644 app/src/main/res/layout/activity_intro.xml create mode 100644 app/src/main/res/layout/intro_end.xml create mode 100644 app/src/main/res/layout/intro_image.xml create mode 100644 app/src/main/res/layout/intro_theme.xml create mode 100644 app/src/main/res/layout/intro_welcome.xml create mode 100644 app/src/main/res/values/strings_intro.xml delete mode 100644 app/src/main/res/values/strings_libs.xml create mode 100644 app/src/main/res/values/strings_temp.xml diff --git a/app/build.gradle b/app/build.gradle index 5708068e518..98179294b00 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ apply plugin: 'com.github.triplet.play' play { jsonFile = file('../files/gplay-keys.json') - track = 'beta' + track = 'alpha' errorOnSizeLimit = true uploadImages = false untrackOld = true @@ -172,4 +172,5 @@ dependencies { compile "com.davemorrissey.labs:subsampling-scale-image-view:${SCALE_IMAGE_VIEW}" compile "com.sothree.slidinguppanel:library:${SLIDING_PANEL}" + } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d27c037c7c8..c4275ae61c6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -105,7 +105,9 @@ android:scheme="https" /> - + diff --git a/app/src/main/assets/css/core/_base.scss b/app/src/main/assets/css/core/_base.scss index 344b66963d6..a715d8bc0da 100644 --- a/app/src/main/assets/css/core/_base.scss +++ b/app/src/main/assets/css/core/_base.scss @@ -1,17 +1,35 @@ @mixin placeholder { - ::-webkit-input-placeholder { - @content - } + ::-webkit-input-placeholder { + @content; + } - :-moz-placeholder { - @content - } + :-moz-placeholder { + @content; + } - ::-moz-placeholder { - @content - } + ::-moz-placeholder { + @content; + } - :-ms-input-placeholder { - @content - } + :-ms-input-placeholder { + @content; + } +} + +@mixin keyframes($name) { + @-webkit-keyframes #{$name} { + @content; + } + + @-moz-keyframes #{$name} { + @content; + } + + @-ms-keyframes #{$name} { + @content; + } + + @keyframes #{$name} { + @content; + } } diff --git a/app/src/main/assets/css/core/_colors.scss b/app/src/main/assets/css/core/_colors.scss index 66fbe5b70e1..32dd2be8f93 100644 --- a/app/src/main/assets/css/core/_colors.scss +++ b/app/src/main/assets/css/core/_colors.scss @@ -8,4 +8,5 @@ $link: #d59ed5 !default; $background: #451515 !default; $background2: rgba(lighten($background, 35%), 0.2) !default; $bg_opaque: rgba($background, 1.0) !default; +$bg_opaque2: rgba($background2, 1.0) !default; $divider: rgba($text, 0.3) !default; diff --git a/app/src/main/assets/css/core/main.compact.css b/app/src/main/assets/css/core/main.compact.css index 713f505b4e5..25568b78e3e 100644 --- a/app/src/main/assets/css/core/main.compact.css +++ b/app/src/main/assets/css/core/main.compact.css @@ -8,9 +8,11 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r .jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p, .mentions-suggest-item, .mentions-suggest { background: #451515 !important; } +._403n, ._1-kc { background: #c74646 !important; } + button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._55fj, .excessItem, ._4e8n, ._5pxa._3uj9, ._5n_5, ._u2d, ._56bu::before, ._5h8f, ._d00, ._2066, ._2k51, ._4qax, .aclb, ._4756, ._w34, ._56bv::before, ._5769, ._34iv, ._z-w, .acbk { background: rgba(199, 70, 70, 0.2) !important; } -[style*="color"], body, input, ._42rv, ._z-z, ._z-v, ._1e8d, ._36nl, ._36nm, ._2_11, ._2_rf, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, .fcb, ._56cz._56c_, ._1gk_, ._55fj, ._45fu, ._18qg, ._1_ac, textarea, ._24pi, ._4en9, ._1kb, ._5p7j, ._2klz, ._5780, ._5781, ._5782, ._3u9u, ._3u9_, ._3u9s, ._1hcx, ._2066, ._1_-1, ._cv_, ._1nbx, ._2cuh, ._4ms9, ._4ms5, ._4ms6, ._31b4, ._31b5, ._5q_r, ._idb, ._27vp, ._4nwe, ._4nw9, ._27vi, .appCenterAppInfo, .appCenterPermissions, ._3c9l, ._3c9m, ._4jn_, ._32qt, ._3mom, ._3moo, ._-7o, ._d00, ._d01, ._559g, ._2new, .appCenterCategorySelectorButton, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, .title, ._46pa, ._336p, ._1rrd, ._2om4, ._3m1m, ._2om2, ._5n_e, .appListExplanation, ._5yt8, ._8he, ._2luw, ._5rgs, h1, h2, h3, h4, h5, h6 { color: #d7b0d7 !important; } +[style*="color"], body, input, ._42rv, ._z-z, ._z-v, ._1e8d, ._36nl, ._36nm, ._2_11, ._2_rf, ._2ip_, ._403p, ._5xu2, ._3ml8, ._3mla, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, .fcb, ._56cz._56c_, ._1gk_, ._55fj, ._45fu, ._18qg, ._1_ac, textarea, ._24pi, ._4en9, ._1kb, ._5p7j, ._2klz, ._5780, ._5781, ._5782, ._3u9u, ._3u9_, ._3u9s, ._1hcx, ._2066, ._1_-1, ._cv_, ._1nbx, ._2cuh, ._4ms9, ._4ms5, ._4ms6, ._31b4, ._31b5, ._5q_r, ._idb, ._27vp, ._4nwe, ._4nw9, ._27vi, .appCenterAppInfo, .appCenterPermissions, ._3c9l, ._3c9m, ._4jn_, ._32qt, ._3mom, ._3moo, ._-7o, ._d00, ._d01, ._559g, ._2new, .appCenterCategorySelectorButton, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, .title, ._46pa, ._336p, ._1rrd, ._2om4, ._3m1m, ._2om2, ._5n_e, .appListExplanation, ._5yt8, ._8he, ._2luw, ._5rgs, h1, h2, h3, h4, h5, h6 { color: #d7b0d7 !important; } ._15kl::before, ._5j35::after, ._2k4b, ._3to7, ._4nw8 { border-left: 1px solid rgba(215, 176, 215, 0.3) !important; } @@ -24,7 +26,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS ._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: rgba(215, 176, 215, 0.3) !important; } -._220g, ._2zh4::before, ._2ip_ ._15kk::before, ._2ip_ ._15kk + ._4u3j::before, ._58a0:before, ._43mh::before, ._43mh::after, ._1_-1::before, ._1kmv:after, ._1_ac:before { background: rgba(215, 176, 215, 0.3) !important; } +._220g, ._2zh4::before, ._2ip_ ._2zh4::before, ._2ip_ ._15kk::before, ._2ip_ ._15kk + ._4u3j::before, ._58a0:before, ._43mh::before, ._43mh::after, ._1_-1::before, ._1kmv:after, ._1_ac:before { background: rgba(215, 176, 215, 0.3) !important; } ._56bf, .touch .btn { border-radius: 0 !important; border: 0 !important; } @@ -49,3 +51,19 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS a, ._5fpq { color: #d59ed5 !important; } .excessItem { outline: rgba(215, 176, 215, 0.3) !important; } + +@-webkit-keyframes highlightFade { 0% { background: rgba(199, 70, 70, 0.2); } + 50% { background: rgba(199, 70, 70, 0.2); } + 100% { background: rgba(255, 0, 255, 0.02); } } + +@-moz-keyframes highlightFade { 0% { background: rgba(199, 70, 70, 0.2); } + 50% { background: rgba(199, 70, 70, 0.2); } + 100% { background: rgba(255, 0, 255, 0.02); } } + +@-ms-keyframes highlightFade { 0% { background: rgba(199, 70, 70, 0.2); } + 50% { background: rgba(199, 70, 70, 0.2); } + 100% { background: rgba(255, 0, 255, 0.02); } } + +@keyframes highlightFade { 0% { background: rgba(199, 70, 70, 0.2); } + 50% { background: rgba(199, 70, 70, 0.2); } + 100% { background: rgba(255, 0, 255, 0.02); } } diff --git a/app/src/main/assets/css/core/main.scss b/app/src/main/assets/css/core/main.scss index 382f64e4620..6f7c619073a 100644 --- a/app/src/main/assets/css/core/main.scss +++ b/app/src/main/assets/css/core/main.scss @@ -29,6 +29,10 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r background: $bg_opaque !important; } +._403n, ._1-kc { + background: $bg_opaque2 !important; +} + button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._55fj, .excessItem, ._4e8n, ._5pxa._3uj9, ._5n_5, ._u2d, ._56bu::before, ._5h8f, ._d00, ._2066, ._2k51, @@ -38,7 +42,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS } [style*="color"], body, input, ._42rv, -._z-z, ._z-v, ._1e8d, ._36nl, ._36nm, ._2_11, ._2_rf, +._z-z, ._z-v, ._1e8d, ._36nl, ._36nm, ._2_11, ._2_rf, ._2ip_, ._403p, ._5xu2, ._3ml8, ._3mla, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, .fcb, ._56cz._56c_, ._1gk_, ._55fj, ._45fu, ._18qg, ._1_ac, textarea, ._24pi, ._4en9, ._1kb, ._5p7j, ._2klz, ._5780, ._5781, ._5782, ._3u9u, ._3u9_, ._3u9s, ._1hcx, ._2066, ._1_-1, ._cv_, ._1nbx, ._2cuh, ._4ms9, ._4ms5, ._4ms6, ._31b4, ._31b5, ._5q_r, ._idb, ._27vp, ._4nwe, ._4nw9, ._27vi, .appCenterAppInfo, .appCenterPermissions, ._3c9l, ._3c9m, ._4jn_, ._32qt, ._3mom, ._3moo, ._-7o, ._d00, ._d01, ._559g, ._2new, .appCenterCategorySelectorButton, @@ -86,7 +90,7 @@ h1, h2, h3, h4, h5, h6 { } ._220g, -._2zh4::before, ._2ip_ ._15kk::before, ._2ip_ ._15kk + ._4u3j::before, ._58a0:before, ._43mh::before, ._43mh::after, ._1_-1::before, ._1kmv:after, ._1_ac:before { +._2zh4::before, ._2ip_ ._2zh4::before, ._2ip_ ._15kk::before, ._2ip_ ._15kk + ._4u3j::before, ._58a0:before, ._43mh::before, ._43mh::after, ._1_-1::before, ._1kmv:after, ._1_ac:before { background: $divider !important; } @@ -138,3 +142,18 @@ a, .excessItem { outline: $divider !important; } + +//new comment +@include keyframes(highlightFade) { + 0% { + background: $background2; + } + + 50% { + background: $background2; + } + + 100% { + background: $bg_transparent; + } +} diff --git a/app/src/main/assets/css/themes/custom.compact.css b/app/src/main/assets/css/themes/custom.compact.css index 3ca538747ca..b9cad06de24 100644 --- a/app/src/main/assets/css/themes/custom.compact.css +++ b/app/src/main/assets/css/themes/custom.compact.css @@ -8,9 +8,11 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r .jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p, .mentions-suggest-item, .mentions-suggest { background: $O$ !important; } +._403n, ._1-kc { background: $OO$ !important; } + button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._55fj, .excessItem, ._4e8n, ._5pxa._3uj9, ._5n_5, ._u2d, ._56bu::before, ._5h8f, ._d00, ._2066, ._2k51, ._4qax, .aclb, ._4756, ._w34, ._56bv::before, ._5769, ._34iv, ._z-w, .acbk { background: $BBT$ !important; } -[style*="color"], body, input, ._42rv, ._z-z, ._z-v, ._1e8d, ._36nl, ._36nm, ._2_11, ._2_rf, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, .fcb, ._56cz._56c_, ._1gk_, ._55fj, ._45fu, ._18qg, ._1_ac, textarea, ._24pi, ._4en9, ._1kb, ._5p7j, ._2klz, ._5780, ._5781, ._5782, ._3u9u, ._3u9_, ._3u9s, ._1hcx, ._2066, ._1_-1, ._cv_, ._1nbx, ._2cuh, ._4ms9, ._4ms5, ._4ms6, ._31b4, ._31b5, ._5q_r, ._idb, ._27vp, ._4nwe, ._4nw9, ._27vi, .appCenterAppInfo, .appCenterPermissions, ._3c9l, ._3c9m, ._4jn_, ._32qt, ._3mom, ._3moo, ._-7o, ._d00, ._d01, ._559g, ._2new, .appCenterCategorySelectorButton, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, .title, ._46pa, ._336p, ._1rrd, ._2om4, ._3m1m, ._2om2, ._5n_e, .appListExplanation, ._5yt8, ._8he, ._2luw, ._5rgs, h1, h2, h3, h4, h5, h6 { color: $T$ !important; } +[style*="color"], body, input, ._42rv, ._z-z, ._z-v, ._1e8d, ._36nl, ._36nm, ._2_11, ._2_rf, ._2ip_, ._403p, ._5xu2, ._3ml8, ._3mla, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, .fcb, ._56cz._56c_, ._1gk_, ._55fj, ._45fu, ._18qg, ._1_ac, textarea, ._24pi, ._4en9, ._1kb, ._5p7j, ._2klz, ._5780, ._5781, ._5782, ._3u9u, ._3u9_, ._3u9s, ._1hcx, ._2066, ._1_-1, ._cv_, ._1nbx, ._2cuh, ._4ms9, ._4ms5, ._4ms6, ._31b4, ._31b5, ._5q_r, ._idb, ._27vp, ._4nwe, ._4nw9, ._27vi, .appCenterAppInfo, .appCenterPermissions, ._3c9l, ._3c9m, ._4jn_, ._32qt, ._3mom, ._3moo, ._-7o, ._d00, ._d01, ._559g, ._2new, .appCenterCategorySelectorButton, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, .title, ._46pa, ._336p, ._1rrd, ._2om4, ._3m1m, ._2om2, ._5n_e, .appListExplanation, ._5yt8, ._8he, ._2luw, ._5rgs, h1, h2, h3, h4, h5, h6 { color: $T$ !important; } ._15kl::before, ._5j35::after, ._2k4b, ._3to7, ._4nw8 { border-left: 1px solid $D$ !important; } @@ -24,7 +26,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS ._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: $D$ !important; } -._220g, ._2zh4::before, ._2ip_ ._15kk::before, ._2ip_ ._15kk + ._4u3j::before, ._58a0:before, ._43mh::before, ._43mh::after, ._1_-1::before, ._1kmv:after, ._1_ac:before { background: $D$ !important; } +._220g, ._2zh4::before, ._2ip_ ._2zh4::before, ._2ip_ ._15kk::before, ._2ip_ ._15kk + ._4u3j::before, ._58a0:before, ._43mh::before, ._43mh::after, ._1_-1::before, ._1kmv:after, ._1_ac:before { background: $D$ !important; } ._56bf, .touch .btn { border-radius: 0 !important; border: 0 !important; } @@ -49,3 +51,19 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS a, ._5fpq { color: $TT$ !important; } .excessItem { outline: $D$ !important; } + +@-webkit-keyframes highlightFade { 0% { background: $BBT$; } + 50% { background: $BBT$; } + 100% { background: $BT$; } } + +@-moz-keyframes highlightFade { 0% { background: $BBT$; } + 50% { background: $BBT$; } + 100% { background: $BT$; } } + +@-ms-keyframes highlightFade { 0% { background: $BBT$; } + 50% { background: $BBT$; } + 100% { background: $BT$; } } + +@keyframes highlightFade { 0% { background: $BBT$; } + 50% { background: $BBT$; } + 100% { background: $BT$; } } diff --git a/app/src/main/assets/css/themes/custom.scss b/app/src/main/assets/css/themes/custom.scss index 307fe8153bb..1b50b97a939 100644 --- a/app/src/main/assets/css/themes/custom.scss +++ b/app/src/main/assets/css/themes/custom.scss @@ -4,6 +4,7 @@ $link: unquote('$TT$'); $background: unquote('$B$'); $background2: unquote('$BBT$'); $bg_opaque: unquote('$O$'); +$bg_opaque2: unquote('$OO$'); $divider: unquote('$D$'); @import "../core/main"; 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 fd020af116a..6806bf241a4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt @@ -1,11 +1,13 @@ package com.pitchedapps.frost.activities +import android.content.Intent import android.os.Bundle import android.support.v7.app.AppCompatActivity import com.pitchedapps.frost.R import com.pitchedapps.frost.utils.Prefs import com.pitchedapps.frost.utils.materialDialogThemed import com.pitchedapps.frost.utils.setFrostTheme +import org.jetbrains.anko.contentView /** * Created by Allan Wang on 2017-06-12. 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 a7c59deb437..2e4ae410cdb 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt @@ -122,7 +122,7 @@ class ImageActivity : AppCompatActivity() { } else { photo.setImage(ImageSource.uri(it)) fabAction = FabStates.DOWNLOAD - photo.animate().alpha(1f).scaleX(1f).scaleY(1f).withEndAction { fab.show() }.start() + photo.animate().alpha(1f).scaleXY(1f).withEndAction { fab.show() }.start() } }) } else { @@ -283,9 +283,15 @@ internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconC * If it's in view, give it some animations */ fun update(fab: FloatingActionButton) { - fab.transition { - setIcon(iicon, color = iconColor) - backgroundTintList = ColorStateList.valueOf(backgroundTint) + if (fab.isHidden) { + fab.setIcon(iicon, color = iconColor) + fab.backgroundTintList = ColorStateList.valueOf(backgroundTint) + fab.show() + } else { + fab.fadeScaleTransition { + setIcon(iicon, color = iconColor) + backgroundTintList = ColorStateList.valueOf(backgroundTint) + } } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt new file mode 100644 index 00000000000..28b8f466ac6 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt @@ -0,0 +1,169 @@ +package com.pitchedapps.frost.activities + +import android.animation.ValueAnimator +import android.content.res.ColorStateList +import android.graphics.Color +import android.os.Bundle +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager +import android.support.v4.app.FragmentPagerAdapter +import android.support.v4.view.ViewPager +import android.support.v7.app.AppCompatActivity +import android.view.View +import android.view.WindowManager +import android.widget.Button +import android.widget.ImageButton +import android.widget.ImageView +import ca.allanwang.kau.ui.views.RippleCanvas +import ca.allanwang.kau.ui.widgets.InkPageIndicator +import ca.allanwang.kau.utils.* +import com.mikepenz.google_material_typeface_library.GoogleMaterial +import com.pitchedapps.frost.R +import com.pitchedapps.frost.intro.* +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. + */ +class IntroActivity : AppCompatActivity(), ViewPager.PageTransformer, ViewPager.OnPageChangeListener { + + val ripple: RippleCanvas by bindView(R.id.intro_ripple) + val viewpager: ViewPager by bindView(R.id.intro_viewpager) + lateinit var adapter: IntroPageAdapter + val indicator: InkPageIndicator by bindView(R.id.intro_indicator) + val skip: Button by bindView(R.id.intro_skip) + val next: ImageButton by bindView(R.id.intro_next) + private var barHasNext = true + + val fragments = listOf( + IntroFragmentWelcome(), + IntroFragmentTheme(), + IntroAccountFragment(), + IntroTabTouchFragment(), + IntroTabContextFragment(), + IntroFragmentEnd() + ) + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_intro) + adapter = IntroPageAdapter(supportFragmentManager, fragments) + viewpager.apply { + setPageTransformer(true, this@IntroActivity) + addOnPageChangeListener(this@IntroActivity) + adapter = this@IntroActivity.adapter + } + indicator.setViewPager(viewpager) + next.setIcon(GoogleMaterial.Icon.gmd_navigate_next) + next.setOnClickListener { + if (barHasNext) viewpager.setCurrentItem(viewpager.currentItem + 1, true) + else finish(next.x + next.pivotX, next.y + next.pivotY) + } + ripple.set(Prefs.bgColor) + theme() + } + + fun theme() { + statusBarColor = Prefs.headerColor + navigationBarColor = Prefs.headerColor + skip.setTextColor(Prefs.textColor) + next.imageTintList = ColorStateList.valueOf(Prefs.textColor) + indicator.setColour(Prefs.textColor) + indicator.invalidate() + fragments.forEach { it.themeFragment() } + } + + /** + * Transformations are mainly handled on a per view basis + * This sifies it by making the first fragment fade out as the second fragment comes in + * All fragments are locked in position + */ + override fun transformPage(page: View, position: Float) { + //only apply to adjacent pages + if ((position < 0 && position > -1) || (position > 0 && position < 1)) { + val pageWidth = page.width + val translateValue = position * -pageWidth + page.translationX = (if (translateValue > -pageWidth) translateValue else 0f) + page.alpha = if (position < 0) 1 + position else 1f + } else { + page.alpha = 1f + page.translationX = 0f + } + + } + + fun finish(x: Float, y: Float) { + val blue = color(R.color.facebook_blue) + window.setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) + ripple.ripple(blue, x, y, 600) { + postDelayed(1000) { finish() } + } + arrayOf(skip, indicator, next, fragments.last().view!!.find(R.id.intro_title), fragments.last().view!!.find(R.id.intro_desc)).forEach { + it.animate().alpha(0f).setDuration(600).start() + } + if (Prefs.textColor != Color.WHITE) { + val f = fragments.last().view!!.find(R.id.intro_image).drawable + ValueAnimator.ofFloat(0f, 1f).apply { + addUpdateListener { + f.setTint(Prefs.textColor.blendWith(Color.WHITE, it.animatedValue as Float)) + } + duration = 600 + start() + } + } + if (Prefs.headerColor != blue) { + ValueAnimator.ofFloat(0f, 1f).apply { + addUpdateListener { + val c = Prefs.headerColor.blendWith(blue, it.animatedValue as Float) + statusBarColor = c + navigationBarColor = c + } + duration = 600 + start() + } + } + } + + override fun finish() { + launchNewTask(MainActivity::class.java, cookies()) + super.finish() + } + + override fun onBackPressed() { + if (viewpager.currentItem > 0) viewpager.setCurrentItem(viewpager.currentItem - 1, true) + else finish() + } + + override fun onPageScrollStateChanged(state: Int) { + + } + + override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) { + fragments[position].onPageScrolled(positionOffset) + if (position + 1 < fragments.size) + fragments[position + 1].onPageScrolled(positionOffset - 1) + } + + override fun onPageSelected(position: Int) { + fragments[position].onPageSelected() + val hasNext = position != fragments.size - 1 + if (barHasNext == hasNext) return + barHasNext = hasNext + next.fadeScaleTransition { + 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) { + + 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 2dccbeb5456..8503145e02d 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/LoginActivity.kt @@ -96,7 +96,8 @@ class LoginActivity : BaseActivity() { loadFbCookiesAsync { cookies -> Handler().postDelayed({ - launchNewTask(MainActivity::class.java, ArrayList(cookies), clearStack = true) + launchNewTask(if (Showcase.intro) IntroActivity::class.java else MainActivity::class.java, + ArrayList(cookies), clearStack = true) }, 1000) } } 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 978659db434..a6396b1be18 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt @@ -86,6 +86,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, var hiddenSearchView: SearchWebView? = null var firstLoadFinished = false set(value) { + if (field && value) return //both vals are already true L.d("First fragment load has finished") field = value if (value && hiddenSearchView == null) { @@ -160,6 +161,14 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, // } setFrostColors(toolbar, themeWindow = false, headers = arrayOf(tabs, appBar), backgrounds = arrayOf(viewPager)) onCreateBilling() + if (Prefs.installDate < 1501454310304 && Showcase.intro) + materialDialogThemed { + title(R.string.intro_title) + content(R.string.intro_desc) + positiveText(R.string.kau_yes) + negativeText(R.string.kau_no) + onPositive { _, _ -> launchIntroActivity(cookies()) } + } } fun tabsForEachView(action: (position: Int, view: BadgedIcon) -> Unit) { @@ -383,6 +392,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract, when (item.itemId) { R.id.action_settings -> { val intent = Intent(this, SettingsActivity::class.java) + intent.putParcelableArrayListExtra(EXTRA_COOKIES, cookies()) val bundle = ActivityOptionsCompat.makeCustomAnimation(this, R.anim.kau_slide_in_right, R.anim.kau_fade_out).toBundle() startActivityForResult(intent, ACTIVITY_SETTINGS, bundle) } 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 d073050b51d..8455bf1edf7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt @@ -79,6 +79,11 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { onClick = { _, _, _ -> kauLaunchAbout(AboutActivity::class.java); true } } + plainText(R.string.replay_intro) { + iicon = GoogleMaterial.Icon.gmd_replay + onClick = {_,_,_-> launchIntroActivity(cookies()); true} + } + if (BuildConfig.DEBUG) { checkbox(R.string.custom_pro, { Prefs.debugPro }, { Prefs.debugPro = it }) } @@ -116,8 +121,6 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { } } - - override fun onCreateOptionsMenu(menu: Menu): Boolean { menuInflater.inflate(R.menu.menu_settings, menu) toolbar.tint(Prefs.iconColor) @@ -143,7 +146,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() { } fun setFrostResult(flag: Int) { - resultFlag = resultFlag and flag + resultFlag = resultFlag or flag } override fun onDestroy() { 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 2f2050cc8a9..ac979c855b3 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt @@ -38,6 +38,7 @@ enum class CssAssets(val folder: String = "themes") : InjectorContract { .replace("\$BT\$", bt) .replace("\$BBT\$", bbt.toRgbaString()) .replace("\$O\$", Prefs.bgColor.withAlpha(255).toRgbaString()) + .replace("\$OO\$", Prefs.bgColor.colorToForeground(0.35f).withAlpha(255).toRgbaString()) .replace("\$D\$", Prefs.textColor.adjustAlpha(0.3f).toRgbaString()) } injector = JsBuilder().css(content).build() diff --git a/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt new file mode 100644 index 00000000000..d1d64712e45 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroFragmentTheme.kt @@ -0,0 +1,51 @@ +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.utils.Prefs +import com.pitchedapps.frost.utils.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) + + override fun viewArray(): Array> + = arrayOf(arrayOf(title), arrayOf(light, dark), arrayOf(amoled, 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) + val currentTheme = Prefs.theme - 1 + if (currentTheme in 0..3) + themeList.forEachIndexed { index, v -> v.scaleXY = if (index == currentTheme) 1.6f else 0.8f } + } + + private fun View.setThemeClick(theme: Theme) { + setOnClickListener { + v -> + Prefs.theme = theme.ordinal + (activity as IntroActivity).apply { + ripple.ripple(Prefs.bgColor, v.x + v.pivotX, v.y + v.pivotY) + 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 new file mode 100644 index 00000000000..d19a488dca7 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroImageFragments.kt @@ -0,0 +1,112 @@ +package com.pitchedapps.frost.intro + +import android.graphics.drawable.Drawable +import android.graphics.drawable.LayerDrawable +import android.os.Bundle +import android.view.View +import ca.allanwang.kau.utils.colorToForeground +import ca.allanwang.kau.utils.tint +import ca.allanwang.kau.utils.withAlpha +import com.pitchedapps.frost.R +import com.pitchedapps.frost.utils.Prefs + +/** + * Created by Allan Wang on 2017-07-28. + */ +abstract class BaseImageIntroFragment(val titleRes: Int, val imageRes: Int, val descRes: Int) : BaseIntroFragment(R.layout.intro_image) { + + val imageDrawable: LayerDrawable by lazyResettableRegistered { image.drawable as LayerDrawable } + val phone: Drawable by lazyResettableRegistered { imageDrawable.findDrawableByLayerId(R.id.intro_phone) } + val screen: Drawable by lazyResettableRegistered { imageDrawable.findDrawableByLayerId(R.id.intro_phone_screen) } + + override fun viewArray(): Array> + = arrayOf(arrayOf(title), arrayOf(desc)) + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + title.setText(titleRes) + image.setImageResource(imageRes) + desc.setText(descRes) + super.onViewCreated(view, savedInstanceState) + } + + override fun themeFragmentImpl() { + super.themeFragmentImpl() + title.setTextColor(Prefs.textColor) + desc.setTextColor(Prefs.textColor) + phone.tint(Prefs.textColor) + screen.tint(Prefs.bgColor) + } + + fun themeImageComponent(color: Int, vararg id: Int) { + id.forEach { imageDrawable.findDrawableByLayerId(it).tint(color) } + } + + override fun onPageScrolledImpl(positionOffset: Float) { + super.onPageScrolledImpl(positionOffset) + val alpha = ((1 - Math.abs(positionOffset)) * 255).toInt() + //apply alpha to all layers except the phone base + (0 until imageDrawable.numberOfLayers).forEach { + val d = imageDrawable.getDrawable(it) + if (d != phone) d.alpha = alpha + } + } + + fun firstImageFragmentTransition(offset: Float) { + if (offset < 0) + image.alpha = 1 + offset + } + + fun lastImageFragmentTransition(offset: Float) { + if (offset > 0) + image.alpha = 1 - offset + } +} + +class IntroAccountFragment : BaseImageIntroFragment( + R.string.intro_multiple_accounts, R.drawable.intro_phone_nav, R.string.intro_multiple_accounts_desc +) { + + override fun themeFragmentImpl() { + super.themeFragmentImpl() + themeImageComponent(Prefs.iconColor, R.id.intro_phone_avatar_1, R.id.intro_phone_avatar_2) + themeImageComponent(Prefs.bgColor.colorToForeground(), R.id.intro_phone_nav) + themeImageComponent(Prefs.headerColor, R.id.intro_phone_header) + } + + override fun onPageScrolledImpl(positionOffset: Float) { + super.onPageScrolledImpl(positionOffset) + firstImageFragmentTransition(positionOffset) + } +} + +class IntroTabTouchFragment : BaseImageIntroFragment( + R.string.intro_easy_navigation, R.drawable.intro_phone_tab, R.string.intro_easy_navigation_desc +) { + + 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.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 +) { + + override fun themeFragmentImpl() { + super.themeFragmentImpl() + themeImageComponent(Prefs.headerColor, R.id.intro_phone_toolbar) + themeImageComponent(Prefs.bgColor.colorToForeground(0.1f), R.id.intro_phone_image) + 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) + } + + 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 new file mode 100644 index 00000000000..552fad3bc48 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/intro/IntroMainFragments.kt @@ -0,0 +1,135 @@ +package com.pitchedapps.frost.intro + +import android.annotation.SuppressLint +import android.content.res.ColorStateList +import android.os.Bundle +import android.support.constraint.ConstraintLayout +import android.support.v4.app.Fragment +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.ImageView +import android.widget.TextView +import ca.allanwang.kau.kotlin.LazyResettableRegistry +import ca.allanwang.kau.utils.Kotterknife +import ca.allanwang.kau.utils.bindViewResettable +import ca.allanwang.kau.utils.setOnSingleTapListener +import com.pitchedapps.frost.R +import com.pitchedapps.frost.activities.IntroActivity +import com.pitchedapps.frost.utils.Prefs +import org.jetbrains.anko.childrenSequence + +/** + * Created by Allan Wang on 2017-07-28. + * + * Contains the base, start, and end fragments + */ + +/** + * The core intro fragment for all other fragments + */ +abstract class BaseIntroFragment(val layoutRes: Int) : Fragment() { + + val screenWidth + get() = resources.displayMetrics.widthPixels + + val lazyRegistry = LazyResettableRegistry() + + protected fun translate(offset: Float, views: Array>) { + val maxTranslation = offset * screenWidth + val increment = maxTranslation / views.size + views.forEachIndexed { i, group -> + group.forEach { + it.translationX = if (offset > 0) -maxTranslation + i * increment else -(i + 1) * increment + it.alpha = 1 - Math.abs(offset) + } + } + } + + fun lazyResettableRegistered(initializer: () -> T) = lazyRegistry.lazy(initializer) + + /* + * Note that these ids aren't actually inside all layouts + * However, they are in most of them, so they are added here + * for convenience + */ + protected val title: TextView by bindViewResettable(R.id.intro_title) + protected val image: ImageView by bindViewResettable(R.id.intro_image) + protected val desc: TextView by bindViewResettable(R.id.intro_desc) + + protected fun defaultViewArray(): Array> = arrayOf(arrayOf(title), arrayOf(image), arrayOf(desc)) + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val view = inflater.inflate(layoutRes, container, false) + return view + } + + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + themeFragment() + } + + override fun onDestroyView() { + super.onDestroyView() + Kotterknife.reset(this) + lazyRegistry.invalidateAll() + } + + fun themeFragment() { + if (view != null) themeFragmentImpl() + } + + protected open fun themeFragmentImpl() { + view?.childrenSequence()?.forEach { (it as? TextView)?.setTextColor(Prefs.textColor) } + } + + protected val viewArray: Array> by lazyResettableRegistered { viewArray() } + + protected abstract fun viewArray(): Array> + + fun onPageScrolled(positionOffset: Float) { + if (view != null) onPageScrolledImpl(positionOffset) + } + + protected open fun onPageScrolledImpl(positionOffset: Float) { + translate(positionOffset, viewArray) + } + + fun onPageSelected() { + if (view != null) onPageSelectedImpl() + } + + protected open fun onPageSelectedImpl() { + + } +} + +class IntroFragmentWelcome : BaseIntroFragment(R.layout.intro_welcome) { + + override fun viewArray(): Array> = defaultViewArray() + + override fun themeFragmentImpl() { + super.themeFragmentImpl() + image.imageTintList = ColorStateList.valueOf(Prefs.textColor) + } +} + +class IntroFragmentEnd : BaseIntroFragment(R.layout.intro_end) { + + val container: ConstraintLayout by bindViewResettable(R.id.intro_end_container) + + override fun viewArray(): Array> = defaultViewArray() + + override fun themeFragmentImpl() { + super.themeFragmentImpl() + image.imageTintList = ColorStateList.valueOf(Prefs.textColor) + } + + @SuppressLint("ClickableViewAccessibility") + override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + container.setOnSingleTapListener { _, event -> + (activity as IntroActivity).finish(event.x, event.y) + } + } +} \ 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 new file mode 100644 index 00000000000..a530df32660 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/AnimatedVectorDelegate.kt @@ -0,0 +1,82 @@ +package com.pitchedapps.frost.utils + +import android.graphics.drawable.AnimatedVectorDrawable +import android.support.annotation.DrawableRes +import android.widget.ImageView +import ca.allanwang.kau.utils.drawable + +/** + * Created by Allan Wang on 2017-07-29. + * + * Delegate for animated vector drawables with two states (start and end) + * Drawables are added lazily depending on the animation direction, and are verified upon load + * Should the bounded view not have an animated drawable upon animating, it is assumed + * that the user has switched the resource themselves and the delegate will not switch the resource + */ +interface AnimatedVectorContract { + fun animate() + fun animateReverse() + fun animateToggle() + val isAtStart: Boolean + fun bind(view: ImageView) + var animatedVectorListener: ((avd: AnimatedVectorDrawable, forwards: Boolean) -> Unit)? +} + +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 +) : AnimatedVectorContract { + + lateinit var view: ImageView + + private var atStart = true + + override val isAtStart: Boolean + get() = atStart + + private val avd: AnimatedVectorDrawable? + get() = view.drawable as? AnimatedVectorDrawable + + 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") + view.context.drawable(avdEnd) as? AnimatedVectorDrawable ?: throw IllegalArgumentException("AnimatedVectorDelegate has an ending drawable that isn't an avd") + view.setImageResource(avdStart) + if (emitOnBind) animatedVectorListener?.invoke(avd!!, false) + } + + override fun animate() = animateImpl(false) + + override fun animateReverse() = animateImpl(true) + + override fun animateToggle() = animateImpl(!atStart) + + 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 + 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/Showcase.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt index 57cbef7e81b..b3601dfb349 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Showcase.kt @@ -14,6 +14,8 @@ object Showcase : KPref() { //check if this is the first time launching the web overlay; show snackbar if true val firstWebOverlay: Boolean by kprefSingle("first_web_overlay") + val intro: Boolean by kprefSingle("intro_pages") + //not a showcase but cannot be in the same file as Prefs var experimentalDefault: Boolean by kpref("experimental_by_default", false) } 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 442216fb1dd..40e16f20667 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt @@ -20,10 +20,7 @@ import com.crashlytics.android.answers.Answers import com.crashlytics.android.answers.CustomEvent import com.pitchedapps.frost.BuildConfig import com.pitchedapps.frost.R -import com.pitchedapps.frost.activities.ImageActivity -import com.pitchedapps.frost.activities.LoginActivity -import com.pitchedapps.frost.activities.SelectorActivity -import com.pitchedapps.frost.activities.WebOverlayActivity +import com.pitchedapps.frost.activities.* import com.pitchedapps.frost.dbflow.CookieModel import com.pitchedapps.frost.facebook.FbTab import com.pitchedapps.frost.facebook.formattedFbUrl @@ -68,6 +65,9 @@ fun Context.launchImageActivity(imageUrl: String, text: String?) { }) } +fun Activity.launchIntroActivity(cookieList: ArrayList) + = launchNewTask(IntroActivity::class.java, cookieList, true) + fun WebOverlayActivity.url(): String { return intent.extras?.getString(ARG_URL) ?: FbTab.FEED.url } @@ -140,4 +140,4 @@ fun Activity.frostNavigationBar() { navigationBarColor = if (Prefs.tintNavBar) Prefs.headerColor else Color.BLACK } -fun RequestBuilder.withRoundIcon() = apply(RequestOptions().transform(CircleCrop())) \ No newline at end of file +fun RequestBuilder.withRoundIcon() = apply(RequestOptions().transform(CircleCrop()))!! \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt index ab9e37d12d1..b3992ff4900 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt @@ -34,7 +34,7 @@ abstract class IABBinder : FrostBilling { override fun Activity.onCreateBilling() { activity = this bp = BillingProcessor.newBillingProcessor(this, PUBLIC_BILLING_KEY, this@IABBinder) - bp!!.initialize() + bp?.initialize() } override fun onDestroyBilling() { @@ -79,10 +79,10 @@ abstract class IABBinder : FrostBilling { L.eThrow("IAB null bp on purchase attempt") return } - if (!bp!!.isOneTimePurchaseSupported) - activity!!.playStorePurchaseUnsupported() + if (!(bp?.isOneTimePurchaseSupported ?: false)) + activity?.playStorePurchaseUnsupported() else - bp!!.purchase(activity, FROST_PRO) + bp?.purchase(activity, FROST_PRO) } } @@ -104,14 +104,14 @@ class IABSettings : IABBinder() { */ override fun restorePurchases() { if (bp == null) return - val load = bp!!.loadOwnedPurchasesFromGoogle() + val load = bp?.loadOwnedPurchasesFromGoogle() ?: return L.d("IAB settings load from google $load") - if (!bp!!.isPurchased(FROST_PRO)) { - if (Prefs.pro) activity!!.playStoreNoLongerPro() + if (!(bp?.isPurchased(FROST_PRO) ?: return)) { + if (Prefs.pro) activity.playStoreNoLongerPro() else purchasePro() } else { - if (!Prefs.pro) activity!!.playStoreFoundPro() - else activity!!.purchaseRestored() + if (!Prefs.pro) activity.playStoreFoundPro() + else activity?.purchaseRestored() } } } @@ -138,12 +138,12 @@ class IABMain : IABBinder() { override fun restorePurchases() { if (restored || bp == null) return restored = true - val load = bp!!.loadOwnedPurchasesFromGoogle() + val load = bp?.loadOwnedPurchasesFromGoogle() ?: false L.d("IAB main load from google $load") - if (!bp!!.isPurchased(FROST_PRO)) { - if (Prefs.pro) activity!!.playStoreNoLongerPro() + if (!(bp?.isPurchased(FROST_PRO) ?: false)) { + if (Prefs.pro) activity.playStoreNoLongerPro() } else { - if (!Prefs.pro) activity!!.playStoreFoundPro() + if (!Prefs.pro) activity.playStoreFoundPro() } onDestroyBilling() } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt index d2f22829934..df0f04fd4c4 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABDialogs.kt @@ -31,7 +31,7 @@ private fun Activity.playRestart() { } else restart() } -fun Activity.playStoreNoLongerPro() { +fun Activity?.playStoreNoLongerPro() { Prefs.pro = false L.d("IAB No longer pro") frostAnswers { @@ -39,6 +39,7 @@ fun Activity.playStoreNoLongerPro() { .putCustomAttribute("result", "no longer pro") .putSuccess(false)) } + if (this == null) return materialDialogThemed { title(R.string.uh_oh) content(R.string.play_store_not_pro) @@ -49,9 +50,10 @@ fun Activity.playStoreNoLongerPro() { } } -fun Activity.playStoreFoundPro() { +fun Activity?.playStoreFoundPro() { Prefs.pro = true L.d("Found pro") + if (this == null) return materialDialogThemed { title(R.string.found_pro) content(R.string.found_pro_desc) 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 8ae54ef3031..df468715984 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt @@ -1,6 +1,8 @@ package com.pitchedapps.frost.views import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable import android.graphics.drawable.GradientDrawable import android.support.constraint.ConstraintLayout import android.util.AttributeSet diff --git a/app/src/main/res/drawable/intro_phone_case.xml b/app/src/main/res/drawable/intro_phone_case.xml new file mode 100644 index 00000000000..105eadefd9c --- /dev/null +++ b/app/src/main/res/drawable/intro_phone_case.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/intro_phone_long_press.xml b/app/src/main/res/drawable/intro_phone_long_press.xml new file mode 100644 index 00000000000..68f78e77ede --- /dev/null +++ b/app/src/main/res/drawable/intro_phone_long_press.xml @@ -0,0 +1,109 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/intro_phone_nav.xml b/app/src/main/res/drawable/intro_phone_nav.xml new file mode 100644 index 00000000000..a4ead7d0b2f --- /dev/null +++ b/app/src/main/res/drawable/intro_phone_nav.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/intro_phone_screen.xml b/app/src/main/res/drawable/intro_phone_screen.xml new file mode 100644 index 00000000000..69aeb26d482 --- /dev/null +++ b/app/src/main/res/drawable/intro_phone_screen.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/intro_phone_tab.xml b/app/src/main/res/drawable/intro_phone_tab.xml new file mode 100644 index 00000000000..822769f0019 --- /dev/null +++ b/app/src/main/res/drawable/intro_phone_tab.xml @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ 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 3c0cc6859fd..c5da87e68d8 100644 --- a/app/src/main/res/layout/activity_image_textless.xml +++ b/app/src/main/res/layout/activity_image_textless.xml @@ -24,7 +24,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="end|bottom" - android:layout_margin="@dimen/fab_margin" + android:layout_margin="@dimen/kau_fab_margin" android:visibility="invisible" /> \ 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 new file mode 100644 index 00000000000..839e33a9ae9 --- /dev/null +++ b/app/src/main/res/layout/activity_intro.xml @@ -0,0 +1,63 @@ + + + + + + + + + +