diff --git a/app/build.gradle b/app/build.gradle index e9779cd2..7ac3df4f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -115,7 +115,7 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0' - __32bitImplementation 'io.lbry:lbrysdk32:0.85.1' -// __64bitImplementation 'io.lbry:lbrysdk64:0.85.1' + __32bitImplementation 'io.lbry:lbrysdk32:0.86.1' +// __64bitImplementation 'io.lbry:lbrysdk64:0.86.1' } diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index 7cfd45fc..a53887c2 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -467,7 +467,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener // setup uri bar setupUriBar(); initNotificationsPage(); - loadUnreadNotificationsCount(); + loadUnseenNotificationsCount(); // other pendingSyncSetQueue = new ArrayList<>(); @@ -1747,19 +1747,6 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener checkSyncedWallet(); } - (new Thread() { - public void run() { - Map params = new HashMap<>(); - try { - Log.d(TAG, "Calling settings_get"); - Log.d(TAG, ((JSONObject) Lbry.parseResponse(Lbry.apiCall("settings_get", params, Lbry.SDK_CONNECTION_STRING))).toString(2)); - } catch (Exception ex) { - // pass - Log.d(TAG, ex.getMessage(), ex); - } - } - }).start(); - //findViewById(R.id.global_sdk_initializing_status).setVisibility(View.GONE); //checkAndEnableShareUsageData(); @@ -2382,7 +2369,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } if (notificationListAdapter != null) { - markNotificationsRead(); + markNotificationsSeen(); } } @@ -2391,17 +2378,17 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener findViewById(R.id.notifications_container).setVisibility(View.GONE); } - private void markNotificationsRead() { + private void markNotificationsSeen() { List all = notificationListAdapter != null ? notificationListAdapter.getItems() : null; if (all != null) { - List unreadIds = new ArrayList<>(); + List unseenIds = new ArrayList<>(); for (LbryNotification notification : all) { - if (!notification.isRead() && notification.getRemoteId() > 0) { - unreadIds.add(notification.getRemoteId()); + if (!notification.isSeen() && notification.getRemoteId() > 0) { + unseenIds.add(notification.getRemoteId()); } } - if (unreadIds.size() > 0) { - NotificationUpdateTask task = new NotificationUpdateTask(unreadIds, true); + if (unseenIds.size() > 0) { + NotificationUpdateTask task = new NotificationUpdateTask(unseenIds, true); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } @@ -2411,14 +2398,14 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener protected Void doInBackground(Void... params) { try { SQLiteDatabase db = dbHelper.getWritableDatabase(); - DatabaseHelper.markNotificationsRead(db); + DatabaseHelper.markNotificationsSeen(db); } catch (Exception ex) { // pass } return null; } protected void onPostExecute(Void result) { - loadUnreadNotificationsCount(); + loadUnseenNotificationsCount(); } }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -3418,7 +3405,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } - private void displayUnreadNotificationCount(int count) { + private void displayUnseenNotificationCount(int count) { String text = count > 99 ? "99+" : String.valueOf(count); TextView badge = findViewById(R.id.notifications_badge_count); @@ -3426,19 +3413,19 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener badge.setText(text); } - private void loadUnreadNotificationsCount() { + private void loadUnseenNotificationsCount() { (new AsyncTask() { @Override protected Integer doInBackground(Void... params) { try { SQLiteDatabase db = dbHelper.getReadableDatabase(); - return DatabaseHelper.getUnreadNotificationsCount(db); + return DatabaseHelper.getUnseenNotificationsCount(db); } catch (Exception ex) { return 0; } } protected void onPostExecute(Integer count) { - displayUnreadNotificationCount(count); + displayUnseenNotificationCount(count); } }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } @@ -3450,10 +3437,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener public void onSuccess(List notifications) { remoteNotifcationsLastLoaded = new Date(); - loadUnreadNotificationsCount(); + loadUnseenNotificationsCount(); loadLocalNotifications(); if (markRead && findViewById(R.id.notifications_container).getVisibility() == View.VISIBLE) { - markNotificationsRead(); + markNotificationsSeen(); } if (notificationsSwipeContainer != null) { @@ -3494,7 +3481,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener 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); - loadUnreadNotificationsCount(); + loadUnseenNotificationsCount(); if (notificationListAdapter == null) { notificationListAdapter = new NotificationListAdapter(notifications, MainActivity.this); @@ -3551,7 +3538,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener return null; } protected void onPostExecute() { - loadUnreadNotificationsCount(); + loadUnseenNotificationsCount(); } }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } diff --git a/app/src/main/java/io/lbry/browser/VerificationActivity.java b/app/src/main/java/io/lbry/browser/VerificationActivity.java index fdd1b923..ade50f8a 100644 --- a/app/src/main/java/io/lbry/browser/VerificationActivity.java +++ b/app/src/main/java/io/lbry/browser/VerificationActivity.java @@ -18,6 +18,7 @@ import com.google.android.material.snackbar.Snackbar; import java.util.Arrays; import io.lbry.browser.adapter.VerificationPagerAdapter; +import io.lbry.browser.listener.SdkStatusListener; import io.lbry.browser.listener.SignInListener; import io.lbry.browser.listener.WalletSyncListener; import io.lbry.browser.model.lbryinc.RewardVerified; @@ -35,6 +36,7 @@ public class VerificationActivity extends FragmentActivity implements SignInList public static final int VERIFICATION_FLOW_REWARDS = 2; public static final int VERIFICATION_FLOW_WALLET = 3; + private List sdkStatusListeners; private BroadcastReceiver sdkReceiver; private String email; private boolean signedIn; @@ -44,6 +46,8 @@ public class VerificationActivity extends FragmentActivity implements SignInList public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + sdkStatusListeners = new ArrayList<>(); + signedIn = Lbryio.isSignedIn(); Intent intent = getIntent(); if (intent != null) { @@ -65,11 +69,18 @@ public class VerificationActivity extends FragmentActivity implements SignInList IntentFilter filter = new IntentFilter(); filter.addAction(LbrynetService.ACTION_STOP_SERVICE); + filter.addAction(MainActivity.ACTION_SDK_READY); sdkReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); - if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) { + if (MainActivity.ACTION_SDK_READY.equals(action)) { + for (SdkStatusListener listener : sdkStatusListeners) { + if (listener != null) { + listener.onSdkReady(); + } + } + } else if (LbrynetService.ACTION_STOP_SERVICE.equals(action)) { finish(); } } @@ -329,4 +340,14 @@ public class VerificationActivity extends FragmentActivity implements SignInList Helper.unregisterReceiver(sdkReceiver, this); super.onDestroy(); } + + public void addSdkStatusListener(SdkStatusListener listener) { + if (!sdkStatusListeners.contains(listener)) { + sdkStatusListeners.add(listener); + } + } + + public void removeSdkStatusListener(SdkStatusListener listener) { + sdkStatusListeners.remove(listener); + } } 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 fe669263..5fc4aea9 100644 --- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java +++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java @@ -124,7 +124,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { private static final String SQL_INSERT_NOTIFICATION = "REPLACE INTO notifications (remote_id, author_url, title, description, rule, target_url, is_read, is_seen, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; private static final String SQL_GET_NOTIFICATIONS = "SELECT id, remote_id, author_url, title, description, rule, target_url, is_read, is_seen, 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_GET_UNSEEN_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_seen <> 1"; private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0"; + private static final String SQL_MARK_NOTIFICATIONS_SEEN = "UPDATE notifications SET is_seen = 1 WHERE is_seen = 0"; private static final String SQL_MARK_NOTIFICATION_READ_AND_SEEN = "UPDATE notifications SET is_read = 1, is_seen = 1 WHERE id = ?"; private static final String SQL_INSERT_SHUFFLE_WATCHED = "REPLACE INTO shuffle_watched (claim_id) VALUES (?)"; @@ -417,6 +419,22 @@ public class DatabaseHelper extends SQLiteOpenHelper { } return count; } + public static int getUnseenNotificationsCount(SQLiteDatabase db) { + int count = 0; + Cursor cursor = null; + try { + cursor = db.rawQuery(SQL_GET_UNSEEN_NOTIFICATIONS_COUNT, null); + if (cursor.moveToNext()) { + count = cursor.getInt(0); + } + } finally { + Helper.closeCursor(cursor); + } + return count; + } + public static void markNotificationsSeen(SQLiteDatabase db) { + db.execSQL(SQL_MARK_NOTIFICATIONS_SEEN); + } public static void markNotificationsRead(SQLiteDatabase db) { db.execSQL(SQL_MARK_NOTIFICATIONS_READ); } diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationUpdateTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationUpdateTask.java index 2e832973..f942f7d6 100644 --- a/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationUpdateTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/NotificationUpdateTask.java @@ -15,25 +15,25 @@ public class NotificationUpdateTask extends AsyncTask { private List ids; private boolean seen; private boolean read; - private boolean updateSeen; + private boolean updateRead; - public NotificationUpdateTask(List ids, boolean read) { - this(ids, read, false, false); + public NotificationUpdateTask(List ids, boolean seen) { + this(ids, false, true, false); } - public NotificationUpdateTask(List ids, boolean read, boolean seen, boolean updateSeen) { + public NotificationUpdateTask(List ids, boolean read, boolean seen, boolean updateRead) { this.ids = ids; this.read = read; this.seen = seen; - this.updateSeen = updateSeen; + this.updateRead = updateRead; } protected Boolean doInBackground(Void... params) { Map options = new HashMap<>(); options.put("notification_ids", Helper.joinL(ids, ",")); - options.put("is_read", String.valueOf(read)); - if (updateSeen) { - options.put("is_seen", String.valueOf(seen)); + options.put("is_seen", String.valueOf(seen)); + if (updateRead) { + options.put("is_read", String.valueOf(read)); } try { diff --git a/app/src/main/java/io/lbry/browser/tasks/wallet/LoadSharedUserStateTask.java b/app/src/main/java/io/lbry/browser/tasks/wallet/LoadSharedUserStateTask.java index 371c1e5f..0bf93baa 100644 --- a/app/src/main/java/io/lbry/browser/tasks/wallet/LoadSharedUserStateTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/wallet/LoadSharedUserStateTask.java @@ -18,6 +18,7 @@ import io.lbry.browser.exceptions.ApiCallException; import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.model.Tag; import io.lbry.browser.model.lbryinc.Subscription; +import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; import io.lbry.browser.utils.LbryUri; @@ -69,6 +70,8 @@ public class LoadSharedUserStateTask extends AsyncTask { value.has("subscriptions") && !value.isNull("subscriptions") ? value.getJSONArray("subscriptions") : null; JSONArray tags = value.has("tags") && !value.isNull("tags") ? value.getJSONArray("tags") : null; + JSONArray following = + value.has("following") && !value.isNull("following") ? value.getJSONArray("following") : null; if (subscriptionUrls != null) { subscriptions = new ArrayList<>(); @@ -78,7 +81,8 @@ public class LoadSharedUserStateTask extends AsyncTask { LbryUri uri = LbryUri.parse(LbryUri.normalize(url)); Subscription subscription = new Subscription(); subscription.setChannelName(uri.getChannelName()); - subscription.setUrl(url); + subscription.setUrl(uri.toString()); + subscription.setNotificationsDisabled(isNotificationsDisabledForSubUrl(uri.toString(), following)); subscriptions.add(subscription); if (db != null) { DatabaseHelper.createOrUpdateSubscription(subscription, db); @@ -125,6 +129,24 @@ public class LoadSharedUserStateTask extends AsyncTask { return false; } + protected boolean isNotificationsDisabledForSubUrl(String url, JSONArray following) { + try { + for (int i = 0; i < following.length(); i++) { + JSONObject item = following.getJSONObject(i); + String itemUrl = Helper.getJSONString("url", null, item); + boolean notificationsDisabled = Helper.getJSONBoolean("notificationsDisabled", true, item); + if (url.equalsIgnoreCase(itemUrl)) { + return notificationsDisabled; + } + } + } catch (JSONException ex) { + // pass + } + + // always default notifications disabled to true + return true; + } + protected void onPostExecute(Boolean result) { if (handler != null) { if (result) { diff --git a/app/src/main/java/io/lbry/browser/tasks/wallet/SaveSharedUserStateTask.java b/app/src/main/java/io/lbry/browser/tasks/wallet/SaveSharedUserStateTask.java index 9a0559af..2b962061 100644 --- a/app/src/main/java/io/lbry/browser/tasks/wallet/SaveSharedUserStateTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/wallet/SaveSharedUserStateTask.java @@ -2,6 +2,7 @@ package io.lbry.browser.tasks.wallet; import android.os.AsyncTask; +import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -11,9 +12,11 @@ import java.util.List; import java.util.Map; import io.lbry.browser.exceptions.ApiCallException; +import io.lbry.browser.exceptions.LbryUriException; import io.lbry.browser.model.lbryinc.Subscription; import io.lbry.browser.utils.Helper; import io.lbry.browser.utils.Lbry; +import io.lbry.browser.utils.LbryUri; import io.lbry.browser.utils.Lbryio; /* @@ -40,9 +43,16 @@ public class SaveSharedUserStateTask extends AsyncTask { protected Boolean doInBackground(Void... params) { // data to save // current subscriptions + List subs = new ArrayList<>(Lbryio.subscriptions); List subscriptionUrls = new ArrayList<>(); - for (Subscription subscription : Lbryio.subscriptions) { - subscriptionUrls.add(subscription.getUrl()); + try { + for (Subscription subscription : subs) { + LbryUri uri = LbryUri.parse(LbryUri.normalize(subscription.getUrl())); + subscriptionUrls.add(uri.toString()); + } + } catch (LbryUriException ex) { + error = ex; + return false; } // followed tags @@ -62,6 +72,7 @@ public class SaveSharedUserStateTask extends AsyncTask { JSONObject value = shared.getJSONObject("value"); value.put("subscriptions", Helper.jsonArrayFromList(subscriptionUrls)); value.put("tags", Helper.jsonArrayFromList(followedTags)); + value.put("following", buildUpdatedNotificationsDisabledStates(subs)); sharedObject = shared; } } @@ -71,6 +82,7 @@ public class SaveSharedUserStateTask extends AsyncTask { JSONObject value = new JSONObject(); value.put("subscriptions", Helper.jsonArrayFromList(subscriptionUrls)); value.put("tags", Helper.jsonArrayFromList(followedTags)); + value.put("following", buildUpdatedNotificationsDisabledStates(subs)); sharedObject = new JSONObject(); sharedObject.put("type", "object"); @@ -91,6 +103,26 @@ public class SaveSharedUserStateTask extends AsyncTask { return false; } + private static JSONArray buildUpdatedNotificationsDisabledStates(List subscriptions) { + JSONArray states = new JSONArray(); + for (Subscription subscription : subscriptions) { + if (!Helper.isNullOrEmpty(subscription.getUrl())) { + try { + JSONObject item = new JSONObject(); + LbryUri uri = LbryUri.parse(LbryUri.normalize(subscription.getUrl())); + item.put("uri", uri.toString()); + item.put("notificationsDisabled", subscription.isNotificationsDisabled()); + states.put(item); + } catch (JSONException | LbryUriException ex) { + // pass + + } + } + } + + return states; + } + protected void onPostExecute(Boolean result) { if (handler != null) { if (result) { diff --git a/app/src/main/java/io/lbry/browser/tasks/wallet/WalletSendTask.java b/app/src/main/java/io/lbry/browser/tasks/wallet/WalletSendTask.java index 8487b0a2..d6183c29 100644 --- a/app/src/main/java/io/lbry/browser/tasks/wallet/WalletSendTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/wallet/WalletSendTask.java @@ -33,6 +33,7 @@ public class WalletSendTask extends AsyncTask { Map options = new HashMap<>(); options.put("addresses", Arrays.asList(recipientAddress)); options.put("amount", amount); + options.put("blocking", true); Lbry.genericApiCall(Lbry.METHOD_WALLET_SEND, options); } catch (ApiCallException ex) { error = ex; diff --git a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java index aa18ff43..75750775 100644 --- a/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/channel/ChannelFragment.java @@ -228,8 +228,11 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen ((MainActivity) context).showMessage(subscription.isNotificationsDisabled() ? R.string.receive_no_notifications : R.string.receive_all_notifications); } - checkIsFollowing(); + + if (context != null) { + context.sendBroadcast(new Intent(MainActivity.ACTION_SAVE_SHARED_USER_STATE)); + } } @Override @@ -268,11 +271,9 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen checkIsFollowing(); FollowingFragment.resetClaimSearchContent = true; - if (Lbry.SDK_READY) { - Context context = getContext(); - if (context instanceof MainActivity) { - ((MainActivity) context).saveSharedUserState(); - } + Context context = getContext(); + if (context != null) { + context.sendBroadcast(new Intent(MainActivity.ACTION_SAVE_SHARED_USER_STATE)); } } diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java index 06b4f994..b4c8a4fc 100644 --- a/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/findcontent/FileViewFragment.java @@ -807,6 +807,10 @@ public class FileViewFragment extends BaseFragment implements R.string.receive_no_notifications : R.string.receive_all_notifications); } checkIsFollowing(); + + if (context != null) { + context.sendBroadcast(new Intent(MainActivity.ACTION_SAVE_SHARED_USER_STATE)); + } } @Override diff --git a/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java b/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java index 213f75bf..db90c8b3 100644 --- a/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java +++ b/app/src/main/java/io/lbry/browser/ui/verification/WalletVerificationFragment.java @@ -21,6 +21,8 @@ import com.google.android.material.textfield.TextInputEditText; import io.lbry.browser.MainActivity; import io.lbry.browser.R; +import io.lbry.browser.VerificationActivity; +import io.lbry.browser.listener.SdkStatusListener; import io.lbry.browser.listener.WalletSyncListener; import io.lbry.browser.model.WalletSync; import io.lbry.browser.tasks.wallet.DefaultSyncTaskHandler; @@ -33,7 +35,7 @@ import io.lbry.browser.utils.Lbryio; import io.lbry.lbrysdk.Utils; import lombok.Setter; -public class WalletVerificationFragment extends Fragment { +public class WalletVerificationFragment extends Fragment implements SdkStatusListener { @Setter private WalletSyncListener listener = null; @@ -86,6 +88,30 @@ public class WalletVerificationFragment extends Fragment { @Override public void onResume() { super.onResume(); + if (!Lbry.SDK_READY) { + Context context = getContext(); + if (context instanceof VerificationActivity) { + VerificationActivity activity = (VerificationActivity) context; + activity.addSdkStatusListener(this); + } + Helper.setViewVisibility(loading, View.VISIBLE); + Helper.setViewVisibility(textLoading, View.VISIBLE); + } else { + onSdkReady(); + } + } + + @Override + public void onStop() { + Context context = getContext(); + if (context instanceof VerificationActivity) { + VerificationActivity activity = (VerificationActivity) context; + activity.removeSdkStatusListener(this); + } + super.onStop(); + } + + public void onSdkReady() { start(); }