diff --git a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java
index 9acc3d3f..af9dd988 100644
--- a/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java
+++ b/app/src/main/java/io/lbry/browser/LbrynetMessagingService.java
@@ -37,6 +37,7 @@ import java.util.List;
 import java.util.Map;
 
 public class LbrynetMessagingService extends FirebaseMessagingService {
+    public static final String ACTION_NOTIFICATION_RECEIVED = "io.lbry.browser.Broadcast.NotificationReceived";
 
     private static final String TAG = "LbrynetMessagingService";
     private static final String NOTIFICATION_CHANNEL_ID = "io.lbry.browser.LBRY_ENGAGEMENT_CHANNEL";
@@ -59,10 +60,6 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
             String title = payload.get("title");
             String body = payload.get("body");
             String name = payload.get("name"); // notification name
-            String contentTitle = payload.get("content_title");
-            String channelUrl = payload.get("channel_url");
-            //String publishTime = payload.get("publish_time");
-            String publishTime = null;
 
             if (type != null && getEnabledTypes().indexOf(type) > -1 && body != null && body.trim().length() > 0) {
                 // only log the receive event for valid notifications received
@@ -72,7 +69,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
                     firebaseAnalytics.logEvent(LbryAnalytics.EVENT_LBRY_NOTIFICATION_RECEIVE, bundle);
                 }
 
-                sendNotification(title, body, type, url, name, contentTitle, channelUrl, publishTime);
+                sendNotification(title, body, type, url, name);
             }
 
             // persist the notification data
@@ -85,6 +82,14 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
                 lnotification.setTargetUrl(url);
                 lnotification.setTimestamp(new Date());
                 DatabaseHelper.createNotification(lnotification, db);
+
+                // send a broadcast
+                Intent intent = new Intent(ACTION_NOTIFICATION_RECEIVED);
+                intent.putExtra("title", title);
+                intent.putExtra("body", body);
+                intent.putExtra("url", url);
+                intent.putExtra("timestamp", lnotification.getTimestamp().getTime());
+                sendBroadcast(intent);
             } catch (Exception ex) {
                 // don't fail if any error occurs while saving a notification
                 Log.e(TAG, "could not save notification", ex);
@@ -119,8 +124,7 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
      *
      * @param messageBody FCM message body received.
      */
-    private void sendNotification(String title, String messageBody, String type, String url, String name,
-                                  String contentTitle, String channelUrl, String publishTime) {
+    private void sendNotification(String title, String messageBody, String type, String url, String name) {
         //Intent intent = new Intent(this, MainActivity.class);
         //intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
         if (url == null) {
@@ -142,8 +146,8 @@ public class LbrynetMessagingService extends FirebaseMessagingService {
                 new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
                         .setColor(ContextCompat.getColor(this, R.color.lbryGreen))
                         .setSmallIcon(R.drawable.ic_lbry)
-                        .setContentTitle(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY))
-                        .setContentText(HtmlCompat.fromHtml(messageBody, HtmlCompat.FROM_HTML_MODE_LEGACY))
+                        .setContentTitle(title)
+                        .setContentText(messageBody)
                         .setAutoCancel(true)
                         .setSound(defaultSoundUri)
                         .setContentIntent(pendingIntent);
diff --git a/app/src/main/java/io/lbry/browser/MainActivity.java b/app/src/main/java/io/lbry/browser/MainActivity.java
index 9f2e82bd..9884fce3 100644
--- a/app/src/main/java/io/lbry/browser/MainActivity.java
+++ b/app/src/main/java/io/lbry/browser/MainActivity.java
@@ -114,6 +114,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 import io.lbry.browser.adapter.NavigationMenuAdapter;
+import io.lbry.browser.adapter.NotificationListAdapter;
 import io.lbry.browser.adapter.UrlSuggestionListAdapter;
 import io.lbry.browser.data.DatabaseHelper;
 import io.lbry.browser.dialog.ContentScopeDialogFragment;
@@ -136,6 +137,7 @@ import io.lbry.browser.model.Tag;
 import io.lbry.browser.model.UrlSuggestion;
 import io.lbry.browser.model.WalletBalance;
 import io.lbry.browser.model.WalletSync;
+import io.lbry.browser.model.lbryinc.LbryNotification;
 import io.lbry.browser.model.lbryinc.Reward;
 import io.lbry.browser.model.lbryinc.Subscription;
 import io.lbry.browser.tasks.GenericTaskHandler;
@@ -223,6 +225,8 @@ public class MainActivity extends AppCompatActivity implements SdkStatusListener
     @Getter
     private String firebaseMessagingToken;
 
+    private NotificationListAdapter notificationListAdapter;
+
     private Map<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
diff --git a/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java b/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java
new file mode 100644
index 00000000..958fd16f
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/adapter/NotificationListAdapter.java
@@ -0,0 +1,103 @@
+package io.lbry.browser.adapter;
+
+import android.content.Context;
+import android.text.format.DateUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.lbry.browser.R;
+import io.lbry.browser.model.lbryinc.LbryNotification;
+import io.lbry.browser.utils.Helper;
+import lombok.Getter;
+import lombok.Setter;
+
+public class NotificationListAdapter extends RecyclerView.Adapter<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);
+    }
+}
\ No newline at end of file
diff --git a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java
index 88f243d0..c3599e40 100644
--- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java
+++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java
@@ -54,6 +54,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
                     ", description TEXT" +
                     ", thumbnail_url TEXT" +
                     ", target_url TEXT" +
+                    ", is_read INTEGER DEFAULT 0 NOT NULL" +
                     ", timestamp TEXT NOT NULL)",
     };
     private static final String[] SQL_CREATE_INDEXES = {
@@ -77,6 +78,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
                     ", description TEXT" +
                     ", thumbnail_url TEXT" +
                     ", target_url TEXT" +
+                    ", is_read INTEGER DEFAULT 0 NOT NULL" +
                     ", timestamp TEXT NOT NULL)",
             "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)"
     };
