diff options
author | Allan Wang <me@allanwang.ca> | 2017-06-14 23:39:05 -0700 |
---|---|---|
committer | Allan Wang <me@allanwang.ca> | 2017-06-14 23:39:05 -0700 |
commit | 610c37698ab93b8d51efcaec9f721292cacfd854 (patch) | |
tree | 2bb97be0f43aa5c5d64237e61dc628938e7350b5 /app/src | |
parent | fbbc92e4c98a30e107fb2a63887f8b6d20bffabb (diff) | |
download | frost-610c37698ab93b8d51efcaec9f721292cacfd854.tar.gz frost-610c37698ab93b8d51efcaec9f721292cacfd854.tar.bz2 frost-610c37698ab93b8d51efcaec9f721292cacfd854.zip |
Create notification service framework
Diffstat (limited to 'app/src')
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 + 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> |