Navigate to previous unreviewed file when pressing "p"

Allow pressing of "p" at the start of file to navigate to previous
unreviewed file(similar to "n") after showing a toast.

Change-Id: I310a2d417a8cf65d75b9de0ec9280e7f03386062
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
index 6f6705e..73fe3b7 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-cursor/gr-diff-cursor.ts
@@ -61,6 +61,8 @@
 
   private lastDisplayedNavigateToNextFileToast: number | null = null;
 
+  private lastDisplayedNavigateToPreviousFileToast: number | null = null;
+
   @property({type: String})
   side = Side.RIGHT;
 
@@ -228,10 +230,32 @@
     return result;
   }
 
-  moveToPreviousChunk(): CursorMoveResult {
+  moveToPreviousChunk(navigateToPreviousFile?: boolean): CursorMoveResult {
     const result = this.cursorManager.previous({
       filter: (row: HTMLElement) => this._isFirstRowOfChunk(row),
     });
+    /*
+     * If user presses p on the first diff chunk, show a toast informing user
+     * that pressing p again will navigate them to previous unreviewed file.
+     * If click happens within the time limit, then navigate to prev file
+     */
+    if (navigateToPreviousFile && this.isAtStart()) {
+      if (
+        this.lastDisplayedNavigateToPreviousFileToast &&
+        Date.now() - this.lastDisplayedNavigateToPreviousFileToast <=
+          NAVIGATE_TO_NEXT_FILE_TIMEOUT_MS
+      ) {
+        // reset for next file
+        this.lastDisplayedNavigateToPreviousFileToast = null;
+        fireEvent(this, 'navigate-to-previous-unreviewed-file');
+      } else {
+        this.lastDisplayedNavigateToPreviousFileToast = Date.now();
+        fireAlert(
+          this,
+          'Press p again to navigate to previous unreviewed file'
+        );
+      }
+    }
     this._fixSide();
     return result;
   }
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
index b5ea72e..88960ab 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view.ts
@@ -636,7 +636,7 @@
       this.$.cursor.moveToPreviousCommentThread();
     } else {
       if (this.modifierPressed(e)) return;
-      this.$.cursor.moveToPreviousChunk();
+      this.$.cursor.moveToPreviousChunk(!e.detail.keyboardEvent?.repeat);
     }
   }
 
@@ -1768,6 +1768,18 @@
     this._navToFile(this._path, unreviewedFiles, 1);
   }
 
+  _navigateToPreviousUnreviewedFile() {
+    if (!this._path) return;
+    if (!this._fileList) return;
+    if (!this._reviewedFiles) return;
+    // Ensure that the currently viewed file always appears in unreviewedFiles
+    // so we resolve the right "next" file.
+    const unreviewedFiles = this._fileList.filter(
+      file => file === this._path || !this._reviewedFiles.has(file)
+    );
+    this._navToFile(this._path, unreviewedFiles, -1);
+  }
+
   _handleNextUnreviewedFile(e: CustomKeyboardEvent) {
     if (this.shouldSuppressKeyboardShortcut(e)) return;
     this._setReviewed(true);
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
index 651e95b..e275d84 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-view/gr-diff-view_html.ts
@@ -428,6 +428,7 @@
   <gr-diff-cursor
     id="cursor"
     on-navigate-to-next-unreviewed-file="_navigateToNextUnreviewedFile"
+    on-navigate-to-previous-unreviewed-file="_navigateToPreviousUnreviewedFile"
     on-navigate-to-next-file-with-comments="_navigateToNextFileWithCommentThread"
   ></gr-diff-cursor>
   <gr-comment-api id="commentAPI"></gr-comment-api>