@@ -93,6 +95,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
 
     private static final String SQL_INSERT_NOTIFICATION = "INSERT INTO notifications (title, description, target_url, timestamp) VALUES (?, ?, ?, ?)";
     private static final String SQL_GET_NOTIFICATIONS = "SELECT id, title, description, target_url, timestamp FROM notifications ORDER BY timestamp DESC LIMIT 500";
+    private static final String SQL_GET_UNREAD_NOTIFICATIONS_COUNT = "SELECT COUNT(id) FROM notifications WHERE is_read <> 1";
+    private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0";
 
     private static final String SQL_INSERT_VIEW_HISTORY =
             "REPLACE INTO view_history (url, claim_id, claim_name, cost, currency, title, publisher_claim_id, publisher_name, publisher_title, thumbnail_url, device, release_time, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
@@ -302,10 +306,27 @@ public class DatabaseHelper extends SQLiteOpenHelper {
                     // invalid timestamp (which shouldn't happen). Skip this item
                     continue;
                 }
+                notifications.add(notification);
             }
         } finally {
             Helper.closeCursor(cursor);
         }
         return notifications;
     }
+    public static int getUnreadNotificationsCount(SQLiteDatabase db) {
+        int count = 0;
+        Cursor cursor = null;
+        try {
+            cursor = db.rawQuery(SQL_GET_UNREAD_NOTIFICATIONS_COUNT, null);
+            if (cursor.moveToNext()) {
+                count = cursor.getInt(0);
+            }
+        } finally {
+            Helper.closeCursor(cursor);
+        }
+        return count;
+    }
+    public static void markNotificationsRead(SQLiteDatabase db) {
+        db.execSQL(SQL_MARK_NOTIFICATIONS_READ);
+    }
 }
diff --git a/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java
index 9e5be8a7..87e8791c 100644
--- a/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java
+++ b/app/src/main/java/io/lbry/browser/model/lbryinc/LbryNotification.java
@@ -11,5 +11,6 @@ public class LbryNotification {
     private String description;
     private String thumbnailUrl;
     private String targetUrl;
+    private boolean read;
     private Date timestamp;
 }
diff --git a/app/src/main/res/drawable/bg_notification_badge.xml b/app/src/main/res/drawable/bg_notification_badge.xml
new file mode 100644
index 00000000..3af51c12
--- /dev/null
+++ b/app/src/main/res/drawable/bg_notification_badge.xml
@@ -0,0 +1,6 @@
+<?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>
\ No newline at end of file
diff --git a/app/src/main/res/layout/app_bar_main.xml b/app/src/main/res/layout/app_bar_main.xml
index f1680941..6777cd17 100644
--- a/app/src/main/res/layout/app_bar_main.xml
+++ b/app/src/main/res/layout/app_bar_main.xml
@@ -28,17 +28,18 @@
                 android:focusable="true"
                 android:focusableInTouchMode="true"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_marginRight="24dp">
+                android:layout_height="wrap_content">
                 <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>
diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml
index aebb1020..3e729743 100644
--- a/app/src/main/res/layout/content_main.xml
+++ b/app/src/main/res/layout/content_main.xml
@@ -41,6 +41,12 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:visibility="gone">
+        <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"
diff --git a/app/src/main/res/layout/list_item_notification.xml b/app/src/main/res/layout/list_item_notification.xml
new file mode 100644
index 00000000..7f7df9ca
--- /dev/null
+++ b/app/src/main/res/layout/list_item_notification.xml
@@ -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>
\ No newline at end of file