aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authorAllan Wang <me@allanwang.ca>2017-06-14 23:39:05 -0700
committerAllan Wang <me@allanwang.ca>2017-06-14 23:39:05 -0700
commit610c37698ab93b8d51efcaec9f721292cacfd854 (patch)
tree2bb97be0f43aa5c5d64237e61dc628938e7350b5 /app
parentfbbc92e4c98a30e107fb2a63887f8b6d20bffabb (diff)
downloadfrost-610c37698ab93b8d51efcaec9f721292cacfd854.tar.gz
frost-610c37698ab93b8d51efcaec9f721292cacfd854.tar.bz2
frost-610c37698ab93b8d51efcaec9f721292cacfd854.zip
Create notification service framework
Diffstat (limited to 'app')
-rw-r--r--app/src/main/AndroidManifest.xml12
-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/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/kotlin/com/pitchedapps/frost/FrostApp.kt3
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt6
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt31
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/NotificationExtensions.kt13
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt121
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt4
-rw-r--r--app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt2
-rw-r--r--app/src/main/res/drawable/frost_f_24.xml14
-rw-r--r--app/src/main/res/layout/activity_selector.xml2
-rw-r--r--app/src/main/res/values/strings.xml1
18 files changed, 219 insertions, 30 deletions
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3d001740..fab2d2a3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -36,7 +36,10 @@
android:configChanges="orientation|screenSize|locale"
android:hardwareAccelerated="true"
android:label="@string/app_name"
- android:theme="@style/AppTheme.NoActionBar">
+ android:theme="@style/AppTheme.NoActionBar" />
+ <activity
+ android:name=".WebOverlayActivity"
+ android:theme="@style/AppTheme.Overlay">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
@@ -88,9 +91,6 @@
</intent-filter>
</activity>
<activity
- android:name=".WebOverlayActivity"
- android:theme="@style/AppTheme.Overlay" />
- <activity
android:name=".LoginActivity"
android:theme="@style/AppTheme.NoActionBar" />
<activity
@@ -100,6 +100,10 @@
android:name=".SettingsActivity"
android:theme="@style/AppTheme.NoActionBar" />
+ <service
+ android:name=".services.NotificationService"
+ android:enabled="true"
+ android:label="@string/frost_notifications" />
<receiver
android:name=".services.NotificationReceiver"
android:enabled="true"
diff --git a/app/src/main/assets/css/core/main.compact.css b/app/src/main/assets/css/core/main.compact.css
index 00d50516..cf0689de 100644
--- a/app/src/main/assets/css/core/main.compact.css
+++ b/app/src/main/assets/css/core/main.compact.css
@@ -1,10 +1,10 @@
#viewport { background: #451515 !important; }
-body, #root, #header, .aclb, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: rgba(255, 0, 255, 0.02) !important; }
+body, #root, #header, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: rgba(255, 0, 255, 0.02) !important; }
.jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p { background: #451515 !important; }
-button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax { background: rgba(147, 45, 45, 0.2) !important; }
+button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax, .aclb, ._4756 { background: rgba(147, 45, 45, 0.2) !important; }
body, input, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, textarea, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, ._46pa, ._336p, h1, h2, h3, h4, h5, h6 { color: #d7b0d7 !important; }
@@ -24,7 +24,7 @@ a, ._5fpq { color: #8c8dd6 !important; }
._15ny::after, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._5lp5, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x { border-bottom: 1px solid rgba(215, 176, 215, 0.3) !important; }
-._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf { border: 1px solid rgba(215, 176, 215, 0.3) !important; }
+._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756 { border: 1px solid rgba(215, 176, 215, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax { 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 eca91f02..bf633148 100644
--- a/app/src/main/assets/css/core/main.scss
+++ b/app/src/main/assets/css/core/main.scss
@@ -5,7 +5,7 @@
background: $background !important;
}
-body, #root, #header, .aclb, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5,
+body, #root, #header, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5,
._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm,
.acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView,
._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 {
@@ -20,7 +20,7 @@ button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before,
._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer,
._4e8n, ._5pxa._3uj9,
//unread
-._4qax {
+._4qax, .aclb, ._4756 {
background: $background2 !important;
}
@@ -58,7 +58,7 @@ a,
//friend card border
._d4i,
-._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf {
+._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756 {
border: 1px solid $divider !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 26affc81..756f8ca0 100644
--- a/app/src/main/assets/css/themes/material_amoled.compact.css
+++ b/app/src/main/assets/css/themes/material_amoled.compact.css
@@ -1,10 +1,10 @@
#viewport { background: #000 !important; }
-body, #root, #header, .aclb, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: #000 !important; }
+body, #root, #header, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: #000 !important; }
.jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p { background: black !important; }
-button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax { background: rgba(51, 51, 51, 0.2) !important; }
+button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax, .aclb, ._4756 { background: rgba(51, 51, 51, 0.2) !important; }
body, input, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, textarea, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, ._46pa, ._336p, h1, h2, h3, h4, h5, h6 { color: #fff !important; }
@@ -24,7 +24,7 @@ a, ._5fpq { color: #B3E5FC !important; }
._15ny::after, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._5lp5, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x { border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important; }
-._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
+._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756 { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax { 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 ce1684e1..62d7e5f3 100644
--- a/app/src/main/assets/css/themes/material_dark.compact.css
+++ b/app/src/main/assets/css/themes/material_dark.compact.css
@@ -1,10 +1,10 @@
#viewport { background: #303030 !important; }
-body, #root, #header, .aclb, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: #303030 !important; }
+body, #root, #header, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: #303030 !important; }
.jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p { background: #303030 !important; }
-button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax { background: rgba(99, 99, 99, 0.2) !important; }
+button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax, .aclb, ._4756 { background: rgba(99, 99, 99, 0.2) !important; }
body, input, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, textarea, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, ._46pa, ._336p, h1, h2, h3, h4, h5, h6 { color: #fff !important; }
@@ -24,7 +24,7 @@ a, ._5fpq { color: #B3E5FC !important; }
._15ny::after, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._5lp5, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x { border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important; }
-._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
+._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756 { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax { 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 3a6f4a8e..31ecc3c8 100644
--- a/app/src/main/assets/css/themes/material_glass.compact.css
+++ b/app/src/main/assets/css/themes/material_glass.compact.css
@@ -1,10 +1,10 @@
#viewport { background: rgba(0, 0, 0, 0.3) !important; }
-body, #root, #header, .aclb, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: transparent !important; }
+body, #root, #header, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: transparent !important; }
.jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p { background: black !important; }
-button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax { background: rgba(51, 51, 51, 0.2) !important; }
+button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax, .aclb, ._4756 { background: rgba(51, 51, 51, 0.2) !important; }
body, input, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, textarea, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, ._46pa, ._336p, h1, h2, h3, h4, h5, h6 { color: #fff !important; }
@@ -24,7 +24,7 @@ a, ._5fpq { color: #B3E5FC !important; }
._15ny::after, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._5lp5, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x { border-bottom: 1px solid rgba(255, 255, 255, 0.3) !important; }
-._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
+._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756 { border: 1px solid rgba(255, 255, 255, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax { 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 973c7880..4b252d22 100644
--- a/app/src/main/assets/css/themes/material_light.compact.css
+++ b/app/src/main/assets/css/themes/material_light.compact.css
@@ -1,10 +1,10 @@
#viewport { background: #fafafa !important; }
-body, #root, #header, .aclb, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: #fafafa !important; }
+body, #root, #header, ._55wo, ._1upc, input, ._2f9r, ._59e9, ._5pz4, ._5lp4, ._5lp5, ._d4i, ._5c9u, div._5y57::before, ._59f6._55so::before, .structuredPublisher, ._94v, ._vqv, ._5lp5, ._55wm, .acw, ._3f50, .mentions-placeholder, .mentions, .mentions-shadow, .mentions-measurer, .acg, ._59tu, ._52z5, ._4l9b, ._4gj3, .groupChromeView, ._uww, textarea, ._15n_, ._skt, ._5f28, ._14_j, ._3bg5, ._53_-, ._52x1 { background: #fafafa !important; }
.jewel, .flyout, ._13e_, ._5-lw, ._5c0e, .jx-result, ._336p { background: #fafafa !important; }
-button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax { background: rgba(255, 255, 255, 0.2) !important; }
+button, button::before, .touch ._56bt, ._56be::before, .btnS, .touch::before, ._5xo2, ._5u5a::before, ._4u3j, ._15ks, ._2v9s, ._5hua, ._59tt, ._41ft, .jx-tokenizer, ._4e8n, ._5pxa._3uj9, ._4qax, .aclb, ._4756 { background: rgba(255, 255, 255, 0.2) !important; }
body, input, ._43mh, .touch .btn, p, span, .fcg, button, ._52j9, ._52jb, ._52ja, ._5j35, ._rnk, ._24u0, ._1g06, ._14ye, textarea, .mentions-input, .mentions-placeholder, .fcw, ._5-7t, .fcl, ._4qas, .thread-title, ._46pa, ._336p, h1, h2, h3, h4, h5, h6 { color: #000 !important; }
@@ -24,7 +24,7 @@ a, ._5fpq { color: #263238 !important; }
._15ny::after, ._ap1, ._52x1, ._59tu, ._usq, ._13e_, ._59f6._55so::before, ._4gj3, .jx-result, ._5lp5, ._5pz4, ._5lp4, ._5lp5, ._3on6, ._5h6z, ._5h6x { border-bottom: 1px solid rgba(0, 0, 0, 0.3) !important; }
-._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf { border: 1px solid rgba(0, 0, 0, 0.3) !important; }
+._d4i, ._4e8n, ._uww, .mentions-placeholder, .mentions-shadow, .mentions-measurer, ._5whq, ._59tt, ._41ft::after, .jx-tokenizer, ._3uqf, ._4756 { border: 1px solid rgba(0, 0, 0, 0.3) !important; }
._4o58::after, .acw, .aclb, ._4qax { border-color: rgba(0, 0, 0, 0.3) !important; }
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
index 85d1c8b5..09a54444 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/FrostApp.kt
@@ -13,6 +13,7 @@ import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerUIUtils
import com.pitchedapps.frost.facebook.FbCookie
+import com.pitchedapps.frost.services.requestNotifications
import com.pitchedapps.frost.utils.CrashReportingTree
import com.pitchedapps.frost.utils.Prefs
import com.raizlabs.android.dbflow.config.FlowConfig
@@ -47,7 +48,7 @@ class FrostApp : Application() {
Prefs.initialize(this, "${com.pitchedapps.frost.BuildConfig.APPLICATION_ID}.prefs")
FbCookie()
super.onCreate()
-
+ requestNotifications(Prefs.userId)
//Drawer profile loading logic
DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String) {
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt
index 9ba83879..386bf4d3 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/LoginActivity.kt
@@ -87,7 +87,7 @@ class LoginActivity : BaseActivity() {
(foundImage, name) ->
refresh = false
L.d("Zip done")
- if (!foundImage) L.e("Could not get profile photo; Invalid id?\n\t$cookie")
+ if (!foundImage) L.e("Could not get profile photo; Invalid userId?\n\t$cookie")
textview.setTextWithFade(String.format(getString(R.string.welcome), name), duration = 500)
/*
* The user may have logged into an account that is already in the database
@@ -96,7 +96,7 @@ class LoginActivity : BaseActivity() {
loadFbCookiesAsync {
cookies ->
Handler().postDelayed({
- launchNewTask(MainActivity::class.java, ArrayList(cookies))
+ launchNewTask(MainActivity::class.java, ArrayList(cookies), clearStack = true)
}, 1000)
}
}
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
index fce3e670..17840a14 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/MainActivity.kt
@@ -1,6 +1,5 @@
package com.pitchedapps.frost
-import android.content.Intent
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
@@ -30,6 +29,7 @@ import com.pitchedapps.frost.facebook.FbCookie.switchUser
import com.pitchedapps.frost.facebook.FbTab
import com.pitchedapps.frost.facebook.PROFILE_PICTURE_URL
import com.pitchedapps.frost.fragments.WebFragment
+import com.pitchedapps.frost.services.requestNotifications
import com.pitchedapps.frost.utils.*
import io.reactivex.disposables.Disposable
import io.reactivex.subjects.PublishSubject
@@ -178,7 +178,9 @@ class MainActivity : BaseActivity() {
})
}
R.id.action_changelog -> showChangelog(R.xml.changelog)
- R.id.action_call -> launchNewTask(LoginActivity::class.java)
+ R.id.action_call -> {
+ requestNotifications(Prefs.userId)
+ }
R.id.action_db -> adapter.pages.saveAsync(this)
R.id.action_restart -> restart()
else -> return super.onOptionsItemSelected(item)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt
new file mode 100644
index 00000000..e71500fc
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/dbflow/NotificationDb.kt
@@ -0,0 +1,31 @@
+package com.pitchedapps.frost.dbflow
+
+import com.pitchedapps.frost.utils.L
+import com.raizlabs.android.dbflow.annotation.ConflictAction
+import com.raizlabs.android.dbflow.annotation.Database
+import com.raizlabs.android.dbflow.annotation.PrimaryKey
+import com.raizlabs.android.dbflow.annotation.Table
+import com.raizlabs.android.dbflow.kotlinextensions.*
+import com.raizlabs.android.dbflow.structure.BaseModel
+
+/**
+ * Created by Allan Wang on 2017-05-30.
+ */
+
+@Database(name = NotificationDb.NAME, version = NotificationDb.VERSION)
+object NotificationDb {
+ const val NAME = "Notifications"
+ const val VERSION = 1
+}
+
+@Table(database = NotificationDb::class, allFields = true, primaryKeyConflict = ConflictAction.REPLACE)
+data class NotificationModel(@PrimaryKey var id: Long = -1L, var epoch: Long = -1L) : BaseModel()
+
+fun lastNotificationTime(id: Long): Long = (select from NotificationModel::class where (NotificationModel_Table.id eq id)).querySingle()?.epoch ?: -1L
+
+fun saveNotificationTime(notificationModel: NotificationModel, callback: (() -> Unit)? = null) {
+ notificationModel.async save {
+ L.d("Fb notification $notificationModel saved")
+ callback?.invoke()
+ }
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationExtensions.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationExtensions.kt
new file mode 100644
index 00000000..ac94b527
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationExtensions.kt
@@ -0,0 +1,13 @@
+package com.pitchedapps.frost.services
+
+import android.content.Context
+import android.content.Intent
+
+/**
+ * Created by Allan Wang on 2017-06-14.
+ */
+fun Context.requestNotifications(id: Long) {
+ val intent = Intent(this, NotificationService::class.java)
+ intent.putExtra(NotificationService.ARG_ID, id)
+ startService(intent)
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
new file mode 100644
index 00000000..3bbecb4f
--- /dev/null
+++ b/app/src/main/kotlin/com/pitchedapps/frost/services/NotificationService.kt
@@ -0,0 +1,121 @@
+package com.pitchedapps.frost.services
+
+import android.app.IntentService
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.support.v4.app.ActivityOptionsCompat
+import android.support.v4.app.NotificationCompat
+import android.support.v4.app.NotificationManagerCompat
+import ca.allanwang.kau.utils.string
+import com.pitchedapps.frost.R
+import com.pitchedapps.frost.WebOverlayActivity
+import com.pitchedapps.frost.dbflow.NotificationModel
+import com.pitchedapps.frost.dbflow.lastNotificationTime
+import com.pitchedapps.frost.dbflow.loadFbCookie
+import com.pitchedapps.frost.dbflow.saveNotificationTime
+import com.pitchedapps.frost.facebook.FACEBOOK_COM
+import com.pitchedapps.frost.facebook.FB_URL_BASE
+import com.pitchedapps.frost.facebook.FbTab
+import com.pitchedapps.frost.utils.ARG_URL
+import com.pitchedapps.frost.utils.L
+import org.jsoup.Jsoup
+import org.jsoup.nodes.Element
+
+/**
+ * Created by Allan Wang on 2017-06-14.
+ */
+class NotificationService : IntentService(NotificationService::class.java.simpleName) {
+
+ companion object {
+ const val ARG_ID = "arg_id"
+ val epochMatcher: Regex by lazy { Regex(":([0-9]*),") }
+ val notifIdMatcher: Regex by lazy { Regex("notif_id\":([0-9]*),") }
+ }
+
+ override fun onHandleIntent(intent: Intent) {
+ val id = intent.getLongExtra(ARG_ID, -1L)
+ L.i("Handling notifications for $id")
+ if (id == -1L) return
+ val data = loadFbCookie(id) ?: return
+ L.i("Using data $data")
+ val doc = Jsoup.connect(FbTab.NOTIFICATIONS.url).cookie(FACEBOOK_COM, data.cookie).get()
+ val unreadNotifications = doc.getElementById("notifications_list").getElementsByClass("aclb")
+ var notifCount = 0
+ var latestEpoch = lastNotificationTime(data.id)
+ L.i("Latest Epoch $latestEpoch")
+ unreadNotifications.forEach {
+ elem ->
+ val notif = parseNotification(data.id, elem)
+ if (notif != null) {
+ if (notif.timestamp <= latestEpoch) return@forEach
+ notif.createNotification(this)
+ latestEpoch = notif.timestamp
+ notifCount++
+ }
+ }
+ saveNotificationTime(NotificationModel(data.id, latestEpoch))
+ summaryNotification(data.id, notifCount)
+ }
+
+ fun parseNotification(userId: Long, element: Element): NotificationContent? {
+ val a = element.getElementsByTag("a").first() ?: return null
+ val dataStore = a.attr("data-store")
+ val notifId = if (dataStore == null) System.currentTimeMillis()
+ else notifIdMatcher.find(dataStore)?.groups?.get(1)?.value?.toLong() ?: System.currentTimeMillis()
+ val abbr = element.getElementsByTag("abbr")
+ val timeString = abbr?.text()
+ var text = a.text().replace("\u00a0", " ") //remove &nbsp;
+ if (timeString != null) text = text.removeSuffix(timeString)
+ text = text.trim()
+ val abbrData = abbr?.attr("data-store")
+ val epoch = if (abbrData == null) -1L else epochMatcher.find(abbrData)?.groups?.get(1)?.value?.toLong() ?: -1L
+ return NotificationContent(userId, notifId.toInt(), a.attr("href"), text, epoch)
+ }
+
+ data class NotificationContent(val userId: Long, val notifId: Int, val href: String, val text: String, val timestamp: Long) {
+ fun createNotification(context: Context) {
+ val intent = Intent(context, WebOverlayActivity::class.java)
+// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP or PendingIntent.FLAG_ONE_SHOT)
+ intent.putExtra(ARG_URL, "$FB_URL_BASE$href")
+ intent.action = System.currentTimeMillis().toString() //dummy action
+ val bundle = ActivityOptionsCompat.makeCustomAnimation(context, R.anim.slide_in_right, R.anim.slide_out_right).toBundle()
+ val pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT, bundle)
+ val notifBuilder = NotificationCompat.Builder(context)
+ .setSmallIcon(R.drawable.frost_f_24)
+ .setContentTitle(context.string(R.string.app_name))
+ .setContentText(text)
+ .setContentIntent(pendingIntent)
+ .setGroup("frost_$userId")
+ .setAutoCancel(true)
+
+ if (timestamp != -1L) notifBuilder.setWhen(timestamp * 1000)
+
+ NotificationManagerCompat.from(context).notify("frost_$userId", notifId, notifBuilder.build())
+ }
+ }
+
+ fun summaryNotification(userId: Long, count: Int) {
+ if (count <= 1) return
+ val notifBuilder = NotificationCompat.Builder(this)
+ .setSmallIcon(R.drawable.frost_f_24)
+ .setContentTitle(string(R.string.app_name))
+ .setContentText("$count notifications")
+ .setGroup("frost_$userId")
+ .setGroupSummary(true)
+ .setAutoCancel(true)
+
+ NotificationManagerCompat.from(this).notify("frost_$userId", userId.toInt(), notifBuilder.build())
+ }
+
+ private fun log(element: Element) {
+ with(element) {
+ L.i("\n\nElement ${text()}")
+ attributes().forEach {
+ L.i("attr ${it.html()}")
+ }
+ L.i("Content ${html()}")
+ }
+ }
+
+} \ No newline at end of file
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
index 4845f553..1ae17cde 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt
@@ -61,7 +61,9 @@ open class FrostWebViewClient(val refreshObservable: Subject<Boolean>) : WebView
internal fun onPageFinishedReveal(view: FrostWebViewCore, animate: Boolean) {
L.d("Page finished reveal")
- view.jsInject(CssHider.HEADER, CssAssets.MATERIAL_DARK, callback = {
+ view.jsInject(CssHider.HEADER,
+// CssAssets.MATERIAL_DARK,
+ callback = {
L.d("Finished ${it.contentToString()}")
refreshObservable.onNext(false)
if (animate) view.circularReveal(offset = 150L)
diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
index 191d9350..721a75de 100644
--- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
+++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt
@@ -52,7 +52,7 @@ class LoginWebView @JvmOverloads constructor(
cookieObservable.onComplete()
loginObservable.onSuccess(CookieModel(id.toLong(), "", cookie))
} catch (e: NumberFormatException) {
- //todo send report that id has changed
+ //todo send report that userId has changed
}
}
}
diff --git a/app/src/main/res/drawable/frost_f_24.xml b/app/src/main/res/drawable/frost_f_24.xml
new file mode 100644
index 00000000..f9b207f1
--- /dev/null
+++ b/app/src/main/res/drawable/frost_f_24.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="177.16534"
+ android:viewportHeight="177.16534">
+
+ <path
+ android:strokeColor="#000"
+ android:strokeWidth="10"
+ android:strokeLineCap="round"
+ android:pathData="M84.0566 31.70696l41.06144 23.88663M83.4628 31.68423l-31.358 18.2953M51.98616
+51.1838v94.26223M52.32337 87.29608l40.97657 23.86425" />
+</vector> \ No newline at end of file
diff --git a/app/src/main/res/layout/activity_selector.xml b/app/src/main/res/layout/activity_selector.xml
index e7332925..7bcc33ab 100644
--- a/app/src/main/res/layout/activity_selector.xml
+++ b/app/src/main/res/layout/activity_selector.xml
@@ -46,7 +46,7 @@
<!--app:layout_constraintEnd_toEndOf="parent"-->
<!--app:layout_constraintHorizontal_bias="0.5"-->
<!--app:layout_constraintStart_toStartOf="parent"-->
- <!--app:layout_constraintTop_toBottomOf="@id/selector_recycler"-->
+ <!--app:layout_constraintTop_toBottomOf="@userId/selector_recycler"-->
<!--tools:layout_editor_absoluteX="8dp"-->
<!--tools:layout_editor_absoluteY="0dp" />-->
</android.support.constraint.ConstraintLayout> \ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 9e51242c..c140a0c8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -39,4 +39,5 @@
<string name="amoled">AMOLED</string>
<string name="glass">Glass</string>
<string name="custom">Custom</string>
+ <string name="frost_notifications">Frost Notifications</string>
</resources>