Refresh notification list. Add is_read flag and display unread count.
This commit is contained in:
parent
9af6b74934
commit
185526eb29
9 changed files with 328 additions and 16 deletions
|
@ -37,6 +37,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
public class LbrynetMessagingService extends FirebaseMessagingService {
|
||||
public static final String ACTION_NOTIFICATION_RECEIVED = "io.lbry.browser.Broadcast.NotificationReceived";
|
||||
|
||||
private static final String TAG = "LbrynetMessagingService";
|
||||
private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
|
||||
|
@ -59,10 +60,6 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
String title = payload.get("title");
|
||||
String body = payload.get("body");
|
||||
String name = payload.get("name"); // notification name
|
||||
String contentTitle = payload.get("content_title");
|
||||
String channelUrl = payload.get("channel_url");
|
||||
//String publishTime = payload.get("publish_time");
|
||||
String publishTime = null;
|
||||
|
||||
if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) {
|
||||
// only log the receive event for valid notifications received
|
||||
|
@ -72,7 +69,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
|
||||
}
|
||||
|
||||
sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime);
|
||||
sendNotification(title, body, type, url, name);
|
||||
}
|
||||
|
||||
// persist the notification data
|
||||
|
@ -85,6 +82,14 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
lnotification.setTargetUrl(url);
|
||||
lnotification.setTimestamp(new Date());
|
||||
DatabaseHelper.createNotification(lnotification, db);
|
||||
|
||||
// send a broadcast
|
||||
Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED);
|
||||
intent.putExtra("title", title);
|
||||
intent.putExtra("body", body);
|
||||
intent.putExtra("url", url);
|
||||
intent.putExtra("timestamp", lnotification.getTimestamp().getTime());
|
||||
sendBroadcast(intent);
|
||||
} catch (Exception ex) {
|
||||
// don't fail if any error occurs while saving a notification
|
||||
Log.e(TAG, "could not save notification", ex);
|
||||
|
@ -119,8 +124,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
*
|
||||
* @param messageBody FCM message body received.
|
||||
*/
|
||||
private void sendNotification(String title, String messageBody, String type, String url, String name,
|
||||
String contentTitle, String channelUrl, String publishTime) {
|
||||
private void sendNotification(String title, String messageBody, String type, String url, String name) {
|
||||
//Intent intent = new Intent(this, MainActivity.class);
|
||||
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
if (url == null) {
|
||||
|
@ -142,8 +146,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
|
|||
new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
|
||||
.setColor(ContextCompat.getColor(this, R.color.lbryGreen))
|
||||
.setSmallIcon(R.drawable.ic_lbry)
|
||||
.setContentTitle(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY))
|
||||
.setContentText(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY))
|
||||
.setContentTitle(title)
|
||||
.setContentText(messageBody)
|
||||
.setAutoCancel(true)
|
||||
.setSound(defaultSoundUri)
|
||||
.setContentIntent(pendingIntent);
|
||||
|
|
|
@ -114,6 +114,7 @@ import java.util.logging.Level;
|
|||
import java.util.logging.Logger;
|
||||
|
||||
import io.lbry.browser.adapter.NavigationMenuAdapter;
|
||||
import io.lbry.browser.adapter.NotificationListAdapter;
|
||||
import io.lbry.browser.adapter.UrlSuggestionListAdapter;
|
||||
import io.lbry.browser.data.DatabaseHelper;
|
||||
import io.lbry.browser.dialog.ContentScopeDialogFragment;
|
||||
|
@ -136,6 +137,7 @@ import io.lbry.browser.model.Tag;
|
|||
import io.lbry.browser.model.UrlSuggestion;
|
||||
import io.lbry.browser.model.WalletBalance;
|
||||
import io.lbry.browser.model.WalletSync;
|
||||
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||
import io.lbry.browser.model.lbryinc.Reward;
|
||||
import io.lbry.browser.model.lbryinc.Subscription;
|
||||
import io.lbry.browser.tasks.GenericTaskHandler;
|
||||
|
@ -223,6 +225,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
@Getter
|
||||
private String firebaseMessagingToken;
|
||||
|
||||
private NotificationListAdapter notificationListAdapter;
|
||||
|
||||
private Map<String, Fragment> openNavFragments;
|
||||
private static final Map<Class, Integer> fragmentClassNavIdMap = new HashMap<>();
|
||||
static {
|
||||
|
@ -439,6 +443,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
// setup uri bar
|
||||
setupUriBar();
|
||||
initNotificationsPage();
|
||||
loadUnreadNotificationsCount();
|
||||
|
||||
// other
|
||||
pendingSyncSetQueue = new ArrayList<>();
|
||||
|
@ -519,6 +524,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
@Override
|
||||
public void onClick(View view) {
|
||||
if (nowPlayingClaim != null && !Helper.isNullOrEmpty(nowPlayingClaimUrl)) {
|
||||
hideNotifications();
|
||||
openFileUrl(nowPlayingClaimUrl);
|
||||
}
|
||||
}
|
||||
|
@ -728,8 +734,9 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
}
|
||||
|
||||
private void openSelectedMenuItem() {
|
||||
hideNotifications();
|
||||
|
||||
switch (selectedMenuItemId) {
|
||||
// TODO: reverse map lookup for class?
|
||||
case NavMenuItem.ID_ITEM_FOLLOWING:
|
||||
openFragment(FollowingFragment.class, true, NavMenuItem.ID_ITEM_FOLLOWING);
|
||||
break;
|
||||
|
@ -1648,6 +1655,10 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
|
||||
public void initNotificationsPage() {
|
||||
findViewById(R.id.notification_list_empty_container).setVisibility(View.VISIBLE);
|
||||
|
||||
RecyclerView notificationsList = findViewById(R.id.notifications_list);
|
||||
LinearLayoutManager llm = new LinearLayoutManager(this);
|
||||
notificationsList.setLayoutManager(llm);
|
||||
}
|
||||
|
||||
public void initPlaybackNotification() {
|
||||
|
@ -2020,6 +2031,7 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
intentFilter.addAction(ACTION_OPEN_REWARDS_PAGE);
|
||||
intentFilter.addAction(ACTION_PUBLISH_SUCCESSFUL);
|
||||
intentFilter.addAction(ACTION_SAVE_SHARED_USER_STATE);
|
||||
intentFilter.addAction(LbrynetMessagingService.ACTION_NOTIFICATION_RECEIVED);
|
||||
requestsReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
|
@ -2040,6 +2052,25 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
saveSharedUserState();
|
||||
} else if (ACTION_PUBLISH_SUCCESSFUL.equalsIgnoreCase(action)) {
|
||||
openPublishesOnSuccessfulPublish();
|
||||
} else if (LbrynetMessagingService.ACTION_NOTIFICATION_RECEIVED.equalsIgnoreCase(action)) {
|
||||
handleNotificationReceived(intent);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleNotificationReceived(Intent intent) {
|
||||
loadUnreadNotificationsCount();
|
||||
|
||||
if (notificationListAdapter != null) {
|
||||
LbryNotification lnotification = new LbryNotification();
|
||||
lnotification.setTitle(intent.getStringExtra("title"));
|
||||
lnotification.setDescription(intent.getStringExtra("body"));
|
||||
lnotification.setTargetUrl(intent.getStringExtra("url"));
|
||||
lnotification.setTimestamp(new Date(intent.getLongExtra("timestamp", System.currentTimeMillis())));
|
||||
// show at the top
|
||||
notificationListAdapter.insertNotification(lnotification, 0);
|
||||
findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE);
|
||||
} else {
|
||||
loadNotifications();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2088,12 +2119,35 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
public void showNotifications() {
|
||||
clearWunderbarFocus(findViewById(R.id.wunderbar));
|
||||
findViewById(R.id.notifications_container).setVisibility(View.VISIBLE);
|
||||
((ImageView) findViewById(R.id.notifications_toggle_icon)).setColorFilter(ContextCompat.getColor(this, R.color.lbryGreen));
|
||||
if (notificationListAdapter == null) {
|
||||
loadNotifications();
|
||||
}
|
||||
markNotificationsRead();
|
||||
}
|
||||
|
||||
public void hideNotifications() {
|
||||
((ImageView) findViewById(R.id.notifications_toggle_icon)).setColorFilter(ContextCompat.getColor(this, R.color.actionBarForeground));
|
||||
findViewById(R.id.notifications_container).setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
private void markNotificationsRead() {
|
||||
(new AsyncTask<Void, Void, Void>() {
|
||||
protected Void doInBackground(Void... params) {
|
||||
try {
|
||||
SQLiteDatabase db = dbHelper.getWritableDatabase();
|
||||
DatabaseHelper.markNotificationsRead(db);
|
||||
} catch (Exception ex) {
|
||||
// pass
|
||||
}
|
||||
return null;
|
||||
}
|
||||
protected void onPostExecute(Void result) {
|
||||
loadUnreadNotificationsCount();
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (findViewById(R.id.url_suggestions_container).getVisibility() == View.VISIBLE) {
|
||||
|
@ -3064,6 +3118,72 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
|
|||
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void displayUnreadNotificationCount(int count) {
|
||||
String text = count > 99 ? "99+" : String.valueOf(count);
|
||||
|
||||
TextView badge = findViewById(R.id.notifications_badge_count);
|
||||
badge.setVisibility(count > 0 ? View.VISIBLE : View.INVISIBLE);
|
||||
badge.setText(text);
|
||||
}
|
||||
|
||||
private void loadUnreadNotificationsCount() {
|
||||
(new AsyncTask<Void, Void, Integer>() {
|
||||
@Override
|
||||
protected Integer doInBackground(Void... params) {
|
||||
try {
|
||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||
return DatabaseHelper.getUnreadNotificationsCount(db);
|
||||
} catch (Exception ex) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
protected void onPostExecute(Integer count) {
|
||||
displayUnreadNotificationCount(count);
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void loadNotifications() {
|
||||
(new AsyncTask<Void, Void, List<LbryNotification>>() {
|
||||
protected void onPreExecute() {
|
||||
findViewById(R.id.notification_list_empty_container).setVisibility(View.GONE);
|
||||
findViewById(R.id.notifications_progress).setVisibility(View.VISIBLE);
|
||||
}
|
||||
@Override
|
||||
protected List<LbryNotification> doInBackground(Void... params) {
|
||||
List<LbryNotification> notifications = new ArrayList<>();
|
||||
try {
|
||||
SQLiteDatabase db = dbHelper.getReadableDatabase();
|
||||
notifications = DatabaseHelper.getNotifications(db);
|
||||
} catch (Exception ex) {
|
||||
// pass
|
||||
}
|
||||
return notifications;
|
||||
}
|
||||
protected void onPostExecute(List<LbryNotification> notifications) {
|
||||
findViewById(R.id.notification_list_empty_container).setVisibility(notifications.size() == 0 ? View.VISIBLE : View.GONE);
|
||||
findViewById(R.id.notifications_progress).setVisibility(View.GONE);
|
||||
notificationListAdapter = new NotificationListAdapter(notifications, MainActivity.this);
|
||||
notificationListAdapter.setClickListener(new NotificationListAdapter.NotificationClickListener() {
|
||||
@Override
|
||||
public void onNotificationClicked(LbryNotification notification) {
|
||||
LbryUri target = LbryUri.tryParse(notification.getTargetUrl());
|
||||
if (target != null) {
|
||||
hideNotifications();
|
||||
if (target.isChannel()) {
|
||||
openChannelUrl(target.toString());
|
||||
} else {
|
||||
openFileUrl(target.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
((RecyclerView) findViewById(R.id.notifications_list)).setAdapter(notificationListAdapter);
|
||||
}
|
||||
}).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
private void checkSyncedWallet() {
|
||||
String password = Utils.getSecureValue(SECURE_VALUE_KEY_SAVED_PASSWORD, this, Lbry.KEYSTORE);
|
||||
// Just check if the current user has a synced wallet, no need to do anything else here
|
||||
|
|
|
@ -0,0 +1,103 @@
|
|||
package io.lbry.browser.adapter;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import io.lbry.browser.R;
|
||||
import io.lbry.browser.model.lbryinc.LbryNotification;
|
||||
import io.lbry.browser.utils.Helper;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
public class NotificationListAdapter extends RecyclerView.Adapter<NotificationListAdapter.ViewHolder> {
|
||||
|
||||
private Context context;
|
||||
private List<LbryNotification> items;
|
||||
@Setter
|
||||
private NotificationClickListener clickListener;
|
||||
@Getter
|
||||
@Setter
|
||||
private int customizeMode;
|
||||
|
||||
public NotificationListAdapter(List<LbryNotification> notifications, Context context) {
|
||||
this.context = context;
|
||||
this.items = new ArrayList<>(notifications);
|
||||
}
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
protected TextView titleView;
|
||||
protected TextView bodyView;
|
||||
protected TextView timeView;
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
titleView = v.findViewById(R.id.notification_title);
|
||||
bodyView = v.findViewById(R.id.notification_body);
|
||||
timeView = v.findViewById(R.id.notification_time);
|
||||
}
|
||||
}
|
||||
|
||||
public int getItemCount() {
|
||||
return items != null ? items.size() : 0;
|
||||
}
|
||||
|
||||
public void insertNotification(LbryNotification notification, int index) {
|
||||
if (!items.contains(notification)) {
|
||||
items.add(index, notification);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addNotification(LbryNotification notification) {
|
||||
if (!items.contains(notification)) {
|
||||
items.add(notification);
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addTags(List<LbryNotification> notifications) {
|
||||
for (LbryNotification notification : notifications) {
|
||||
if (!items.contains(notification)) {
|
||||
items.add(notification);
|
||||
}
|
||||
}
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
@Override
|
||||
public NotificationListAdapter.ViewHolder onCreateViewHolder(ViewGroup root, int viewType) {
|
||||
View v = LayoutInflater.from(context).inflate(R.layout.list_item_notification, root, false);
|
||||
return new NotificationListAdapter.ViewHolder(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(NotificationListAdapter.ViewHolder vh, int position) {
|
||||
LbryNotification notification = items.get(position);
|
||||
vh.titleView.setText(notification.getTitle());
|
||||
vh.titleView.setVisibility(!Helper.isNullOrEmpty(notification.getTitle()) ? View.VISIBLE : View.GONE);
|
||||
vh.bodyView.setText(notification.getDescription());
|
||||
vh.timeView.setText(DateUtils.getRelativeTimeSpanString(
|
||||
notification.getTimestamp().getTime(),
|
||||
System.currentTimeMillis(), 0, DateUtils.FORMAT_ABBREV_RELATIVE));
|
||||
|
||||
vh.itemView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
if (clickListener != null) {
|
||||
clickListener.onNotificationClicked(notification);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public interface NotificationClickListener {
|
||||
void onNotificationClicked(LbryNotification notification);
|
||||
}
|
||||
}
|
|
@ -54,6 +54,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
", description TEXT" +
|
||||
", thumbnail_url TEXT" +
|
||||
", target_url TEXT" +
|
||||
", is_read INTEGER DEFAULT 0 NOT NULL" +
|
||||
", timestamp TEXT NOT NULL)",
|
||||
};
|
||||
private static final String[] SQL_CREATE_INDEXES = {
|
||||
|
@ -77,6 +78,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
", description TEXT" +
|
||||
", thumbnail_url TEXT" +
|
||||
", target_url TEXT" +
|
||||
", is_read INTEGER DEFAULT 0 NOT NULL" +
|
||||
", timestamp TEXT NOT NULL)",
|
||||
"CREATE INDEX idx_notification_timestamp ON notifications (timestamp)"
|
||||
};
|
||||
|
@ -93,6 +95,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
|
||||
private static final String SQL_INSERT_NOTIFICATION = "INSERT INTO notifications (title, description, target_url, timestamp) VALUES (?, ?, ?, ?)";
|
||||
private static final String SQL_GET_NOTIFICATIONS = "SELECT id, title, description, target_url, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500";
|
||||
private static final String SQL_GET_UNREAD_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_read <> 1";
|
||||
private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0";
|
||||
|
||||
private static final String SQL_INSERT_VIEW_HISTORY =
|
||||
"REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
@ -302,10 +306,27 @@ public class DatabaseHelper extends SQLiteOpenHelper {
|
|||
// invalid timestamp (which shouldn't happen). Skip this item
|
||||
continue;
|
||||
}
|
||||
notifications.add(notification);
|
||||
}
|
||||
} finally {
|
||||
Helper.closeCursor(cursor);
|
||||
}
|
||||
return notifications;
|
||||
}
|
||||
public static int getUnreadNotificationsCount(SQLiteDatabase db) {
|
||||
int count = 0;
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
cursor = db.rawQuery(SQL_GET_UNREAD_NOTIFICATIONS_COUNT, null);
|
||||
if (cursor.moveToNext()) {
|
||||
count = cursor.getInt(0);
|
||||
}
|
||||
} finally {
|
||||
Helper.closeCursor(cursor);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
public static void markNotificationsRead(SQLiteDatabase db) {
|
||||
db.execSQL(SQL_MARK_NOTIFICATIONS_READ);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,5 +11,6 @@ public class LbryNotification {
|
|||
private String description;
|
||||
private String thumbnailUrl;
|
||||
private String targetUrl;
|
||||
private boolean read;
|
||||
private Date timestamp;
|
||||
}
|
||||
|
|
6
app/src/main/res/drawable/bg_notification_badge.xml
Normal file
6
app/src/main/res/drawable/bg_notification_badge.xml
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/red" />
|
||||
<corners android:radius="16dp" />
|
||||
</shape>
|
|
@ -28,17 +28,18 @@
|
|||
android:focusable="true"
|
||||
android:focusableInTouchMode="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="24dp">
|
||||
android:layout_height="wrap_content">
|
||||
<EditText
|
||||
android:id="@+id/wunderbar"
|
||||
android:background="@android:color/transparent"
|
||||
android:layout_centerVertical="true"
|
||||
android:drawableLeft="@drawable/ic_search"
|
||||
android:drawablePadding="8dp"
|
||||
android:drawableTint="@color/actionBarForeground"
|
||||
android:fontFamily="@font/inter"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="24dp"
|
||||
android:hint="@string/uri_placeholder"
|
||||
android:imeOptions="actionGo"
|
||||
android:inputType="textNoSuggestions"
|
||||
|
@ -53,6 +54,7 @@
|
|||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="24dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:visibility="gone">
|
||||
|
@ -63,19 +65,38 @@
|
|||
android:tint="@color/actionBarForeground" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
<RelativeLayout
|
||||
android:id="@+id/wunderbar_notifications"
|
||||
android:clickable="true"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true">
|
||||
<ImageView
|
||||
android:id="@+id/notifications_toggle_icon"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_centerInParent="true"
|
||||
android:src="@drawable/ic_notifications"
|
||||
android:tint="@color/actionBarForeground" />
|
||||
</LinearLayout>
|
||||
<TextView
|
||||
android:id="@+id/notifications_badge_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/bg_notification_badge"
|
||||
android:fontFamily="@font/inter"
|
||||
android:gravity="center_horizontal"
|
||||
android:minWidth="12dp"
|
||||
android:paddingLeft="2dp"
|
||||
android:paddingRight="2dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:textColor="@color/white"
|
||||
android:textSize="10sp"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
</RelativeLayout>
|
||||
</androidx.appcompat.widget.Toolbar>
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
|
|
@ -41,6 +41,12 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone">
|
||||
<ProgressBar
|
||||
android:id="@+id/notifications_progress"
|
||||
android:layout_centerInParent="true"
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:visibility="gone" />
|
||||
<LinearLayout
|
||||
android:id="@+id/notification_list_empty_container"
|
||||
android:orientation="vertical"
|
||||
|
|
30
app/src/main/res/layout/list_item_notification.xml
Normal file
30
app/src/main/res/layout/list_item_notification.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp">
|
||||
<TextView
|
||||
android:id="@+id/notification_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="2dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textStyle="bold"
|
||||
android:textSize="13sp" />
|
||||
<TextView
|
||||
android:id="@+id/notification_body"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="14sp" />
|
||||
<TextView
|
||||
android:id="@+id/notification_time"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:fontFamily="@font/inter"
|
||||
android:textSize="11sp" />
|
||||
</LinearLayout>
|
Loading…
Reference in a new issue