aboutsummaryrefslogtreecommitdiff
path: root/app/src/main
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-08-03 22:21:51 -0700
committerGitHub <noreply@github.com>2017-08-03 22:21:51 -0700
commit7746e63373c905faa6d7e45e45fffc48d3ffff85 (patch)
tree5d1bd4338a722619bb892abb308b369abc61f396 /app/src/main
parent5583f519dd7c4843f045029b0e48fd882dd79c71 (diff)
downloadfrost-7746e63373c905faa6d7e45e45fffc48d3ffff85.tar.gz
frost-7746e63373c905faa6d7e45e45fffc48d3ffff85.tar.bz2
frost-7746e63373c905faa6d7e45e45fffc48d3ffff85.zip
Add IM notifications, FAQ, video uploading, and geolocations (#107)
* Test canary * Update activities to use kau base * Update dependencies * Cherry pick faq * Update kau and add faq * Add readme badges * Add im notifications and video uploading * Update theme * Update and fix unit tests * Add geolocation * Prepare alpha test * Remove explicit nonnull request
Diffstat (limited to 'app/src/main')
-rw-r--r--app/src/main/AndroidManifest.xml17
-rw-r--r--app/src/main/assets/css/core/main.compact.css6
-rw-r--r--app/src/main/assets/css/core/main.scss6
-rw-r--r--app/src/main/assets/css/themes/custom.compact.css6
-rw-r--r--app/src/main/assets/css/themes/material_amoled.compact.css6
-rw-r--r--app/src/main/assets/css/themes/material_dark.compact.css6
-rw-r--r--app/src/main/assets/css/themes/material_glass.compact.css6
-rw-r--r--app/src/main/assets/css/themes/material_light.compact.css6
-rw-r--r--app/src/main/assets/js/notif_msg.js25
-rw-r--r--app/src/main/assets/js/notif_msg.min.js17
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/AboutActivity.kt9
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/ImagePickerActivity.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt27
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt25
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/MediaPickerActivity.kt10
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt12
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt23
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt35
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt63
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt9
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt1
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/utils/iab/IABBinder.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt2
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt16
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt58
-rw-r--r--app/src/main/play/en-CA/listing/fulldescription9
-rw-r--r--app/src/main/res/layout/intro_end.xml2
-rw-r--r--app/src/main/res/values/colors.xml3
-rw-r--r--app/src/main/res/values/strings.xml4
-rw-r--r--app/src/main/res/values/strings_about.xml23
-rw-r--r--app/src/main/res/values/strings_pref_notifications.xml2
-rw-r--r--app/src/main/res/values/strings_preferences.xml (renamed from app/src/main/res/values/strings_preferences)4
-rw-r--r--app/src/main/res/xml/frost_changelog.xml13
-rw-r--r--app/src/main/res/xml/frost_faq.xml17
46 files changed, 329 insertions, 212 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c4275ae6..c4b5b9dc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -10,6 +10,8 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.VIBRATE" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!--<uses-permission android:name="android.permission.USE_FINGERPRINT" />-->
<uses-permission android:name="com.android.vending.BILLING" />
@@ -18,13 +20,13 @@
android:allowBackup="true"
android:fullBackupContent="@xml/frost_backup_rules"
android:icon="@mipmap/ic_launcher_round"
- android:label="@string/app_name"
+ android:label="@string/frost_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/FrostTheme.Splash">
<activity
android:name=".StartActivity"
- android:label="@string/app_name"
+ android:label="@string/frost_name"
android:noHistory="true"
android:theme="@style/FrostTheme.Splash">
<intent-filter>
@@ -36,12 +38,12 @@
android:name=".activities.MainActivity"
android:configChanges="orientation|screenSize|locale"
android:hardwareAccelerated="true"
- android:label="@string/app_name"
+ android:label="@string/frost_name"
android:theme="@style/FrostTheme" />
<activity
android:name=".activities.WebOverlayActivity"
android:hardwareAccelerated="true"
- android:label="@string/app_name"
+ android:label="@string/frost_name"
android:launchMode="singleTop"
android:theme="@style/FrostTheme.Overlay.Slide" />
<activity
@@ -122,10 +124,13 @@
android:theme="@style/Kau.About" />
<activity
android:name=".activities.ImageActivity"
- android:theme="@style/Kau.ImagePicker.Overlay" />
+ android:theme="@style/FrostTheme.Transparent" />
<activity
android:name=".activities.ImagePickerActivity"
- android:theme="@style/FrostTheme.Overlay.Slide" />
+ android:theme="@style/Kau.MediaPicker.Overlay" />
+ <activity
+ android:name=".activities.VideoPickerActivity"
+ android:theme="@style/Kau.MediaPicker.Overlay" />
<service
android:name=".services.NotificationService"
diff --git a/app/src/main/assets/css/core/main.compact.css b/app/src/main/assets/css/core/main.compact.css
index 25568b78..ca6a9d3a 100644
--- a/app/src/main/assets/css/core/main.compact.css
+++ b/app/src/main/assets/css/core/main.compact.css
@@ -10,9 +10,9 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
._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; }
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp, ._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, ._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; }
+[style*="color"], body, input, ._42rv, ._4qau, ._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; }
@@ -22,7 +22,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
._15ny::after, ._z-w, ._8i2, ._2nk0, ._2u4w, ._577z:not(:last-child) ._ygd, ._3u9u, ._3mgz, ._52x6, ._2066, ._5luf, .mAppCenterFatLabel, .appCenterCategorySelectorButton, ._1q6v, ._5q_r, ._5yt8, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._2om3, ._2ol-, ._1f9d, ._vef, ._55x2 > *, .al, ._44qk, ._1gkq, ._5rgs, ._5xuj, ._1sv1, ._idb, ._5lp5, ._3-2-, ._3to6, ._ir5, ._4nw6, ._4nwh, ._27ve, div._51v6::before, ._3c9h::before, ._2s20, ._gui, ._5jku, ._2foa, ._2y60, ._5fu3, ._4en9, ._1kb:not(:last-child) ._1kc, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x, ._2om4, ._5fjw > div, ._5fjv > :first-child, ._5fjw > :first-child, ._5fjv, ._5fjw, ._4z83 { border-bottom: 1px solid rgba(215, 176, 215, 0.3) !important; }
-._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(215, 176, 215, 0.3) !important; }
+._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._2cpp, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(215, 176, 215, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: rgba(215, 176, 215, 0.3) !important; }
diff --git a/app/src/main/assets/css/core/main.scss b/app/src/main/assets/css/core/main.scss
index 6f7c6190..5f532cf4 100644
--- a/app/src/main/assets/css/core/main.scss
+++ b/app/src/main/assets/css/core/main.scss
@@ -33,7 +33,7 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
background: $bg_opaque2 !important;
}
-button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h,
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp,
._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,
@@ -41,7 +41,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
background: $background2 !important;
}
-[style*="color"], body, input, ._42rv,
+[style*="color"], body, input, ._42rv, ._4qau,
._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,
@@ -78,7 +78,7 @@ h1, h2, h3, h4, h5, h6 {
//friend card border
._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest,
-._1_y5, ._lr0, ._5hgt,
+._1_y5, ._lr0, ._5hgt, ._2cpp,
._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f {
border: 1px solid $divider !important;
}
diff --git a/app/src/main/assets/css/themes/custom.compact.css b/app/src/main/assets/css/themes/custom.compact.css
index b9cad06d..e8add9c8 100644
--- a/app/src/main/assets/css/themes/custom.compact.css
+++ b/app/src/main/assets/css/themes/custom.compact.css
@@ -10,9 +10,9 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
._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; }
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp, ._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, ._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; }
+[style*="color"], body, input, ._42rv, ._4qau, ._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; }
@@ -22,7 +22,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
._15ny::after, ._z-w, ._8i2, ._2nk0, ._2u4w, ._577z:not(:last-child) ._ygd, ._3u9u, ._3mgz, ._52x6, ._2066, ._5luf, .mAppCenterFatLabel, .appCenterCategorySelectorButton, ._1q6v, ._5q_r, ._5yt8, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._2om3, ._2ol-, ._1f9d, ._vef, ._55x2 > *, .al, ._44qk, ._1gkq, ._5rgs, ._5xuj, ._1sv1, ._idb, ._5lp5, ._3-2-, ._3to6, ._ir5, ._4nw6, ._4nwh, ._27ve, div._51v6::before, ._3c9h::before, ._2s20, ._gui, ._5jku, ._2foa, ._2y60, ._5fu3, ._4en9, ._1kb:not(:last-child) ._1kc, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x, ._2om4, ._5fjw > div, ._5fjv > :first-child, ._5fjw > :first-child, ._5fjv, ._5fjw, ._4z83 { border-bottom: 1px solid $D$ !important; }
-._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid $D$ !important; }
+._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._2cpp, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid $D$ !important; }
._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: $D$ !important; }
diff --git a/app/src/main/assets/css/themes/material_amoled.compact.css b/app/src/main/assets/css/themes/material_amoled.compact.css
index f61519d1..576e755a 100644
--- a/app/src/main/assets/css/themes/material_amoled.compact.css
+++ b/app/src/main/assets/css/themes/material_amoled.compact.css
@@ -10,9 +10,9 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
._403n, ._1-kc { background: #595959 !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(89, 89, 89, 0.2) !important; }
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp, ._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(89, 89, 89, 0.2) !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: #fff !important; }
+[style*="color"], body, input, ._42rv, ._4qau, ._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: #fff !important; }
._15kl::before, ._5j35::after, ._2k4b, ._3to7, ._4nw8 { border-left: 1px solid rgba(255, 255, 255, 0.3) !important; }
@@ -22,7 +22,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
._15ny::after, ._z-w, ._8i2, ._2nk0, ._2u4w, ._577z:not(:last-child) ._ygd, ._3u9u, ._3mgz, ._52x6, ._2066, ._5luf, .mAppCenterFatLabel, .appCenterCategorySelectorButton, ._1q6v, ._5q_r, ._5yt8, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._2om3, ._2ol-, ._1f9d, ._vef, ._55x2 > *, .al, ._44qk, ._1gkq, ._5rgs, ._5xuj, ._1sv1, ._idb, ._5lp5, ._3-2-, ._3to6, ._ir5, ._4nw6, ._4nwh, ._27ve, div._51v6::before, ._3c9h::before, ._2s20, ._gui, ._5jku, ._2foa, ._2y60, ._5fu3, ._4en9, ._1kb:not(:last-child) ._1kc, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x, ._2om4, ._5fjw > div, ._5fjv > :first-child, ._5fjw > :first-child, ._5fjv, ._5fjw, ._4z83 { border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important; }
-._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
+._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._2cpp, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: rgba(255, 255, 255, 0.3) !important; }
diff --git a/app/src/main/assets/css/themes/material_dark.compact.css b/app/src/main/assets/css/themes/material_dark.compact.css
index 1b30aca8..860d01e5 100644
--- a/app/src/main/assets/css/themes/material_dark.compact.css
+++ b/app/src/main/assets/css/themes/material_dark.compact.css
@@ -10,9 +10,9 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
._403n, ._1-kc { background: #898989 !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(137, 137, 137, 0.2) !important; }
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp, ._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(137, 137, 137, 0.2) !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: #fff !important; }
+[style*="color"], body, input, ._42rv, ._4qau, ._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: #fff !important; }
._15kl::before, ._5j35::after, ._2k4b, ._3to7, ._4nw8 { border-left: 1px solid rgba(255, 255, 255, 0.3) !important; }
@@ -22,7 +22,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
._15ny::after, ._z-w, ._8i2, ._2nk0, ._2u4w, ._577z:not(:last-child) ._ygd, ._3u9u, ._3mgz, ._52x6, ._2066, ._5luf, .mAppCenterFatLabel, .appCenterCategorySelectorButton, ._1q6v, ._5q_r, ._5yt8, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._2om3, ._2ol-, ._1f9d, ._vef, ._55x2 > *, .al, ._44qk, ._1gkq, ._5rgs, ._5xuj, ._1sv1, ._idb, ._5lp5, ._3-2-, ._3to6, ._ir5, ._4nw6, ._4nwh, ._27ve, div._51v6::before, ._3c9h::before, ._2s20, ._gui, ._5jku, ._2foa, ._2y60, ._5fu3, ._4en9, ._1kb:not(:last-child) ._1kc, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x, ._2om4, ._5fjw > div, ._5fjv > :first-child, ._5fjw > :first-child, ._5fjv, ._5fjw, ._4z83 { border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important; }
-._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
+._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._2cpp, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: rgba(255, 255, 255, 0.3) !important; }
diff --git a/app/src/main/assets/css/themes/material_glass.compact.css b/app/src/main/assets/css/themes/material_glass.compact.css
index ff44628c..bd0f5671 100644
--- a/app/src/main/assets/css/themes/material_glass.compact.css
+++ b/app/src/main/assets/css/themes/material_glass.compact.css
@@ -10,9 +10,9 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
._403n, ._1-kc { background: gray !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(128, 128, 128, 0.05) !important; }
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp, ._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(128, 128, 128, 0.05) !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: #fff !important; }
+[style*="color"], body, input, ._42rv, ._4qau, ._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: #fff !important; }
._15kl::before, ._5j35::after, ._2k4b, ._3to7, ._4nw8 { border-left: 1px solid rgba(255, 255, 255, 0.3) !important; }
@@ -22,7 +22,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
._15ny::after, ._z-w, ._8i2, ._2nk0, ._2u4w, ._577z:not(:last-child) ._ygd, ._3u9u, ._3mgz, ._52x6, ._2066, ._5luf, .mAppCenterFatLabel, .appCenterCategorySelectorButton, ._1q6v, ._5q_r, ._5yt8, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._2om3, ._2ol-, ._1f9d, ._vef, ._55x2 > *, .al, ._44qk, ._1gkq, ._5rgs, ._5xuj, ._1sv1, ._idb, ._5lp5, ._3-2-, ._3to6, ._ir5, ._4nw6, ._4nwh, ._27ve, div._51v6::before, ._3c9h::before, ._2s20, ._gui, ._5jku, ._2foa, ._2y60, ._5fu3, ._4en9, ._1kb:not(:last-child) ._1kc, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x, ._2om4, ._5fjw > div, ._5fjv > :first-child, ._5fjw > :first-child, ._5fjv, ._5fjw, ._4z83 { border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important; }
-._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
+._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._2cpp, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: rgba(255, 255, 255, 0.3) !important; }
diff --git a/app/src/main/assets/css/themes/material_light.compact.css b/app/src/main/assets/css/themes/material_light.compact.css
index 0047a32b..f2b086a3 100644
--- a/app/src/main/assets/css/themes/material_light.compact.css
+++ b/app/src/main/assets/css/themes/material_light.compact.css
@@ -10,9 +10,9 @@ body, #root, #header, [style*="background-color"], ._55wo, ._1upc, input, ._2f9r
._403n, ._1-kc { background: white !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(255, 255, 255, 0.2) !important; }
+button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._590n, ._4g8h, ._2cpp, ._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(255, 255, 255, 0.2) !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: #000 !important; }
+[style*="color"], body, input, ._42rv, ._4qau, ._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: #000 !important; }
._15kl::before, ._5j35::after, ._2k4b, ._3to7, ._4nw8 { border-left: 1px solid rgba(0, 0, 0, 0.3) !important; }
@@ -22,7 +22,7 @@ button:not([style*=image]), button::before, .touch ._56bt, ._56be::before, .btnS
._15ny::after, ._z-w, ._8i2, ._2nk0, ._2u4w, ._577z:not(:last-child) ._ygd, ._3u9u, ._3mgz, ._52x6, ._2066, ._5luf, .mAppCenterFatLabel, .appCenterCategorySelectorButton, ._1q6v, ._5q_r, ._5yt8, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._2om3, ._2ol-, ._1f9d, ._vef, ._55x2 > *, .al, ._44qk, ._1gkq, ._5rgs, ._5xuj, ._1sv1, ._idb, ._5lp5, ._3-2-, ._3to6, ._ir5, ._4nw6, ._4nwh, ._27ve, div._51v6::before, ._3c9h::before, ._2s20, ._gui, ._5jku, ._2foa, ._2y60, ._5fu3, ._4en9, ._1kb:not(:last-child) ._1kc, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x, ._2om4, ._5fjw > div, ._5fjv > :first-child, ._5fjw > :first-child, ._5fjv, ._5fjw, ._4z83 { border-bottom: 1px solid rgba(0, 0, 0, 0.3) !important; }
-._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(0, 0, 0, 0.3) !important; }
+._d4i, ._f6s, .mentions-suggest-item, .mentions-suggest, ._1_y5, ._lr0, ._5hgt, ._2cpp, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756, ._1rrd, ._5n_f { border: 1px solid rgba(0, 0, 0, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax, ._5h8f { border-color: rgba(0, 0, 0, 0.3) !important; }
diff --git a/app/src/main/assets/js/notif_msg.js b/app/src/main/assets/js/notif_msg.js
new file mode 100644
index 00000000..83405f39
--- /dev/null
+++ b/app/src/main/assets/js/notif_msg.js
@@ -0,0 +1,25 @@
+//binds callbacks to an invisible webview to take in the search events
+if (!window.hasOwnProperty('frost_notif_msg')) {
+ console.log('Registering frost_notif_msg');
+ window.frost_notif_msg = true;
+ var finished = false;
+ var x = new MutationObserver(function(mutations) {
+ var _f_thread = document.querySelector('#threadlist_rows');
+ if (!_f_thread) return;
+ console.log('Found message threads', _f_thread.outerHTML);
+ if (typeof Frost !== 'undefined') Frost.handleHtml(_f_thread.outerHTML);
+ finished = true;
+ x.disconnect();
+ });
+ x.observe(document, {
+ childList: true,
+ subtree: true
+ });
+ setTimeout(function() {
+ if (!finished) {
+ finished = true;
+ console.log('Message thread timeout cancellation')
+ if (typeof Frost !== 'undefined') Frost.handleHtml("");
+ }
+ }, 20000);
+}
diff --git a/app/src/main/assets/js/notif_msg.min.js b/app/src/main/assets/js/notif_msg.min.js
new file mode 100644
index 00000000..cb965d02
--- /dev/null
+++ b/app/src/main/assets/js/notif_msg.min.js
@@ -0,0 +1,17 @@
+if(!window.hasOwnProperty("frost_notif_msg")){
+console.log("Registering frost_notif_msg"),
+window.frost_notif_msg=!0
+;var finished=!1,x=new MutationObserver(function(e){
+var o=document.querySelector("#threadlist_rows")
+;o&&(console.log("Found message threads",o.outerHTML),
+"undefined"!=typeof Frost&&Frost.handleHtml(o.outerHTML),
+finished=!0,x.disconnect())
+})
+;x.observe(document,{
+childList:!0,
+subtree:!0
+}),setTimeout(function(){
+finished||(finished=!0,console.log("Message thread timeout cancellation"),
+"undefined"!=typeof Frost&&Frost.handleHtml(""))
+},2e4)
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
index 12cb955d..c2b3cc0f 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/StartActivity.kt
@@ -1,7 +1,7 @@
package com.pitchedapps.frost
import android.os.Bundle
-import android.support.v7.app.AppCompatActivity
+import ca.allanwang.kau.internal.KauBaseActivity
import com.pitchedapps.frost.activities.LoginActivity
import com.pitchedapps.frost.activities.MainActivity
import com.pitchedapps.frost.activities.SelectorActivity
@@ -14,7 +14,7 @@ import com.pitchedapps.frost.utils.launchNewTask
/**
* Created by Allan Wang on 2017-05-28.
*/
-class StartActivity : AppCompatActivity() {
+class StartActivity : KauBaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
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 80d2aa48..a1717de1 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,10 @@
package com.pitchedapps.frost.activities
+import android.os.Bundle
import android.support.constraint.ConstraintLayout
import android.support.constraint.ConstraintSet
import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
@@ -11,6 +13,8 @@ import ca.allanwang.kau.about.LibraryIItem
import ca.allanwang.kau.adapters.FastItemThemedAdapter
import ca.allanwang.kau.adapters.ThemableIItem
import ca.allanwang.kau.adapters.ThemableIItemDelegate
+import ca.allanwang.kau.animators.FadeScaleAnimatorAdd
+import ca.allanwang.kau.animators.KauAnimator
import ca.allanwang.kau.utils.*
import com.mikepenz.aboutlibraries.Libs
import com.mikepenz.aboutlibraries.entity.Library
@@ -23,6 +27,9 @@ import com.mikepenz.iconics.typeface.IIcon
import com.pitchedapps.frost.BuildConfig
import com.pitchedapps.frost.R
import com.pitchedapps.frost.utils.Prefs
+import org.jetbrains.anko.doAsync
+import org.jetbrains.anko.uiThread
+import java.security.InvalidParameterException
/**
@@ -34,6 +41,8 @@ class AboutActivity : AboutActivityBase(null, {
backgroundColor = Prefs.bgColor.withMinAlpha(200)
cutoutForeground = if (0xff3b5998.toInt().isColorVisibleOn(Prefs.bgColor)) 0xff3b5998.toInt() else Prefs.accentColor
cutoutDrawableRes = R.drawable.frost_f_256
+ faqXmlRes = R.xml.frost_faq
+ faqParseNewLine = false
}) {
override fun getLibraries(libs: Libs): List<Library> {
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 6806bf24..77a20d04 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/BaseActivity.kt
@@ -1,18 +1,16 @@
package com.pitchedapps.frost.activities
-import android.content.Intent
import android.os.Bundle
-import android.support.v7.app.AppCompatActivity
+import ca.allanwang.kau.internal.KauBaseActivity
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.
*/
-open class BaseActivity : AppCompatActivity() {
+abstract class BaseActivity : KauBaseActivity() {
override fun onBackPressed() {
if (isTaskRoot && Prefs.exitConfirmation) {
materialDialogThemed {
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 2e4ae410..e419c21c 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImageActivity.kt
@@ -10,14 +10,13 @@ import android.os.Bundle
import android.os.Environment
import android.support.design.widget.FloatingActionButton
import android.support.v4.content.FileProvider
-import android.support.v7.app.AppCompatActivity
import android.view.View
import android.view.ViewGroup
import android.widget.ProgressBar
import android.widget.TextView
import ca.allanwang.kau.email.sendEmail
+import ca.allanwang.kau.internal.KauBaseActivity
import ca.allanwang.kau.permissions.PERMISSION_WRITE_EXTERNAL_STORAGE
-import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult
import ca.allanwang.kau.permissions.kauRequestPermissions
import ca.allanwang.kau.utils.*
import com.bumptech.glide.Glide
@@ -44,7 +43,7 @@ import java.util.*
/**
* Created by Allan Wang on 2017-07-15.
*/
-class ImageActivity : AppCompatActivity() {
+class ImageActivity : KauBaseActivity() {
val progress: ProgressBar by bindView(R.id.image_progress)
val container: ViewGroup by bindView(R.id.image_container)
@@ -230,11 +229,6 @@ class ImageActivity : AppCompatActivity() {
deleteTempFile()
super.onDestroy()
}
-
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- kauOnRequestPermissionsResult(permissions, grantResults)
- }
}
internal enum class FabStates(val iicon: IIcon, val iconColor: Int = Prefs.iconColor, val backgroundTint: Int = Prefs.iconBackgroundColor.withAlpha(255)) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImagePickerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/ImagePickerActivity.kt
deleted file mode 100644
index f18d358e..00000000
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/ImagePickerActivity.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package com.pitchedapps.frost.activities
-
-import android.content.res.ColorStateList
-import android.os.Bundle
-import ca.allanwang.kau.imagepicker.ImagePickerActivityBase
-import ca.allanwang.kau.imagepicker.ImagePickerActivityOverlayBase
-import com.pitchedapps.frost.utils.Prefs
-
-/**
- * Created by Allan Wang on 2017-07-23.
- */
-class ImagePickerActivity : ImagePickerActivityOverlayBase() \ 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 28b8f466..2321a936 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/IntroActivity.kt
@@ -8,12 +8,12 @@ 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.internal.KauBaseActivity
import ca.allanwang.kau.ui.views.RippleCanvas
import ca.allanwang.kau.ui.widgets.InkPageIndicator
import ca.allanwang.kau.utils.*
@@ -28,8 +28,11 @@ import org.jetbrains.anko.find
/**
* Created by Allan Wang on 2017-07-25.
+ *
+ * A beautiful intro activity
+ * Phone showcases are drawn via layers
*/
-class IntroActivity : AppCompatActivity(), ViewPager.PageTransformer, ViewPager.OnPageChangeListener {
+class IntroActivity : KauBaseActivity(), ViewPager.PageTransformer, ViewPager.OnPageChangeListener {
val ripple: RippleCanvas by bindView(R.id.intro_ripple)
val viewpager: ViewPager by bindView(R.id.intro_viewpager)
@@ -63,6 +66,7 @@ class IntroActivity : AppCompatActivity(), ViewPager.PageTransformer, ViewPager.
if (barHasNext) viewpager.setCurrentItem(viewpager.currentItem + 1, true)
else finish(next.x + next.pivotX, next.y + next.pivotY)
}
+ skip.setOnClickListener { finish() }
ripple.set(Prefs.bgColor)
theme()
}
@@ -102,18 +106,19 @@ class IntroActivity : AppCompatActivity(), ViewPager.PageTransformer, ViewPager.
ripple.ripple(blue, x, y, 600) {
postDelayed(1000) { finish() }
}
- arrayOf(skip, indicator, next, fragments.last().view!!.find<View>(R.id.intro_title), fragments.last().view!!.find<View>(R.id.intro_desc)).forEach {
- it.animate().alpha(0f).setDuration(600).start()
+ arrayOf(skip, indicator, next, fragments.last().view?.find<View>(R.id.intro_title), fragments.last().view?.find<View>(R.id.intro_desc)).forEach {
+ it?.animate()?.alpha(0f)?.setDuration(600)?.start()
}
if (Prefs.textColor != Color.WHITE) {
- val f = fragments.last().view!!.find<ImageView>(R.id.intro_image).drawable
- ValueAnimator.ofFloat(0f, 1f).apply {
- addUpdateListener {
- f.setTint(Prefs.textColor.blendWith(Color.WHITE, it.animatedValue as Float))
+ val f = fragments.last().view?.find<ImageView>(R.id.intro_image)?.drawable
+ if (f != null)
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ addUpdateListener {
+ f.setTint(Prefs.textColor.blendWith(Color.WHITE, it.animatedValue as Float))
+ }
+ duration = 600
+ start()
}
- duration = 600
- start()
- }
}
if (Prefs.headerColor != blue) {
ValueAnimator.ofFloat(0f, 1f).apply {
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 a6396b1b..df1228bd 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MainActivity.kt
@@ -23,12 +23,11 @@ import android.view.Menu
import android.view.MenuItem
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
-import ca.allanwang.kau.changelog.showChangelog
-import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult
import ca.allanwang.kau.searchview.SearchItem
import ca.allanwang.kau.searchview.SearchView
import ca.allanwang.kau.searchview.bindSearchView
import ca.allanwang.kau.utils.*
+import ca.allanwang.kau.xml.showChangelog
import co.zsmb.materialdrawerkt.builders.Builder
import co.zsmb.materialdrawerkt.builders.accountHeader
import co.zsmb.materialdrawerkt.builders.drawer
@@ -57,6 +56,7 @@ import com.pitchedapps.frost.fragments.WebFragment
import com.pitchedapps.frost.utils.*
import com.pitchedapps.frost.utils.iab.FrostBilling
import com.pitchedapps.frost.utils.iab.IABMain
+import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import com.pitchedapps.frost.views.BadgedIcon
import com.pitchedapps.frost.views.FrostViewPager
import com.pitchedapps.frost.web.SearchWebView
@@ -117,12 +117,11 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract,
Prefs.versionCode = BuildConfig.VERSION_CODE
if (!BuildConfig.DEBUG) {
showChangelog(R.xml.frost_changelog, Prefs.textColor) { theme() }
- frostAnswersCustom("Version") {
- putCustomAttribute("Version code", BuildConfig.VERSION_CODE)
- putCustomAttribute("Version name", BuildConfig.VERSION_NAME)
- putCustomAttribute("Build type", BuildConfig.BUILD_TYPE)
- putCustomAttribute("Frost id", Prefs.frostId)
- }
+ frostAnswersCustom("Version",
+ "Version code" to BuildConfig.VERSION_CODE,
+ "Version name" to BuildConfig.VERSION_NAME,
+ "Build type" to BuildConfig.BUILD_TYPE,
+ "Frost id" to Prefs.frostId)
}
}
setContentView(R.layout.activity_main)
@@ -388,6 +387,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract,
return true
}
+ @SuppressLint("RestrictedApi")
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> {
@@ -402,7 +402,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract,
}
override fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams) {
- openImagePicker(filePathCallback, fileChooserParams)
+ openMediaPicker(filePathCallback, fileChooserParams)
}
@SuppressLint("NewApi")
@@ -435,11 +435,6 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract,
}
}
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- kauOnRequestPermissionsResult(permissions, grantResults)
- }
-
override fun onResume() {
super.onResume()
FbCookie.switchBackUser { }
@@ -447,7 +442,7 @@ class MainActivity : BaseActivity(), SearchWebView.SearchContract,
override fun onStart() {
//validate some pro features
- if (!Prefs.pro) {
+ if (!IS_FROST_PRO) {
if (Prefs.theme == Theme.CUSTOM.ordinal) Prefs.theme = Theme.DEFAULT.ordinal
}
super.onStart()
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/activities/MediaPickerActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/activities/MediaPickerActivity.kt
new file mode 100644
index 00000000..0d041e7a
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/MediaPickerActivity.kt
@@ -0,0 +1,10 @@
+package com.pitchedapps.frost.activities
+
+import ca.allanwang.kau.mediapicker.MediaPickerActivityOverlayBase
+import ca.allanwang.kau.mediapicker.MediaType
+
+/**
+ * Created by Allan Wang on 2017-07-23.
+ */
+class ImagePickerActivity : MediaPickerActivityOverlayBase(MediaType.IMAGE)
+class VideoPickerActivity : MediaPickerActivityOverlayBase(MediaType.VIDEO) \ 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 8455bf1e..7cbbe4df 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/SettingsActivity.kt
@@ -1,18 +1,22 @@
package com.pitchedapps.frost.activities
+import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import ca.allanwang.kau.about.kauLaunchAbout
-import ca.allanwang.kau.changelog.showChangelog
import ca.allanwang.kau.kpref.activity.CoreAttributeContract
import ca.allanwang.kau.kpref.activity.KPrefActivity
import ca.allanwang.kau.kpref.activity.KPrefAdapterBuilder
import ca.allanwang.kau.kpref.activity.items.KPrefItemBase
import ca.allanwang.kau.ui.views.RippleCanvas
-import ca.allanwang.kau.utils.*
+import ca.allanwang.kau.utils.finishSlideOut
+import ca.allanwang.kau.utils.setMenuIcons
+import ca.allanwang.kau.utils.string
+import ca.allanwang.kau.utils.tint
+import ca.allanwang.kau.xml.showChangelog
import com.mikepenz.community_material_typeface_library.CommunityMaterial
import com.mikepenz.google_material_typeface_library.GoogleMaterial
import com.pitchedapps.frost.BuildConfig
@@ -75,13 +79,14 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() {
}
plainText(R.string.about_frost) {
+ descRes = R.string.about_frost_desc
iicon = GoogleMaterial.Icon.gmd_info
onClick = { _, _, _ -> kauLaunchAbout(AboutActivity::class.java); true }
}
plainText(R.string.replay_intro) {
iicon = GoogleMaterial.Icon.gmd_replay
- onClick = {_,_,_-> launchIntroActivity(cookies()); true}
+ onClick = { _, _, _ -> launchIntroActivity(cookies()); true }
}
if (BuildConfig.DEBUG) {
@@ -98,6 +103,7 @@ class SettingsActivity : KPrefActivity(), FrostBilling by IABSettings() {
setFrostResult(MainActivity.REQUEST_RESTART)
}
+ @SuppressLint("MissingSuperCall")
override fun onCreate(savedInstanceState: Bundle?) {
setFrostTheme(true)
super.onCreate(savedInstanceState)
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 13d72ffe..7b612166 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/activities/WebOverlayActivity.kt
@@ -5,13 +5,12 @@ import android.net.Uri
import android.os.Bundle
import android.support.design.widget.CoordinatorLayout
import android.support.design.widget.Snackbar
-import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.Toolbar
import android.view.Menu
import android.view.MenuItem
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
-import ca.allanwang.kau.permissions.kauOnRequestPermissionsResult
+import ca.allanwang.kau.internal.KauBaseActivity
import ca.allanwang.kau.swipe.kauSwipeOnCreate
import ca.allanwang.kau.swipe.kauSwipeOnDestroy
import ca.allanwang.kau.swipe.kauSwipeOnPostCreate
@@ -31,7 +30,7 @@ import com.pitchedapps.frost.web.FrostWebView
/**
* Created by Allan Wang on 2017-06-01.
*/
-open class WebOverlayActivity : AppCompatActivity(),
+open class WebOverlayActivity : KauBaseActivity(),
ActivityWebContract, FileChooserContract by FileChooserDelegate() {
val toolbar: Toolbar by bindView(R.id.overlay_toolbar)
@@ -126,18 +125,13 @@ open class WebOverlayActivity : AppCompatActivity(),
}
override fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams) {
- openImagePicker(filePathCallback, fileChooserParams)
+ openMediaPicker(filePathCallback, fileChooserParams)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (onActivityResultWeb(requestCode, resultCode, data)) return
}
- override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults)
- kauOnRequestPermissionsResult(permissions, grantResults)
- }
-
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_web, menu)
toolbar.tint(Prefs.iconColor)
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 bd31d6ce..fd8a3677 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/contracts/FileChooser.kt
@@ -5,16 +5,18 @@ import android.content.Intent
import android.net.Uri
import android.webkit.ValueCallback
import android.webkit.WebChromeClient
-import ca.allanwang.kau.imagepicker.kauLaunchImagePicker
-import ca.allanwang.kau.imagepicker.kauOnImagePickerResult
+import ca.allanwang.kau.mediapicker.MediaPickerActivityOverlayBase
+import ca.allanwang.kau.mediapicker.MediaType
+import ca.allanwang.kau.mediapicker.kauLaunchMediaPicker
+import ca.allanwang.kau.mediapicker.kauOnMediaPickerResult
import com.pitchedapps.frost.activities.ImagePickerActivity
+import com.pitchedapps.frost.activities.VideoPickerActivity
import com.pitchedapps.frost.utils.L
-import java.io.File
/**
* Created by Allan Wang on 2017-07-04.
*/
-const val IMAGE_CHOOSER_REQUEST = 67
+const val MEDIA_CHOOSER_RESULT = 67
interface FileChooserActivityContract {
fun openFileChooser(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams)
@@ -22,7 +24,7 @@ interface FileChooserActivityContract {
interface FileChooserContract {
var filePathCallback: ValueCallback<Array<Uri>>?
- fun Activity.openImagePicker(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams)
+ fun Activity.openMediaPicker(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams)
fun Activity.onActivityResultWeb(requestCode: Int, resultCode: Int, intent: Intent?): Boolean
}
@@ -30,16 +32,17 @@ class FileChooserDelegate : FileChooserContract {
override var filePathCallback: ValueCallback<Array<Uri>>? = null
- override fun Activity.openImagePicker(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams) {
+ override fun Activity.openMediaPicker(filePathCallback: ValueCallback<Array<Uri>>, fileChooserParams: WebChromeClient.FileChooserParams) {
this@FileChooserDelegate.filePathCallback = filePathCallback
- kauLaunchImagePicker(ImagePickerActivity::class.java, IMAGE_CHOOSER_REQUEST)
+ val isVideo = fileChooserParams.acceptTypes.firstOrNull() == "video/*"
+ kauLaunchMediaPicker(if (isVideo) VideoPickerActivity::class.java else ImagePickerActivity::class.java, MEDIA_CHOOSER_RESULT)
}
override fun Activity.onActivityResultWeb(requestCode: Int, resultCode: Int, intent: Intent?): Boolean {
L.d("FileChooser On activity results web $requestCode")
- if (requestCode != IMAGE_CHOOSER_REQUEST) return false
- val results = kauOnImagePickerResult(resultCode, intent).map { it.uri }.toTypedArray()
- L.d("FileChooser result ${results.contentToString()}")
+ if (requestCode != MEDIA_CHOOSER_RESULT) return false
+ val results = kauOnMediaPickerResult(resultCode, intent).map { it.uri }.toTypedArray()
+ L.i("FileChooser result ${results.contentToString()}")
//proper path content://com.android.providers.media.documents/document/image%3A36341
L.d("FileChooser Callback received; ${filePathCallback != null}")
filePathCallback?.onReceiveValue(results)
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 622be067..7cd93d14 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/facebook/FbUrlFormatter.kt
@@ -1,5 +1,7 @@
package com.pitchedapps.frost.facebook
+import com.pitchedapps.frost.utils.L
+
/**
* Created by Allan Wang on 2017-07-07.
*
@@ -13,22 +15,27 @@ class FbUrlFormatter(url: String) {
val cleaned: String
init {
- var cleanedUrl = url
- discardable.forEach { cleanedUrl = cleanedUrl.replace(it, "", true) }
- val changed = cleanedUrl != url //note that discardables strip away the first ?
- decoder.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) }
- val qm = cleanedUrl.indexOf(if (changed) "&" else "?")
- if (qm > -1) {
- cleanedUrl.substring(qm + 1).split("&").forEach {
- val p = it.split("=")
- queries.put(p[0], p.elementAtOrNull(1) ?: "")
+ if (url.isNullOrBlank()) cleaned = ""
+ else {
+ var cleanedUrl = url
+ discardable.forEach { cleanedUrl = cleanedUrl.replace(it, "", true) }
+ val changed = cleanedUrl != url //note that discardables strip away the first ?
+ decoder.forEach { (k, v) -> cleanedUrl = cleanedUrl.replace(k, v, true) }
+ val qm = cleanedUrl.indexOf(if (changed) "&" else "?")
+ if (qm > -1) {
+ cleanedUrl.substring(qm + 1).split("&").forEach {
+ val p = it.split("=")
+ queries.put(p[0], p.elementAtOrNull(1) ?: "")
+ }
+ cleanedUrl = cleanedUrl.substring(0, qm)
}
- cleanedUrl = cleanedUrl.substring(0, qm)
+ discardableQueries.forEach { queries.remove(it) }
+ if (cleanedUrl.startsWith("#!/")) cleanedUrl = cleanedUrl.substring(2)
+ if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1)
+ cleanedUrl = cleanedUrl.replaceFirst(".facebook.com//", ".facebook.com/") //sometimes we are given a bad url
+ L.v("Formatted url from $url to $cleanedUrl")
+ cleaned = cleanedUrl
}
- discardableQueries.forEach { queries.remove(it) }
- if (cleanedUrl.startsWith("#!/")) cleanedUrl = cleanedUrl.substring(2)
- if (cleanedUrl.startsWith("/")) cleanedUrl = FB_URL_BASE + cleanedUrl.substring(1)
- cleaned = cleanedUrl
}
override fun toString(): String {
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 ac979c85..0992a9cb 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/CssAssets.kt
@@ -3,7 +3,6 @@ package com.pitchedapps.frost.injectors
import android.graphics.Color
import android.webkit.WebView
import ca.allanwang.kau.utils.*
-import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
/**
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 de270948..fae1846b 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsActions.kt
@@ -15,7 +15,9 @@ enum class JsActions(body: String) : InjectorContract {
*/
LOGIN_CHECK("document.getElementById('signup-button')&&Frost.loadLogin();"),
BASE_HREF("document.write(\"<base href='$FB_URL_BASE'/>\");"),
- GET_MESSAGES("setTimeout(function(){Frost.handleHtml(document.getElementById('threadlist_rows').outerHtml)},1000)"),
+ /**
+ * Used as a pseudoinjector for maybe functions
+ */
EMPTY("");
val function = "!function(){$body}();"
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 b22abd70..d2201c52 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/injectors/JsAssets.kt
@@ -8,7 +8,7 @@ import android.webkit.WebView
* The enum name must match the css file name
*/
enum class JsAssets : InjectorContract {
- MENU, CLICK_A, CONTEXT_A, HEADER_BADGES, SEARCH, TEXTAREA_LISTENER
+ MENU, CLICK_A, CONTEXT_A, HEADER_BADGES, SEARCH, TEXTAREA_LISTENER, NOTIF_MSG
;
var file = "${name.toLowerCase()}.min.js"
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 05497904..3ddad869 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
@@ -14,10 +14,13 @@ import com.pitchedapps.frost.dbflow.loadFbCookiesSync
import com.pitchedapps.frost.facebook.FACEBOOK_COM
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
+import com.pitchedapps.frost.facebook.formattedFbUrl
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import com.pitchedapps.frost.utils.frostAnswersCustom
+import com.pitchedapps.frost.web.MessageWebView
import org.jetbrains.anko.doAsync
+import org.jetbrains.anko.uiThread
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.util.concurrent.Future
@@ -32,6 +35,8 @@ class NotificationService : JobService() {
var future: Future<Unit>? = null
+ val startTime = System.currentTimeMillis()
+
companion object {
val epochMatcher: Regex by lazy { Regex(":([0-9]*?),") }
val notifIdMatcher: Regex by lazy { Regex("notif_id\":([0-9]*?),") }
@@ -40,38 +45,47 @@ class NotificationService : JobService() {
}
override fun onStopJob(params: JobParameters?): Boolean {
+ val time = System.currentTimeMillis() - startTime
+ L.d("Notification service has finished abruptly in $time ms")
+ frostAnswersCustom("NotificationTime",
+ "Type" to "Service force stop",
+ "IM Included" to Prefs.notificationsInstantMessages,
+ "Duration" to time)
future?.cancel(true)
future = null
return false
}
+ fun finish(params: JobParameters?) {
+ val time = System.currentTimeMillis() - startTime
+ L.d("Notification service has finished in $time ms")
+ frostAnswersCustom("NotificationTime",
+ "Type" to "Service",
+ "IM Included" to Prefs.notificationsInstantMessages,
+ "Duration" to time)
+ jobFinished(params, false)
+ future?.cancel(true)
+ future = null
+ }
+
override fun onStartJob(params: JobParameters?): Boolean {
future = doAsync {
if (Prefs.notificationAllAccounts) {
val cookies = loadFbCookiesSync()
cookies.forEach { fetchGeneralNotifications(it) }
-// if (Prefs.notificationsInstantMessages) {
-// Prefs.prevId = Prefs.userId
-// uiThread {
-// val messageWebView = MessageWebView(this@NotificationService, params)
-// cookies.forEach { messageWebView.request(it) }
-// }
-// return@doAsync
-// }
} else {
val currentCookie = loadFbCookie(Prefs.userId)
if (currentCookie != null) {
fetchGeneralNotifications(currentCookie)
-// if (Prefs.notificationsInstantMessages) {
-// uiThread { MessageWebView(this@NotificationService, params).request(currentCookie) }
-// return@doAsync
-// }
}
}
- L.d("Finished notifications")
- jobFinished(params, false)
- future = null
+ L.d("Finished main notifications")
+ if (Prefs.notificationsInstantMessages) {
+ val currentCookie = loadFbCookie(Prefs.userId)
+ if (currentCookie != null)
+ uiThread { MessageWebView(this@NotificationService, params, currentCookie) }
+ } else finish(params)
}
return true
}
@@ -104,10 +118,7 @@ class NotificationService : JobService() {
}
if (newLatestEpoch != prevLatestEpoch) prevNotifTime.copy(epoch = newLatestEpoch).save()
L.d("Notif new latest epoch ${lastNotificationTime(data.id).epoch}")
- frostAnswersCustom("Notifications") {
- putCustomAttribute("Type", "General")
- putCustomAttribute("Count", notifCount)
- }
+ frostAnswersCustom("Notifications", "Type" to "General", "Count" to notifCount)
summaryNotification(data.id, notifCount)
}
@@ -132,12 +143,6 @@ class NotificationService : JobService() {
val doc = Jsoup.parseBodyFragment(content)
val unreadNotifications = (doc.getElementById("threadlist_rows") ?: return L.eThrow("Notification messages not found")).getElementsByClass("aclb")
var notifCount = 0
- L.d("IM notif count ${unreadNotifications.size}")
- unreadNotifications.forEach {
- with(it) {
- L.d("notif ${id()} ${className()}")
- }
- }
val prevNotifTime = lastNotificationTime(data.id)
val prevLatestEpoch = prevNotifTime.epochIm
L.v("Notif Prev Latest Im Epoch $prevLatestEpoch")
@@ -154,10 +159,7 @@ class NotificationService : JobService() {
}
if (newLatestEpoch != prevLatestEpoch) prevNotifTime.copy(epochIm = newLatestEpoch).save()
L.d("Notif new latest im epoch ${lastNotificationTime(data.id).epochIm}")
- frostAnswersCustom("Notifications") {
- putCustomAttribute("Type", "Message")
- putCustomAttribute("Count", notifCount)
- }
+ frostAnswersCustom("Notifications", "Type" to "Message", "Count" to notifCount)
summaryNotification(data.id, notifCount)
}
@@ -173,7 +175,8 @@ class NotificationService : JobService() {
//fetch convo pic
val p = element.select("i.img[style*=url]")
val pUrl = profMatcher.find(p.attr("style"))?.groups?.get(1)?.value ?: ""
- return NotificationContent(data, notifId.toInt(), a.attr("href"), a.text(), text, epoch, pUrl)
+ L.v("url ${a.attr("href")}")
+ return NotificationContent(data, notifId.toInt(), a.attr("href"), a.text(), text, epoch, pUrl.formattedFbUrl)
}
private fun Context.debugNotification(text: String) {
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 9c9754bb..e37afc33 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Appearance.kt
@@ -41,7 +41,7 @@ fun SettingsActivity.getAppearancePrefs(): KPrefAdapterBuilder.() -> Unit = {
setFrostTheme(true)
themeExterior()
invalidateOptionsMenu()
- frostAnswersCustom("Theme") { putCustomAttribute("Count", text.toString()) }
+ frostAnswersCustom("Theme", "Count" to text)
}
true
}
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 05a852ee..594cbe01 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/settings/Experimental.kt
@@ -22,7 +22,9 @@ fun SettingsActivity.getExperimentalPrefs(): KPrefAdapterBuilder.() -> Unit = {
// Experimental content starts here ------------------
-
+ checkbox(R.string.notification_messages, { Prefs.notificationsInstantMessages }, { Prefs.notificationsInstantMessages = it }) {
+ descRes = R.string.notification_messages_desc
+ }
// Experimental content ends here --------------------
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 a20e755f..b053b9dd 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Prefs.kt
@@ -97,7 +97,8 @@ object Prefs : KPref() {
var notificationAllAccounts: Boolean by kpref("notification_all_accounts", true)
- var notificationsInstantMessages: Boolean by kpref("notification_im", true)
+ //todo remove from experimental once stabilized
+ var notificationsInstantMessages: Boolean by kpref("notification_im", Showcase.experimentalDefault)
var notificationVibrate: Boolean by kpref("notification_vibrate", true)
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 40e16f20..cc3ea52e 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/Utils.kt
@@ -116,9 +116,14 @@ fun frostAnswers(action: Answers.() -> Unit) {
Answers.getInstance().action()
}
-fun frostAnswersCustom(name: String, action: CustomEvent.() -> Unit = {}) {
+fun frostAnswersCustom(name: String, vararg events: Pair<String, Any>) {
frostAnswers {
- logCustom(CustomEvent("Frost $name").apply { action() })
+ logCustom(CustomEvent("Frost $name").apply {
+ events.forEach { (key, value) ->
+ if (value is Number) putCustomAttribute(key, value)
+ else putCustomAttribute(key, value.toString())
+ }
+ })
}
}
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 ea66030f..3918a993 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/utils/WebContextMenu.kt
@@ -41,6 +41,7 @@ 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) }),
SHARE_LINK(R.string.share_link, { c, wc -> c.shareText(wc.url) }),
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 b3992ff4..bad7f8fd 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
@@ -15,6 +15,10 @@ import com.pitchedapps.frost.utils.frostAnswers
*/
private const val FROST_PRO = "frost_pro"
+/**
+ * Implemented pro checker with a hook for debug builds
+ * Use this when checking if the pro feature is enabled
+ */
val IS_FROST_PRO: Boolean
get() = (BuildConfig.DEBUG && Prefs.debugPro) || Prefs.pro
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 df468715..8ae54ef3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/views/BadgedIcon.kt
@@ -1,8 +1,6 @@
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/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
index b8ba0d1d..343674d5 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClients.kt
@@ -1,10 +1,9 @@
package com.pitchedapps.frost.web
import android.net.Uri
-import android.webkit.ConsoleMessage
-import android.webkit.ValueCallback
-import android.webkit.WebChromeClient
-import android.webkit.WebView
+import android.webkit.*
+import ca.allanwang.kau.permissions.PERMISSION_ACCESS_FINE_LOCATION
+import ca.allanwang.kau.permissions.kauRequestPermissions
import ca.allanwang.kau.utils.snackbar
import com.pitchedapps.frost.contracts.ActivityWebContract
import com.pitchedapps.frost.utils.L
@@ -33,6 +32,7 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() {
val progressObservable: Subject<Int> = webCore.progressObservable
val titleObservable: BehaviorSubject<String> = webCore.titleObservable
val activityContract = (webCore.context as? ActivityWebContract)
+ val context = webCore.context!!
companion object {
val consoleBlacklist = setOf(
@@ -62,4 +62,12 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() {
return activityContract != null
}
+ override fun onGeolocationPermissionsShowPrompt(origin: String, callback: GeolocationPermissions.Callback) {
+ L.d("Requesting geolocation")
+ context.kauRequestPermissions(PERMISSION_ACCESS_FINE_LOCATION) {
+ granted, _ ->
+ L.d("Geolocation response received; ${if (granted) "granted" else "denied"}")
+ callback(origin, granted, true)
+ }
+ }
} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
index 6ec1aec5..1679d7a3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt
@@ -16,6 +16,7 @@ import ca.allanwang.kau.utils.withAlpha
import com.pitchedapps.frost.R
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
+import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.Prefs
import io.reactivex.android.schedulers.AndroidSchedulers
@@ -61,7 +62,7 @@ class FrostWebView @JvmOverloads constructor(
baseEnum = enum
with(settings) {
javaScriptEnabled = true
- if (url.contains("com/message"))
+ if (url.contains("/message"))
userAgentString = USER_AGENT_BASIC
allowFileAccess = true
textZoom = Prefs.webTextScaling
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 cb5125c4..9f7dd916 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClients.kt
@@ -1,6 +1,5 @@
package com.pitchedapps.frost.web
-import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
@@ -17,6 +16,7 @@ import com.pitchedapps.frost.facebook.FB_URL_BASE
import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.injectors.*
import com.pitchedapps.frost.utils.*
+import com.pitchedapps.frost.utils.iab.IS_FROST_PRO
import io.reactivex.subjects.Subject
/**
@@ -71,8 +71,8 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient
}
view.jsInject(
CssAssets.ROUND_ICONS.maybe(Prefs.showRoundedIcons),
- CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && Prefs.pro),
- CssHider.ADS.maybe(!Prefs.showFacebookAds && Prefs.pro)
+ CssHider.PEOPLE_YOU_MAY_KNOW.maybe(!Prefs.showSuggestedFriends && IS_FROST_PRO),
+ CssHider.ADS.maybe(!Prefs.showFacebookAds && IS_FROST_PRO)
)
onPageFinishedActions(url)
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt
index 0f3a12b6..53fa0657 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/MessageWebView.kt
@@ -6,23 +6,24 @@ import android.webkit.JavascriptInterface
import android.webkit.WebView
import ca.allanwang.kau.utils.gone
import com.pitchedapps.frost.dbflow.CookieModel
-import com.pitchedapps.frost.facebook.FbCookie
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.USER_AGENT_BASIC
-import com.pitchedapps.frost.injectors.JsActions
+import com.pitchedapps.frost.injectors.JsAssets
import com.pitchedapps.frost.services.NotificationService
import com.pitchedapps.frost.utils.L
import com.pitchedapps.frost.utils.frostAnswersCustom
import org.jetbrains.anko.doAsync
-import org.jetbrains.anko.runOnUiThread
-@SuppressLint("ViewConstructor")
/**
* Created by Allan Wang on 2017-07-17.
*
* Bare boned headless view made solely to extract conversation info
*/
-class MessageWebView(val service: NotificationService, val params: JobParameters?) : WebView(service) {
+@SuppressLint("ViewConstructor")
+class MessageWebView(val service: NotificationService, val params: JobParameters?, val cookie: CookieModel) : WebView(service) {
+
+ private val startTime = System.currentTimeMillis()
+ private var isCancelled = false
init {
gone()
@@ -33,48 +34,33 @@ class MessageWebView(val service: NotificationService, val params: JobParameters
private fun setupWebview() {
settings.javaScriptEnabled = true
settings.userAgentString = USER_AGENT_BASIC
- webViewClient = HeadlessWebViewClient("MessageNotifs", JsActions.GET_MESSAGES)
+ webViewClient = HeadlessWebViewClient("MessageNotifs", JsAssets.NOTIF_MSG)
webChromeClient = QuietChromeClient()
addJavascriptInterface(MessageJSI(), "Frost")
+ loadUrl(FbTab.MESSAGES.url)
}
- private val startTime = System.currentTimeMillis()
- private val endTime: Long by lazy { System.currentTimeMillis() }
- private var inProgress = false
- private val pendingRequests: MutableList<CookieModel> = mutableListOf()
- private lateinit var data: CookieModel
-
- fun request(data: CookieModel) {
- pendingRequests.add(data)
- if (inProgress) return
- inProgress = true
- load(data)
+ fun finish() {
+ if (isCancelled) return
+ isCancelled = true
+ post { destroy() }
+ service.finish(params)
}
- private fun load(data: CookieModel) {
- L.d("Notif retrieving messages", data.toString())
- this.data = data
- FbCookie.setWebCookie(data.cookie) { context.runOnUiThread { L.d("Notif messages load"); loadUrl(FbTab.MESSAGES.url) } }
+ override fun destroy() {
+ L.d("MessageWebView destroyed")
+ super.destroy()
}
inner class MessageJSI {
@JavascriptInterface
fun handleHtml(html: String) {
- L.d("Notif messages received", data.toString())
- doAsync { service.fetchMessageNotifications(data, html) }
- pendingRequests.remove(data)
- if (pendingRequests.isEmpty()) {
- val time = endTime - startTime
- L.d("Notif messages finished $time")
- frostAnswersCustom("Notifications") {
- putCustomAttribute("Message retrieval duration", time)
- }
- post { destroy() }
- service.jobFinished(params, false)
- service.future = null
- } else {
- load(pendingRequests.first())
- }
+ if (isCancelled) return
+ if (html.length < 10) return finish()
+ val time = System.currentTimeMillis() - startTime
+ L.d("Notif messages fetched in $time ms")
+ frostAnswersCustom("NotificationTime", "Type" to "IM Headless", "Duration" to time)
+ doAsync { service.fetchMessageNotifications(cookie, html); finish() }
}
}
diff --git a/app/src/main/play/en-CA/listing/fulldescription b/app/src/main/play/en-CA/listing/fulldescription
index 32cf0503..16b0e8f7 100644
--- a/app/src/main/play/en-CA/listing/fulldescription
+++ b/app/src/main/play/en-CA/listing/fulldescription
@@ -8,13 +8,18 @@ While being a web wrapper, Frost contains many unique and native features such a
• 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)
-Permissions used and why:
+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.
-• Read/write external storage - Needed to upload photos in a new status and save photos when prompted
• 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:
diff --git a/app/src/main/res/layout/intro_end.xml b/app/src/main/res/layout/intro_end.xml
index 10132546..67931e43 100644
--- a/app/src/main/res/layout/intro_end.xml
+++ b/app/src/main/res/layout/intro_end.xml
@@ -12,7 +12,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/intro_end"
- app:layout_constraintBottom_toTopOf="@+id/intro_image"
+ app:layout_constraintBottom_toTopOf="@id/intro_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index e6dc5b24..4c685908 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
- <color name="colorPrimary">@color/facebook_blue</color>
- <color name="colorPrimaryDark">@color/facebook_blue_dark</color>
- <color name="colorAccent">#FF4081</color>
<color name="frost_splash_background">@color/facebook_blue</color>
<color name="facebook_blue">#3b5998</color>
<color name="facebook_blue_dark">#2e4b86</color>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 92ab2491..d4a7c9dc 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,9 +1,6 @@
<resources>
<string name="dev_email" translatable="false">pitchedapps@gmail.com</string>
<string name="play_store_package_id" translatable="false">com.pitchedapps.frost</string>
- <string name="about_frost">About Frost for Facebook</string>
- <string name="frost_description">Frost is a fully themable, fully functional alternative to the official Facebook app, made from scratch and proudly open sourced.</string>
- <string name="section_format">Hello World from section: %1$d</string>
<string name="feed">Feed</string>
<string name="most_recent">Most Recent</string>
@@ -46,6 +43,7 @@
<string name="debug_link_subject">Frost for Facebook: Link Debug</string>
<string name="debug_link_content">Write here. Note that your link may contain private information, but I won\'t be able to see it as the post isn\'t public. The url will still help with debugging though.</string>
<string name="debug_link_desc">If a link isn\'t loading properly, you can email me so I can help debug it. Clicking okay will open an email request</string>
+ <string name="open_link">Open Link</string>
<string name="copy_link">Copy Link</string>
<string name="copy_text">Copy Text</string>
<string name="debug_image_link_subject">Frost for Facebook: Image Link Debug</string>
diff --git a/app/src/main/res/values/strings_about.xml b/app/src/main/res/values/strings_about.xml
new file mode 100644
index 00000000..68590718
--- /dev/null
+++ b/app/src/main/res/values/strings_about.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+
+ <string name="frost_description">Frost is a fully themable,
+ fully functional alternative to the official Facebook app, made from scratch and proudly open sourced.</string>
+
+ <string name="faq_title">Frost FAQ</string>
+
+ <string name="faq_feature">Can you add feature xxx?</string>
+ <string name="faq_feature_desc">I\'m always opened to suggestions,
+ and if a feature will enhance your experience, I\'d like to hear it.
+ However, please consider taking a look at my
+ <a href="https://github.com/AllanWang/Frost-for-Facebook/issues">issue tracker</a></string>
+
+ <string name="faq_cannot_scroll_horizontally">I can\'t scroll horizontally in the webviews.</string>
+ <string name="faq_cannot_scroll_horizontally_desc">This is known since the viewpager takes priority for horizontal scrolling.
+ Frost has addressed this by allowing horizontal web scrolls if you tap and hold before scrolling.</string>
+
+ <string name="faq_more_frequent_notifications">Can I get more frequent notifications?</string>
+ <string name="faq_more_frequent_notifications_desc">I made the decision to prioritize battery life by using a newer job scheduler for Android.
+ This means that your framework picks the best time to fetch the notifications, and the lowest window is 15 minutes.
+ This is also why I don\'t require the wakelock permission</string>
+</resources> \ No newline at end of file
diff --git a/app/src/main/res/values/strings_pref_notifications.xml b/app/src/main/res/values/strings_pref_notifications.xml
index 1d605c2b..00c30b57 100644
--- a/app/src/main/res/values/strings_pref_notifications.xml
+++ b/app/src/main/res/values/strings_pref_notifications.xml
@@ -9,6 +9,8 @@
<string name="empty_keyword">Empty Keyword</string>
<string name="notification_all_accounts">Notify from all accounts</string>
<string name="notification_all_accounts_desc">Get notifications for every account that is logged in. Disabling this will only fetch notifications form the currently selected account.</string>
+ <string name="notification_messages">Enable message notifications</string>
+ <string name="notification_messages_desc">Get instant message notifications for your current account.</string>
<string name="notification_fetch_now">Fetch Notifications Now</string>
<string name="notification_fetch_now_desc">Trigger the notification fetcher one time.</string>
<string name="notification_fetch_success">Fetching Notifications…</string>
diff --git a/app/src/main/res/values/strings_preferences b/app/src/main/res/values/strings_preferences.xml
index 1108d08d..c2ba0b36 100644
--- a/app/src/main/res/values/strings_preferences
+++ b/app/src/main/res/values/strings_preferences.xml
@@ -16,5 +16,9 @@
<string name="get_pro">Get Frost Pro</string>
<string name="get_pro_desc">Purchase or restore pro and unlock the full potential of Frost! Includes ad blockers, custom themes, full configurations, and much more to come!</string>
+ <string name="about_frost">About Frost for Facebook</string>
+ <string name="about_frost_desc">Version, Credits, and FAQs</string>
+
+
<string name="replay_intro">Replay Introduction</string>
</resources> \ No newline at end of file
diff --git a/app/src/main/res/xml/frost_changelog.xml b/app/src/main/res/xml/frost_changelog.xml
index 4b41553b..8f68de9f 100644
--- a/app/src/main/res/xml/frost_changelog.xml
+++ b/app/src/main/res/xml/frost_changelog.xml
@@ -10,14 +10,19 @@
<!--<version title="Beta Updates" />-->
- <version title="v1.5"/>
+ <version title="v1.4.2"/>
+ <item text="Experimental: Add notifications for messages; report to me if this drains your battery" />
+ <item text="Add FAQ in the about section" />
+ <item text="Add video uploading" />
+ <item text="Add open link option in context menu" />
+ <item text="Add geolocation" />
+ <item text="Update theme" />
+
+ <version title="v1.4.1"/>
<item text="Add intro pages" />
<item text="Style new comment highlights" />
<item text="Style reaction background" />
<item text="Disable pull to refresh when typing is detected" />
- <item text="" />
- <item text="" />
- <item text="" />
<version title="v1.4" />
<item text="Update IAB helper" />
diff --git a/app/src/main/res/xml/frost_faq.xml b/app/src/main/res/xml/frost_faq.xml
new file mode 100644
index 00000000..e46d2d50
--- /dev/null
+++ b/app/src/main/res/xml/frost_faq.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <question><![CDATA[Can you add feature xxx?]]></question>
+ <answer><![CDATA[I&apos;m always opened to suggestions,
+ and if a feature will enhance your experience, I&apos;d like to hear it.
+ However, please consider taking a look at my
+ <a href="https://github.com/AllanWang/Frost-for-Facebook/issues">issue tracker</a> first to avoid duplicate requests.]]></answer>
+
+ <question><![CDATA[I can&apos;t scroll horizontally in the webviews.]]></question>
+ <answer><![CDATA[This is known since the viewpager takes priority for horizontal scrolling.
+ Frost has addressed this by allowing horizontal web scrolls if you tap and hold before scrolling.]]></answer>
+
+ <question><![CDATA[Can I get more frequent notifications?]]></question>
+ <answer><![CDATA[I made the decision to prioritize battery life by using a newer job scheduler for Android.
+ This means that your framework picks the best time to fetch the notifications, and the lowest window is 15 minutes.
+ This is also why I don&apos;t require the wakelock permission]]></answer>
+</resources> \ No newline at end of file