From eeca602f7a1de40d8e31ca040549ffcc0e96fbcc Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Wed, 23 Sep 2020 15:31:34 +0100
Subject: [PATCH 1/5] keep track of watched content for subsequent shuffle
 sessions

---
 .../io/lbry/browser/data/DatabaseHelper.java  | 35 ++++++++-
 .../ui/findcontent/ShuffleFragment.java       | 78 ++++++++++++++++++-
 2 files changed, 107 insertions(+), 6 deletions(-)

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 bc4d43ce..9aece297 100644
--- a/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java
+++ b/app/src/main/java/io/lbry/browser/data/DatabaseHelper.java
@@ -21,7 +21,7 @@ import io.lbry.browser.utils.Helper;
 import io.lbry.browser.utils.LbryUri;
 
 public class DatabaseHelper extends SQLiteOpenHelper {
-    public static final int DATABASE_VERSION = 6;
+    public static final int DATABASE_VERSION = 7;
     public static final String DATABASE_NAME = "LbryApp.db";
     private static DatabaseHelper instance;
 
@@ -60,6 +60,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
                     ", is_read INTEGER DEFAULT 0 NOT NULL" +
                     ", is_seen INTEGER DEFAULT 0 NOT NULL " +
                     ", timestamp TEXT NOT NULL)",
+            "CREATE TABLE shuffle_watched (id INTEGER PRIMARY KEY NOT NULL, claim_id TEXT NOT NULL)"
     };
     private static final String[] SQL_CREATE_INDEXES = {
             "CREATE UNIQUE INDEX idx_subscription_url ON subscriptions (url)",
@@ -69,7 +70,8 @@ public class DatabaseHelper extends SQLiteOpenHelper {
             "CREATE UNIQUE INDEX idx_view_history_url_device ON view_history (url, device)",
             "CREATE INDEX idx_view_history_device ON view_history (device)",
             "CREATE UNIQUE INDEX idx_notification_remote_id ON notifications (remote_id)",
-            "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)"
+            "CREATE INDEX idx_notification_timestamp ON notifications (timestamp)",
+            "CREATE UNIQUE INDEX idx_shuffle_watched_claim ON shuffle_watched (claim_id)",
     };
 
     private static final String[] SQL_V1_V2_UPGRADE = {
@@ -99,6 +101,10 @@ public class DatabaseHelper extends SQLiteOpenHelper {
     private static final String[] SQL_V5_V6_UPGRADE = {
             "ALTER TABLE notifications ADD COLUMN author_url TEXT"
     };
+    private static final String[] SQL_V6_V7_UPGRADE = {
+            "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_INSERT_SUBSCRIPTION = "REPLACE INTO subscriptions (channel_name, url) VALUES (?, ?)";
     private static final String SQL_CLEAR_SUBSCRIPTIONS = "DELETE FROM subscriptions";
@@ -116,6 +122,9 @@ public class DatabaseHelper extends SQLiteOpenHelper {
     private static final String SQL_MARK_NOTIFICATIONS_READ = "UPDATE notifications SET is_read = 1 WHERE is_read = 0";
     private static final String SQL_MARK_NOTIFICATION_READ_AND_SEEN = "UPDATE notifications SET is_read = 1, is_seen = 1 WHERE id = ?";
 
+    private static final String SQL_INSERT_SHUFFLE_WATCHED = "REPLACE INTO shuffle_watched (claim_id) VALUES (?)";
+    private static final String SQL_GET_SHUFFLE_WATCHED_CLAIMS = "SELECT claim_id FROM shuffle_watched";
+
     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 (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
     private static final String SQL_GET_VIEW_HISTORY =
@@ -174,6 +183,11 @@ public class DatabaseHelper extends SQLiteOpenHelper {
                 db.execSQL(sql);
             }
         }
+        if (oldVersion < 7) {
+            for (String sql : SQL_V6_V7_UPGRADE) {
+                db.execSQL(sql);
+            }
+        }
     }
     public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
 
@@ -190,6 +204,7 @@ public class DatabaseHelper extends SQLiteOpenHelper {
     public static void clearUrlHistoryBefore(Date date, SQLiteDatabase db) {
         db.execSQL(SQL_CLEAR_URL_HISTORY_BEFORE_TIME, new Object[] { new SimpleDateFormat(Helper.ISO_DATE_FORMAT_PATTERN).format(new Date()) });
     }
+
     // History items are essentially url suggestions
     public static List<UrlSuggestion> getRecentHistory(SQLiteDatabase db) {
         List<UrlSuggestion> suggestions = new ArrayList<>();
@@ -376,4 +391,20 @@ public class DatabaseHelper extends SQLiteOpenHelper {
     public static void markNotificationReadAndSeen(long notificationId, SQLiteDatabase db) {
         db.execSQL(SQL_MARK_NOTIFICATION_READ_AND_SEEN, new Object[] { notificationId });
     }
+    public static void createOrUpdateShuffleWatched(String claimId, SQLiteDatabase db) {
+        db.execSQL(SQL_INSERT_SHUFFLE_WATCHED, new Object[] { claimId });
+    }
+    public static List<String> getShuffleWatchedClaims(SQLiteDatabase db) {
+        List<String> claimIds = new ArrayList<>();
+        Cursor cursor = null;
+        try {
+            cursor = db.rawQuery(SQL_GET_SHUFFLE_WATCHED_CLAIMS, null);
+            while (cursor.moveToNext()) {
+                claimIds.add(cursor.getString(0));
+            }
+        } finally {
+            Helper.closeCursor(cursor);
+        }
+        return claimIds;
+    }
 }
diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java
index eb6ed675..115bd6f1 100644
--- a/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java
@@ -3,6 +3,7 @@ package io.lbry.browser.ui.findcontent;
 import android.content.Context;
 import android.content.Intent;
 import android.content.SharedPreferences;
+import android.database.sqlite.SQLiteDatabase;
 import android.graphics.Color;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -45,6 +46,7 @@ import java.util.concurrent.TimeUnit;
 
 import io.lbry.browser.MainActivity;
 import io.lbry.browser.R;
+import io.lbry.browser.data.DatabaseHelper;
 import io.lbry.browser.exceptions.LbryUriException;
 import io.lbry.browser.model.Claim;
 import io.lbry.browser.model.lbryinc.Reward;
@@ -70,6 +72,7 @@ public class ShuffleFragment extends BaseFragment {
     private int playlistIndex;
     private Claim current;
     private List<Claim> playlist;
+    private List<String> watchedContentClaimIds;
 
     private long sessionStart;
     private ProgressBar surfModeLoading;
@@ -104,6 +107,10 @@ public class ShuffleFragment extends BaseFragment {
                         logPlay(currentUrl, startTimeMillis);
                         playbackStarted = true;
                         isPlaying = true;
+
+                        if (current != null) {
+                            saveWatchedContent(current.getClaimId());
+                        }
                     }
 
                     renderTotalDuration();
@@ -227,13 +234,14 @@ public class ShuffleFragment extends BaseFragment {
         }
 
         if (playlist == null) {
-            loadContent();
+            loadWatchedContentList();
         } else {
             if (current != null) {
                 playbackCurrentClaim();
             } else {
                 startPlaylist();
             }
+            loadAndScheduleDurations();
         }
     }
 
@@ -264,6 +272,46 @@ public class ShuffleFragment extends BaseFragment {
 
     }
 
+    private void loadWatchedContentList() {
+        (new AsyncTask<Void, Void, List<String>>() {
+            protected List<String> doInBackground(Void... params) {
+                MainActivity activity = (MainActivity) getContext();
+                if (activity != null) {
+                    try {
+                        SQLiteDatabase db = activity.getDbHelper().getReadableDatabase();
+                        return DatabaseHelper.getShuffleWatchedClaims(db);
+                    } catch (Exception ex) {
+                        // pass
+                    }
+                }
+                return null;
+            }
+            protected void onPostExecute(List<String> claimIds) {
+                watchedContentClaimIds = new ArrayList<>(claimIds);
+                if (playlist == null) {
+                    loadContent();
+                }
+            }
+        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
+    private void saveWatchedContent(final String claimId) {
+        (new AsyncTask<Void, Void, Void>() {
+            protected Void doInBackground(Void... params) {
+                MainActivity activity = (MainActivity) getContext();
+                if (activity != null) {
+                    try {
+                        SQLiteDatabase db = activity.getDbHelper().getWritableDatabase();
+                        DatabaseHelper.createOrUpdateShuffleWatched(claimId, db);
+                    } catch (Exception ex) {
+                        // pass
+                    }
+                }
+                return  null;
+            }
+        }).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+    }
+
     private void loadContent() {
         if (playlist == null || playlist.size() == 0) {
             Helper.setViewVisibility(surfModeLoading, View.VISIBLE);
@@ -301,6 +349,7 @@ public class ShuffleFragment extends BaseFragment {
         playlistIndex = 0;
         current = playlist.get(playlistIndex);
         checkCurrentClaimIsVideo(false);
+        checkCurrentClaimWatched(false);
         playbackCurrentClaim();
     }
 
@@ -311,11 +360,26 @@ public class ShuffleFragment extends BaseFragment {
                 playlistIndex--;
             } else {
                 playlistIndex++;
+                checkPlaylistSize();
             }
             current = playlist.get(playlistIndex);
         }
     }
 
+    private void checkCurrentClaimWatched(boolean previous) {
+        if (current != null && watchedContentClaimIds != null) {
+            while (watchedContentClaimIds.contains(current.getClaimId())) {
+                if (previous) {
+                    playlistIndex--;
+                } else {
+                    playlistIndex++;
+                    checkPlaylistSize();
+                }
+                current = playlist.get(playlistIndex);
+            }
+        }
+    }
+
     private void playPreviousClaim() {
         if (playlist == null || playlist.size() == 0) {
             return;
@@ -325,6 +389,7 @@ public class ShuffleFragment extends BaseFragment {
         }
         current = playlist.get(playlistIndex);
         checkCurrentClaimIsVideo(true);
+        checkCurrentClaimWatched(true);
         playbackCurrentClaim();
     }
     private void playNextClaim() {
@@ -334,13 +399,18 @@ public class ShuffleFragment extends BaseFragment {
         if (playlistIndex < playlist.size() - 1) {
             playlistIndex++;
         }
+        checkPlaylistSize();
+        current = playlist.get(playlistIndex);
+        checkCurrentClaimIsVideo(false);
+        checkCurrentClaimWatched(false);
+        playbackCurrentClaim();
+    }
+
+    private void checkPlaylistSize() {
         if (playlist.size() - playlistIndex < 10) {
             currentClaimSearchPage++;
             loadContent();
         }
-        current = playlist.get(playlistIndex);
-        checkCurrentClaimIsVideo(false);
-        playbackCurrentClaim();
     }
 
     private void playbackCurrentClaim() {

From 991a98b571d7dc4dd1a0a67cfdeaa6a0a6621dd9 Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Wed, 23 Sep 2020 16:35:59 +0100
Subject: [PATCH 2/5] fix shuffle mode player getting stuck

---
 .../ui/findcontent/ShuffleFragment.java       | 21 +++++++++++++++++--
 1 file changed, 19 insertions(+), 2 deletions(-)

diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java
index 115bd6f1..27ce3766 100644
--- a/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/findcontent/ShuffleFragment.java
@@ -21,6 +21,7 @@ import androidx.annotation.NonNull;
 import androidx.preference.PreferenceManager;
 
 import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.PlaybackParameters;
 import com.google.android.exoplayer2.Player;
 import com.google.android.exoplayer2.SimpleExoPlayer;
 import com.google.android.exoplayer2.audio.AudioAttributes;
@@ -243,6 +244,23 @@ public class ShuffleFragment extends BaseFragment {
             }
             loadAndScheduleDurations();
         }
+
+        if (MainActivity.appPlayer != null) {
+            if (MainActivity.playerReassigned) {
+                setPlayerForPlayerView();
+                MainActivity.playerReassigned = false;
+            }
+        }
+    }
+
+    private void setPlayerForPlayerView() {
+        View root = getView();
+        if (root != null) {
+            PlayerView view = root.findViewById(R.id.shuffle_exoplayer_view);
+            view.setVisibility(View.VISIBLE);
+            view.setPlayer(null);
+            view.setPlayer(MainActivity.appPlayer);
+        }
     }
 
     public void onPause() {
@@ -502,8 +520,7 @@ public class ShuffleFragment extends BaseFragment {
         playbackStarted = false;
         startTimeMillis = 0;
 
-        /*
-        if (MainActivity.appPlayer != null) {
+        /*if (MainActivity.appPlayer != null) {
             MainActivity.appPlayer.stop(true);
             MainActivity.appPlayer.removeListener(fileViewPlayerListener);
             PlaybackParameters params = new PlaybackParameters(1.0f);

From 1b88f565aff650a1edce2a1c4268796e13db1988 Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Wed, 23 Sep 2020 16:37:41 +0100
Subject: [PATCH 3/5] bumpversion 0.16.4 --> 0.16.5

---
 app/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/build.gradle b/app/build.gradle
index 46d77c0c..132db6ec 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,8 +16,8 @@ android {
         applicationId "io.lbry.browser"
         minSdkVersion 21
         targetSdkVersion 29
-        versionCode 1604
-        versionName "0.16.4"
+        versionCode 1605
+        versionName "0.16.5"
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }

From 5d210961c19e6a93c7382b28a75c11394ca4f85d Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Fri, 25 Sep 2020 14:41:40 +0100
Subject: [PATCH 4/5] apply mature filter to Editor's Choice

---
 .../ui/findcontent/EditorsChoiceFragment.java |  3 ++-
 .../io/lbry/browser/utils/Predefined.java     | 23 ++++++++++++++++++-
 2 files changed, 24 insertions(+), 2 deletions(-)

diff --git a/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java b/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java
index cd8dd19e..2a041e11 100644
--- a/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java
+++ b/app/src/main/java/io/lbry/browser/ui/findcontent/EditorsChoiceFragment.java
@@ -32,6 +32,7 @@ import io.lbry.browser.ui.BaseFragment;
 import io.lbry.browser.utils.Helper;
 import io.lbry.browser.utils.Lbry;
 import io.lbry.browser.utils.LbryAnalytics;
+import io.lbry.browser.utils.Predefined;
 
 public class EditorsChoiceFragment extends BaseFragment {
 
@@ -72,7 +73,7 @@ public class EditorsChoiceFragment extends BaseFragment {
         return Lbry.buildClaimSearchOptions(
                 Claim.TYPE_REPOST,
                 null,
-                null, /*canShowMatureContent ? null : new ArrayList<>(Predefined.MATURE_TAGS),*/
+                canShowMatureContent ? null : new ArrayList<>(Predefined.MATURE_TAGS),
                 new ArrayList<>(titleChannelIdsMap.values()),
                 null,
                 Arrays.asList(Claim.ORDER_BY_RELEASE_TIME),
diff --git a/app/src/main/java/io/lbry/browser/utils/Predefined.java b/app/src/main/java/io/lbry/browser/utils/Predefined.java
index 48d8ec4e..167c36b2 100644
--- a/app/src/main/java/io/lbry/browser/utils/Predefined.java
+++ b/app/src/main/java/io/lbry/browser/utils/Predefined.java
@@ -493,7 +493,28 @@ public final class Predefined {
             "covidcuts",
             "covid-19"
     );
-    public static final List<String> MATURE_TAGS = Arrays.asList("mature", "nsfw", "porn", "xxx");
+    public static final List<String> MATURE_TAGS = Arrays.asList(
+            "porn",
+            "porno",
+            "nsfw",
+            "mature",
+            "xxx",
+            "sex",
+            "creampie",
+            "blowjob",
+            "handjob",
+            "vagina",
+            "boobs",
+            "big boobs",
+            "big dick",
+            "pussy",
+            "cumshot",
+            "anal",
+            "hard fucking",
+            "ass",
+            "fuck",
+            "hentai"
+    );
     public static final List<String> ADJECTIVES = Arrays.asList(
             "aback",
             "abaft",

From a5d4eda4d12945882784a904c975ded558065ffd Mon Sep 17 00:00:00 2001
From: Akinwale Ariwodola <akinwale@gmail.com>
Date: Fri, 25 Sep 2020 14:45:48 +0100
Subject: [PATCH 5/5] bumpversion 0.16.5 --> 0.16.6

---
 app/build.gradle | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/app/build.gradle b/app/build.gradle
index 132db6ec..c8f9a60b 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -16,8 +16,8 @@ android {
         applicationId "io.lbry.browser"
         minSdkVersion 21
         targetSdkVersion 29
-        versionCode 1605
-        versionName "0.16.5"
+        versionCode 1606
+        versionName "0.16.6"
 
         testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
     }