From 2be098e1a6d474e02c1d51fdb51d2271b75793fc Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Mon, 13 Jul 2020 17:07:19 +0100 Subject: [PATCH 01/12] display notification bell icon beside URL bar --- .../main/res/drawable-anydpi/ic_notifications.xml | 11 +++++++++++ .../main/res/drawable-hdpi/ic_notifications.png | Bin 0 -> 273 bytes .../main/res/drawable-mdpi/ic_notifications.png | Bin 0 -> 203 bytes .../main/res/drawable-xhdpi/ic_notifications.png | Bin 0 -> 333 bytes .../main/res/drawable-xxhdpi/ic_notifications.png | Bin 0 -> 477 bytes app/src/main/res/layout/app_bar_main.xml | 14 ++++++++++++++ 6 files changed, 25 insertions(+) create mode 100644 app/src/main/res/drawable-anydpi/ic_notifications.xml create mode 100644 app/src/main/res/drawable-hdpi/ic_notifications.png create mode 100644 app/src/main/res/drawable-mdpi/ic_notifications.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_notifications.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_notifications.png diff --git a/app/src/main/res/drawable-anydpi/ic_notifications.xml b/app/src/main/res/drawable-anydpi/ic_notifications.xml new file mode 100644 index 00000000..0dbf589c --- /dev/null +++ b/app/src/main/res/drawable-anydpi/ic_notifications.xml @@ -0,0 +1,11 @@ + + + diff --git a/app/src/main/res/drawable-hdpi/ic_notifications.png b/app/src/main/res/drawable-hdpi/ic_notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..3a83a649ffda7df0a1d77ada089cd0dd350248e7 GIT binary patch literal 273 zcmV+s0q*{ZP)SOk$PA_{H~?uzrt*&w*_MMqSn4KyDuPS zTVI%(5)L5#W{Jj3sJjDZ=*BaUpw$S>P>lqg0iY8SbOnGeNKg*|^+=EafCLgG5oJ&Y zWzb)MXwV)7;#o0a#-Ti6+)*AeZs$qwkhhY#LR+svAwi7=bO;HWF@SpN_<5Rtza+Ij XSc4UXr(rY200000NkvXXu0mjfOh#>@ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_notifications.png b/app/src/main/res/drawable-mdpi/ic_notifications.png new file mode 100644 index 0000000000000000000000000000000000000000..a3a94d02822b2025d3b8b8769ac36aba68d19510 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjlRRA}1CrB7R`2YXEk3$aY zQJ*av7*akYX>41x?co}SIbA7?9cR6C55H}wu$uJHfJbQa;wuIEI&6!R^^16?Gd*H; zi7=4wXg#q}p^xKmqQxW`?p+=m7IeyRKbx3vkf%r|!iP(4YeGjP!xaISRjdlOTTJFu zcxxEU*|TFodas$_$)&=XiH&js{!K}HCti+VU~q}wvfq8u=iNZpF?hQAxvXxVFl6%d?V zxk`&=+kvge^x7ve87;_};K^m6%jg#5aI=l&BTGan>y_7&6ubNzgZnFlcfU>1_~iZI zYxADRoH{$6Ua#+{j}43Yr1`;(W5e$mfv5W$t(*2dX6w;l{?_rSPj+ezi;WG-jaoMm z#$x_YeN&VkyfA#=AXxBGqTpFoz~MsyEFyBuT-(%rbxa(Xp=g17-DB$ma?YFf%;!j| zyu+bZxrf88a?b3inufju_r2S`&J|Zwc+Yu4mF0-+ec!j=&qtg}6}g^%=Y38cV+3WkZ$c%0*mYx`$8j9TaU56fk|gO$ep;6zA22OxEXBF>XDtFH$>8r-1_blf zJy0ABBygN+ku1Tf2FWrUvq+ZWm_xD{$IQn+fe6HLoCA}4uvp`EEL;S-TLb9UMWA7A zzW-bjkp5%cV*#9deXOf@sPhZbgS6}VvDSCeiQbv?aBI`_Pq6869LI4S_s6{hYDz literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index dc408393..13b03f9b 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -61,6 +61,20 @@ android:src="@drawable/ic_close" android:tint="@color/actionBarForeground" /> + + + + -- 2.45.2 From 7234c0e45e3a7d8fd1d800e253f1f7f0cc70e9b5 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Tue, 21 Jul 2020 19:02:14 +0100 Subject: [PATCH 02/12] notification model --- .../java/io/lbry/browser/data/DatabaseHelper.java | 8 ++++++++ .../io/lbry/browser/model/lbryinc/Notification.java | 12 ++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java diff --git a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java index 67dabb82..7788add2 100644 --- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java +++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java @@ -63,6 +63,14 @@ public class DatabaseHelper extends SQLiteOpenHelper { "ALTER TABLE view_history ADD COLUMN currency TEXT" }; + private static final String[] SQL_V2_V3_UPGRADE = { + "CREATE TABLE notifications (" + + " id INTEGER PRIMARY KEY NOT NULL" + + ", title TEXT" + + ", description TEXT" + + + }; + private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)"; private static final String SQL_CLEAR_SUBSCRIPTIONS = "DELETE FROM subscriptions"; private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?"; diff --git a/app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java b/app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java new file mode 100644 index 00000000..9946e44a --- /dev/null +++ b/app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java @@ -0,0 +1,12 @@ +package io.lbry.browser.model.lbryinc; + +import lombok.Data; + +@Data +public class Notification { + private long id; + private String title; + private String description; + private String thumbnailUrl; + private String targetUrl; +} -- 2.45.2 From 97c13a3619e5dba764013f3af40321ed13a60b86 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 22 Jul 2020 15:00:00 +0100 Subject: [PATCH 03/12] persist received notifications --- .../lbry/browser/LbrynetMessagingService.java | 26 +++++++- .../java/io/lbry/browser/MainActivity.java | 38 +++++++++++- .../io/lbry/browser/data/DatabaseHelper.java | 61 +++++++++++++++++-- ...otification.java => LbryNotification.java} | 5 +- app/src/main/res/layout/app_bar_main.xml | 1 + app/src/main/res/layout/content_main.xml | 38 ++++++++++++ app/src/main/res/values/strings.xml | 3 + 7 files changed, 161 insertions(+), 11 deletions(-) rename app/src/main/java/io/lbry/browser/model/lbryinc/{Notification.java => LbryNotification.java} (71%) diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java index 62536467..9acc3d3f 100644 --- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java +++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java @@ -1,31 +1,38 @@ package io.lbry.browser; +import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.database.sqlite.SQLiteDatabase; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; +import androidx.core.text.HtmlCompat; import androidx.preference.PreferenceManager; +import android.text.Html; import android.util.Log; import com.google.firebase.analytics.FirebaseAnalytics; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; +import io.lbry.browser.data.DatabaseHelper; +import io.lbry.browser.model.lbryinc.LbryNotification; import io.lbry.browser.utils.LbryAnalytics; import io.lbry.lbrysdk.LbrynetService; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.ArrayList; +import java.util.Date; import java.util.List; import java.util.Map; @@ -67,6 +74,21 @@ public class LbrynetMessagingService extends FirebaseMessagingService { sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime); } + + // persist the notification data + try { + DatabaseHelper helper = DatabaseHelper.getInstance(); + SQLiteDatabase db = helper.getWritableDatabase(); + LbryNotification lnotification = new LbryNotification(); + lnotification.setTitle(title); + lnotification.setDescription(body); + lnotification.setTargetUrl(url); + lnotification.setTimestamp(new Date()); + DatabaseHelper.createNotification(lnotification, db); + } catch (Exception ex) { + // don't fail if any error occurs while saving a notification + Log.e(TAG, "could not save notification", ex); + } } } @@ -120,8 +142,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService { new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) .setColor(ContextCompat.getColor(this, R.color.lbryGreen)) .setSmallIcon(R.drawable.ic_lbry) - .setContentTitle(title) - .setContentText(messageBody) + .setContentTitle(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY)) + .setContentText(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY)) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index a6abf1c7..15162fdc 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -438,6 +438,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener // setup uri bar setupUriBar(); + initNotificationsPage(); // other pendingSyncSetQueue = new ArrayList<>(); @@ -502,6 +503,18 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } }); + findViewById(R.id.wunderbar_notifications).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + View container = findViewById(R.id.notifications_container); + if (container.getVisibility() != View.VISIBLE) { + showNotifications(); + } else { + hideNotifications(); + } + } + }); + findViewById(R.id.global_now_playing_card).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -1059,7 +1072,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener View container = findViewById(R.id.url_suggestions_container); View closeIcon = findViewById(R.id.wunderbar_close); EditText wunderbar = findViewById(R.id.wunderbar); - wunderbar.setPadding(0, 0, visible ? getScaledValue(36) : 0, 0); + //wunderbar.setPadding(0, 0, visible ? getScaledValue(36) : 0, 0); container.setVisibility(visible ? View.VISIBLE : View.GONE); closeIcon.setVisibility(visible ? View.VISIBLE : View.GONE); @@ -1094,8 +1107,13 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener @Override public void onFocusChange(View view, boolean hasFocus) { if (hasFocus) { + hideNotifications(); + findViewById(R.id.wunderbar_notifications).setVisibility(View.INVISIBLE); + InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(view, 0); + } else { + findViewById(R.id.wunderbar_notifications).setVisibility(View.VISIBLE); } if (canShowUrlSuggestions()) { @@ -1629,6 +1647,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private static final String CHANNEL_ID_PLAYBACK = "io.lbry.browser.LBRY_PLAYBACK_CHANNEL"; private static final int PLAYBACK_NOTIFICATION_ID = 3; + public void initNotificationsPage() { + findViewById(R.id.notification_list_empty_container).setVisibility(View.VISIBLE); + } + public void initPlaybackNotification() { if (isBackgroundPlaybackEnabled()) { playerNotificationManager.setPlayer(MainActivity.appPlayer); @@ -2063,13 +2085,25 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener setBackgroundTint(Color.RED).setTextColor(Color.WHITE).show(); } + public void showNotifications() { + clearWunderbarFocus(findViewById(R.id.wunderbar)); + findViewById(R.id.notifications_container).setVisibility(View.VISIBLE); + } + + public void hideNotifications() { + findViewById(R.id.notifications_container).setVisibility(View.GONE); + } + @Override public void onBackPressed() { - if (findViewById(R.id.url_suggestions_container).getVisibility() == View.VISIBLE) { clearWunderbarFocus(findViewById(R.id.wunderbar)); return; } + if (findViewById(R.id.notifications_container).getVisibility() == View.VISIBLE) { + hideNotifications(); + return; + } if (backPressInterceptor != null && backPressInterceptor.onBackPressed()) { return; } diff --git a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java index 7788add2..88f243d0 100644 --- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java +++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java @@ -4,7 +4,6 @@ import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; -import android.opengl.Visibility; import java.math.BigDecimal; import java.text.ParseException; @@ -13,16 +12,16 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.model.Tag; import io.lbry.browser.model.UrlSuggestion; import io.lbry.browser.model.ViewHistory; +import io.lbry.browser.model.lbryinc.LbryNotification; import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.LbryUri; public class DatabaseHelper extends SQLiteOpenHelper { - public static final int DATABASE_VERSION = 2; + public static final int DATABASE_VERSION = 3; public static final String DATABASE_NAME = "LbryApp.db"; private static DatabaseHelper instance; @@ -48,7 +47,14 @@ public class DatabaseHelper extends SQLiteOpenHelper { ", thumbnail_url TEXT" + ", release_time INTEGER " + ", device TEXT" + - ", timestamp TEXT NOT NULL)" + ", timestamp TEXT NOT NULL)", + "CREATE TABLE notifications (" + + " id INTEGER PRIMARY KEY NOT NULL" + + ", title TEXT" + + ", description TEXT" + + ", thumbnail_url TEXT" + + ", target_url TEXT" + + ", timestamp TEXT NOT NULL)", }; private static final String[] SQL_CREATE_INDEXES = { "CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)", @@ -56,7 +62,8 @@ public class DatabaseHelper extends SQLiteOpenHelper { "CREATE UNIQUE INDEX idx_url_history_url ON url_history (url)", "CREATE UNIQUE INDEX idx_tag_name ON tags (name)", "CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)", - "CREATE INDEX idx_view_history_device ON view_history (device)" + "CREATE INDEX idx_view_history_device ON view_history (device)", + "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)" }; private static final String[] SQL_V1_V2_UPGRADE = { @@ -68,7 +75,10 @@ public class DatabaseHelper extends SQLiteOpenHelper { " id INTEGER PRIMARY KEY NOT NULL" + ", title TEXT" + ", description TEXT" + - + ", thumbnail_url TEXT" + + ", target_url TEXT" + + ", timestamp TEXT NOT NULL)", + "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)" }; private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)"; @@ -81,6 +91,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?"; private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10"; + private static final String SQL_INSERT_NOTIFICATION = "INSERT INTO notifications (title, description, target_url, timestamp) VALUES (?, ?, ?, ?)"; + private static final String SQL_GET_NOTIFICATIONS = "SELECT id, title, description, target_url, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500"; + private static final String SQL_INSERT_VIEW_HISTORY = "REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String SQL_GET_VIEW_HISTORY = @@ -119,6 +132,11 @@ public class DatabaseHelper extends SQLiteOpenHelper { db.execSQL(sql); } } + if (oldVersion < 3) { + for (String sql : SQL_V2_V3_UPGRADE) { + db.execSQL(sql); + } + } } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { @@ -259,4 +277,35 @@ public class DatabaseHelper extends SQLiteOpenHelper { return subscriptions; } + public static void createNotification(LbryNotification notification, SQLiteDatabase db) { + db.execSQL(SQL_INSERT_NOTIFICATION, new Object[] { + notification.getTitle(), + notification.getDescription(), + notification.getTargetUrl(), + new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(notification.getTimestamp() != null ? notification.getTimestamp() : new Date()) + }); + } + public static List getNotifications(SQLiteDatabase db) { + List notifications = new ArrayList<>(); + Cursor cursor = null; + try { + cursor = db.rawQuery(SQL_GET_NOTIFICATIONS, null); + while (cursor.moveToNext()) { + LbryNotification notification = new LbryNotification(); + notification.setId(cursor.getLong(0)); + notification.setTitle(cursor.getString(1)); + notification.setDescription(cursor.getString(2)); + notification.setTargetUrl(cursor.getString(3)); + try { + notification.setTimestamp(new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).parse(cursor.getString(4))); + } catch (ParseException ex) { + // invalid timestamp (which shouldn't happen). Skip this item + continue; + } + } + } finally { + Helper.closeCursor(cursor); + } + return notifications; + } } diff --git a/app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java similarity index 71% rename from app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java rename to app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java index 9946e44a..9e5be8a7 100644 --- a/app/src/main/java/io/lbry/browser/model/lbryinc/Notification.java +++ b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java @@ -1,12 +1,15 @@ package io.lbry.browser.model.lbryinc; +import java.util.Date; + import lombok.Data; @Data -public class Notification { +public class LbryNotification { private long id; private String title; private String description; private String thumbnailUrl; private String targetUrl; + private Date timestamp; } diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index 13b03f9b..f1680941 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -42,6 +42,7 @@ android:hint="@string/uri_placeholder" android:imeOptions="actionGo" android:inputType="textNoSuggestions" + android:paddingRight="36dp" android:selectAllOnFocus="true" android:singleLine="true" android:textFontWeight="300" diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 9fd48cf6..aebb1020 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -33,6 +33,44 @@ android:layout_height="match_parent" /> + + + + + + + + The lbrynet.log file could not be found. The lbrynet.log file cannot be shared due to permission restrictions. + + It\'s quiet here! New notifications will be displayed when you receive them. + -- 2.45.2 From feb7f260dcf5d979c37f2cc17edfac61de778930 Mon Sep 17 00:00:00 2001 From: Javi Rueda Date: Thu, 23 Jul 2020 05:36:15 +0200 Subject: [PATCH 04/12] Allow to publish files via Send To feature --- app/src/main/AndroidManifest.xml | 7 +++++++ .../java/io/lbry/browser/MainActivity.java | 21 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 7ac0cf49..f7d535e9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -50,6 +50,13 @@ + + + + + + + diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 961a5090..4368970a 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -8,6 +8,7 @@ import android.app.NotificationManager; import android.app.PendingIntent; import android.app.PictureInPictureParams; import android.content.BroadcastReceiver; +import android.content.ClipData; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -579,6 +580,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener protected void onNewIntent(Intent intent) { super.onNewIntent(intent); + checkSendToIntent(intent); checkUrlIntent(intent); checkNotificationOpenIntent(intent); } @@ -833,6 +835,12 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener openFragment(FileViewFragment.class, true, NavMenuItem.ID_ITEM_FOLLOWING, params); } + public void openSendTo(String path) { + Map params = new HashMap<>(); + params.put("directFilePath", path); + openFragment(PublishFormFragment.class, true, NavMenuItem.ID_ITEM_NEW_PUBLISH, params); + } + public void openFileClaim(Claim claim) { Map params = new HashMap<>(); params.put("claimId", claim.getClaimId()); @@ -2644,6 +2652,19 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener LbryAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_OPEN, bundle); } + private void checkSendToIntent(Intent intent) { + String intentAction = intent.getAction(); + if (intentAction != null && intentAction.equals("android.intent.action.SEND")) { + ClipData clipData = intent.getClipData(); + if (clipData != null) { + Uri uri = clipData.getItemAt(0).getUri(); + + String path = Helper.getRealPathFromURI_API19(this, uri); + openSendTo(path); + } + } + } + private void registerServiceActionsReceiver() { IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(DownloadManager.ACTION_DOWNLOAD_EVENT); -- 2.45.2 From 185526eb299ee7ea3cd9a39ca0791f45cf18bbd5 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 24 Jul 2020 06:17:53 +0100 Subject: [PATCH 05/12] Refresh notification list. Add is_read flag and display unread count. --- .../lbry/browser/LbrynetMessagingService.java | 22 ++-- .../java/io/lbry/browser/MainActivity.java | 122 +++++++++++++++++- .../adapter/NotificationListAdapter.java | 103 +++++++++++++++ .../io/lbry/browser/data/DatabaseHelper.java | 21 +++ .../model/lbryinc/LbryNotification.java | 1 + .../res/drawable/bg_notification_badge.xml | 6 + app/src/main/res/layout/app_bar_main.xml | 33 ++++- app/src/main/res/layout/content_main.xml | 6 + .../res/layout/list_item_notification.xml | 30 +++++ 9 files changed, 328 insertions(+), 16 deletions(-) create mode 100644 app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java create mode 100644 app/src/main/res/drawable/bg_notification_badge.xml create mode 100644 app/src/main/res/layout/list_item_notification.xml diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java index 9acc3d3f..af9dd988 100644 --- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java +++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java @@ -37,6 +37,7 @@ import java.util.List; import java.util.Map; public class LbrynetMessagingService extends FirebaseMessagingService { + public static final String ACTION_NOTIFICATION_RECEIVED = "io.lbry.browser.Broadcast.NotificationReceived"; private static final String TAG = "LbrynetMessagingService"; private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL"; @@ -59,10 +60,6 @@ public class LbrynetMessagingService extends FirebaseMessagingService { String title = payload.get("title"); String body = payload.get("body"); String name = payload.get("name"); // notification name - String contentTitle = payload.get("content_title"); - String channelUrl = payload.get("channel_url"); - //String publishTime = payload.get("publish_time"); - String publishTime = null; if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) { // only log the receive event for valid notifications received @@ -72,7 +69,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService { firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle); } - sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime); + sendNotification(title, body, type, url, name); } // persist the notification data @@ -85,6 +82,14 @@ public class LbrynetMessagingService extends FirebaseMessagingService { lnotification.setTargetUrl(url); lnotification.setTimestamp(new Date()); DatabaseHelper.createNotification(lnotification, db); + + // send a broadcast + Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED); + intent.putExtra("title", title); + intent.putExtra("body", body); + intent.putExtra("url", url); + intent.putExtra("timestamp", lnotification.getTimestamp().getTime()); + sendBroadcast(intent); } catch (Exception ex) { // don't fail if any error occurs while saving a notification Log.e(TAG, "could not save notification", ex); @@ -119,8 +124,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService { * * @param messageBody FCM message body received. */ - private void sendNotification(String title, String messageBody, String type, String url, String name, - String contentTitle, String channelUrl, String publishTime) { + private void sendNotification(String title, String messageBody, String type, String url, String name) { //Intent intent = new Intent(this, MainActivity.class); //intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); if (url == null) { @@ -142,8 +146,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService { new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID) .setColor(ContextCompat.getColor(this, R.color.lbryGreen)) .setSmallIcon(R.drawable.ic_lbry) - .setContentTitle(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY)) - .setContentText(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY)) + .setContentTitle(title) + .setContentText(messageBody) .setAutoCancel(true) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 9f2e82bd..9884fce3 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -114,6 +114,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import io.lbry.browser.adapter.NavigationMenuAdapter; +import io.lbry.browser.adapter.NotificationListAdapter; import io.lbry.browser.adapter.UrlSuggestionListAdapter; import io.lbry.browser.data.DatabaseHelper; import io.lbry.browser.dialog.ContentScopeDialogFragment; @@ -136,6 +137,7 @@ import io.lbry.browser.model.Tag; import io.lbry.browser.model.UrlSuggestion; import io.lbry.browser.model.WalletBalance; import io.lbry.browser.model.WalletSync; +import io.lbry.browser.model.lbryinc.LbryNotification; import io.lbry.browser.model.lbryinc.Reward; import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.tasks.GenericTaskHandler; @@ -223,6 +225,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener @Getter private String firebaseMessagingToken; + private NotificationListAdapter notificationListAdapter; + private Map openNavFragments; private static final Map fragmentClassNavIdMap = new HashMap<>(); static { @@ -439,6 +443,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener // setup uri bar setupUriBar(); initNotificationsPage(); + loadUnreadNotificationsCount(); // other pendingSyncSetQueue = new ArrayList<>(); @@ -519,6 +524,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener @Override public void onClick(View view) { if (nowPlayingClaim != null && !Helper.isNullOrEmpty(nowPlayingClaimUrl)) { + hideNotifications(); openFileUrl(nowPlayingClaimUrl); } } @@ -728,8 +734,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } private void openSelectedMenuItem() { + hideNotifications(); + switch (selectedMenuItemId) { - // TODO: reverse map lookup for class? case NavMenuItem.ID_ITEM_FOLLOWING: openFragment(FollowingFragment.class, true, NavMenuItem.ID_ITEM_FOLLOWING); break; @@ -1648,6 +1655,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public void initNotificationsPage() { findViewById(R.id.notification_list_empty_container).setVisibility(View.VISIBLE); + + RecyclerView notificationsList = findViewById(R.id.notifications_list); + LinearLayoutManager llm = new LinearLayoutManager(this); + notificationsList.setLayoutManager(llm); } public void initPlaybackNotification() { @@ -2020,6 +2031,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener intentFilter.addAction(ACTION_OPEN_REWARDS_PAGE); intentFilter.addAction(ACTION_PUBLISH_SUCCESSFUL); intentFilter.addAction(ACTION_SAVE_SHARED_USER_STATE); + intentFilter.addAction(LbrynetMessagingService.ACTION_NOTIFICATION_RECEIVED); requestsReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -2040,6 +2052,25 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener saveSharedUserState(); } else if (ACTION_PUBLISH_SUCCESSFUL.equalsIgnoreCase(action)) { openPublishesOnSuccessfulPublish(); + } else if (LbrynetMessagingService.ACTION_NOTIFICATION_RECEIVED.equalsIgnoreCase(action)) { + handleNotificationReceived(intent); + } + } + + private void handleNotificationReceived(Intent intent) { + loadUnreadNotificationsCount(); + + if (notificationListAdapter != null) { + LbryNotification lnotification = new LbryNotification(); + lnotification.setTitle(intent.getStringExtra("title")); + lnotification.setDescription(intent.getStringExtra("body")); + lnotification.setTargetUrl(intent.getStringExtra("url")); + lnotification.setTimestamp(new Date(intent.getLongExtra("timestamp", System.currentTimeMillis()))); + // show at the top + notificationListAdapter.insertNotification(lnotification, 0); + findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE); + } else { + loadNotifications(); } } @@ -2088,12 +2119,35 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public void showNotifications() { clearWunderbarFocus(findViewById(R.id.wunderbar)); findViewById(R.id.notifications_container).setVisibility(View.VISIBLE); + ((ImageView) findViewById(R.id.notifications_toggle_icon)).setColorFilter(ContextCompat.getColor(this, R.color.lbryGreen)); + if (notificationListAdapter == null) { + loadNotifications(); + } + markNotificationsRead(); } public void hideNotifications() { + ((ImageView) findViewById(R.id.notifications_toggle_icon)).setColorFilter(ContextCompat.getColor(this, R.color.actionBarForeground)); findViewById(R.id.notifications_container).setVisibility(View.GONE); } + private void markNotificationsRead() { + (new AsyncTask() { + protected Void doInBackground(Void... params) { + try { + SQLiteDatabase db = dbHelper.getWritableDatabase(); + DatabaseHelper.markNotificationsRead(db); + } catch (Exception ex) { + // pass + } + return null; + } + protected void onPostExecute(Void result) { + loadUnreadNotificationsCount(); + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + @Override public void onBackPressed() { if (findViewById(R.id.url_suggestions_container).getVisibility() == View.VISIBLE) { @@ -3064,6 +3118,72 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } + private void displayUnreadNotificationCount(int count) { + String text = count > 99 ? "99+" : String.valueOf(count); + + TextView badge = findViewById(R.id.notifications_badge_count); + badge.setVisibility(count > 0 ? View.VISIBLE : View.INVISIBLE); + badge.setText(text); + } + + private void loadUnreadNotificationsCount() { + (new AsyncTask() { + @Override + protected Integer doInBackground(Void... params) { + try { + SQLiteDatabase db = dbHelper.getReadableDatabase(); + return DatabaseHelper.getUnreadNotificationsCount(db); + } catch (Exception ex) { + return 0; + } + } + protected void onPostExecute(Integer count) { + displayUnreadNotificationCount(count); + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + private void loadNotifications() { + (new AsyncTask>() { + protected void onPreExecute() { + findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE); + findViewById(R.id.notifications_progress).setVisibility(View.VISIBLE); + } + @Override + protected List doInBackground(Void... params) { + List notifications = new ArrayList<>(); + try { + SQLiteDatabase db = dbHelper.getReadableDatabase(); + notifications = DatabaseHelper.getNotifications(db); + } catch (Exception ex) { + // pass + } + return notifications; + } + protected void onPostExecute(List notifications) { + findViewById(R.id.notification_list_empty_container).setVisibility(notifications.size() == 0 ? View.VISIBLE : View.GONE); + findViewById(R.id.notifications_progress).setVisibility(View.GONE); + notificationListAdapter = new NotificationListAdapter(notifications, MainActivity.this); + notificationListAdapter.setClickListener(new NotificationListAdapter.NotificationClickListener() { + @Override + public void onNotificationClicked(LbryNotification notification) { + LbryUri target = LbryUri.tryParse(notification.getTargetUrl()); + if (target != null) { + hideNotifications(); + if (target.isChannel()) { + openChannelUrl(target.toString()); + } else { + openFileUrl(target.toString()); + } + } + } + }); + + ((RecyclerView) findViewById(R.id.notifications_list)).setAdapter(notificationListAdapter); + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + private void checkSyncedWallet() { String password = Utils.getSecureValue(SECURE_VALUE_KEY_SAVED_PASSWORD, this, Lbry.KEYSTORE); // Just check if the current user has a synced wallet, no need to do anything else here diff --git a/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java new file mode 100644 index 00000000..958fd16f --- /dev/null +++ b/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java @@ -0,0 +1,103 @@ +package io.lbry.browser.adapter; + +import android.content.Context; +import android.text.format.DateUtils; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; + +import io.lbry.browser.R; +import io.lbry.browser.model.lbryinc.LbryNotification; +import io.lbry.browser.utils.Helper; +import lombok.Getter; +import lombok.Setter; + +public class NotificationListAdapter extends RecyclerView.Adapter { + + private Context context; + private List items; + @Setter + private NotificationClickListener clickListener; + @Getter + @Setter + private int customizeMode; + + public NotificationListAdapter(List notifications, Context context) { + this.context = context; + this.items = new ArrayList<>(notifications); + } + + public static class ViewHolder extends RecyclerView.ViewHolder { + protected TextView titleView; + protected TextView bodyView; + protected TextView timeView; + public ViewHolder(View v) { + super(v); + titleView = v.findViewById(R.id.notification_title); + bodyView = v.findViewById(R.id.notification_body); + timeView = v.findViewById(R.id.notification_time); + } + } + + public int getItemCount() { + return items != null ? items.size() : 0; + } + + public void insertNotification(LbryNotification notification, int index) { + if (!items.contains(notification)) { + items.add(index, notification); + } + notifyDataSetChanged(); + } + + public void addNotification(LbryNotification notification) { + if (!items.contains(notification)) { + items.add(notification); + } + notifyDataSetChanged(); + } + + public void addTags(List notifications) { + for (LbryNotification notification : notifications) { + if (!items.contains(notification)) { + items.add(notification); + } + } + notifyDataSetChanged(); + } + @Override + public NotificationListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) { + View v = LayoutInflater.from(context).inflate(R.layout.list_item_notification, root, false); + return new NotificationListAdapter.ViewHolder(v); + } + + @Override + public void onBindViewHolder(NotificationListAdapter.ViewHolder vh, int position) { + LbryNotification notification = items.get(position); + vh.titleView.setText(notification.getTitle()); + vh.titleView.setVisibility(!Helper.isNullOrEmpty(notification.getTitle()) ? View.VISIBLE : View.GONE); + vh.bodyView.setText(notification.getDescription()); + vh.timeView.setText(DateUtils.getRelativeTimeSpanString( + notification.getTimestamp().getTime(), + System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE)); + + vh.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (clickListener != null) { + clickListener.onNotificationClicked(notification); + } + } + }); + } + + public interface NotificationClickListener { + void onNotificationClicked(LbryNotification notification); + } +} \ No newline at end of file diff --git a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java index 88f243d0..c3599e40 100644 --- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java +++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java @@ -54,6 +54,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { ", description TEXT" + ", thumbnail_url TEXT" + ", target_url TEXT" + + ", is_read INTEGER DEFAULT 0 NOT NULL" + ", timestamp TEXT NOT NULL)", }; private static final String[] SQL_CREATE_INDEXES = { @@ -77,6 +78,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { ", description TEXT" + ", thumbnail_url TEXT" + ", target_url TEXT" + + ", is_read INTEGER DEFAULT 0 NOT NULL" + ", timestamp TEXT NOT NULL)", "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)" }; @@ -93,6 +95,8 @@ public class DatabaseHelper extends SQLiteOpenHelper { private static final String SQL_INSERT_NOTIFICATION = "INSERT INTO notifications (title, description, target_url, timestamp) VALUES (?, ?, ?, ?)"; private static final String SQL_GET_NOTIFICATIONS = "SELECT id, title, description, target_url, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500"; + private static final String SQL_GET_UNREAD_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_read <> 1"; + private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0"; private static final String SQL_INSERT_VIEW_HISTORY = "REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; @@ -302,10 +306,27 @@ public class DatabaseHelper extends SQLiteOpenHelper { // invalid timestamp (which shouldn't happen). Skip this item continue; } + notifications.add(notification); } } finally { Helper.closeCursor(cursor); } return notifications; } + public static int getUnreadNotificationsCount(SQLiteDatabase db) { + int count = 0; + Cursor cursor = null; + try { + cursor = db.rawQuery(SQL_GET_UNREAD_NOTIFICATIONS_COUNT, null); + if (cursor.moveToNext()) { + count = cursor.getInt(0); + } + } finally { + Helper.closeCursor(cursor); + } + return count; + } + public static void markNotificationsRead(SQLiteDatabase db) { + db.execSQL(SQL_MARK_NOTIFICATIONS_READ); + } } diff --git a/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java index 9e5be8a7..87e8791c 100644 --- a/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java +++ b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java @@ -11,5 +11,6 @@ public class LbryNotification { private String description; private String thumbnailUrl; private String targetUrl; + private boolean read; private Date timestamp; } diff --git a/app/src/main/res/drawable/bg_notification_badge.xml b/app/src/main/res/drawable/bg_notification_badge.xml new file mode 100644 index 00000000..3af51c12 --- /dev/null +++ b/app/src/main/res/drawable/bg_notification_badge.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml index f1680941..6777cd17 100644 --- a/app/src/main/res/layout/app_bar_main.xml +++ b/app/src/main/res/layout/app_bar_main.xml @@ -28,17 +28,18 @@ android:focusable="true" android:focusableInTouchMode="true" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_marginRight="24dp"> + android:layout_height="wrap_content"> @@ -63,19 +65,38 @@ android:tint="@color/actionBarForeground" /> - - + + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index aebb1020..3e729743 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -41,6 +41,12 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="gone"> + + + + + + \ No newline at end of file -- 2.45.2 From 5ed0b5c3153ba0ef3dfeebc8c16ce292426b0b3b Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Fri, 24 Jul 2020 06:20:35 +0100 Subject: [PATCH 06/12] Hide notifications when opening the navigatinon drawer. Open selected notification item before hiding the list. --- app/src/main/java/io/lbry/browser/MainActivity.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 9884fce3..3016707a 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -480,6 +480,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public void onDrawerSlide(View drawerView, float slideOffset) { if (slideOffset != 0) { clearWunderbarFocus(findViewById(R.id.wunderbar)); + hideNotifications(); } super.onDrawerSlide(drawerView, slideOffset); } @@ -3169,12 +3170,12 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public void onNotificationClicked(LbryNotification notification) { LbryUri target = LbryUri.tryParse(notification.getTargetUrl()); if (target != null) { - hideNotifications(); if (target.isChannel()) { openChannelUrl(target.toString()); } else { openFileUrl(target.toString()); } + hideNotifications(); } } }); -- 2.45.2 From e78f54077f3463a9c08357df866edb7d4d54cbc5 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 29 Jul 2020 15:11:24 +0100 Subject: [PATCH 07/12] update local store with remote notifications --- .../lbry/browser/LbrynetMessagingService.java | 8 +- .../java/io/lbry/browser/MainActivity.java | 26 +++- .../io/lbry/browser/data/DatabaseHelper.java | 20 +++- .../model/lbryinc/LbryNotification.java | 1 + .../tasks/lbryinc/ListNotificationsTask.java | 113 ++++++++++++++++++ .../java/io/lbry/browser/utils/Helper.java | 1 + 6 files changed, 156 insertions(+), 13 deletions(-) create mode 100644 app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java index af9dd988..a5efd40a 100644 --- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java +++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java @@ -1,6 +1,5 @@ package io.lbry.browser; -import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; @@ -14,10 +13,8 @@ import android.os.Build; import android.os.Bundle; import androidx.core.app.NotificationCompat; import androidx.core.content.ContextCompat; -import androidx.core.text.HtmlCompat; import androidx.preference.PreferenceManager; -import android.text.Html; import android.util.Log; import com.google.firebase.analytics.FirebaseAnalytics; @@ -27,10 +24,7 @@ import com.google.firebase.messaging.RemoteMessage; import io.lbry.browser.data.DatabaseHelper; import io.lbry.browser.model.lbryinc.LbryNotification; import io.lbry.browser.utils.LbryAnalytics; -import io.lbry.lbrysdk.LbrynetService; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -81,7 +75,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService { lnotification.setDescription(body); lnotification.setTargetUrl(url); lnotification.setTimestamp(new Date()); - DatabaseHelper.createNotification(lnotification, db); + DatabaseHelper.createOrUpdateNotification(lnotification, db); // send a broadcast Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED); diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 3016707a..75a689d2 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -148,6 +148,7 @@ import io.lbry.browser.tasks.lbryinc.FetchRewardsTask; import io.lbry.browser.tasks.LighthouseAutoCompleteTask; import io.lbry.browser.tasks.MergeSubscriptionsTask; import io.lbry.browser.tasks.claim.ResolveTask; +import io.lbry.browser.tasks.lbryinc.ListNotificationsTask; import io.lbry.browser.tasks.localdata.FetchRecentUrlHistoryTask; import io.lbry.browser.tasks.wallet.DefaultSyncTaskHandler; import io.lbry.browser.tasks.wallet.LoadSharedUserStateTask; @@ -1562,6 +1563,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener try { Lbryio.AUTH_TOKEN = new String(Utils.decrypt( Base64.decode(encryptedAuthToken, Base64.NO_WRAP), this, Lbry.KEYSTORE), "UTF8"); + Log.d(TAG, Lbryio.AUTH_TOKEN); } catch (Exception ex) { // pass. A new auth token would have to be generated if the old one cannot be decrypted Log.e(TAG, "Could not decrypt existing auth token.", ex); @@ -2071,7 +2073,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener notificationListAdapter.insertNotification(lnotification, 0); findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE); } else { - loadNotifications(); + loadRemoteNotifications(); } } @@ -2122,7 +2124,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener findViewById(R.id.notifications_container).setVisibility(View.VISIBLE); ((ImageView) findViewById(R.id.notifications_toggle_icon)).setColorFilter(ContextCompat.getColor(this, R.color.lbryGreen)); if (notificationListAdapter == null) { - loadNotifications(); + loadRemoteNotifications(); } markNotificationsRead(); } @@ -3144,7 +3146,25 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - private void loadNotifications() { + private void loadRemoteNotifications() { + findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE); + ListNotificationsTask task = new ListNotificationsTask(this, findViewById(R.id.notifications_progress), new ListNotificationsTask.ListNotificationsHandler() { + @Override + public void onSuccess(List notifications) { + loadLocalNotifications(); + } + + @Override + public void onError(Exception exception) { + // pass + Log.e(TAG, "error loading remote notifications", exception); + loadLocalNotifications(); + } + }); + task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + + private void loadLocalNotifications() { (new AsyncTask>() { protected void onPreExecute() { findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE); diff --git a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java index c3599e40..c0ee9527 100644 --- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java +++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java @@ -21,7 +21,7 @@ import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.LbryUri; public class DatabaseHelper extends SQLiteOpenHelper { - public static final int DATABASE_VERSION = 3; + public static final int DATABASE_VERSION = 4; public static final String DATABASE_NAME = "LbryApp.db"; private static DatabaseHelper instance; @@ -50,6 +50,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { ", timestamp TEXT NOT NULL)", "CREATE TABLE notifications (" + " id INTEGER PRIMARY KEY NOT NULL" + + ", remote_id INTEGER NOT NULL" + ", title TEXT" + ", description TEXT" + ", thumbnail_url TEXT" + @@ -64,6 +65,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { "CREATE UNIQUE INDEX idx_tag_name ON tags (name)", "CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)", "CREATE INDEX idx_view_history_device ON view_history (device)", + "CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)", "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)" }; @@ -83,6 +85,11 @@ public class DatabaseHelper extends SQLiteOpenHelper { "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)" }; + private static final String[] SQL_V3_V4_UPGRADE = { + "ALTER TABLE notifications ADD COLUMN remote_id INTEGER", + "CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)", + }; + private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)"; private static final String SQL_CLEAR_SUBSCRIPTIONS = "DELETE FROM subscriptions"; private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?"; @@ -93,7 +100,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { private static final String SQL_CLEAR_URL_HISTORY_BEFORE_TIME = "DELETE FROM url_history WHERE timestamp < ?"; private static final String SQL_GET_RECENT_URL_HISTORY = "SELECT value, url, type FROM url_history ORDER BY timestamp DESC LIMIT 10"; - private static final String SQL_INSERT_NOTIFICATION = "INSERT INTO notifications (title, description, target_url, timestamp) VALUES (?, ?, ?, ?)"; + private static final String SQL_INSERT_NOTIFICATION = "REPLACE INTO notifications (remote_id, title, description, target_url, is_read, timestamp) VALUES (?, ?, ?, ?, ?, ?)"; private static final String SQL_GET_NOTIFICATIONS = "SELECT id, title, description, target_url, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500"; private static final String SQL_GET_UNREAD_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_read <> 1"; private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0"; @@ -141,6 +148,11 @@ public class DatabaseHelper extends SQLiteOpenHelper { db.execSQL(sql); } } + if (oldVersion < 4) { + for (String sql : SQL_V3_V4_UPGRADE) { + db.execSQL(sql); + } + } } public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { @@ -281,11 +293,13 @@ public class DatabaseHelper extends SQLiteOpenHelper { return subscriptions; } - public static void createNotification(LbryNotification notification, SQLiteDatabase db) { + public static void createOrUpdateNotification(LbryNotification notification, SQLiteDatabase db) { db.execSQL(SQL_INSERT_NOTIFICATION, new Object[] { + notification.getRemoteId(), notification.getTitle(), notification.getDescription(), notification.getTargetUrl(), + notification.isRead() ? 1 : 0, new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(notification.getTimestamp() != null ? notification.getTimestamp() : new Date()) }); } diff --git a/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java index 87e8791c..9736f284 100644 --- a/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java +++ b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java @@ -7,6 +7,7 @@ import lombok.Data; @Data public class LbryNotification { private long id; + private long remoteId; private String title; private String description; private String thumbnailUrl; diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java new file mode 100644 index 00000000..317ee033 --- /dev/null +++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java @@ -0,0 +1,113 @@ +package io.lbry.browser.tasks.lbryinc; + +import android.content.Context; +import android.database.sqlite.SQLiteDatabase; +import android.os.AsyncTask; +import android.view.View; +import android.widget.ProgressBar; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Locale; + +import io.lbry.browser.MainActivity; +import io.lbry.browser.data.DatabaseHelper; +import io.lbry.browser.exceptions.LbryioRequestException; +import io.lbry.browser.exceptions.LbryioResponseException; +import io.lbry.browser.model.lbryinc.LbryNotification; +import io.lbry.browser.utils.Helper; +import io.lbry.browser.utils.Lbryio; + +public class ListNotificationsTask extends AsyncTask> { + private Context context; + private ListNotificationsHandler handler; + private ProgressBar progressBar; + private Exception error; + + public ListNotificationsTask(Context context, ProgressBar progressBar, ListNotificationsHandler handler) { + this.context = context; + this.progressBar = progressBar; + this.handler = handler; + } + protected void onPreExecute() { + Helper.setViewVisibility(progressBar, View.VISIBLE); + } + protected List doInBackground(Void... params) { + List notifications = new ArrayList<>(); + SQLiteDatabase db = null; + try { + JSONArray array = (JSONArray) Lbryio.parseResponse(Lbryio.call("notification", "list", context)); + if (array != null) { + for (int i = 0; i < array.length(); i++) { + JSONObject item = array.getJSONObject(i); + if (item.has("notification_parameters")) { + LbryNotification notification = new LbryNotification(); + + JSONObject notificationParams = item.getJSONObject("notification_parameters"); + if (notificationParams.has("device")) { + JSONObject device = notificationParams.getJSONObject("device"); + notification.setTitle(Helper.getJSONString("title", null, device)); + notification.setDescription(Helper.getJSONString("text", null, device)); + notification.setTargetUrl(Helper.getJSONString("target", null, device)); + } + if (notificationParams.has("dynamic")) { + JSONObject dynamic = notificationParams.getJSONObject("dynamic"); + String channelUrl = Helper.getJSONString("channelURI", null, dynamic); + if (!Helper.isNullOrEmpty(channelUrl)) { + notification.setTargetUrl(channelUrl); + } + } + + notification.setRemoteId(Helper.getJSONLong("id", 0, item)); + notification.setRead(Helper.getJSONBoolean("is_read", false, item)); + + try { + SimpleDateFormat dateFormat = new SimpleDateFormat(Helper.ISO_DATE_FORMAT_JSON, Locale.US); + notification.setTimestamp(dateFormat.parse(Helper.getJSONString("created_at", dateFormat.format(new Date()), item))); + } catch (ParseException ex) { + notification.setTimestamp(new Date()); + } + + if (notification.getRemoteId() > 0 && !Helper.isNullOrEmpty(notification.getDescription())) { + notifications.add(notification); + } + } + } + + if (context instanceof MainActivity) { + db = ((MainActivity) context).getDbHelper().getWritableDatabase(); + for (LbryNotification notification : notifications) { + DatabaseHelper.createOrUpdateNotification(notification, db); + } + } + } + } catch (ClassCastException | LbryioRequestException | LbryioResponseException | JSONException | IllegalStateException ex) { + error = ex; + return null; + } + + return notifications; + } + protected void onPostExecute(List notifications) { + Helper.setViewVisibility(progressBar, View.GONE); + if (handler != null) { + if (notifications != null) { + handler.onSuccess(notifications); + } else { + handler.onError(error); + } + } + } + + public interface ListNotificationsHandler { + void onSuccess(List notifications); + void onError(Exception exception); + } +} diff --git a/app/src/main/java/io/lbry/browser/utils/Helper.java b/app/src/main/java/io/lbry/browser/utils/Helper.java index eac70533..5114e840 100644 --- a/app/src/main/java/io/lbry/browser/utils/Helper.java +++ b/app/src/main/java/io/lbry/browser/utils/Helper.java @@ -70,6 +70,7 @@ public final class Helper { public static final String METHOD_GET = "GET"; public static final String METHOD_POST = "POST"; public static final String ISO_DATE_FORMAT_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSS"; + public static final String ISO_DATE_FORMAT_JSON = "yyyy-MM-dd'T'HH:mm:ss'Z'"; public static final String SDK_AMOUNT_FORMAT = "0.0#######"; public static final MediaType FORM_MEDIA_TYPE = MediaType.parse("application/x-www-form-urlencoded"); public static final MediaType JSON_MEDIA_TYPE = MediaType.get("application/json; charset=utf-8"); -- 2.45.2 From b335e47cfa162294461857f27824d6751dc297d9 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Wed, 29 Jul 2020 15:30:59 +0100 Subject: [PATCH 08/12] use card view for notification items --- .../java/io/lbry/browser/MainActivity.java | 1 - app/src/main/res/layout/content_main.xml | 5 +- .../res/layout/list_item_notification.xml | 60 +++++++++++-------- 3 files changed, 38 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 75a689d2..06179a01 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -1563,7 +1563,6 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener try { Lbryio.AUTH_TOKEN = new String(Utils.decrypt( Base64.decode(encryptedAuthToken, Base64.NO_WRAP), this, Lbry.KEYSTORE), "UTF8"); - Log.d(TAG, Lbryio.AUTH_TOKEN); } catch (Exception ex) { // pass. A new auth token would have to be generated if the old one cannot be decrypted Log.e(TAG, "Could not decrypt existing auth token.", ex); diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index 3e729743..e4315423 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -74,7 +74,10 @@ + android:layout_height="match_parent" + android:paddingTop="8dp" + android:clipToPadding="false" + /> diff --git a/app/src/main/res/layout/list_item_notification.xml b/app/src/main/res/layout/list_item_notification.xml index 7f7df9ca..ed2834cd 100644 --- a/app/src/main/res/layout/list_item_notification.xml +++ b/app/src/main/res/layout/list_item_notification.xml @@ -1,30 +1,38 @@ - - + - - - \ No newline at end of file + android:padding="16dp"> + + + + + \ No newline at end of file -- 2.45.2 From f0c625c2cb3dcf765c0c0cec75d8e1b6f9691f50 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sat, 1 Aug 2020 08:35:21 +0100 Subject: [PATCH 09/12] make notification cards clickable --- app/src/main/res/layout/list_item_notification.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/list_item_notification.xml b/app/src/main/res/layout/list_item_notification.xml index ed2834cd..488e1d15 100644 --- a/app/src/main/res/layout/list_item_notification.xml +++ b/app/src/main/res/layout/list_item_notification.xml @@ -1,6 +1,8 @@ -- 2.45.2 From 96808d1f295e2df34bae0f6633e53771734a1020 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Sun, 9 Aug 2020 11:12:49 +0100 Subject: [PATCH 10/12] handle comment hash --- app/build.gradle | 8 +-- .../lbry/browser/LbrynetMessagingService.java | 2 + .../java/io/lbry/browser/MainActivity.java | 8 +-- .../browser/adapter/CommentListAdapter.java | 10 ++++ .../lbry/browser/tasks/CommentListTask.java | 4 +- ...onsTask.java => NotificationListTask.java} | 15 ++++-- .../ui/findcontent/FileViewFragment.java | 51 +++++++++++++------ .../main/res/layout/fragment_file_view.xml | 13 ----- 8 files changed, 68 insertions(+), 43 deletions(-) rename app/src/main/java/io/lbry/browser/tasks/lbryinc/{ListNotificationsTask.java => NotificationListTask.java} (83%) diff --git a/app/build.gradle b/app/build.gradle index 99ed5f8e..3b8e12de 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -16,8 +16,8 @@ android { applicationId "io.lbry.browser" minSdkVersion 21 targetSdkVersion 29 - versionCode 1516 - versionName "0.15.16" + versionCode 1517 + versionName "0.15.17" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -101,8 +101,8 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' - __32bitImplementation 'io.lbry:lbrysdk32:0.79.1' - __64bitImplementation 'io.lbry:lbrysdk64:0.79.1' + __32bitImplementation 'io.lbry:lbrysdk32:0.80.0' + __64bitImplementation 'io.lbry:lbrysdk64:0.80.0' } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java index a5efd40a..33cf1c6c 100644 --- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java +++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java @@ -121,6 +121,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService { private void sendNotification(String title, String messageBody, String type, String url, String name) { //Intent intent = new Intent(this, MainActivity.class); //intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + android.util.Log.d("#HELP", "Title=" + title + "; Body=" + messageBody + "; Type=" + type +"; url=" + url + "; name=" + name); + if (url == null) { if (TYPE_REWARD.equals(type)) { url = "lbry://?rewards"; diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 06179a01..1a5919e7 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -148,7 +148,7 @@ import io.lbry.browser.tasks.lbryinc.FetchRewardsTask; import io.lbry.browser.tasks.LighthouseAutoCompleteTask; import io.lbry.browser.tasks.MergeSubscriptionsTask; import io.lbry.browser.tasks.claim.ResolveTask; -import io.lbry.browser.tasks.lbryinc.ListNotificationsTask; +import io.lbry.browser.tasks.lbryinc.NotificationListTask; import io.lbry.browser.tasks.localdata.FetchRecentUrlHistoryTask; import io.lbry.browser.tasks.wallet.DefaultSyncTaskHandler; import io.lbry.browser.tasks.wallet.LoadSharedUserStateTask; @@ -3147,7 +3147,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private void loadRemoteNotifications() { findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE); - ListNotificationsTask task = new ListNotificationsTask(this, findViewById(R.id.notifications_progress), new ListNotificationsTask.ListNotificationsHandler() { + NotificationListTask task = new NotificationListTask(this, findViewById(R.id.notifications_progress), new NotificationListTask.ListNotificationsHandler() { @Override public void onSuccess(List notifications) { loadLocalNotifications(); @@ -3190,9 +3190,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener LbryUri target = LbryUri.tryParse(notification.getTargetUrl()); if (target != null) { if (target.isChannel()) { - openChannelUrl(target.toString()); + openChannelUrl(notification.getTargetUrl()); } else { - openFileUrl(target.toString()); + openFileUrl(notification.getTargetUrl()); } hideNotifications(); } diff --git a/app/src/main/java/io/lbry/browser/adapter/CommentListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/CommentListAdapter.java index 68754c98..dbb0a8e5 100644 --- a/app/src/main/java/io/lbry/browser/adapter/CommentListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/CommentListAdapter.java @@ -61,6 +61,16 @@ public class CommentListAdapter extends RecyclerView.Adapter> { options.put("claim_id", claim); options.put("page", page); options.put("page_size", pageSize); + options.put("hidden", false); options.put("include_replies", false); options.put("is_channel_signature_valid", true); + options.put("skip_validation", true); options.put("visible", true); - options.put("hidden", false); + JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options); JSONArray items = result.getJSONArray("items"); diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java similarity index 83% rename from app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java rename to app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java index 317ee033..657e0269 100644 --- a/app/src/main/java/io/lbry/browser/tasks/lbryinc/ListNotificationsTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java @@ -25,13 +25,13 @@ import io.lbry.browser.model.lbryinc.LbryNotification; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbryio; -public class ListNotificationsTask extends AsyncTask> { +public class NotificationListTask extends AsyncTask> { private Context context; private ListNotificationsHandler handler; private ProgressBar progressBar; private Exception error; - public ListNotificationsTask(Context context, ProgressBar progressBar, ListNotificationsHandler handler) { + public NotificationListTask(Context context, ProgressBar progressBar, ListNotificationsHandler handler) { this.context = context; this.progressBar = progressBar; this.handler = handler; @@ -59,9 +59,14 @@ public class ListNotificationsTask extends AsyncTask comments, boolean hasReachedEnd) { Context ctx = getContext(); @@ -2167,6 +2177,15 @@ public class FileViewFragment extends BaseFragment implements relatedContentList.setAdapter(commentListAdapter); commentListAdapter.notifyDataSetChanged(); + // check for the position of commentHash if set + if (!Helper.isNullOrEmpty(commentHash)) { + int position = commentListAdapter.getPositionForComment(commentHash); + if (position > -1) { + android.util.Log.d("#HELP", "scrolling to position: " + position); + relatedContentList.getLayoutManager().scrollToPosition(position); + } + } + checkNoComments(); resolveCommentPosters(); } diff --git a/app/src/main/res/layout/fragment_file_view.xml b/app/src/main/res/layout/fragment_file_view.xml index 1ff24b8e..46ad0a64 100644 --- a/app/src/main/res/layout/fragment_file_view.xml +++ b/app/src/main/res/layout/fragment_file_view.xml @@ -721,19 +721,6 @@ android:textSize="14sp" android:visibility="gone" /> - - Date: Thu, 13 Aug 2020 14:11:42 +0100 Subject: [PATCH 11/12] fix remote notifications not loading. fix comment scroll. --- .../lbry/browser/LbrynetMessagingService.java | 8 +++-- .../tasks/lbryinc/NotificationListTask.java | 2 +- .../ui/findcontent/FileViewFragment.java | 29 +++++++++++++------ 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java index 33cf1c6c..dfad0466 100644 --- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java +++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java @@ -23,6 +23,7 @@ import com.google.firebase.messaging.RemoteMessage; import io.lbry.browser.data.DatabaseHelper; import io.lbry.browser.model.lbryinc.LbryNotification; +import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.LbryAnalytics; import java.util.ArrayList; @@ -54,6 +55,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService { String title = payload.get("title"); String body = payload.get("body"); String name = payload.get("name"); // notification name + String hash = payload.get("hash"); // comment hash if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) { // only log the receive event for valid notifications received @@ -63,6 +65,10 @@ public class LbrynetMessagingService extends FirebaseMessagingService { firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle); } + if (!Helper.isNullOrEmpty(hash)) { + url = String.format("%s?comment_hash=%s", url, hash); + } + sendNotification(title, body, type, url, name); } @@ -121,8 +127,6 @@ public class LbrynetMessagingService extends FirebaseMessagingService { private void sendNotification(String title, String messageBody, String type, String url, String name) { //Intent intent = new Intent(this, MainActivity.class); //intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); - android.util.Log.d("#HELP", "Title=" + title + "; Body=" + messageBody + "; Type=" + type +"; url=" + url + "; name=" + name); - if (url == null) { if (TYPE_REWARD.equals(type)) { url = "lbry://?rewards"; diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java index 657e0269..89ede753 100644 --- a/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationListTask.java @@ -57,7 +57,7 @@ public class NotificationListTask extends AsyncTask -1) { - android.util.Log.d("#HELP", "scrolling to position: " + position); - relatedContentList.getLayoutManager().scrollToPosition(position); - } - } - + scrollToCommentHash(); checkNoComments(); resolveCommentPosters(); } @@ -2200,6 +2197,20 @@ public class FileViewFragment extends BaseFragment implements } } + private void scrollToCommentHash() { + View root = getView(); + // check for the position of commentHash if set + if (root != null && !Helper.isNullOrEmpty(commentHash) && commentListAdapter != null && commentListAdapter.getItemCount() > 0) { + RecyclerView commentList = root.findViewById(R.id.file_view_comments_list); + int position = commentListAdapter.getPositionForComment(commentHash); + if (position > -1) { + NestedScrollView scrollView = root.findViewById(R.id.file_view_scroll_view); + scrollView.requestChildFocus(commentList, commentList); + commentList.getLayoutManager().scrollToPosition(position); + } + } + } + private void checkNoComments() { View root = getView(); if (root != null) { -- 2.45.2 From 7f9ab48855c473e7010fe936b8a7073e6cf8e870 Mon Sep 17 00:00:00 2001 From: Akinwale Ariwodola Date: Tue, 18 Aug 2020 14:16:57 +0100 Subject: [PATCH 12/12] Improve in-app comment notification linking. Add icons. --- .../lbry/browser/LbrynetMessagingService.java | 4 ++ .../java/io/lbry/browser/MainActivity.java | 3 +- .../browser/adapter/ClaimListAdapter.java | 17 +++++- .../adapter/NotificationListAdapter.java | 33 +++++++++++ .../io/lbry/browser/data/DatabaseHelper.java | 35 +++++++++--- .../java/io/lbry/browser/model/Claim.java | 1 + .../model/lbryinc/LbryNotification.java | 2 + .../tasks/lbryinc/NotificationListTask.java | 2 + .../ui/findcontent/FileViewFragment.java | 23 ++++++-- .../res/layout/list_item_notification.xml | 56 +++++++++++-------- app/src/main/res/layout/list_item_stream.xml | 23 ++++++++ app/src/main/res/values/strings.xml | 3 + app/src/main/res/xml/settings.xml | 6 ++ 13 files changed, 171 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java index dfad0466..aa8f1fe6 100644 --- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java +++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java @@ -36,6 +36,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService { private static final String TAG = "LbrynetMessagingService"; private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL"; + private static final String TYPE_COMMENT = "comment"; private static final String TYPE_SUBSCRIPTION = "subscription"; private static final String TYPE_REWARD = "reward"; private static final String TYPE_INTERESTS = "interests"; @@ -169,6 +170,9 @@ public class LbrynetMessagingService extends FirebaseMessagingService { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); List enabledTypes = new ArrayList(); + if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_COMMENTS, true)) { + enabledTypes.add(TYPE_COMMENT); + } if (sp.getBoolean(MainActivity.PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS, true)) { enabledTypes.add(TYPE_SUBSCRIPTION); } diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 1a5919e7..d9ab24a8 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -286,6 +286,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public static final String PREFERENCE_KEY_DARK_MODE = "io.lbry.browser.preference.userinterface.DarkMode"; public static final String PREFERENCE_KEY_SHOW_MATURE_CONTENT = "io.lbry.browser.preference.userinterface.ShowMatureContent"; public static final String PREFERENCE_KEY_SHOW_URL_SUGGESTIONS = "io.lbry.browser.preference.userinterface.UrlSuggestions"; + public static final String PREFERENCE_KEY_NOTIFICATION_COMMENTS = "io.lbry.browser.preference.notifications.Comments"; public static final String PREFERENCE_KEY_NOTIFICATION_SUBSCRIPTIONS = "io.lbry.browser.preference.notifications.Subscriptions"; public static final String PREFERENCE_KEY_NOTIFICATION_REWARDS = "io.lbry.browser.preference.notifications.Rewards"; public static final String PREFERENCE_KEY_NOTIFICATION_CONTENT_INTERESTS = "io.lbry.browser.preference.notifications.ContentInterests"; @@ -571,7 +572,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public boolean isBackgroundPlaybackEnabled() { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(this); - return sp.getBoolean(PREFERENCE_KEY_BACKGROUND_PLAYBACK, false); + return sp.getBoolean(PREFERENCE_KEY_BACKGROUND_PLAYBACK, true); } public boolean initialSubscriptionMergeDone() { diff --git a/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java index c21bbf20..c36cbf3c 100644 --- a/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/ClaimListAdapter.java @@ -193,6 +193,10 @@ public class ClaimListAdapter extends RecyclerView.Adapter { + private static final String RULE_CREATOR_SUBSCRIBER = "creator_subscriber"; + private static final String RULE_COMMENT = "comment"; + private Context context; private List items; @Setter @@ -37,11 +43,13 @@ public class NotificationListAdapter extends RecyclerView.Adapter loadingPlaceholders = new ArrayList<>(); + for (int i = 0; i < 15; i++) { + Claim placeholder = new Claim(); + placeholder.setLoadingPlaceholder(true); + loadingPlaceholders.add(placeholder); + } + relatedContentAdapter = new ClaimListAdapter(loadingPlaceholders, context); + RecyclerView relatedContentList = root.findViewById(R.id.file_view_related_content_list); + relatedContentList.setAdapter(relatedContentAdapter); + String title = claim.getTitle(); String claimId = claim.getClaimId(); ProgressBar relatedLoading = root.findViewById(R.id.file_view_related_content_progress); - Context context = getContext(); boolean canShowMatureContent = false; if (context != null) { SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context); @@ -2109,10 +2120,14 @@ public class FileViewFragment extends BaseFragment implements Context ctx = getContext(); if (ctx != null) { - relatedContentAdapter = new ClaimListAdapter(filteredClaims, ctx); + relatedContentAdapter.setItems(filteredClaims); relatedContentAdapter.setListener(new ClaimListAdapter.ClaimListItemListener() { @Override public void onClaimClicked(Claim claim) { + if (claim.isLoadingPlaceholder()) { + return; + } + if (context instanceof MainActivity) { MainActivity activity = (MainActivity) context; if (claim.getName().startsWith("@")) { @@ -2154,7 +2169,7 @@ public class FileViewFragment extends BaseFragment implements View root = getView(); ProgressBar commentsLoading = root.findViewById(R.id.file_view_comments_progress); if (claim != null && root != null) { - CommentListTask task = new CommentListTask(1, 100, claim.getClaimId(), commentsLoading, new CommentListHandler() { + CommentListTask task = new CommentListTask(1, 200, claim.getClaimId(), commentsLoading, new CommentListHandler() { @Override public void onSuccess(List comments, boolean hasReachedEnd) { Context ctx = getContext(); @@ -2224,7 +2239,7 @@ public class FileViewFragment extends BaseFragment implements long st = System.currentTimeMillis();; List urlsToResolve = new ArrayList<>(commentListAdapter.getClaimUrlsToResolve()); if (urlsToResolve.size() > 0) { - ResolveTask task = new ResolveTask(urlsToResolve, Lbry.SDK_CONNECTION_STRING, null, new ClaimListResultHandler() { + ResolveTask task = new ResolveTask(urlsToResolve, Lbry.LBRY_TV_CONNECTION_STRING, null, new ClaimListResultHandler() { @Override public void onSuccess(List claims) { if (commentListAdapter != null) { diff --git a/app/src/main/res/layout/list_item_notification.xml b/app/src/main/res/layout/list_item_notification.xml index 488e1d15..840442f0 100644 --- a/app/src/main/res/layout/list_item_notification.xml +++ b/app/src/main/res/layout/list_item_notification.xml @@ -9,30 +9,42 @@ android:layout_marginRight="8dp" android:layout_marginBottom="8dp"> - + + - - + android:padding="16dp"> + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/list_item_stream.xml b/app/src/main/res/layout/list_item_stream.xml index 04f785a8..6e73ec64 100644 --- a/app/src/main/res/layout/list_item_stream.xml +++ b/app/src/main/res/layout/list_item_stream.xml @@ -138,6 +138,13 @@ android:src="@drawable/ic_check" android:tint="@color/nextLbryGreen" /> + + + + + + + diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index c54f18e5..8e9647bf 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -7,6 +7,7 @@ app:iconSpaceReserved="false"> +