Merge from upstream
This commit is contained in:
commit
e024876163
19 changed files with 490 additions and 59 deletions
|
@ -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"
|
||||
}
|
||||
|
|
|
@ -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<WalletSync> 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<LbryNotification> 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<LbryNotification> notifications) {
|
||||
List<Long> remoteIds = new ArrayList<>();
|
||||
for (LbryNotification notification : notifications) {
|
||||
remoteIds.add(notification.getRemoteId());
|
||||
}
|
||||
(new AsyncTask<Void, Void, Void>() {
|
||||
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);
|
||||
|
|
|
@ -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<NotificationLi
|
|||
|
||||
private Context context;
|
||||
private List<LbryNotification> items;
|
||||
private List<LbryNotification> selectedItems;
|
||||
@Setter
|
||||
private NotificationClickListener clickListener;
|
||||
@Getter
|
||||
@Setter
|
||||
private int customizeMode;
|
||||
private boolean inSelectionMode;
|
||||
@Setter
|
||||
private SelectionModeListener selectionModeListener;
|
||||
|
||||
public NotificationListAdapter(List<LbryNotification> 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<NotificationLi
|
|||
protected TextView timeView;
|
||||
protected SolidIconView iconView;
|
||||
protected ImageView thumbnailView;
|
||||
protected View selectedOverlayView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
layoutView = v.findViewById(R.id.notification_layout);
|
||||
|
@ -70,12 +77,25 @@ public class NotificationListAdapter extends RecyclerView.Adapter<NotificationLi
|
|||
timeView = v.findViewById(R.id.notification_time);
|
||||
iconView = v.findViewById(R.id.notification_icon);
|
||||
thumbnailView = v.findViewById(R.id.notification_author_thumbnail);
|
||||
selectedOverlayView = v.findViewById(R.id.notification_selected_overlay);
|
||||
}
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return items != null ? items.size() : 0;
|
||||
}
|
||||
public List<LbryNotification> 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<NotificationLi
|
|||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
public void removeNotifications(List<LbryNotification> notifications) {
|
||||
for (LbryNotification notification : notifications) {
|
||||
items.remove(notification);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public List<String> getAuthorUrls() {
|
||||
List<String> urls = new ArrayList<>();
|
||||
|
@ -158,9 +184,8 @@ public class NotificationListAdapter extends RecyclerView.Adapter<NotificationLi
|
|||
@Override
|
||||
public void onBindViewHolder(NotificationListAdapter.ViewHolder vh, int position) {
|
||||
LbryNotification notification = items.get(position);
|
||||
|
||||
|
||||
vh.layoutView.setBackgroundColor(ContextCompat.getColor(context, notification.isSeen() ? android.R.color.transparent : R.color.nextLbryGreenSemiTransparent));
|
||||
vh.selectedOverlayView.setVisibility(isNotificationSelected(notification) ? View.VISIBLE : View.GONE);
|
||||
|
||||
vh.titleView.setVisibility(!Helper.isNullOrEmpty(notification.getTitle()) ? View.VISIBLE : View.GONE);
|
||||
vh.titleView.setText(notification.getTitle());
|
||||
|
@ -181,11 +206,49 @@ public class NotificationListAdapter extends RecyclerView.Adapter<NotificationLi
|
|||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (clickListener != null) {
|
||||
clickListener.onNotificationClicked(notification);
|
||||
if (inSelectionMode) {
|
||||
toggleSelectedNotification(notification);
|
||||
} else {
|
||||
if (clickListener != null) {
|
||||
clickListener.onNotificationClicked(notification);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
vh.itemView.setOnLongClickListener(new View.OnLongClickListener() {
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (!inSelectionMode) {
|
||||
inSelectionMode = true;
|
||||
if (selectionModeListener != null) {
|
||||
selectionModeListener.onEnterSelectionMode();
|
||||
}
|
||||
}
|
||||
toggleSelectedNotification(notification);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void toggleSelectedNotification(LbryNotification notification) {
|
||||
if (selectedItems.contains(notification)) {
|
||||
selectedItems.remove(notification);
|
||||
} else {
|
||||
selectedItems.add(notification);
|
||||
}
|
||||
|
||||
if (selectionModeListener != null) {
|
||||
selectionModeListener.onItemSelectionToggled();
|
||||
}
|
||||
|
||||
if (selectedItems.size() == 0) {
|
||||
inSelectionMode = false;
|
||||
if (selectionModeListener != null) {
|
||||
selectionModeListener.onExitSelectionMode();
|
||||
}
|
||||
}
|
||||
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private long getLocalNotificationTime(LbryNotification notification) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.database.sqlite.SQLiteDatabase;
|
|||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.SQLInput;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
|
@ -21,13 +22,13 @@ import io.lbry.browser.utils.Helper;
|
|||
import io.lbry.browser.utils.LbryUri;
|
||||
|
||||
public class DatabaseHelper extends SQLiteOpenHelper {
|
||||
public static final int DATABASE_VERSION = 7;
|
||||
public static final int DATABASE_VERSION = 8;
|
||||
public static final String DATABASE_NAME = "LbryApp.db";
|
||||
private static DatabaseHelper instance;
|
||||
|
||||
private static final String[] SQL_CREATE_TABLES = {
|
||||
// local subscription store
|
||||
"CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL)",
|
||||
"CREATE TABLE subscriptions (url TEXT PRIMARY KEY NOT NULL, channel_name TEXT NOT NULL, is_notifications_disabled INTEGER DEFAULT 0 NOT NULL)",
|
||||
// url entry / suggestion history
|
||||
"CREATE TABLE url_history (id INTEGER PRIMARY KEY NOT NULL, value TEXT NOT NULL, url TEXT, type INTEGER NOT NULL, timestamp TEXT NOT NULL)",
|
||||
// tags (known and followed)
|
||||
|
@ -105,11 +106,15 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
"CREATE TABLE shuffle_watched (id INTEGER PRIMARY KEY NOT NULL, claim_id TEXT NOT NULL)",
|
||||
"CREATE UNIQUE INDEX idx_shuffle_watched_claim ON shuffle_watched (claim_id)"
|
||||
};
|
||||
private static final String[] SQL_V7_V8_UPGRADE = {
|
||||
"AlTER TABLE subscriptions ADD COLUMN is_notifications_disabled INTEGER DEFAULT 0 NOT NULL"
|
||||
};
|
||||
|
||||
private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)";
|
||||
private static final String SQL_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url, is_notifications_disabled) VALUES (?, ?, ?)";
|
||||
private static final String SQL_UPDATE_SUBSCRIPTION_NOTIFICATION = "UPDATE subscriptions SET is_notification_disabled = ? WHERE url = ?";
|
||||
private static final String SQL_CLEAR_SUBSCRIPTIONS = "DELETE FROM subscriptions";
|
||||
private static final String SQL_DELETE_SUBSCRIPTION = "DELETE FROM subscriptions WHERE url = ?";
|
||||
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url FROM subscriptions";
|
||||
private static final String SQL_GET_SUBSCRIPTIONS = "SELECT channel_name, url, is_notifications_disabled FROM subscriptions";
|
||||
|
||||
private static final String SQL_INSERT_URL_HISTORY = "REPLACE INTO url_history (value, url, type, timestamp) VALUES (?, ?, ?, ?)";
|
||||
private static final String SQL_CLEAR_URL_HISTORY = "DELETE FROM url_history";
|
||||
|
@ -188,6 +193,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
db.execSQL(sql);
|
||||
}
|
||||
}
|
||||
if (oldVersion < 8) {
|
||||
for (String sql : SQL_V7_V8_UPGRADE) {
|
||||
db.execSQL(sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
|
||||
|
@ -304,7 +314,14 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
}
|
||||
|
||||
public static void createOrUpdateSubscription(Subscription subscription, SQLiteDatabase db) {
|
||||
db.execSQL(SQL_INSERT_SUBSCRIPTION, new Object[] { subscription.getChannelName(), subscription.getUrl() });
|
||||
db.execSQL(SQL_INSERT_SUBSCRIPTION, new Object[] {
|
||||
subscription.getChannelName(),
|
||||
subscription.getUrl(),
|
||||
subscription.isNotificationsDisabled() ? 1 : 0
|
||||
});
|
||||
}
|
||||
public static void setSubscriptionNotificationDisabled(boolean flag, String url, SQLiteDatabase db) {
|
||||
db.execSQL(SQL_UPDATE_SUBSCRIPTION_NOTIFICATION, new Object[] { flag ? 1 : 0, url });
|
||||
}
|
||||
public static void deleteSubscription(Subscription subscription, SQLiteDatabase db) {
|
||||
db.execSQL(SQL_DELETE_SUBSCRIPTION, new Object[] { subscription.getUrl() });
|
||||
|
@ -321,6 +338,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
Subscription subscription = new Subscription();
|
||||
subscription.setChannelName(cursor.getString(0));
|
||||
subscription.setUrl(cursor.getString(1));
|
||||
subscription.setNotificationsDisabled(cursor.getInt(2) == 1);
|
||||
subscriptions.add(subscription);
|
||||
}
|
||||
} finally {
|
||||
|
@ -372,6 +390,20 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
}
|
||||
return notifications;
|
||||
}
|
||||
public static void deleteNotifications(List<LbryNotification> notifications, SQLiteDatabase db) {
|
||||
StringBuilder sb = new StringBuilder("DELETE FROM notifications WHERE remote_id IN (");
|
||||
List<Object> 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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -52,7 +52,6 @@ public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
|
|||
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<Comment> children = new ArrayList<>();
|
||||
|
@ -78,7 +77,6 @@ public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
|
|||
}
|
||||
} catch (Exception ex) {
|
||||
error = ex;
|
||||
android.util.Log.d("LbryMain", ex.toString(), ex);
|
||||
}
|
||||
return comments;
|
||||
}
|
||||
|
|
|
@ -76,13 +76,15 @@ public class MergeSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
|
|||
// check for any remote subs that may have been removed, and unsubscribe from them
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
JSONObject item = array.getJSONObject(i);
|
||||
// TODO: Refactor by creating static Subscription.fromJSON method
|
||||
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);
|
||||
Subscription subscription = new Subscription(channelName, url.toString());
|
||||
Subscription subscription = new Subscription(channelName, url.toString(), isNotificationsDisabled);
|
||||
remoteSubs.add(subscription);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,11 +51,11 @@ public class ChannelSubscribeTask extends AsyncTask<Void, Void, Boolean> {
|
|||
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 {
|
||||
|
|
|
@ -49,11 +49,12 @@ public class FetchSubscriptionsTask extends AsyncTask<Void, Void, List<Subscript
|
|||
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);
|
||||
Subscription subscription = new Subscription(channelName, url.toString());
|
||||
Subscription subscription = new Subscription(channelName, url.toString(), isNotificationsDisabled);
|
||||
subscriptions.add(subscription);
|
||||
// Persist the subscription locally if it doesn't exist
|
||||
if (db != null) {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package io.lbry.browser.tasks.lbryinc;
|
||||
|
||||
import android.os.AsyncTask;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import io.lbry.browser.exceptions.LbryioRequestException;
|
||||
import io.lbry.browser.exceptions.LbryioResponseException;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import io.lbry.browser.utils.Lbryio;
|
||||
|
||||
public class NotificationDeleteTask extends AsyncTask<Void, Void, Boolean> {
|
||||
private List<Long> ids;
|
||||
|
||||
public NotificationDeleteTask(List<Long> ids) {
|
||||
this.ids = ids;
|
||||
}
|
||||
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
Map<String, String> 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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Reward> rewards) {
|
||||
synchronized (lock) {
|
||||
|
|
|
@ -71,13 +71,18 @@
|
|||
android:textSize="16sp"
|
||||
android:textAlignment="center" />
|
||||
</LinearLayout>
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/notifications_list"
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/notifications_list_swipe_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="8dp"
|
||||
android:clipToPadding="false"
|
||||
/>
|
||||
android:layout_height="match_parent">
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/notifications_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="8dp"
|
||||
android:clipToPadding="false"
|
||||
/>
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<include layout="@layout/floating_wallet_balance" />
|
||||
|
|
|
@ -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"/>
|
||||
</RelativeLayout>
|
||||
<RelativeLayout
|
||||
android:id="@+id/channel_view_subscribe_notify"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:visibility="gone">
|
||||
<io.lbry.browser.ui.controls.SolidIconView
|
||||
android:id="@+id/channel_view_icon_bell"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:text="@string/fa_bell_slash"
|
||||
android:textColor="@color/foreground"
|
||||
android:textSize="20dp"/>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
</LinearLayout>
|
||||
|
|
|
@ -503,7 +503,6 @@
|
|||
android:id="@+id/file_view_publisher_area"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/file_view_publisher_info_area"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
|
@ -513,7 +512,7 @@
|
|||
android:paddingTop="12dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingBottom="12dp"
|
||||
android:layout_toStartOf="@id/file_view_icon_follow">
|
||||
android:layout_toStartOf="@id/file_view_publisher_area_actions">
|
||||
<RelativeLayout
|
||||
android:id="@+id/file_view_publisher_avatar"
|
||||
android:layout_width="50dp"
|
||||
|
@ -570,33 +569,50 @@
|
|||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<io.lbry.browser.ui.controls.OutlineIconView
|
||||
android:id="@+id/file_view_icon_follow"
|
||||
android:clickable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_alignParentEnd="true"
|
||||
<LinearLayout
|
||||
android:id="@+id/file_view_publisher_area_actions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/fa_heart"
|
||||
android:textColor="@color/red"
|
||||
android:textSize="20dp" />
|
||||
android:layout_alignParentEnd="true">
|
||||
<io.lbry.browser.ui.controls.OutlineIconView
|
||||
android:id="@+id/file_view_icon_follow"
|
||||
android:clickable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/fa_heart"
|
||||
android:textColor="@color/red"
|
||||
android:textSize="20dp" />
|
||||
|
||||
<io.lbry.browser.ui.controls.SolidIconView
|
||||
android:id="@+id/file_view_icon_unfollow"
|
||||
android:clickable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/fa_heart_broken"
|
||||
android:textSize="20dp"
|
||||
android:visibility="invisible" />
|
||||
<io.lbry.browser.ui.controls.SolidIconView
|
||||
android:id="@+id/file_view_icon_unfollow"
|
||||
android:clickable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/fa_heart_broken"
|
||||
android:textColor="@color/foreground"
|
||||
android:textSize="20dp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<io.lbry.browser.ui.controls.SolidIconView
|
||||
android:id="@+id/file_view_icon_bell"
|
||||
android:clickable="true"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/fa_bell_slash"
|
||||
android:textColor="@color/foreground"
|
||||
android:textSize="20dp"
|
||||
android:visibility="gone"/>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<View
|
||||
|
|
|
@ -28,6 +28,20 @@
|
|||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:visibility="invisible" />
|
||||
<RelativeLayout
|
||||
android:layout_centerHorizontal="true"
|
||||
android:background="@drawable/bg_channel_overlay_icon"
|
||||
android:id="@+id/notification_selected_overlay"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:visibility="gone">
|
||||
<ImageView
|
||||
android:layout_width="36dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/ic_check"
|
||||
android:tint="@color/nextLbryGreen" />
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
|
|
10
app/src/main/res/menu/menu_notification.xml
Normal file
10
app/src/main/res/menu/menu_notification.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/action_delete"
|
||||
android:icon="@drawable/ic_delete"
|
||||
android:title="@string/delete"
|
||||
app:iconTint="@color/actionBarForeground"
|
||||
app:showAsAction="always" />
|
||||
</menu>
|
|
@ -117,6 +117,8 @@
|
|||
<string name="content">Content</string>
|
||||
<string name="website">Website</string>
|
||||
<string name="reposted">reposted</string>
|
||||
<string name="receive_all_notifications">You will receive all notifications</string>
|
||||
<string name="receive_no_notifications">You will not receive notifications for this channel</string>
|
||||
<plurals name="follower_count">
|
||||
<item quantity="one">%1$s follower</item>
|
||||
<item quantity="other">%1$s followers</item>
|
||||
|
@ -382,6 +384,7 @@
|
|||
<string name="channel_to_show_support_as">Channel to show support as</string>
|
||||
<string name="make_this_a_tip">Make this a tip</string>
|
||||
<string name="send_revocable_support">Send Revocable Support</string>
|
||||
<string name="send_lbc_tip">Tip %1$s</string>
|
||||
<plurals name="send_lbc_tip">
|
||||
<item quantity="one">Tip %1$s Credit</item>
|
||||
<item quantity="other">Tip %1$s Credits</item>
|
||||
|
@ -616,6 +619,10 @@
|
|||
|
||||
<!-- Notifications -->
|
||||
<string name="no_notifications">It\'s quiet here! New notifications will be displayed when you receive them.</string>
|
||||
<plurals name="confirm_delete_notifications">
|
||||
<item quantity="one">Are you sure you want to remove the selected notification?</item>
|
||||
<item quantity="other">Are you sure you want to remove the selected notifications?</item>
|
||||
</plurals>
|
||||
|
||||
<!-- Font Awesome -->
|
||||
<string name="fa_gift" translatable="false"></string>
|
||||
|
@ -645,4 +652,7 @@
|
|||
<string name="fa_comment_alt" translatable="false"></string>
|
||||
<string name="fa_broadcast_tower" translatable="false"></string>
|
||||
<string name="fa_random" translatable="false"></string>
|
||||
|
||||
<string name="fa_bell" translatable="false"></string>
|
||||
<string name="fa_bell_slash" translatable="false"></string>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue