diff --git a/app/build.gradle b/app/build.gradle index 26f53287..afe48177 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,8 +14,8 @@ android { applicationId "io.lbry.browser" minSdkVersion 21 targetSdkVersion 29 - versionCode 1606 - versionName "0.16.6" + versionCode 1607 + versionName "0.16.7" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java index e306f308..a74d3a83 100644 --- a/app/src/main/java/io/lbry/browser/MainActivity.java +++ b/app/src/main/java/io/lbry/browser/MainActivity.java @@ -11,6 +11,7 @@ import android.content.BroadcastReceiver; import android.content.ClipData; import android.content.ComponentName; import android.content.Context; +import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -36,6 +37,7 @@ import android.text.style.TypefaceSpan; import android.util.Base64; import android.util.Log; import android.view.KeyEvent; +import android.view.MenuItem; import android.view.View; import android.view.Menu; import android.view.WindowManager; @@ -64,7 +66,9 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBarDrawerToggle; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatDelegate; +import androidx.appcompat.view.ActionMode; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.core.app.ActivityCompat; import androidx.core.app.NotificationCompat; @@ -87,6 +91,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; +import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.java_websocket.client.WebSocketClient; import org.java_websocket.handshake.ServerHandshake; @@ -131,6 +136,7 @@ import io.lbry.browser.listener.FilePickerListener; import io.lbry.browser.listener.PIPModeListener; import io.lbry.browser.listener.ScreenOrientationListener; import io.lbry.browser.listener.SdkStatusListener; +import io.lbry.browser.listener.SelectionModeListener; import io.lbry.browser.listener.StoragePermissionListener; import io.lbry.browser.listener.WalletBalanceListener; import io.lbry.browser.model.Claim; @@ -151,6 +157,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.NotificationDeleteTask; import io.lbry.browser.tasks.lbryinc.NotificationListTask; import io.lbry.browser.tasks.lbryinc.NotificationUpdateTask; import io.lbry.browser.tasks.localdata.FetchRecentUrlHistoryTask; @@ -195,7 +202,9 @@ import lombok.Setter; import lombok.SneakyThrows; import okhttp3.OkHttpClient; -public class MainActivity extends AppCompatActivity implements SdkStatusListener, SharedPreferences.OnSharedPreferenceChangeListener { +public class MainActivity extends AppCompatActivity implements SdkStatusListener, + SharedPreferences.OnSharedPreferenceChangeListener, + ActionMode.Callback, SelectionModeListener { private static final String CHANNEL_ID_PLAYBACK = "io.lbry.browser.LBRY_PLAYBACK_CHANNEL"; private static final int PLAYBACK_NOTIFICATION_ID = 3; private static final String SPECIAL_URL_PREFIX = "lbry://?"; @@ -347,6 +356,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener private MediaSessionCompat mediaSession; private boolean receivedStopService; private ActionBarDrawerToggle toggle; + private SwipeRefreshLayout notificationsSwipeContainer; private SyncSetTask syncSetTask = null; private List pendingSyncSetQueue; @Getter @@ -530,6 +540,16 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } }); + notificationsSwipeContainer = findViewById(R.id.notifications_list_swipe_container); + notificationsSwipeContainer.setColorSchemeResources(R.color.nextLbryGreen); + notificationsSwipeContainer.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() { + @Override + public void onRefresh() { + notificationsSwipeContainer.setRefreshing(true); + loadRemoteNotifications(false); + } + }); + findViewById(R.id.global_now_playing_card).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -1795,6 +1815,103 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener } } + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + this.actionMode = mode; + if (isDarkMode()) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_VISIBLE); + } + + actionMode.getMenuInflater().inflate(R.menu.menu_notification, menu); + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { + return true; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + if (R.id.action_delete == item.getItemId()) { + if (notificationListAdapter != null && notificationListAdapter.getSelectedCount() > 0) { + + final List selectedNotifications = new ArrayList<>(notificationListAdapter.getSelectedItems()); + String message = getResources().getQuantityString(R.plurals.confirm_delete_notifications, selectedNotifications.size()); + AlertDialog.Builder builder = new AlertDialog.Builder(this). + setTitle(R.string.delete_selection). + setMessage(message) + .setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + handleDeleteSelectedNotifications(selectedNotifications); + } + }).setNegativeButton(R.string.no, null); + builder.show(); + return true; + } + } + return false; + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + if (notificationListAdapter != null) { + notificationListAdapter.clearSelectedItems(); + notificationListAdapter.setInSelectionMode(false); + notificationListAdapter.notifyDataSetChanged(); + } + if (isDarkMode()) { + getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR); + } + this.actionMode = null; + } + + @Override + public void onEnterSelectionMode() { + startSupportActionMode(this); + } + + @Override + public void onExitSelectionMode() { + if (actionMode != null) { + actionMode.finish(); + } + } + + @Override + public void onItemSelectionToggled() { + if (actionMode != null) { + actionMode.setTitle(notificationListAdapter != null ? String.valueOf(notificationListAdapter.getSelectedCount()) : ""); + actionMode.invalidate(); + } + } + + private void handleDeleteSelectedNotifications(List notifications) { + List remoteIds = new ArrayList<>(); + for (LbryNotification notification : notifications) { + remoteIds.add(notification.getRemoteId()); + } + (new AsyncTask() { + protected Void doInBackground(Void... params) { + try { + SQLiteDatabase db = dbHelper.getWritableDatabase(); + DatabaseHelper.deleteNotifications(notifications, db); + } catch (Exception ex) { + // pass + } + return null; + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + new NotificationDeleteTask(remoteIds).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + if (notificationListAdapter != null) { + notificationListAdapter.removeNotifications(notifications); + } + if (actionMode != null) { + actionMode.finish(); + } + } + private class PlayerNotificationDescriptionAdapter implements PlayerNotificationManager.MediaDescriptionAdapter { @Override @@ -2631,11 +2748,12 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener JSONObject item = array.getJSONObject(i); String claimId = item.getString("claim_id"); String channelName = item.getString("channel_name"); + boolean isNotificationsDisabled = item.getBoolean("is_notifications_disabled"); LbryUri url = new LbryUri(); url.setChannelName(channelName); url.setClaimId(claimId); - subscriptions.add(new Subscription(channelName, url.toString())); + subscriptions.add(new Subscription(channelName, url.toString(), isNotificationsDisabled)); subUrls.add(url.toString()); } Lbryio.subscriptions = subscriptions; @@ -3040,7 +3158,6 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener // TODO: Broadcast startup status changes JSONObject startupStatus = status.getJSONObject("startup_status"); - android.util.Log.d(TAG, startupStatus.toString(2)); sdkReady = startupStatus.getBoolean("file_manager") && startupStatus.getBoolean("wallet"); } } catch (ConnectException | JSONException ex) { @@ -3308,6 +3425,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener if (markRead && findViewById(R.id.notifications_container).getVisibility() == View.VISIBLE) { markNotificationsRead(); } + + if (notificationsSwipeContainer != null) { + notificationsSwipeContainer.setRefreshing(false); + } } @Override @@ -3315,6 +3436,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener // pass Log.e(TAG, "error loading remote notifications", exception); loadLocalNotifications(); + if (notificationsSwipeContainer != null) { + notificationsSwipeContainer.setRefreshing(false); + } } }); task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); @@ -3344,6 +3468,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener if (notificationListAdapter == null) { notificationListAdapter = new NotificationListAdapter(notifications, MainActivity.this); + notificationListAdapter.setSelectionModeListener(MainActivity.this); ((RecyclerView) findViewById(R.id.notifications_list)).setAdapter(notificationListAdapter); } else { notificationListAdapter.addNotifications(notifications); diff --git a/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java index cfdba94c..3865eb5b 100644 --- a/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java +++ b/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java @@ -14,6 +14,7 @@ import androidx.recyclerview.widget.RecyclerView; import com.bumptech.glide.Glide; import com.bumptech.glide.request.RequestOptions; +import com.google.android.material.snackbar.Snackbar; import java.util.ArrayList; import java.util.Calendar; @@ -24,6 +25,7 @@ import java.util.List; import java.util.TimeZone; import io.lbry.browser.R; +import io.lbry.browser.listener.SelectionModeListener; import io.lbry.browser.model.Claim; import io.lbry.browser.model.lbryinc.LbryNotification; import io.lbry.browser.ui.controls.SolidIconView; @@ -43,15 +45,19 @@ public class NotificationListAdapter extends RecyclerView.Adapter items; + private List selectedItems; @Setter private NotificationClickListener clickListener; @Getter @Setter - private int customizeMode; + private boolean inSelectionMode; + @Setter + private SelectionModeListener selectionModeListener; public NotificationListAdapter(List notifications, Context context) { this.context = context; this.items = new ArrayList<>(notifications); + this.selectedItems = new ArrayList<>(); Collections.sort(items, Collections.reverseOrder(new LbryNotification())); } @@ -62,6 +68,7 @@ public class NotificationListAdapter extends RecyclerView.Adapter getSelectedItems() { + return this.selectedItems; + } + public int getSelectedCount() { + return selectedItems != null ? selectedItems.size() : 0; + } + public void clearSelectedItems() { + this.selectedItems.clear(); + } + public boolean isNotificationSelected(LbryNotification notification) { + return selectedItems.contains(notification); + } public void insertNotification(LbryNotification notification, int index) { if (!items.contains(notification)) { @@ -90,6 +110,12 @@ public class NotificationListAdapter extends RecyclerView.Adapter notifications) { + for (LbryNotification notification : notifications) { + items.remove(notification); + } + notifyDataSetChanged(); + } public List getAuthorUrls() { List urls = new ArrayList<>(); @@ -158,9 +184,8 @@ public class NotificationListAdapter extends RecyclerView.Adapter notifications, SQLiteDatabase db) { + StringBuilder sb = new StringBuilder("DELETE FROM notifications WHERE remote_id IN ("); + List remoteIds = new ArrayList<>(); + String delim = ""; + for (int i = 0; i < notifications.size(); i++) { + remoteIds.add(String.valueOf(notifications.get(i).getRemoteId())); + sb.append(delim).append("?"); + delim = ","; + } + sb.append(")"); + + String sql = sb.toString(); + db.execSQL(sql, remoteIds.toArray()); + } public static int getUnreadNotificationsCount(SQLiteDatabase db) { int count = 0; Cursor cursor = null; diff --git a/app/src/main/java/io/lbry/browser/model/lbryinc/Subscription.java b/app/src/main/java/io/lbry/browser/model/lbryinc/Subscription.java index 30f2412a..6d302e52 100644 --- a/app/src/main/java/io/lbry/browser/model/lbryinc/Subscription.java +++ b/app/src/main/java/io/lbry/browser/model/lbryinc/Subscription.java @@ -11,17 +11,21 @@ public class Subscription { @Getter @Setter private String url; + @Getter + @Setter + private boolean isNotificationsDisabled; public Subscription() { } - public Subscription(String channelName, String url) { + public Subscription(String channelName, String url, boolean isNotificationsDisabled) { this.channelName = channelName; this.url = url; + this.isNotificationsDisabled = isNotificationsDisabled; } public static Subscription fromClaim(Claim claim) { - return new Subscription(claim.getName(), claim.getPermanentUrl()); + return new Subscription(claim.getName(), claim.getPermanentUrl(), false); } public String toString() { return url; diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java index cb135060..bb08073e 100644 --- a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java @@ -52,7 +52,6 @@ public class CommentListTask extends AsyncTask> { options.put("visible", true); JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options); - android.util.Log.d("LbryMain", result.toString(2)); JSONArray items = result.getJSONArray("items"); List children = new ArrayList<>(); @@ -78,7 +77,6 @@ public class CommentListTask extends AsyncTask> { } } catch (Exception ex) { error = ex; - android.util.Log.d("LbryMain", ex.toString(), ex); } return comments; } diff --git a/app/src/main/java/io/lbry/browser/tasks/MergeSubscriptionsTask.java b/app/src/main/java/io/lbry/browser/tasks/MergeSubscriptionsTask.java index 2d516e13..842c381e 100644 --- a/app/src/main/java/io/lbry/browser/tasks/MergeSubscriptionsTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/MergeSubscriptionsTask.java @@ -76,13 +76,15 @@ public class MergeSubscriptionsTask extends AsyncTask { options.put("claim_id", channelClaimId); if (!isUnsubscribing) { options.put("channel_name", subscription.getChannelName()); + options.put("notifications_disabled", String.valueOf(subscription.isNotificationsDisabled()).toLowerCase()); } String action = isUnsubscribing ? "delete" : "new"; - Lbryio.call("subscription", action, options, context); - + Object response = Lbryio.parseResponse(Lbryio.call("subscription", action, options, context)); if (!isUnsubscribing) { Lbryio.addSubscription(subscription); } else { diff --git a/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchSubscriptionsTask.java b/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchSubscriptionsTask.java index da886beb..e3c2a1f8 100644 --- a/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchSubscriptionsTask.java +++ b/app/src/main/java/io/lbry/browser/tasks/lbryinc/FetchSubscriptionsTask.java @@ -49,11 +49,12 @@ public class FetchSubscriptionsTask extends AsyncTask { + private List ids; + + public NotificationDeleteTask(List ids) { + this.ids = ids; + } + + protected Boolean doInBackground(Void... params) { + Map options = new HashMap<>(); + options.put("notification_ids", Helper.joinL(ids, ",")); + + try { + Object result = Lbryio.parseResponse(Lbryio.call("notification", "delete", options, null)); + return "ok".equalsIgnoreCase(result.toString()); + } catch (LbryioResponseException | LbryioRequestException ex) { + // pass + } + return false; + } +} 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 9149e0c4..722b84c9 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 @@ -80,6 +80,8 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen private View buttonShare; private View buttonTip; private View buttonFollowUnfollow; + private View buttonBell; + private SolidIconView iconBell; private int subCount; private OutlineIconView iconFollow; private SolidIconView iconUnfollow; @@ -112,6 +114,8 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen buttonFollowUnfollow = root.findViewById(R.id.channel_view_follow_unfollow); iconFollow = root.findViewById(R.id.channel_view_icon_follow); iconUnfollow = root.findViewById(R.id.channel_view_icon_unfollow); + buttonBell = root.findViewById(R.id.channel_view_subscribe_notify); + iconBell = root.findViewById(R.id.channel_view_icon_bell); tabPager = root.findViewById(R.id.channel_view_pager); tabLayout = root.findViewById(R.id.channel_view_tabs); @@ -202,6 +206,39 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen } }); + buttonBell.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + if (claim != null) { + boolean isNotificationsDisabled = Lbryio.isNotificationsDisabled(claim); + final Subscription subscription = Subscription.fromClaim(claim); + subscription.setNotificationsDisabled(!isNotificationsDisabled); + view.setEnabled(false); + Context context = getContext(); + new ChannelSubscribeTask(context, claim.getClaimId(), subscription, false, new ChannelSubscribeTask.ChannelSubscribeHandler() { + @Override + public void onSuccess() { + view.setEnabled(true); + Lbryio.updateSubscriptionNotificationsDisabled(subscription); + + Context context = getContext(); + if (context instanceof MainActivity) { + ((MainActivity) context).showMessage(subscription.isNotificationsDisabled() ? + R.string.receive_no_notifications : R.string.receive_all_notifications); + } + + checkIsFollowing(); + } + + @Override + public void onError(Exception exception) { + view.setEnabled(true); + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + }); + buttonFollowUnfollow.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { @@ -213,7 +250,7 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen subscribing = true; boolean isFollowing = Lbryio.isFollowing(claim); Subscription subscription = Subscription.fromClaim(claim); - buttonFollowUnfollow.setEnabled(false); + view.setEnabled(false); new ChannelSubscribeTask(getContext(), claim.getClaimId(), subscription, isFollowing, new ChannelSubscribeTask.ChannelSubscribeHandler() { @Override public void onSuccess() { @@ -280,8 +317,14 @@ public class ChannelFragment extends BaseFragment implements FetchChannelsListen private void checkIsFollowing() { if (claim != null) { boolean isFollowing = Lbryio.isFollowing(claim); + boolean notificationsDisabled = Lbryio.isNotificationsDisabled(claim); Helper.setViewVisibility(iconFollow, !isFollowing ? View.VISIBLE : View.GONE); Helper.setViewVisibility(iconUnfollow, isFollowing ? View.VISIBLE : View.GONE); + Helper.setViewVisibility(buttonBell, isFollowing ? View.VISIBLE : View.GONE); + + if (iconBell != null) { + iconBell.setText(notificationsDisabled ? R.string.fa_bell : R.string.fa_bell_slash); + } } } 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 2a68643f..b67a74e3 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 @@ -785,6 +785,38 @@ public class FileViewFragment extends BaseFragment implements } } + private View.OnClickListener bellIconListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + if (claim != null && claim.getSigningChannel() != null) { + Claim publisher = claim.getSigningChannel(); + boolean isNotificationsDisabled = Lbryio.isNotificationsDisabled(publisher); + final Subscription subscription = Subscription.fromClaim(publisher); + subscription.setNotificationsDisabled(!isNotificationsDisabled); + view.setEnabled(false); + Context context = getContext(); + new ChannelSubscribeTask(context, publisher.getClaimId(), subscription, false, new ChannelSubscribeTask.ChannelSubscribeHandler() { + @Override + public void onSuccess() { + view.setEnabled(true); + Lbryio.updateSubscriptionNotificationsDisabled(subscription); + Context context = getContext(); + if (context instanceof MainActivity) { + ((MainActivity) context).showMessage(subscription.isNotificationsDisabled() ? + R.string.receive_no_notifications : R.string.receive_all_notifications); + } + checkIsFollowing(); + } + + @Override + public void onError(Exception exception) { + view.setEnabled(true); + } + }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); + } + } + }; + private View.OnClickListener followUnfollowListener = new View.OnClickListener() { @Override public void onClick(View view) { @@ -1170,8 +1202,10 @@ public class FileViewFragment extends BaseFragment implements View buttonFollow = root.findViewById(R.id.file_view_icon_follow); View buttonUnfollow = root.findViewById(R.id.file_view_icon_unfollow); + View buttonBell = root.findViewById(R.id.file_view_icon_bell); buttonFollow.setOnClickListener(followUnfollowListener); buttonUnfollow.setOnClickListener(followUnfollowListener); + buttonBell.setOnClickListener(bellIconListener); commentChannelSpinnerAdapter = new InlineChannelSpinnerAdapter(getContext(), R.layout.spinner_item_channel, new ArrayList<>()); commentChannelSpinnerAdapter.addPlaceholder(false); @@ -2524,13 +2558,18 @@ public class FileViewFragment extends BaseFragment implements private void checkIsFollowing() { if (claim != null && claim.getSigningChannel() != null) { boolean isFollowing = Lbryio.isFollowing(claim.getSigningChannel()); + boolean notificationsDisabled = Lbryio.isNotificationsDisabled(claim.getSigningChannel()); Context context = getContext(); View root = getView(); if (context != null && root != null) { OutlineIconView iconFollow = root.findViewById(R.id.file_view_icon_follow); SolidIconView iconUnfollow = root.findViewById(R.id.file_view_icon_unfollow); - Helper.setViewVisibility(iconFollow, !isFollowing ? View.VISIBLE: View.INVISIBLE); - Helper.setViewVisibility(iconUnfollow, isFollowing ? View.VISIBLE : View.INVISIBLE); + SolidIconView iconBell = root.findViewById(R.id.file_view_icon_bell); + Helper.setViewVisibility(iconFollow, !isFollowing ? View.VISIBLE: View.GONE); + Helper.setViewVisibility(iconUnfollow, isFollowing ? View.VISIBLE : View.GONE); + Helper.setViewVisibility(iconBell, isFollowing ? View.VISIBLE : View.GONE); + + iconBell.setText(notificationsDisabled ? R.string.fa_bell : R.string.fa_bell_slash); } } } diff --git a/app/src/main/java/io/lbry/browser/utils/Lbryio.java b/app/src/main/java/io/lbry/browser/utils/Lbryio.java index 9dfdc38f..10e379a3 100644 --- a/app/src/main/java/io/lbry/browser/utils/Lbryio.java +++ b/app/src/main/java/io/lbry/browser/utils/Lbryio.java @@ -327,6 +327,15 @@ public final class Lbryio { } } + public static void updateSubscriptionNotificationsDisabled(Subscription subscription) { + synchronized (lock) { + int index = subscriptions.indexOf(subscription); + if (index > -1) { + subscriptions.get(index).setNotificationsDisabled(subscription.isNotificationsDisabled()); + } + } + } + public static void addSubscription(Subscription subscription) { synchronized (lock) { if (!subscriptions.contains(subscription)) { @@ -358,6 +367,15 @@ public final class Lbryio { public static boolean isFollowing(Claim claim) { return subscriptions.contains(Subscription.fromClaim(claim)); } + public static boolean isNotificationsDisabled(Claim claim) { + Subscription sub = Subscription.fromClaim(claim); + int index = subscriptions.indexOf(sub); + if (index > -1) { + Subscription actual = subscriptions.get(subscriptions.indexOf(sub)); + return actual.isNotificationsDisabled(); + } + return false; + } public static void updateRewardsLists(List rewards) { synchronized (lock) { diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index ed30a9f0..0edffd26 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -71,13 +71,18 @@ android:textSize="16sp" android:textAlignment="center" /> - + android:layout_height="match_parent"> + + diff --git a/app/src/main/res/layout/fragment_channel.xml b/app/src/main/res/layout/fragment_channel.xml index 9cd5b5a1..84797cb4 100644 --- a/app/src/main/res/layout/fragment_channel.xml +++ b/app/src/main/res/layout/fragment_channel.xml @@ -224,9 +224,27 @@ android:layout_width="24dp" android:layout_height="24dp" android:text="@string/fa_heart_broken" + android:textColor="@color/foreground" android:textSize="20dp" android:visibility="invisible"/> + + + diff --git a/app/src/main/res/layout/fragment_file_view.xml b/app/src/main/res/layout/fragment_file_view.xml index 97fa2df9..d62cbbfc 100644 --- a/app/src/main/res/layout/fragment_file_view.xml +++ b/app/src/main/res/layout/fragment_file_view.xml @@ -503,7 +503,6 @@ android:id="@+id/file_view_publisher_area" android:layout_width="match_parent" android:layout_height="wrap_content"> - + android:layout_toStartOf="@id/file_view_publisher_area_actions"> - + android:layout_alignParentEnd="true"> + - + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1689d657..70d98f9c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -117,6 +117,8 @@ Content Website reposted + You will receive all notifications + You will not receive notifications for this channel %1$s follower %1$s followers @@ -382,6 +384,7 @@ Channel to show support as Make this a tip Send Revocable Support + Tip %1$s Tip %1$s Credit Tip %1$s Credits @@ -616,6 +619,10 @@ It\'s quiet here! New notifications will be displayed when you receive them. + + Are you sure you want to remove the selected notification? + Are you sure you want to remove the selected notifications? + @@ -645,4 +652,7 @@ + + +