Compare commits
108 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 90170cb3d5 | |||
| 4dcb141f3a | |||
| 133721917f | |||
| 766e23d265 | |||
| 77d8e84e14 | |||
| 00c1cca412 | |||
| 4968833d05 | |||
| d172fa17f6 | |||
| 3c99b38db7 | |||
|
|
1128937cac | ||
| 6fc1228173 | |||
| b48a2efb7d | |||
| 412cb2408e | |||
| 682bc91855 | |||
| f03120e5a1 | |||
| 8dd63b30e8 | |||
| 54006c378f | |||
| 9269b66aa8 | |||
| cfac433861 | |||
| a28f8c3dd2 | |||
| 4001dee1bd | |||
| d1ffd0d77f | |||
| 91ad50350d | |||
| a88d43807e | |||
| 98619664cf | |||
| 39f8ad2106 | |||
| 82ce38d7b5 | |||
| 12eb453fc7 | |||
| a84324d3bc | |||
| ed2211586e | |||
| c09950d0af | |||
| e9a30382a3 | |||
| 7bf3311102 | |||
| cbad40245f | |||
| 75c4fcbb9e | |||
| f3b7f155b7 | |||
| 6427a80bd1 | |||
| 5b65e87225 | |||
| 1b8b19fde5 | |||
| 03d7aed258 | |||
| 23d149093f | |||
| 27f12716d9 | |||
| 048877bbb6 | |||
| 87a652d911 | |||
| d6863dc1fd | |||
| f1d934b0a6 | |||
| 5850f7a621 | |||
| dd23e84ccf | |||
| b060518778 | |||
| de95f13feb | |||
| 0205f13e53 | |||
| b4de97dfe2 | |||
| 35bc6cf31c | |||
| c58e8b1a00 | |||
| accdf99503 | |||
| 47b609369b | |||
| 23b1ca4371 | |||
| 73d666d1f5 | |||
| b27c13cf74 | |||
| bd1a4f0939 | |||
| 5abed23cf2 | |||
| 9d0948e124 | |||
| 678bc77a23 | |||
| 00cdeee5c6 | |||
| 2d251554ad | |||
| 1b5d70ae2d | |||
| 2d2901f6dc | |||
| a0b27ec105 | |||
| 093ef136e7 | |||
| 8660de530d | |||
| bda6f253e0 | |||
| 4eb974567f | |||
| 4f5bad5874 | |||
| 1c6e798632 | |||
| 3186fb42e7 | |||
| 4b7185fbb0 | |||
| f0d8555a8a | |||
| f338dfcb12 | |||
| 188d781b0d | |||
| adb1f07fd0 | |||
| 82e51be096 | |||
| d7f6d12f59 | |||
| 0db57fbff1 | |||
| b1bdc19afb | |||
| b75a95a708 | |||
| c3fb5dcd5f | |||
| 21911f93d1 | |||
| f7c96d81e9 | |||
| 9b2040059d | |||
| 08f190fc6e | |||
| 4d1b0fe301 | |||
| f139db07d9 | |||
|
|
73a4129000 | ||
| 1ddf797e28 | |||
|
|
18280f0478 | ||
|
|
4348705a0a | ||
| 5a1b92547d | |||
|
|
9e44713985 | ||
|
|
e93837fef7 | ||
| 6006c9d0e8 | |||
|
|
c93543186a | ||
|
|
e1b74d7a36 | ||
| 6375bc3413 | |||
|
|
9c99e0d2ef | ||
|
|
518ccaadc8 | ||
| a766b395c1 | |||
| 1746869b45 | |||
|
|
533366b90b |
@@ -11,8 +11,6 @@ name: Check
|
|||||||
env:
|
env:
|
||||||
CARGO_TERM_COLOR: always
|
CARGO_TERM_COLOR: always
|
||||||
|
|
||||||
# ensure that the workflow is only triggered once per PR, subsequent pushes to the PR will cancel
|
|
||||||
# and restart the workflow. See https://docs.github.com/en/actions/using-jobs/using-concurrency
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
@@ -24,14 +22,18 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: rustfmt
|
components: rustfmt
|
||||||
|
|
||||||
- name: Run cargo fmt
|
- name: Run cargo fmt
|
||||||
run: cargo fmt -- --check
|
run: cargo fmt -- --check
|
||||||
|
|
||||||
- name: Cache Cargo dependencies
|
- name: Cache Cargo dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
name: ${{ matrix.toolchain }} / clippy
|
name: ${{ matrix.toolchain }} / clippy
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -45,12 +47,15 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: clippy
|
components: clippy
|
||||||
|
|
||||||
- name: Run clippy action
|
- name: Run clippy action
|
||||||
uses: clechasseur/rs-clippy-check@v3
|
uses: clechasseur/rs-clippy-check@v3
|
||||||
|
|
||||||
- name: Cache Cargo dependencies
|
- name: Cache Cargo dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
doc:
|
doc:
|
||||||
@@ -61,8 +66,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust nightly
|
- name: Install Rust nightly
|
||||||
uses: dtolnay/rust-toolchain@nightly
|
uses: dtolnay/rust-toolchain@nightly
|
||||||
|
|
||||||
- name: Run cargo doc
|
- name: Run cargo doc
|
||||||
run: cargo doc --no-deps --all-features
|
run: cargo doc --no-deps --all-features
|
||||||
env:
|
env:
|
||||||
@@ -73,9 +80,11 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install 1.82.0
|
- name: Install 1.82.0
|
||||||
uses: dtolnay/rust-toolchain@master
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: 1.82.0
|
toolchain: 1.82.0
|
||||||
|
|
||||||
- name: cargo +1.82.0 check
|
- name: cargo +1.82.0 check
|
||||||
run: cargo check
|
run: cargo check
|
||||||
|
|||||||
@@ -18,7 +18,139 @@ on:
|
|||||||
- major
|
- major
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
bump:
|
build-release-artifacts:
|
||||||
|
name: build-release
|
||||||
|
runs-on: ${{ matrix.job.os }}
|
||||||
|
env:
|
||||||
|
RUST_BACKTRACE: 1
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
matrix:
|
||||||
|
# prettier-ignore
|
||||||
|
job:
|
||||||
|
- { name: "macOS-arm64", os: "macOS-latest", target: "aarch64-apple-darwin", artifact_suffix: "macos-arm64", use-cross: true }
|
||||||
|
- { name: "macOS-amd64", os: "macOS-latest", target: "x86_64-apple-darwin", artifact_suffix: "macos" }
|
||||||
|
- { name: "windows-amd64", os: "windows-latest", target: "x86_64-pc-windows-msvc", artifact_suffix: "windows" }
|
||||||
|
- { name: "windows-aarch64", os: "windows-latest", target: "aarch64-pc-windows-msvc", artifact_suffix: "windows-aarch64", use-cross: true }
|
||||||
|
- { name: "linux-gnu", os: "ubuntu-latest", target: "x86_64-unknown-linux-gnu", artifact_suffix: "linux" }
|
||||||
|
- { name: "linux-musl", os: "ubuntu-latest", target: "x86_64-unknown-linux-musl", artifact_suffix: "linux-musl", use-cross: true, }
|
||||||
|
- { name: "linux-aarch64-gnu", os: "ubuntu-latest", target: "aarch64-unknown-linux-gnu", artifact_suffix: "aarch64-gnu", use-cross: true, test-bin: "--bin managarr" }
|
||||||
|
- { name: "linux-aarch64-musl", os: "ubuntu-latest", target: "aarch64-unknown-linux-musl", artifact_suffix: "aarch64-musl", use-cross: true, test-bin: "--bin managarr" }
|
||||||
|
- { name: "linux-arm-gnu", os: "ubuntu-latest", target: "arm-unknown-linux-gnueabi", artifact_suffix: "armv6-gnu", use-cross: true, test-bin: "--bin managarr" }
|
||||||
|
- { name: "linux-arm-musl", os: "ubuntu-latest", target: "arm-unknown-linux-musleabihf", artifact_suffix: "armv6-musl", use-cross: true, test-bin: "--bin managarr" }
|
||||||
|
- { name: "linux-armv7-gnu", os: "ubuntu-latest", target: "armv7-unknown-linux-gnueabihf", artifact_suffix: "armv7-gnu", use-cross: true, test-bin: "--bin managarr" }
|
||||||
|
- { name: "linux-armv7-musl", os: "ubuntu-latest", target: "armv7-unknown-linux-musleabihf", artifact_suffix: "armv7-musl", use-cross: true, test-bin: "--bin managarr" }
|
||||||
|
rust: [stable]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check if actor is repository owner
|
||||||
|
if: ${{ github.actor != github.repository_owner }}
|
||||||
|
run: |
|
||||||
|
echo "You are not authorized to run this workflow."
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 1
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
name: Cache Cargo registry
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }}
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
if: startsWith(matrix.job.name, 'linux-')
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/bin
|
||||||
|
key: ${{ runner.os }}-cargo-bin-${{ hashFiles('.github/workflows/release.yml') }}
|
||||||
|
|
||||||
|
- uses: dtolnay/rust-toolchain@stable
|
||||||
|
name: Set Rust toolchain
|
||||||
|
with:
|
||||||
|
targets: ${{ matrix.job.target }}
|
||||||
|
|
||||||
|
- uses: taiki-e/setup-cross-toolchain-action@v1
|
||||||
|
with:
|
||||||
|
# NB: sets CARGO_BUILD_TARGET evar - do not need --target flag in build
|
||||||
|
target: ${{ matrix.job.target }}
|
||||||
|
|
||||||
|
- uses: taiki-e/install-action@cross
|
||||||
|
if: ${{ matrix.job.use-cross }}
|
||||||
|
|
||||||
|
- name: Installing needed Ubuntu dependencies
|
||||||
|
if: matrix.job.os == 'ubuntu-latest'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get -y update
|
||||||
|
case ${{ matrix.job.target }} in
|
||||||
|
arm*-linux-*) sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
|
||||||
|
aarch64-*-linux-*) sudo apt-get -y install gcc-aarch64-linux-gnu ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: cargo build --release --verbose --target=${{ matrix.job.target }} --locked
|
||||||
|
|
||||||
|
- name: Verify file
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
file target/${{ matrix.job.target }}/release/managarr
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
if: matrix.job.target != 'aarch64-apple-darwin' && matrix.job.target != 'aarch64-pc-windows-msvc'
|
||||||
|
run: cargo test --release --verbose --target=${{ matrix.job.target }} ${{ matrix.job.test-bin }}
|
||||||
|
|
||||||
|
- name: Packaging final binary (Windows)
|
||||||
|
if: matrix.job.os == 'windows-latest'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cd target/${{ matrix.job.target }}/release
|
||||||
|
BINARY_NAME=managarr.exe
|
||||||
|
if [ "${{ matrix.job.target }}" != "aarch64-pc-windows-msvc" ]; then
|
||||||
|
# strip the binary
|
||||||
|
strip $BINARY_NAME
|
||||||
|
fi
|
||||||
|
RELEASE_NAME=managarr-${{ matrix.job.artifact_suffix }}
|
||||||
|
tar czvf $RELEASE_NAME.tar.gz $BINARY_NAME
|
||||||
|
# create sha checksum files
|
||||||
|
certutil -hashfile $RELEASE_NAME.tar.gz sha256 | grep -E [A-Fa-f0-9]{64} > $RELEASE_NAME.sha256
|
||||||
|
echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Packaging final binary (macOS and Linux)
|
||||||
|
if: matrix.job.os != 'windows-latest'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
# set the right strip executable
|
||||||
|
STRIP="strip";
|
||||||
|
case ${{ matrix.job.target }} in
|
||||||
|
arm*-linux-*) STRIP="arm-linux-gnueabihf-strip" ;;
|
||||||
|
aarch64-*-linux-*) STRIP="aarch64-linux-gnu-strip" ;;
|
||||||
|
esac;
|
||||||
|
cd target/${{ matrix.job.target }}/release
|
||||||
|
BINARY_NAME=managarr
|
||||||
|
# strip the binary
|
||||||
|
"$STRIP" "$BINARY_NAME"
|
||||||
|
RELEASE_NAME=managarr-${{ matrix.job.artifact_suffix }}
|
||||||
|
tar czvf $RELEASE_NAME.tar.gz $BINARY_NAME
|
||||||
|
# create sha checksum files
|
||||||
|
shasum -a 256 $RELEASE_NAME.tar.gz > $RELEASE_NAME.sha256
|
||||||
|
echo "RELEASE_NAME=$RELEASE_NAME" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Add SHA to artifacts
|
||||||
|
run: |
|
||||||
|
mkdir -p artifacts
|
||||||
|
cp target/${{ matrix.job.target }}/release/${{ env.RELEASE_NAME }}.sha256 artifacts/
|
||||||
|
|
||||||
|
- name: Upload artifacts
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
publish-github-release:
|
||||||
|
name: publish-github-release
|
||||||
|
needs: [build-release-artifacts]
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Configure SSH for Git
|
- name: Configure SSH for Git
|
||||||
@@ -34,6 +166,12 @@ jobs:
|
|||||||
ssh-key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
|
ssh-key: ${{ secrets.RELEASE_BOT_SSH_KEY }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Download all artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@v4
|
uses: actions/setup-python@v4
|
||||||
with:
|
with:
|
||||||
@@ -58,12 +196,22 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git commit --amend --no-edit -m "$(git log -1 --pretty=%B) [skip ci]"
|
git commit --amend --no-edit -m "$(git log -1 --pretty=%B) [skip ci]"
|
||||||
|
|
||||||
|
- name: Install Rust stable
|
||||||
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
|
- name: Update the Cargo.lock
|
||||||
|
run: |
|
||||||
|
cargo update
|
||||||
|
git add Cargo.lock
|
||||||
|
git commit -m "chore: Bump the version in Cargo.lock"
|
||||||
|
|
||||||
- name: Get the new version tag
|
- name: Get the new version tag
|
||||||
id: version
|
id: version
|
||||||
run: |
|
run: |
|
||||||
NEW_TAG=$(cz version --project)
|
NEW_TAG=$(cz version --project)
|
||||||
echo "New version: $NEW_TAG"
|
echo "New version: $NEW_TAG"
|
||||||
echo "version=$NEW_TAG" >> $GITHUB_ENV
|
echo "version=$NEW_TAG" >> $GITHUB_ENV
|
||||||
|
echo "$NEW_TAG" > artifacts/release-version
|
||||||
|
|
||||||
- name: Get the previous version tag
|
- name: Get the previous version tag
|
||||||
id: prev_version
|
id: prev_version
|
||||||
@@ -84,8 +232,33 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
with:
|
with:
|
||||||
tag_name: ${{ env.version }}
|
files: |
|
||||||
name: "Release ${{ env.version }}"
|
artifacts/managarr-macos-arm64.tar.gz
|
||||||
|
artifacts/managarr-macos-arm64.sha256
|
||||||
|
artifacts/managarr-macos.tar.gz
|
||||||
|
artifacts/managarr-macos.sha256
|
||||||
|
artifacts/managarr-windows.tar.gz
|
||||||
|
artifacts/managarr-windows.sha256
|
||||||
|
artifacts/managarr-windows-aarch64.tar.gz
|
||||||
|
artifacts/managarr-windows-aarch64.sha256
|
||||||
|
artifacts/managarr-linux.tar.gz
|
||||||
|
artifacts/managarr-linux.sha256
|
||||||
|
artifacts/managarr-linux-musl.tar.gz
|
||||||
|
artifacts/managarr-linux-musl.sha256
|
||||||
|
artifacts/managarr-aarch64-gnu.tar.gz
|
||||||
|
artifacts/managarr-aarch64-gnu.sha256
|
||||||
|
artifacts/managarr-aarch64-musl.tar.gz
|
||||||
|
artifacts/managarr-aarch64-musl.sha256
|
||||||
|
artifacts/managarr-armv6-gnu.tar.gz
|
||||||
|
artifacts/managarr-armv6-gnu.sha256
|
||||||
|
artifacts/managarr-armv6-musl.tar.gz
|
||||||
|
artifacts/managarr-armv6-musl.sha256
|
||||||
|
artifacts/managarr-armv7-gnu.tar.gz
|
||||||
|
artifacts/managarr-armv7-gnu.sha256
|
||||||
|
artifacts/managarr-armv7-musl.tar.gz
|
||||||
|
artifacts/managarr-armv7-musl.sha256
|
||||||
|
tag_name: v${{ env.version }}
|
||||||
|
name: "v${{ env.version }}"
|
||||||
body: ${{ env.changelog_body }}
|
body: ${{ env.changelog_body }}
|
||||||
draft: false
|
draft: false
|
||||||
prerelease: false
|
prerelease: false
|
||||||
@@ -96,9 +269,49 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git push origin --follow-tags
|
git push origin --follow-tags
|
||||||
|
|
||||||
release-crate:
|
- name: Upload artifacts
|
||||||
needs: bump
|
uses: actions/upload-artifact@v3
|
||||||
name: Release Crate
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
publish-docker-image:
|
||||||
|
needs: [build-release-artifacts]
|
||||||
|
name: Publishing Docker image to Docker Hub
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Get release artifacts
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: artifacts
|
||||||
|
path: artifacts
|
||||||
|
|
||||||
|
- name: Validate release environment variables
|
||||||
|
run: |
|
||||||
|
echo "Release version: ${{ env.version }}"
|
||||||
|
|
||||||
|
- name: Login to Docker Hub
|
||||||
|
uses: docker/login-action@v3
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
- name: Push to Docker Hub
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
tags: darkalex17/managarr:latest, darkalex17/managarr:x86_64, darkalex17/managarr:x86_64-${{ env.version }}
|
||||||
|
push: true
|
||||||
|
|
||||||
|
- name: Push to Docker Hub
|
||||||
|
uses: docker/build-push-action@v5
|
||||||
|
with:
|
||||||
|
file: Dockerfile.arm64
|
||||||
|
tags: darkalex17/managarr:arm64, darkalex17/managarr:arm64-${{ env.version }}
|
||||||
|
push: true
|
||||||
|
|
||||||
|
publish-crate:
|
||||||
|
needs: publish-github-release
|
||||||
|
name: Publish Crate
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Check if actor is repository owner
|
- name: Check if actor is repository owner
|
||||||
@@ -111,8 +324,26 @@ jobs:
|
|||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Ensure repository is up-to-date
|
||||||
|
run: |
|
||||||
|
git fetch --all
|
||||||
|
git pull
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
name: Cache Cargo registry
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/registry
|
||||||
|
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('Cargo.lock') }}
|
||||||
|
|
||||||
|
- uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: ~/.cargo/bin
|
||||||
|
key: ${{ runner.os }}-cargo-bin-${{ hashFiles('.github/workflows/release.yml') }}
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- uses: katyo/publish-crates@v2
|
- uses: katyo/publish-crates@v2
|
||||||
with:
|
with:
|
||||||
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
||||||
|
|||||||
@@ -34,16 +34,20 @@ jobs:
|
|||||||
toolchain: [stable, beta]
|
toolchain: [stable, beta]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install ${{ matrix.toolchain }}
|
- name: Install ${{ matrix.toolchain }}
|
||||||
uses: dtolnay/rust-toolchain@master
|
uses: dtolnay/rust-toolchain@master
|
||||||
with:
|
with:
|
||||||
toolchain: ${{ matrix.toolchain }}
|
toolchain: ${{ matrix.toolchain }}
|
||||||
|
|
||||||
# enable this ci template to run regardless of whether the lockfile is checked in or not
|
# enable this ci template to run regardless of whether the lockfile is checked in or not
|
||||||
- name: cargo generate-lockfile
|
- name: cargo generate-lockfile
|
||||||
if: hashFiles('Cargo.lock') == ''
|
if: hashFiles('Cargo.lock') == ''
|
||||||
run: cargo generate-lockfile
|
run: cargo generate-lockfile
|
||||||
|
|
||||||
- name: cargo test --locked
|
- name: cargo test --locked
|
||||||
run: cargo test --locked --all-features --all-targets
|
run: cargo test --locked --all-features --all-targets
|
||||||
|
|
||||||
minimal-versions:
|
minimal-versions:
|
||||||
# This action chooses the oldest version of the dependencies permitted by Cargo.toml to ensure
|
# This action chooses the oldest version of the dependencies permitted by Cargo.toml to ensure
|
||||||
# that this crate is compatible with the minimal version that this crate and its dependencies
|
# that this crate is compatible with the minimal version that this crate and its dependencies
|
||||||
@@ -71,18 +75,25 @@ jobs:
|
|||||||
name: ubuntu / stable / minimal-versions
|
name: ubuntu / stable / minimal-versions
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- name: Install nightly for -Zdirect-minimal-versions
|
- name: Install nightly for -Zdirect-minimal-versions
|
||||||
uses: dtolnay/rust-toolchain@nightly
|
uses: dtolnay/rust-toolchain@nightly
|
||||||
|
|
||||||
- name: rustup default stable
|
- name: rustup default stable
|
||||||
run: rustup default stable
|
run: rustup default stable
|
||||||
|
|
||||||
- name: cargo update -Zdirect-minimal-versions
|
- name: cargo update -Zdirect-minimal-versions
|
||||||
run: cargo +nightly update -Zdirect-minimal-versions
|
run: cargo +nightly update -Zdirect-minimal-versions
|
||||||
|
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
run: cargo test --locked --all-features --all-targets
|
run: cargo test --locked --all-features --all-targets
|
||||||
|
|
||||||
- name: Cache Cargo dependencies
|
- name: Cache Cargo dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
os-check:
|
os-check:
|
||||||
# run cargo test on mac and windows
|
# run cargo test on mac and windows
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
@@ -100,15 +111,20 @@ jobs:
|
|||||||
# if: runner.os == 'Windows'
|
# if: runner.os == 'Windows'
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
|
|
||||||
- name: cargo generate-lockfile
|
- name: cargo generate-lockfile
|
||||||
if: hashFiles('Cargo.lock') == ''
|
if: hashFiles('Cargo.lock') == ''
|
||||||
run: cargo generate-lockfile
|
run: cargo generate-lockfile
|
||||||
|
|
||||||
- name: cargo test
|
- name: cargo test
|
||||||
run: cargo test --locked --all-features --all-targets
|
run: cargo test --locked --all-features --all-targets
|
||||||
|
|
||||||
- name: Cache Cargo dependencies
|
- name: Cache Cargo dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
# use llvm-cov to build and collect coverage and outputs in a format that
|
# use llvm-cov to build and collect coverage and outputs in a format that
|
||||||
# is compatible with codecov.io
|
# is compatible with codecov.io
|
||||||
@@ -136,21 +152,28 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Install Rust stable
|
- name: Install Rust stable
|
||||||
uses: dtolnay/rust-toolchain@stable
|
uses: dtolnay/rust-toolchain@stable
|
||||||
with:
|
with:
|
||||||
components: llvm-tools-preview
|
components: llvm-tools-preview
|
||||||
|
|
||||||
- name: cargo install cargo-llvm-cov
|
- name: cargo install cargo-llvm-cov
|
||||||
uses: taiki-e/install-action@cargo-llvm-cov
|
uses: taiki-e/install-action@cargo-llvm-cov
|
||||||
|
|
||||||
- name: cargo generate-lockfile
|
- name: cargo generate-lockfile
|
||||||
if: hashFiles('Cargo.lock') == ''
|
if: hashFiles('Cargo.lock') == ''
|
||||||
run: cargo generate-lockfile
|
run: cargo generate-lockfile
|
||||||
|
|
||||||
- name: cargo llvm-cov
|
- name: cargo llvm-cov
|
||||||
run: cargo llvm-cov --locked --all-features --lcov --output-path lcov.info
|
run: cargo llvm-cov --locked --all-features --lcov --output-path lcov.info
|
||||||
|
|
||||||
- name: Record Rust version
|
- name: Record Rust version
|
||||||
run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV"
|
run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Cache Cargo dependencies
|
- name: Cache Cargo dependencies
|
||||||
uses: Swatinem/rust-cache@v2
|
uses: Swatinem/rust-cache@v2
|
||||||
|
|
||||||
- name: Upload to codecov.io
|
- name: Upload to codecov.io
|
||||||
uses: codecov/codecov-action@v4
|
uses: codecov/codecov-action@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -5,6 +5,35 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## v0.3.7 (2024-11-26)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **ci**: Forgot to also pull in the most recent changes [skip ci]
|
||||||
|
|
||||||
|
## v0.3.6 (2024-11-26)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **ci**: Ensure the Release Crate job fetches the most recent commit before publishing the crate [skip ci]
|
||||||
|
|
||||||
|
## v0.3.4 (2024-11-26)
|
||||||
|
|
||||||
|
## v0.3.3 (2024-11-26)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **ci**: Properly prefix version tags with 'v' [skip ci]
|
||||||
|
- **ci**: Bump the version in the Cargo.lock file and commit it as well when releasing [skip ci]
|
||||||
|
|
||||||
|
## v0.3.2 (2024-11-26)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **ci**: Updated the Cargo.lock file [skip ci]
|
||||||
|
- **ci**: Use a different GitHub action to release the crate to Crates.io [skip ci]
|
||||||
|
- **ci**: Don't manually push the tags and let Commitizen do it [skip ci]
|
||||||
|
|
||||||
## v0.3.1 (2024-11-26)
|
## v0.3.1 (2024-11-26)
|
||||||
|
|
||||||
### Fix
|
### Fix
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "allocator-api2"
|
name = "allocator-api2"
|
||||||
version = "0.2.20"
|
version = "0.2.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android-tzdata"
|
name = "android-tzdata"
|
||||||
@@ -142,7 +142,7 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -195,9 +195,9 @@ checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bstr"
|
name = "bstr"
|
||||||
version = "1.11.0"
|
version = "1.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22"
|
checksum = "786a307d683a5bf92e6fd5fd69a7eb613751668d1d8d67d802846dfe367c62c8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata",
|
||||||
@@ -218,9 +218,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.8.0"
|
version = "1.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da"
|
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cargo-husky"
|
name = "cargo-husky"
|
||||||
@@ -245,9 +245,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.1"
|
version = "1.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fd9de9f2205d5ef3fd67e685b0df337994ddd4495e2a28d185500d0e1edfea47"
|
checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"shlex",
|
"shlex",
|
||||||
]
|
]
|
||||||
@@ -319,14 +319,14 @@ dependencies = [
|
|||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.7.3"
|
version = "0.7.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7"
|
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
@@ -407,7 +407,7 @@ checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
"mio 1.0.2",
|
"mio 1.0.3",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustix",
|
"rustix",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
@@ -444,6 +444,41 @@ dependencies = [
|
|||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deranged"
|
name = "deranged"
|
||||||
version = "0.3.11"
|
version = "0.3.11"
|
||||||
@@ -464,12 +499,30 @@ dependencies = [
|
|||||||
"syn 1.0.109",
|
"syn 1.0.109",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_setters"
|
||||||
|
version = "0.1.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4e8ef033054e131169b8f0f9a7af8f5533a9436fadf3c500ed547f730f07090d"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.90",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "destructure_traitobject"
|
name = "destructure_traitobject"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
|
checksum = "3c877555693c14d2f84191cfd3ad8582790fc52b5e2274b40b59cf5f5cea25c7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "deunicode"
|
||||||
|
version = "1.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "diff"
|
name = "diff"
|
||||||
version = "0.1.13"
|
version = "0.1.13"
|
||||||
@@ -532,7 +585,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -576,19 +629,19 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "errno"
|
name = "errno"
|
||||||
version = "0.3.9"
|
version = "0.3.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.2.0"
|
version = "2.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
@@ -688,7 +741,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -762,7 +815,7 @@ dependencies = [
|
|||||||
"futures-sink",
|
"futures-sink",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 0.2.12",
|
"http 0.2.12",
|
||||||
"indexmap 2.6.0",
|
"indexmap 2.7.0",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@@ -780,8 +833,8 @@ dependencies = [
|
|||||||
"fnv",
|
"fnv",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-sink",
|
"futures-sink",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
"indexmap 2.6.0",
|
"indexmap 2.7.0",
|
||||||
"slab",
|
"slab",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
@@ -830,9 +883,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.1.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258"
|
checksum = "f16ca2af56261c99fba8bac40a10251ce8188205a4c448fbb745a2e4daa76fea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"fnv",
|
"fnv",
|
||||||
@@ -857,7 +910,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -868,7 +921,7 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
@@ -941,7 +994,7 @@ dependencies = [
|
|||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2 0.4.7",
|
"h2 0.4.7",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"httparse",
|
"httparse",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -958,7 +1011,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
"hyper 1.5.1",
|
"hyper 1.5.1",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"rustls",
|
"rustls",
|
||||||
@@ -993,7 +1046,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"hyper 1.5.1",
|
"hyper 1.5.1",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
@@ -1141,9 +1194,15 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "1.0.3"
|
version = "1.0.3"
|
||||||
@@ -1177,9 +1236,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.6.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
@@ -1211,7 +1270,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c"
|
checksum = "b23a0c8dfe501baac4adf6ebbfa6eddf8f0c07f56b058cc1288017e32397846c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1243,10 +1302,11 @@ checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.72"
|
version = "0.3.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
|
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -1258,9 +1318,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.165"
|
version = "0.2.168"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fcb4d3d38eab6c5239a362fa8bae48c03baf980a6e7079f063942d563ef3533e"
|
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libredox"
|
name = "libredox"
|
||||||
@@ -1353,7 +1413,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "managarr"
|
name = "managarr"
|
||||||
version = "0.3.1"
|
version = "0.3.7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"assert_cmd",
|
"assert_cmd",
|
||||||
@@ -1369,6 +1429,8 @@ dependencies = [
|
|||||||
"crossterm",
|
"crossterm",
|
||||||
"ctrlc",
|
"ctrlc",
|
||||||
"derivative",
|
"derivative",
|
||||||
|
"derive_setters",
|
||||||
|
"deunicode",
|
||||||
"dirs-next",
|
"dirs-next",
|
||||||
"human-panic",
|
"human-panic",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
@@ -1379,6 +1441,8 @@ dependencies = [
|
|||||||
"managarr-tree-widget",
|
"managarr-tree-widget",
|
||||||
"mockall",
|
"mockall",
|
||||||
"mockito",
|
"mockito",
|
||||||
|
"openssl",
|
||||||
|
"paste",
|
||||||
"pretty_assertions",
|
"pretty_assertions",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"regex",
|
"regex",
|
||||||
@@ -1438,11 +1502,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mio"
|
name = "mio"
|
||||||
version = "1.0.2"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi",
|
"wasi",
|
||||||
@@ -1472,7 +1535,7 @@ dependencies = [
|
|||||||
"cfg-if",
|
"cfg-if",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1602,7 +1665,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1611,6 +1674,15 @@ version = "0.1.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "300.4.0+3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a709e02f2b4aca747929cca5ed248880847c650233cf8b8cdc48f40aaf4898a6"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.104"
|
version = "0.9.104"
|
||||||
@@ -1619,6 +1691,7 @@ checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
@@ -1640,9 +1713,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_info"
|
name = "os_info"
|
||||||
version = "3.8.2"
|
version = "3.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
|
checksum = "e5ca711d8b83edbb00b44d504503cd247c9c0bd8b0fa2694f2a1a3d8165379ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -1852,9 +1925,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
]
|
]
|
||||||
@@ -1917,7 +1990,7 @@ dependencies = [
|
|||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2 0.4.7",
|
"h2 0.4.7",
|
||||||
"http 1.1.0",
|
"http 1.2.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper 1.5.1",
|
"hyper 1.5.1",
|
||||||
@@ -1989,7 +2062,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"relative-path",
|
"relative-path",
|
||||||
"rustc_version",
|
"rustc_version",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2010,22 +2083,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.41"
|
version = "0.38.42"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6"
|
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustls"
|
name = "rustls"
|
||||||
version = "0.23.18"
|
version = "0.23.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c9cc1d47e243d655ace55ed38201c19ae02c148ae56412ab8750e8f0166ab7f"
|
checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
@@ -2112,9 +2185,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "semver"
|
name = "semver"
|
||||||
version = "1.0.23"
|
version = "1.0.24"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
|
checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
@@ -2143,7 +2216,7 @@ checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2226,7 +2299,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
|
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"mio 1.0.2",
|
"mio 1.0.3",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2262,9 +2335,9 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.7"
|
version = "0.5.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
|
checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
@@ -2313,7 +2386,7 @@ dependencies = [
|
|||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"rustversion",
|
"rustversion",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2335,9 +2408,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.89"
|
version = "2.0.90"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44d46482f1c1c87acd84dea20c1bf5ebff4c757009ed6bf19cfd36fb10e92c4e"
|
checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2361,7 +2434,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2421,7 +2494,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2436,9 +2509,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.36"
|
version = "0.3.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
|
checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -2492,7 +2565,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2507,12 +2580,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.26.0"
|
version = "0.26.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4"
|
checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pki-types",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2557,7 +2629,7 @@ version = "0.22.22"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.6.0",
|
"indexmap 2.7.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
@@ -2572,9 +2644,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tracing"
|
name = "tracing"
|
||||||
version = "0.1.40"
|
version = "0.1.41"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
|
checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
@@ -2736,9 +2808,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen"
|
name = "wasm-bindgen"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
|
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
@@ -2747,36 +2819,36 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-backend"
|
name = "wasm-bindgen-backend"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
|
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bumpalo",
|
"bumpalo",
|
||||||
"log",
|
"log",
|
||||||
"once_cell",
|
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-futures"
|
name = "wasm-bindgen-futures"
|
||||||
version = "0.4.45"
|
version = "0.4.49"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b"
|
checksum = "38176d9b44ea84e9184eff0bc34cc167ed044f816accfe5922e54d84cf48eca2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
|
"once_cell",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro"
|
name = "wasm-bindgen-macro"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
|
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote",
|
"quote",
|
||||||
"wasm-bindgen-macro-support",
|
"wasm-bindgen-macro-support",
|
||||||
@@ -2784,28 +2856,28 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-macro-support"
|
name = "wasm-bindgen-macro-support"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
|
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
"wasm-bindgen-backend",
|
"wasm-bindgen-backend",
|
||||||
"wasm-bindgen-shared",
|
"wasm-bindgen-shared",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasm-bindgen-shared"
|
name = "wasm-bindgen-shared"
|
||||||
version = "0.2.95"
|
version = "0.2.99"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
|
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "web-sys"
|
name = "web-sys"
|
||||||
version = "0.3.72"
|
version = "0.3.76"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112"
|
checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
@@ -3086,7 +3158,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3108,7 +3180,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -3128,7 +3200,7 @@ checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -3157,5 +3229,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.89",
|
"syn 2.0.90",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "managarr"
|
name = "managarr"
|
||||||
version = "0.3.1"
|
version = "0.3.7"
|
||||||
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
authors = ["Alex Clarke <alex.j.tusa@gmail.com>"]
|
||||||
description = "A TUI and CLI to manage your Servarrs"
|
description = "A TUI and CLI to manage your Servarrs"
|
||||||
keywords = ["managarr", "ratatui", "dashboard", "servarr", "tui"]
|
keywords = ["managarr", "ratatui", "dashboard", "servarr", "tui"]
|
||||||
@@ -36,7 +36,10 @@ strum = { version = "0.26.3", features = ["derive"] }
|
|||||||
strum_macros = "0.26.4"
|
strum_macros = "0.26.4"
|
||||||
tokio = { version = "1.36.0", features = ["full"] }
|
tokio = { version = "1.36.0", features = ["full"] }
|
||||||
tokio-util = "0.7.8"
|
tokio-util = "0.7.8"
|
||||||
ratatui = { version = "0.29.0", features = ["all-widgets"] }
|
ratatui = { version = "0.29.0", features = [
|
||||||
|
"all-widgets",
|
||||||
|
"unstable-widget-ref",
|
||||||
|
] }
|
||||||
urlencoding = "2.1.2"
|
urlencoding = "2.1.2"
|
||||||
clap = { version = "4.5.20", features = ["derive", "cargo", "env"] }
|
clap = { version = "4.5.20", features = ["derive", "cargo", "env"] }
|
||||||
clap_complete = "4.5.33"
|
clap_complete = "4.5.33"
|
||||||
@@ -47,6 +50,10 @@ async-trait = "0.1.83"
|
|||||||
dirs-next = "2.0.0"
|
dirs-next = "2.0.0"
|
||||||
managarr-tree-widget = "0.24.0"
|
managarr-tree-widget = "0.24.0"
|
||||||
indicatif = "0.17.9"
|
indicatif = "0.17.9"
|
||||||
|
derive_setters = "0.1.6"
|
||||||
|
deunicode = "1.6.0"
|
||||||
|
paste = "1.0.15"
|
||||||
|
openssl = { version = "0.10.68", features = ["vendored"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_cmd = "2.0.16"
|
assert_cmd = "2.0.16"
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
FROM clux/muslrust:stable AS builder
|
FROM messense/rust-musl-cross:x86_64-musl AS builder
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
# Download and compile Rust dependencies in an empty project and cache as a separate Docker layer
|
# Download and compile Rust dependencies in an empty project and cache as a separate Docker layer
|
||||||
@@ -6,7 +6,7 @@ RUN USER=root cargo new --bin managarr-temp
|
|||||||
|
|
||||||
WORKDIR /usr/src/managarr-temp
|
WORKDIR /usr/src/managarr-temp
|
||||||
COPY Cargo.* .
|
COPY Cargo.* .
|
||||||
RUN cargo build --release --target x86_64-unknown-linux-musl
|
RUN cargo build --release
|
||||||
# remove src from empty project
|
# remove src from empty project
|
||||||
RUN rm -r src
|
RUN rm -r src
|
||||||
COPY src ./src
|
COPY src ./src
|
||||||
@@ -15,7 +15,7 @@ RUN rm ./target/x86_64-unknown-linux-musl/release/deps/managarr*
|
|||||||
|
|
||||||
RUN --mount=type=cache,target=/volume/target \
|
RUN --mount=type=cache,target=/volume/target \
|
||||||
--mount=type=cache,target=/root/.cargo/registry \
|
--mount=type=cache,target=/root/.cargo/registry \
|
||||||
cargo build --release --target x86_64-unknown-linux-musl --bin managarr
|
cargo build --release --bin managarr
|
||||||
RUN mv target/x86_64-unknown-linux-musl/release/managarr .
|
RUN mv target/x86_64-unknown-linux-musl/release/managarr .
|
||||||
|
|
||||||
FROM debian:stable-slim
|
FROM debian:stable-slim
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FROM messense/rust-musl-cross:armv7-musleabihf AS builder
|
||||||
|
WORKDIR /usr/src
|
||||||
|
|
||||||
|
# Download and compile Rust dependencies in an empty project and cache as a separate Docker layer
|
||||||
|
RUN USER=root cargo new --bin managarr-temp
|
||||||
|
RUN apt update && apt install -y libssl-dev pkg-config
|
||||||
|
|
||||||
|
WORKDIR /usr/src/managarr-temp
|
||||||
|
COPY Cargo.* .
|
||||||
|
RUN cargo build --release
|
||||||
|
# remove src from empty project
|
||||||
|
RUN rm -r src
|
||||||
|
COPY src ./src
|
||||||
|
# remove previous deps
|
||||||
|
RUN rm ./target/armv7-unknown-linux-musleabihf/release/deps/managarr*
|
||||||
|
|
||||||
|
RUN --mount=type=cache,target=/volume/target \
|
||||||
|
--mount=type=cache,target=/root/.cargo/registry \
|
||||||
|
cargo build --release --bin managarr
|
||||||
|
RUN mv target/armv7-unknown-linux-musleabihf/release/managarr .
|
||||||
|
|
||||||
|
FROM debian:stable-slim
|
||||||
|
|
||||||
|
# Copy the compiled binary from the builder container
|
||||||
|
COPY --from=builder --chown=nonroot:nonroot /usr/src/managarr-temp/managarr /usr/local/bin
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/usr/local/bin/managarr" ]
|
||||||
@@ -5,13 +5,16 @@
|
|||||||

|

|
||||||

|

|
||||||
[](https://crates.io/crates/managarr)
|
[](https://crates.io/crates/managarr)
|
||||||
|

|
||||||

|

|
||||||
[](https://codecov.io/gh/Dark-Alex-17/managarr)
|
[](https://codecov.io/gh/Dark-Alex-17/managarr)
|
||||||

|

|
||||||
|
[](https://github.com/Dark-Alex-17/managarr/releases)
|
||||||
|

|
||||||
|
|
||||||
Managarr is a TUI and CLI to help you manage your HTPC (Home Theater PC). Built with 🤎 in Rust!
|
Managarr is a TUI and CLI to help you manage your HTPC (Home Theater PC). Built with 🤎 in Rust!
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## What Servarrs are supported?
|
## What Servarrs are supported?
|
||||||
|
|
||||||
@@ -46,64 +49,94 @@ cargo install --locked managarr
|
|||||||
### Docker
|
### Docker
|
||||||
Run Managarr as a docker container by mounting your `config.yml` file to `/root/.config/managarr/config.yml`. For example:
|
Run Managarr as a docker container by mounting your `config.yml` file to `/root/.config/managarr/config.yml`. For example:
|
||||||
```shell
|
```shell
|
||||||
docker run --rm -it -v ~/.config/managarr/config.yml:/root/.config/managarr/config.yml darkalex17/managarr
|
docker run --rm -it -v /home/aclarke/.config/managarr/config.yml:/root/.config/managarr/config.yml darkalex17/managarr:latest
|
||||||
|
```
|
||||||
|
|
||||||
|
For ARM64 users, you can use the `arm64` tag:
|
||||||
|
```shell
|
||||||
|
docker run --rm -it -v /home/aclarke/.config/managarr/config.yml:/root/.config/managarr/config.yml darkalex17/managarr:arm64
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also clone this repo and run `make docker` to build a docker image locally and run it using the above command.
|
You can also clone this repo and run `make docker` to build a docker image locally and run it using the above command.
|
||||||
|
|
||||||
Please note that you will need to create and popular your configuration file first before starting the container. Otherwise, the container will fail to start.
|
Please note that you will need to create and popular your configuration file first before starting the container. Otherwise, the container will fail to start.
|
||||||
|
|
||||||
|
**Note:** If you run into errors using relative file paths when mounting the volume with the configuration file, try using an absolute path.
|
||||||
|
|
||||||
|
### Manual
|
||||||
|
Binaries are available on the [releases](https://github.com/Dark-Alex-17/managarr/releases) page for the following platforms:
|
||||||
|
|
||||||
|
| Platform | Architecture(s) |
|
||||||
|
|----------------|----------------------------|
|
||||||
|
| macOS | x86_64, arm64 |
|
||||||
|
| Linux GNU/MUSL | x86_64,armv6,armv7,aarch64 |
|
||||||
|
| Windows | x86_64,aarch64 |
|
||||||
|
|
||||||
|
#### Windows Instructions
|
||||||
|
To use a binary from the releases page on Windows, do the following:
|
||||||
|
|
||||||
|
1. Download the latest binary [binary](https://github.com/Dark-Alex-17/managarr/releases) for your OS.
|
||||||
|
2. Use 7-Zip or TarTool to unpack the Tar file.
|
||||||
|
3. Run the executable `managarr.exe`!
|
||||||
|
|
||||||
|
#### Linux/MacOS Instructions
|
||||||
|
To use a binary from the releases page on Linux/MacOS, do the following:
|
||||||
|
|
||||||
|
1. Download the latest binary [binary](https://github.com/Dark-Alex-17/managarr/releases) for your OS.
|
||||||
|
2. `cd` to the directory where you downloaded the binary.
|
||||||
|
3. Extract the binary with `tar -C /usr/local/bin -xzf managarr-<arch>.tar.gz` (NB: This may require `sudo`)
|
||||||
|
4. Now you can run `managarr`!
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
Key:
|
Key:
|
||||||
|
|
||||||
| Symbol | Status |
|
| Symbol | Status |
|
||||||
|--------------------|-----------|
|
|--------|-----------|
|
||||||
| :white_check_mark: | Supported |
|
| ✅ | Supported |
|
||||||
| :x: | Missing |
|
| ❌ | Missing |
|
||||||
| :clock3: | Planned |
|
| 🕒 | Planned |
|
||||||
| :no_entry_sign: | Won't Add |
|
| 🚫 | Won't Add |
|
||||||
|
|
||||||
### Radarr
|
### Radarr
|
||||||
|
|
||||||
| TUI | CLI | Feature |
|
| TUI | CLI | Feature |
|
||||||
|--------------------|--------------------|----------------------------------------------------------------------------------------------------------------|
|
|-----|-----|----------------------------------------------------------------------------------------------------------------|
|
||||||
| :white_check_mark: | :white_check_mark: | View your library, downloads, collections, and blocklist |
|
| ✅ | ✅ | View your library, downloads, collections, and blocklist |
|
||||||
| :white_check_mark: | :white_check_mark: | View details of a specific movie including description, history, downloaded file info, or the credits |
|
| ✅ | ✅ | View details of a specific movie including description, history, downloaded file info, or the credits |
|
||||||
| :white_check_mark: | :white_check_mark: | View details of any collection and the movies in them |
|
| ✅ | ✅ | View details of any collection and the movies in them |
|
||||||
| :no_entry_sign: | :white_check_mark: | View your host and security configs from the CLI to programmatically fetch the API token, among other settings |
|
| 🚫 | ✅ | View your host and security configs from the CLI to programmatically fetch the API token, among other settings |
|
||||||
| :white_check_mark: | :white_check_mark: | Search your library or collections |
|
| ✅ | ✅ | Search your library or collections |
|
||||||
| :white_check_mark: | :white_check_mark: | Add movies to your library |
|
| ✅ | ✅ | Add movies to your library |
|
||||||
| :white_check_mark: | :white_check_mark: | Delete movies, downloads, and indexers |
|
| ✅ | ✅ | Delete movies, downloads, and indexers |
|
||||||
| :white_check_mark: | :white_check_mark: | Trigger automatic searches for movies |
|
| ✅ | ✅ | Trigger automatic searches for movies |
|
||||||
| :white_check_mark: | :white_check_mark: | Trigger refresh and disk scan for movies, downloads, and collections |
|
| ✅ | ✅ | Trigger refresh and disk scan for movies, downloads, and collections |
|
||||||
| :white_check_mark: | :white_check_mark: | Manually search for movies |
|
| ✅ | ✅ | Manually search for movies |
|
||||||
| :white_check_mark: | :white_check_mark: | Edit your movies, collections, and indexers |
|
| ✅ | ✅ | Edit your movies, collections, and indexers |
|
||||||
| :white_check_mark: | :white_check_mark: | Manage your tags |
|
| ✅ | ✅ | Manage your tags |
|
||||||
| :white_check_mark: | :white_check_mark: | Manage your root folders |
|
| ✅ | ✅ | Manage your root folders |
|
||||||
| :white_check_mark: | :white_check_mark: | Manage your blocklist |
|
| ✅ | ✅ | Manage your blocklist |
|
||||||
| :white_check_mark: | :white_check_mark: | View and browse logs, tasks, events queues, and updates |
|
| ✅ | ✅ | View and browse logs, tasks, events queues, and updates |
|
||||||
| :white_check_mark: | :white_check_mark: | Manually trigger scheduled tasks |
|
| ✅ | ✅ | Manually trigger scheduled tasks |
|
||||||
|
|
||||||
### Sonarr
|
### Sonarr
|
||||||
|
|
||||||
| TUI | CLI | Feature |
|
| TUI | CLI | Feature |
|
||||||
|----------|--------------------|--------------------------------------------------------------------------------------------------------------------|
|
|-----|-----|--------------------------------------------------------------------------------------------------------------------|
|
||||||
| :clock3: | :white_check_mark: | View your library, downloads, blocklist, episodes |
|
| ✅ | ✅ | View your library, downloads, blocklist, episodes |
|
||||||
| :clock3: | :white_check_mark: | View details of a specific series, or episode including description, history, downloaded file info, or the credits |
|
| ✅ | ✅ | View details of a specific series, or episode including description, history, downloaded file info, or the credits |
|
||||||
| :clock3: | :white_check_mark: | View your host and security configs from the CLI to programmatically fetch the API token, among other settings |
|
| 🚫 | ✅ | View your host and security configs from the CLI to programmatically fetch the API token, among other settings |
|
||||||
| :clock3: | :white_check_mark: | Search your library |
|
| ✅ | ✅ | Search your library |
|
||||||
| :clock3: | :white_check_mark: | Add series to your library |
|
| ✅ | ✅ | Add series to your library |
|
||||||
| :clock3: | :white_check_mark: | Delete series, downloads, indexers, root folders, and episode files |
|
| ✅ | ✅ | Delete series, downloads, indexers, root folders, and episode files |
|
||||||
| :clock3: | :white_check_mark: | Mark history events as failed |
|
| ✅ | ✅ | Trigger automatic searches for series, seasons, or episodes |
|
||||||
| :clock3: | :white_check_mark: | Trigger automatic searches for series, seasons, or episodes |
|
| ✅ | ✅ | Trigger refresh and disk scan for series and downloads |
|
||||||
| :clock3: | :white_check_mark: | Trigger refresh and disk scan for series and downloads |
|
| ✅ | ✅ | Manually search for series, seasons, or episodes |
|
||||||
| :clock3: | :white_check_mark: | Manually search for series, seasons, or episodes |
|
| ✅ | ✅ | Edit your series and indexers |
|
||||||
| :clock3: | :white_check_mark: | Edit your series and indexers |
|
| ✅ | ✅ | Manage your tags |
|
||||||
| :clock3: | :white_check_mark: | Manage your tags |
|
| ✅ | ✅ | Manage your root folders |
|
||||||
| :clock3: | :white_check_mark: | Manage your root folders |
|
| ✅ | ✅ | Manage your blocklist |
|
||||||
| :clock3: | :white_check_mark: | Manage your blocklist |
|
| ✅ | ✅ | View and browse logs, tasks, events queues, and updates |
|
||||||
| :clock3: | :white_check_mark: | View and browse logs, tasks, events queues, and updates |
|
| ✅ | ✅ | Manually trigger scheduled tasks |
|
||||||
| :clock3: | :white_check_mark: | Manually trigger scheduled tasks |
|
|
||||||
|
|
||||||
### Readarr
|
### Readarr
|
||||||
|
|
||||||
@@ -141,7 +174,7 @@ To see all available commands, simply run `managarr --help`:
|
|||||||
|
|
||||||
```shell
|
```shell
|
||||||
$ managarr --help
|
$ managarr --help
|
||||||
managarr 0.3.0
|
managarr 0.4.0
|
||||||
Alex Clarke <alex.j.tusa@gmail.com>
|
Alex Clarke <alex.j.tusa@gmail.com>
|
||||||
|
|
||||||
A TUI and CLI to manage your Servarrs
|
A TUI and CLI to manage your Servarrs
|
||||||
@@ -186,6 +219,8 @@ Commands:
|
|||||||
start-task Start the specified Sonarr task
|
start-task Start the specified Sonarr task
|
||||||
test-indexer Test the indexer with the given ID. Note that a successful test returns an empty JSON body; i.e. '{}'
|
test-indexer Test the indexer with the given ID. Note that a successful test returns an empty JSON body; i.e. '{}'
|
||||||
test-all-indexers Test all Sonarr indexers
|
test-all-indexers Test all Sonarr indexers
|
||||||
|
toggle-episode-monitoring Toggle monitoring for the specified episode
|
||||||
|
toggle-season-monitoring Toggle monitoring for the specified season that corresponds to the specified series ID
|
||||||
help Print this message or the help of the given subcommand(s)
|
help Print this message or the help of the given subcommand(s)
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
@@ -275,7 +310,6 @@ Managarr supports using environment variables on startup so you don't have to al
|
|||||||
|-----------------------------------------|--------------------------------------------------------------------------------|----------------------------------|
|
|-----------------------------------------|--------------------------------------------------------------------------------|----------------------------------|
|
||||||
| `MANAGARR_CONFIG_FILE` | Set the path to the config file | `--config` |
|
| `MANAGARR_CONFIG_FILE` | Set the path to the config file | `--config` |
|
||||||
| `MANAGARR_DISABLE_SPINNER` | Disable the CLI spinner (this can be useful when scripting and parsing output) | `--disable-spinner` |
|
| `MANAGARR_DISABLE_SPINNER` | Disable the CLI spinner (this can be useful when scripting and parsing output) | `--disable-spinner` |
|
||||||
|-----------------------------------------|--------------------------------------------------------------------------------|----------------------------------|
|
|
||||||
|
|
||||||
## Track My Progress for the Beta release (With Sonarr Support!)
|
## Track My Progress for the Beta release (With Sonarr Support!)
|
||||||
Progress for the beta release can be followed on my [Wekan Board](https://wekan.alexjclarke.com/b/dHoGjBb44MHM9HSv4/managarr)
|
Progress for the beta release can be followed on my [Wekan Board](https://wekan.alexjclarke.com/b/dHoGjBb44MHM9HSv4/managarr)
|
||||||
@@ -283,13 +317,22 @@ with all items tagged `Beta`.
|
|||||||
|
|
||||||
## Screenshots
|
## Screenshots
|
||||||
|
|
||||||

|
### Radarr
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|
|
||||||
|
### Sonarr
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
### General
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
* [ratatui](https://github.com/tui-rs-revival/ratatui)
|
* [ratatui](https://github.com/tui-rs-revival/ratatui)
|
||||||
@@ -301,7 +344,7 @@ with all items tagged `Beta`.
|
|||||||
|
|
||||||
## Servarr Requirements
|
## Servarr Requirements
|
||||||
* [Radarr >= 5.3.6.8612](https://radarr.video/docs/api/)
|
* [Radarr >= 5.3.6.8612](https://radarr.video/docs/api/)
|
||||||
* [Sonarr >= v3](https://sonarr.tv/docs/api/)
|
* [Sonarr >= v4](https://sonarr.tv/docs/api/)
|
||||||
* [Readarr v1](https://readarr.com/docs/api/)
|
* [Readarr v1](https://readarr.com/docs/api/)
|
||||||
* [Lidarr v1](https://lidarr.audio/docs/api/)
|
* [Lidarr v1](https://lidarr.audio/docs/api/)
|
||||||
* [Whisparr >= v3](https://whisparr.com/docs/api/)
|
* [Whisparr >= v3](https://whisparr.com/docs/api/)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
|
Before Width: | Height: | Size: 154 KiB After Width: | Height: | Size: 154 KiB |
|
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
|
Before Width: | Height: | Size: 374 KiB After Width: | Height: | Size: 374 KiB |
|
Before Width: | Height: | Size: 382 KiB After Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 176 KiB After Width: | Height: | Size: 176 KiB |
|
Before Width: | Height: | Size: 236 KiB After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 211 KiB |
|
After Width: | Height: | Size: 305 KiB |
|
After Width: | Height: | Size: 196 KiB |
|
After Width: | Height: | Size: 124 KiB |
|
After Width: | Height: | Size: 203 KiB |
@@ -19,6 +19,7 @@ mod tests {
|
|||||||
assert_eq!(app.navigation_stack, vec![DEFAULT_ROUTE]);
|
assert_eq!(app.navigation_stack, vec![DEFAULT_ROUTE]);
|
||||||
assert!(app.network_tx.is_none());
|
assert!(app.network_tx.is_none());
|
||||||
assert!(!app.cancellation_token.is_cancelled());
|
assert!(!app.cancellation_token.is_cancelled());
|
||||||
|
assert!(app.is_first_render);
|
||||||
assert_eq!(app.error, HorizontallyScrollableText::default());
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
assert_eq!(app.server_tabs.index, 0);
|
assert_eq!(app.server_tabs.index, 0);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -55,14 +56,11 @@ mod tests {
|
|||||||
fn test_navigation_stack_methods() {
|
fn test_navigation_stack_methods() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &DEFAULT_ROUTE);
|
assert_eq!(app.get_current_route(), DEFAULT_ROUTE);
|
||||||
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
|
||||||
assert!(app.is_routing);
|
assert!(app.is_routing);
|
||||||
|
|
||||||
app.is_routing = false;
|
app.is_routing = false;
|
||||||
@@ -70,20 +68,20 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert!(app.is_routing);
|
assert!(app.is_routing);
|
||||||
|
|
||||||
app.is_routing = false;
|
app.is_routing = false;
|
||||||
app.pop_navigation_stack();
|
app.pop_navigation_stack();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &DEFAULT_ROUTE);
|
assert_eq!(app.get_current_route(), DEFAULT_ROUTE);
|
||||||
assert!(app.is_routing);
|
assert!(app.is_routing);
|
||||||
|
|
||||||
app.is_routing = false;
|
app.is_routing = false;
|
||||||
app.pop_navigation_stack();
|
app.pop_navigation_stack();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &DEFAULT_ROUTE);
|
assert_eq!(app.get_current_route(), DEFAULT_ROUTE);
|
||||||
assert!(app.is_routing);
|
assert!(app.is_routing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,19 +118,23 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_reset() {
|
fn test_reset() {
|
||||||
|
let radarr_data = RadarrData {
|
||||||
|
version: "test".into(),
|
||||||
|
..RadarrData::default()
|
||||||
|
};
|
||||||
|
let sonarr_data = SonarrData {
|
||||||
|
version: "test".into(),
|
||||||
|
..SonarrData::default()
|
||||||
|
};
|
||||||
|
let data = Data {
|
||||||
|
radarr_data,
|
||||||
|
sonarr_data,
|
||||||
|
};
|
||||||
let mut app = App {
|
let mut app = App {
|
||||||
tick_count: 2,
|
tick_count: 2,
|
||||||
error: "Test error".to_owned().into(),
|
error: "Test error".to_owned().into(),
|
||||||
data: Data {
|
is_first_render: false,
|
||||||
radarr_data: RadarrData {
|
data,
|
||||||
version: "test".to_owned(),
|
|
||||||
..RadarrData::default()
|
|
||||||
},
|
|
||||||
sonarr_data: SonarrData {
|
|
||||||
version: "test".to_owned(),
|
|
||||||
..SonarrData::default()
|
|
||||||
},
|
|
||||||
},
|
|
||||||
..App::default()
|
..App::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -140,6 +142,7 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
assert_eq!(app.error, HorizontallyScrollableText::default());
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
|
assert!(app.is_first_render);
|
||||||
assert!(app.data.radarr_data.version.is_empty());
|
assert!(app.data.radarr_data.version.is_empty());
|
||||||
assert!(app.data.sonarr_data.version.is_empty());
|
assert!(app.data.sonarr_data.version.is_empty());
|
||||||
}
|
}
|
||||||
@@ -188,12 +191,13 @@ mod tests {
|
|||||||
let mut app = App {
|
let mut app = App {
|
||||||
tick_until_poll: 2,
|
tick_until_poll: 2,
|
||||||
network_tx: Some(sync_network_tx),
|
network_tx: Some(sync_network_tx),
|
||||||
|
is_first_render: true,
|
||||||
..App::default()
|
..App::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
|
|
||||||
app.on_tick(true).await;
|
app.on_tick().await;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -219,6 +223,14 @@ mod tests {
|
|||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetStatus.into()
|
RadarrEvent::GetStatus.into()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetMovies.into()
|
RadarrEvent::GetMovies.into()
|
||||||
@@ -237,7 +249,7 @@ mod tests {
|
|||||||
..App::default()
|
..App::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app.on_tick(false).await;
|
app.on_tick().await;
|
||||||
assert!(!app.is_routing);
|
assert!(!app.is_routing);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +262,7 @@ mod tests {
|
|||||||
..App::default()
|
..App::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
app.on_tick(false).await;
|
app.on_tick().await;
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,77 @@ pub fn build_context_clue_string(context_clues: &[(KeyBinding, &str)]) -> String
|
|||||||
.join(" | ")
|
.join(" | ")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static SERVARR_CONTEXT_CLUES: [ContextClue; 2] = [
|
pub static SERVARR_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||||
(DEFAULT_KEYBINDINGS.tab, "change servarr"),
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.next_servarr,
|
||||||
|
DEFAULT_KEYBINDINGS.next_servarr.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.previous_servarr,
|
||||||
|
DEFAULT_KEYBINDINGS.previous_servarr.desc,
|
||||||
|
),
|
||||||
(DEFAULT_KEYBINDINGS.quit, DEFAULT_KEYBINDINGS.quit.desc),
|
(DEFAULT_KEYBINDINGS.quit, DEFAULT_KEYBINDINGS.quit.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static BARE_POPUP_CONTEXT_CLUES: [ContextClue; 1] =
|
pub static BARE_POPUP_CONTEXT_CLUES: [ContextClue; 1] =
|
||||||
[(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)];
|
[(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc)];
|
||||||
|
|
||||||
|
pub static BLOCKLIST_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.clear, "clear blocklist"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static CONFIRMATION_PROMPT_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.confirm, "submit"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static DOWNLOADS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, "update downloads"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static ROOT_FOLDERS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 6] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "edit indexer"),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.settings,
|
||||||
|
DEFAULT_KEYBINDINGS.settings.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.test, "test indexer"),
|
||||||
|
(DEFAULT_KEYBINDINGS.test_all, "test all indexers"),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SYSTEM_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.tasks, "open tasks"),
|
||||||
|
(DEFAULT_KEYBINDINGS.events, "open events"),
|
||||||
|
(DEFAULT_KEYBINDINGS.logs, "open logs"),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, "open updates"),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
mod test {
|
mod test {
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
|
||||||
use crate::app::context_clues::{BARE_POPUP_CONTEXT_CLUES, SERVARR_CONTEXT_CLUES};
|
use crate::app::context_clues::{
|
||||||
|
BARE_POPUP_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES,
|
||||||
|
DOWNLOADS_CONTEXT_CLUES, INDEXERS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES,
|
||||||
|
SERVARR_CONTEXT_CLUES, SYSTEM_CONTEXT_CLUES,
|
||||||
|
};
|
||||||
use crate::app::{context_clues::build_context_clue_string, key_binding::DEFAULT_KEYBINDINGS};
|
use crate::app::{context_clues::build_context_clue_string, key_binding::DEFAULT_KEYBINDINGS};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -24,8 +28,13 @@ mod test {
|
|||||||
|
|
||||||
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.tab);
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.next_servarr);
|
||||||
assert_str_eq!(*description, "change servarr");
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.next_servarr.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.previous_servarr);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.previous_servarr.desc);
|
||||||
|
|
||||||
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
let (key_binding, description) = servarr_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
@@ -44,4 +53,160 @@ mod test {
|
|||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
assert_eq!(bare_popup_context_clues_iter.next(), None);
|
assert_eq!(bare_popup_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_downloads_context_clues() {
|
||||||
|
let mut downloads_context_clues_iter = DOWNLOADS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
||||||
|
assert_str_eq!(*description, "update downloads");
|
||||||
|
assert_eq!(downloads_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_context_clues() {
|
||||||
|
let mut blocklist_context_clues_iter = BLOCKLIST_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "details");
|
||||||
|
|
||||||
|
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.clear);
|
||||||
|
assert_str_eq!(*description, "clear blocklist");
|
||||||
|
assert_eq!(blocklist_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_confirmation_prompt_context_clues() {
|
||||||
|
let mut confirmation_prompt_context_clues_iter = CONFIRMATION_PROMPT_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.confirm);
|
||||||
|
assert_str_eq!(*description, "submit");
|
||||||
|
|
||||||
|
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, "cancel");
|
||||||
|
assert_eq!(confirmation_prompt_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_root_folders_context_clues() {
|
||||||
|
let mut root_folders_context_clues_iter = ROOT_FOLDERS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.add);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.add.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
assert_eq!(root_folders_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexers_context_clues() {
|
||||||
|
let mut indexers_context_clues_iter = INDEXERS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "edit indexer");
|
||||||
|
|
||||||
|
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.settings);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.settings.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test);
|
||||||
|
assert_str_eq!(*description, "test indexer");
|
||||||
|
|
||||||
|
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test_all);
|
||||||
|
assert_str_eq!(*description, "test all indexers");
|
||||||
|
|
||||||
|
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
assert_eq!(indexers_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_context_clues() {
|
||||||
|
let mut system_context_clues_iter = SYSTEM_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.tasks);
|
||||||
|
assert_str_eq!(*description, "open tasks");
|
||||||
|
|
||||||
|
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.events);
|
||||||
|
assert_str_eq!(*description, "open events");
|
||||||
|
|
||||||
|
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.logs);
|
||||||
|
assert_str_eq!(*description, "open logs");
|
||||||
|
|
||||||
|
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
||||||
|
assert_str_eq!(*description, "open updates");
|
||||||
|
|
||||||
|
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
assert_eq!(system_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,11 @@ generate_keybindings! {
|
|||||||
left,
|
left,
|
||||||
right,
|
right,
|
||||||
backspace,
|
backspace,
|
||||||
|
next_servarr,
|
||||||
|
previous_servarr,
|
||||||
clear,
|
clear,
|
||||||
search,
|
search,
|
||||||
|
auto_search,
|
||||||
settings,
|
settings,
|
||||||
filter,
|
filter,
|
||||||
sort,
|
sort,
|
||||||
@@ -25,12 +28,12 @@ generate_keybindings! {
|
|||||||
tasks,
|
tasks,
|
||||||
test,
|
test,
|
||||||
test_all,
|
test_all,
|
||||||
|
toggle_monitoring,
|
||||||
refresh,
|
refresh,
|
||||||
update,
|
update,
|
||||||
events,
|
events,
|
||||||
home,
|
home,
|
||||||
end,
|
end,
|
||||||
tab,
|
|
||||||
delete,
|
delete,
|
||||||
submit,
|
submit,
|
||||||
confirm,
|
confirm,
|
||||||
@@ -69,16 +72,28 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
|||||||
key: Key::Backspace,
|
key: Key::Backspace,
|
||||||
desc: "backspace",
|
desc: "backspace",
|
||||||
},
|
},
|
||||||
|
next_servarr: KeyBinding {
|
||||||
|
key: Key::Tab,
|
||||||
|
desc: "next servarr",
|
||||||
|
},
|
||||||
|
previous_servarr: KeyBinding {
|
||||||
|
key: Key::BackTab,
|
||||||
|
desc: "previous servarr",
|
||||||
|
},
|
||||||
clear: KeyBinding {
|
clear: KeyBinding {
|
||||||
key: Key::Char('c'),
|
key: Key::Char('c'),
|
||||||
desc: "clear",
|
desc: "clear",
|
||||||
},
|
},
|
||||||
|
auto_search: KeyBinding {
|
||||||
|
key: Key::Char('S'),
|
||||||
|
desc: "auto search",
|
||||||
|
},
|
||||||
search: KeyBinding {
|
search: KeyBinding {
|
||||||
key: Key::Char('s'),
|
key: Key::Char('s'),
|
||||||
desc: "search",
|
desc: "search",
|
||||||
},
|
},
|
||||||
settings: KeyBinding {
|
settings: KeyBinding {
|
||||||
key: Key::Char('s'),
|
key: Key::Char('S'),
|
||||||
desc: "settings",
|
desc: "settings",
|
||||||
},
|
},
|
||||||
filter: KeyBinding {
|
filter: KeyBinding {
|
||||||
@@ -113,6 +128,10 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
|||||||
key: Key::Char('T'),
|
key: Key::Char('T'),
|
||||||
desc: "test all",
|
desc: "test all",
|
||||||
},
|
},
|
||||||
|
toggle_monitoring: KeyBinding {
|
||||||
|
key: Key::Char('m'),
|
||||||
|
desc: "toggle monitoring",
|
||||||
|
},
|
||||||
refresh: KeyBinding {
|
refresh: KeyBinding {
|
||||||
key: Key::Ctrl('r'),
|
key: Key::Ctrl('r'),
|
||||||
desc: "refresh",
|
desc: "refresh",
|
||||||
@@ -129,10 +148,6 @@ pub const DEFAULT_KEYBINDINGS: KeyBindings = KeyBindings {
|
|||||||
key: Key::End,
|
key: Key::End,
|
||||||
desc: "end",
|
desc: "end",
|
||||||
},
|
},
|
||||||
tab: KeyBinding {
|
|
||||||
key: Key::Tab,
|
|
||||||
desc: "tab",
|
|
||||||
},
|
|
||||||
delete: KeyBinding {
|
delete: KeyBinding {
|
||||||
key: Key::Delete,
|
key: Key::Delete,
|
||||||
desc: "delete",
|
desc: "delete",
|
||||||
|
|||||||
@@ -13,9 +13,12 @@ mod test {
|
|||||||
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, "left")]
|
#[case(DEFAULT_KEYBINDINGS.left, Key::Left, "left")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, "right")]
|
#[case(DEFAULT_KEYBINDINGS.right, Key::Right, "right")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, "backspace")]
|
#[case(DEFAULT_KEYBINDINGS.backspace, Key::Backspace, "backspace")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.next_servarr, Key::Tab, "next servarr")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.previous_servarr, Key::BackTab, "previous servarr")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.clear, Key::Char('c'), "clear")]
|
#[case(DEFAULT_KEYBINDINGS.clear, Key::Char('c'), "clear")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.auto_search, Key::Char('S'), "auto search")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.search, Key::Char('s'), "search")]
|
#[case(DEFAULT_KEYBINDINGS.search, Key::Char('s'), "search")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.settings, Key::Char('s'), "settings")]
|
#[case(DEFAULT_KEYBINDINGS.settings, Key::Char('S'), "settings")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.filter, Key::Char('f'), "filter")]
|
#[case(DEFAULT_KEYBINDINGS.filter, Key::Char('f'), "filter")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), "sort")]
|
#[case(DEFAULT_KEYBINDINGS.sort, Key::Char('o'), "sort")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), "edit")]
|
#[case(DEFAULT_KEYBINDINGS.edit, Key::Char('e'), "edit")]
|
||||||
@@ -24,11 +27,11 @@ mod test {
|
|||||||
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
#[case(DEFAULT_KEYBINDINGS.tasks, Key::Char('t'), "tasks")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
#[case(DEFAULT_KEYBINDINGS.test, Key::Char('t'), "test")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")]
|
#[case(DEFAULT_KEYBINDINGS.test_all, Key::Char('T'), "test all")]
|
||||||
|
#[case(DEFAULT_KEYBINDINGS.toggle_monitoring, Key::Char('m'), "toggle monitoring")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), "refresh")]
|
#[case(DEFAULT_KEYBINDINGS.refresh, Key::Ctrl('r'), "refresh")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), "update")]
|
#[case(DEFAULT_KEYBINDINGS.update, Key::Char('u'), "update")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, "home")]
|
#[case(DEFAULT_KEYBINDINGS.home, Key::Home, "home")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.end, Key::End, "end")]
|
#[case(DEFAULT_KEYBINDINGS.end, Key::End, "end")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.tab, Key::Tab, "tab")]
|
|
||||||
#[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, "delete")]
|
#[case(DEFAULT_KEYBINDINGS.delete, Key::Delete, "delete")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, "submit")]
|
#[case(DEFAULT_KEYBINDINGS.submit, Key::Enter, "submit")]
|
||||||
#[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), "submit")]
|
#[case(DEFAULT_KEYBINDINGS.confirm, Key::Ctrl('s'), "submit")]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::process;
|
use std::process;
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::{anyhow, Error};
|
||||||
use colored::Colorize;
|
use colored::Colorize;
|
||||||
use log::{debug, error};
|
use log::{debug, error};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -21,6 +21,7 @@ pub mod context_clues;
|
|||||||
pub mod key_binding;
|
pub mod key_binding;
|
||||||
mod key_binding_tests;
|
mod key_binding_tests;
|
||||||
pub mod radarr;
|
pub mod radarr;
|
||||||
|
pub mod sonarr;
|
||||||
|
|
||||||
const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies, None);
|
const DEFAULT_ROUTE: Route = Route::Radarr(ActiveRadarrBlock::Movies, None);
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ pub struct App<'a> {
|
|||||||
navigation_stack: Vec<Route>,
|
navigation_stack: Vec<Route>,
|
||||||
network_tx: Option<Sender<NetworkEvent>>,
|
network_tx: Option<Sender<NetworkEvent>>,
|
||||||
cancellation_token: CancellationToken,
|
cancellation_token: CancellationToken,
|
||||||
|
pub is_first_render: bool,
|
||||||
pub server_tabs: TabState,
|
pub server_tabs: TabState,
|
||||||
pub error: HorizontallyScrollableText,
|
pub error: HorizontallyScrollableText,
|
||||||
pub tick_until_poll: u64,
|
pub tick_until_poll: u64,
|
||||||
@@ -76,26 +78,26 @@ impl<'a> App<'a> {
|
|||||||
self.tick_count = 0;
|
self.tick_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allowing this code for now since we'll eventually be implementing additional Servarr support and we'll need it then
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn reset(&mut self) {
|
pub fn reset(&mut self) {
|
||||||
self.reset_tick_count();
|
self.reset_tick_count();
|
||||||
self.error = HorizontallyScrollableText::default();
|
self.error = HorizontallyScrollableText::default();
|
||||||
|
self.is_first_render = true;
|
||||||
self.data = Data::default();
|
self.data = Data::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_error(&mut self, error: anyhow::Error) {
|
pub fn handle_error(&mut self, error: Error) {
|
||||||
if self.error.text.is_empty() {
|
if self.error.text.is_empty() {
|
||||||
self.error = error.to_string().into();
|
self.error = error.to_string().into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn on_tick(&mut self, is_first_render: bool) {
|
pub async fn on_tick(&mut self) {
|
||||||
if self.tick_count % self.tick_until_poll == 0 || self.is_routing || self.should_refresh {
|
if self.tick_count % self.tick_until_poll == 0 || self.is_routing || self.should_refresh {
|
||||||
if let Route::Radarr(active_radarr_block, _) = self.get_current_route() {
|
match self.get_current_route() {
|
||||||
self
|
Route::Radarr(active_radarr_block, _) => self.radarr_on_tick(active_radarr_block).await,
|
||||||
.radarr_on_tick(*active_radarr_block, is_first_render)
|
Route::Sonarr(active_sonarr_block, _) => self.sonarr_on_tick(active_sonarr_block).await,
|
||||||
.await;
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.is_routing = false;
|
self.is_routing = false;
|
||||||
@@ -130,8 +132,8 @@ impl<'a> App<'a> {
|
|||||||
self.push_navigation_stack(route);
|
self.push_navigation_stack(route);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_route(&self) -> &Route {
|
pub fn get_current_route(&self) -> Route {
|
||||||
self.navigation_stack.last().unwrap_or(&DEFAULT_ROUTE)
|
*self.navigation_stack.last().unwrap_or(&DEFAULT_ROUTE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +144,7 @@ impl<'a> Default for App<'a> {
|
|||||||
network_tx: None,
|
network_tx: None,
|
||||||
cancellation_token: CancellationToken::new(),
|
cancellation_token: CancellationToken::new(),
|
||||||
error: HorizontallyScrollableText::default(),
|
error: HorizontallyScrollableText::default(),
|
||||||
|
is_first_render: true,
|
||||||
server_tabs: TabState::new(vec![
|
server_tabs: TabState::new(vec![
|
||||||
TabRoute {
|
TabRoute {
|
||||||
title: "Radarr",
|
title: "Radarr",
|
||||||
@@ -176,7 +179,7 @@ impl<'a> Default for App<'a> {
|
|||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Data<'a> {
|
pub struct Data<'a> {
|
||||||
pub radarr_data: RadarrData<'a>,
|
pub radarr_data: RadarrData<'a>,
|
||||||
pub sonarr_data: SonarrData,
|
pub sonarr_data: SonarrData<'a>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
|
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
|
||||||
|
|||||||
@@ -17,11 +17,23 @@ impl<'a> App<'a> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Collections => {
|
ActiveRadarrBlock::Collections => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
|
||||||
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetCollections.into())
|
.dispatch_network_event(RadarrEvent::GetCollections.into())
|
||||||
.await;
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetMovies.into())
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::CollectionDetails => {
|
ActiveRadarrBlock::CollectionDetails => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetTags.into())
|
||||||
|
.await;
|
||||||
self.is_loading = true;
|
self.is_loading = true;
|
||||||
self.populate_movie_collection_table().await;
|
self.populate_movie_collection_table().await;
|
||||||
self.is_loading = false;
|
self.is_loading = false;
|
||||||
@@ -37,6 +49,12 @@ impl<'a> App<'a> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Movies => {
|
ActiveRadarrBlock::Movies => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetTags.into())
|
||||||
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetMovies.into())
|
.dispatch_network_event(RadarrEvent::GetMovies.into())
|
||||||
.await;
|
.await;
|
||||||
@@ -45,6 +63,9 @@ impl<'a> App<'a> {
|
|||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::Indexers => {
|
ActiveRadarrBlock::Indexers => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(RadarrEvent::GetTags.into())
|
||||||
|
.await;
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetIndexers.into())
|
.dispatch_network_event(RadarrEvent::GetIndexers.into())
|
||||||
.await;
|
.await;
|
||||||
@@ -119,11 +140,11 @@ impl<'a> App<'a> {
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
self.check_for_prompt_action().await;
|
self.check_for_radarr_prompt_action().await;
|
||||||
self.reset_tick_count();
|
self.reset_tick_count();
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn check_for_prompt_action(&mut self) {
|
async fn check_for_radarr_prompt_action(&mut self) {
|
||||||
if self.data.radarr_data.prompt_confirm {
|
if self.data.radarr_data.prompt_confirm {
|
||||||
self.data.radarr_data.prompt_confirm = false;
|
self.data.radarr_data.prompt_confirm = false;
|
||||||
if let Some(radarr_event) = &self.data.radarr_data.prompt_confirm_action {
|
if let Some(radarr_event) = &self.data.radarr_data.prompt_confirm_action {
|
||||||
@@ -136,19 +157,17 @@ impl<'a> App<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) async fn radarr_on_tick(
|
pub(super) async fn radarr_on_tick(&mut self, active_radarr_block: ActiveRadarrBlock) {
|
||||||
&mut self,
|
if self.is_first_render {
|
||||||
active_radarr_block: ActiveRadarrBlock,
|
self.refresh_radarr_metadata().await;
|
||||||
is_first_render: bool,
|
|
||||||
) {
|
|
||||||
if is_first_render {
|
|
||||||
self.refresh_metadata().await;
|
|
||||||
self.dispatch_by_radarr_block(&active_radarr_block).await;
|
self.dispatch_by_radarr_block(&active_radarr_block).await;
|
||||||
|
self.is_first_render = false;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.should_refresh {
|
if self.should_refresh {
|
||||||
self.dispatch_by_radarr_block(&active_radarr_block).await;
|
self.dispatch_by_radarr_block(&active_radarr_block).await;
|
||||||
self.refresh_metadata().await;
|
self.refresh_radarr_metadata().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.is_routing {
|
if self.is_routing {
|
||||||
@@ -156,16 +175,15 @@ impl<'a> App<'a> {
|
|||||||
self.cancellation_token.cancel();
|
self.cancellation_token.cancel();
|
||||||
} else {
|
} else {
|
||||||
self.dispatch_by_radarr_block(&active_radarr_block).await;
|
self.dispatch_by_radarr_block(&active_radarr_block).await;
|
||||||
self.refresh_metadata().await;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.tick_count % self.tick_until_poll == 0 {
|
if self.tick_count % self.tick_until_poll == 0 {
|
||||||
self.refresh_metadata().await;
|
self.refresh_radarr_metadata().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn refresh_metadata(&mut self) {
|
async fn refresh_radarr_metadata(&mut self) {
|
||||||
self
|
self
|
||||||
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
|
.dispatch_network_event(RadarrEvent::GetQualityProfiles.into())
|
||||||
.await;
|
.await;
|
||||||
|
|||||||
@@ -35,60 +35,6 @@ pub static COLLECTIONS_CONTEXT_CLUES: [ContextClue; 8] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static DOWNLOADS_CONTEXT_CLUES: [ContextClue; 2] = [
|
|
||||||
(
|
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
|
||||||
),
|
|
||||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static BLOCKLIST_CONTEXT_CLUES: [ContextClue; 5] = [
|
|
||||||
(
|
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
|
||||||
),
|
|
||||||
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
|
||||||
(DEFAULT_KEYBINDINGS.submit, "details"),
|
|
||||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
|
||||||
(DEFAULT_KEYBINDINGS.clear, "clear blocklist"),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static ROOT_FOLDERS_CONTEXT_CLUES: [ContextClue; 3] = [
|
|
||||||
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
|
||||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
|
||||||
(
|
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static INDEXERS_CONTEXT_CLUES: [ContextClue; 6] = [
|
|
||||||
(DEFAULT_KEYBINDINGS.submit, "edit indexer"),
|
|
||||||
(
|
|
||||||
DEFAULT_KEYBINDINGS.settings,
|
|
||||||
DEFAULT_KEYBINDINGS.settings.desc,
|
|
||||||
),
|
|
||||||
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
|
||||||
(DEFAULT_KEYBINDINGS.test, "test indexer"),
|
|
||||||
(DEFAULT_KEYBINDINGS.test_all, "test all indexers"),
|
|
||||||
(
|
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static SYSTEM_CONTEXT_CLUES: [ContextClue; 5] = [
|
|
||||||
(DEFAULT_KEYBINDINGS.tasks, "open tasks"),
|
|
||||||
(DEFAULT_KEYBINDINGS.events, "open events"),
|
|
||||||
(DEFAULT_KEYBINDINGS.logs, "open logs"),
|
|
||||||
(DEFAULT_KEYBINDINGS.update, "open updates"),
|
|
||||||
(
|
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
|
||||||
DEFAULT_KEYBINDINGS.refresh.desc,
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static MOVIE_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
pub static MOVIE_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
(
|
(
|
||||||
DEFAULT_KEYBINDINGS.refresh,
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
@@ -96,7 +42,10 @@ pub static MOVIE_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
|||||||
),
|
),
|
||||||
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||||
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
(DEFAULT_KEYBINDINGS.search, "auto search"),
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -108,7 +57,10 @@ pub static MANUAL_MOVIE_SEARCH_CONTEXT_CLUES: [ContextClue; 6] = [
|
|||||||
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||||
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
(DEFAULT_KEYBINDINGS.search, "auto search"),
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -120,17 +72,13 @@ pub static ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
|
|||||||
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static CONFIRMATION_PROMPT_CONTEXT_CLUES: [ContextClue; 2] = [
|
|
||||||
(DEFAULT_KEYBINDINGS.confirm, "submit"),
|
|
||||||
(DEFAULT_KEYBINDINGS.esc, "cancel"),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
|
pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
(DEFAULT_KEYBINDINGS.submit, "start task"),
|
(DEFAULT_KEYBINDINGS.submit, "start task"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|
||||||
pub static COLLECTION_DETAILS_CONTEXT_CLUES: [ContextClue; 2] = [
|
pub static COLLECTION_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||||
(DEFAULT_KEYBINDINGS.submit, "show overview/add movie"),
|
(DEFAULT_KEYBINDINGS.submit, "show overview/add movie"),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, "edit collection"),
|
||||||
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ mod tests {
|
|||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::radarr::radarr_context_clues::{
|
use crate::app::radarr::radarr_context_clues::{
|
||||||
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, BLOCKLIST_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES,
|
ADD_MOVIE_SEARCH_RESULTS_CONTEXT_CLUES, COLLECTIONS_CONTEXT_CLUES,
|
||||||
COLLECTION_DETAILS_CONTEXT_CLUES, CONFIRMATION_PROMPT_CONTEXT_CLUES, DOWNLOADS_CONTEXT_CLUES,
|
COLLECTION_DETAILS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES,
|
||||||
INDEXERS_CONTEXT_CLUES, LIBRARY_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES,
|
MANUAL_MOVIE_SEARCH_CONTEXTUAL_CONTEXT_CLUES, MANUAL_MOVIE_SEARCH_CONTEXT_CLUES,
|
||||||
MANUAL_MOVIE_SEARCH_CONTEXT_CLUES, MOVIE_DETAILS_CONTEXT_CLUES, ROOT_FOLDERS_CONTEXT_CLUES,
|
MOVIE_DETAILS_CONTEXT_CLUES, SYSTEM_TASKS_CONTEXT_CLUES,
|
||||||
SYSTEM_CONTEXT_CLUES, SYSTEM_TASKS_CONTEXT_CLUES,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -113,141 +112,6 @@ mod tests {
|
|||||||
assert_eq!(collections_context_clues.next(), None);
|
assert_eq!(collections_context_clues.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_downloads_context_clues() {
|
|
||||||
let mut downloads_context_clues_iter = DOWNLOADS_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = downloads_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
|
||||||
assert_eq!(downloads_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_blocklist_context_clues() {
|
|
||||||
let mut blocklist_context_clues_iter = BLOCKLIST_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
|
||||||
assert_str_eq!(*description, "details");
|
|
||||||
|
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = blocklist_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.clear);
|
|
||||||
assert_str_eq!(*description, "clear blocklist");
|
|
||||||
assert_eq!(blocklist_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_root_folders_context_clues() {
|
|
||||||
let mut root_folders_context_clues_iter = ROOT_FOLDERS_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.add);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.add.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = root_folders_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
|
||||||
assert_eq!(root_folders_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_indexers_context_clues() {
|
|
||||||
let mut indexers_context_clues_iter = INDEXERS_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
|
||||||
assert_str_eq!(*description, "edit indexer");
|
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.settings);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.settings.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test);
|
|
||||||
assert_str_eq!(*description, "test indexer");
|
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.test_all);
|
|
||||||
assert_str_eq!(*description, "test all indexers");
|
|
||||||
|
|
||||||
let (key_binding, description) = indexers_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
|
||||||
assert_eq!(indexers_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_system_context_clues() {
|
|
||||||
let mut system_context_clues_iter = SYSTEM_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.tasks);
|
|
||||||
assert_str_eq!(*description, "open tasks");
|
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.events);
|
|
||||||
assert_str_eq!(*description, "open events");
|
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.logs);
|
|
||||||
assert_str_eq!(*description, "open logs");
|
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
|
||||||
assert_str_eq!(*description, "open updates");
|
|
||||||
|
|
||||||
let (key_binding, description) = system_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
|
||||||
assert_eq!(system_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_movie_details_context_clues() {
|
fn test_movie_details_context_clues() {
|
||||||
let mut movie_details_context_clues_iter = MOVIE_DETAILS_CONTEXT_CLUES.iter();
|
let mut movie_details_context_clues_iter = MOVIE_DETAILS_CONTEXT_CLUES.iter();
|
||||||
@@ -269,8 +133,8 @@ mod tests {
|
|||||||
|
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
assert_str_eq!(*description, "auto search");
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
let (key_binding, description) = movie_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
@@ -305,8 +169,8 @@ mod tests {
|
|||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
assert_str_eq!(*description, "auto search");
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
let (key_binding, description) = manual_movie_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
@@ -349,22 +213,6 @@ mod tests {
|
|||||||
assert_eq!(add_movie_search_results_context_clues_iter.next(), None);
|
assert_eq!(add_movie_search_results_context_clues_iter.next(), None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_confirmation_prompt_context_clues() {
|
|
||||||
let mut confirmation_prompt_context_clues_iter = CONFIRMATION_PROMPT_CONTEXT_CLUES.iter();
|
|
||||||
|
|
||||||
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.confirm);
|
|
||||||
assert_str_eq!(*description, "submit");
|
|
||||||
|
|
||||||
let (key_binding, description) = confirmation_prompt_context_clues_iter.next().unwrap();
|
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
|
||||||
assert_str_eq!(*description, "cancel");
|
|
||||||
assert_eq!(confirmation_prompt_context_clues_iter.next(), None);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_tasks_context_clues() {
|
fn test_system_tasks_context_clues() {
|
||||||
let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter();
|
let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter();
|
||||||
@@ -392,6 +240,11 @@ mod tests {
|
|||||||
|
|
||||||
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
|
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
||||||
|
assert_str_eq!(*description, "edit collection");
|
||||||
|
|
||||||
|
let (key_binding, description) = collection_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
assert_eq!(collection_details_context_clues_iter.next(), None);
|
assert_eq!(collection_details_context_clues_iter.next(), None);
|
||||||
|
|||||||
@@ -38,17 +38,25 @@ mod tests {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetCollections.into()
|
RadarrEvent::GetCollections.into()
|
||||||
);
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetMovies.into()
|
||||||
|
);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_dispatch_by_collection_details_block() {
|
async fn test_dispatch_by_collection_details_block() {
|
||||||
let (mut app, _) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
app.data.radarr_data.collections.set_items(vec![Collection {
|
app.data.radarr_data.collections.set_items(vec![Collection {
|
||||||
movies: Some(vec![CollectionMovie::default()]),
|
movies: Some(vec![CollectionMovie::default()]),
|
||||||
@@ -60,6 +68,14 @@ mod tests {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(!app.is_loading);
|
assert!(!app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
assert!(!app.data.radarr_data.collection_movies.items.is_empty());
|
assert!(!app.data.radarr_data.collection_movies.items.is_empty());
|
||||||
assert_eq!(app.tick_count, 0);
|
assert_eq!(app.tick_count, 0);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
@@ -80,6 +96,14 @@ mod tests {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::AddMovie(None).into()
|
RadarrEvent::AddMovie(None).into()
|
||||||
@@ -132,6 +156,14 @@ mod tests {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetMovies.into()
|
RadarrEvent::GetMovies.into()
|
||||||
@@ -153,6 +185,10 @@ mod tests {
|
|||||||
.await;
|
.await;
|
||||||
|
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
RadarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetIndexers.into()
|
RadarrEvent::GetIndexers.into()
|
||||||
@@ -459,22 +495,22 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_check_for_prompt_action_no_prompt_confirm() {
|
async fn test_check_for_radarr_prompt_action_no_prompt_confirm() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.prompt_confirm = false;
|
app.data.radarr_data.prompt_confirm = false;
|
||||||
|
|
||||||
app.check_for_prompt_action().await;
|
app.check_for_radarr_prompt_action().await;
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_check_for_prompt_action() {
|
async fn test_check_for_radarr_prompt_action() {
|
||||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::GetStatus);
|
app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::GetStatus);
|
||||||
|
|
||||||
app.check_for_prompt_action().await;
|
app.check_for_radarr_prompt_action().await;
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -490,7 +526,7 @@ mod tests {
|
|||||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
app.is_routing = true;
|
app.is_routing = true;
|
||||||
|
|
||||||
app.refresh_metadata().await;
|
app.refresh_radarr_metadata().await;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -522,8 +558,9 @@ mod tests {
|
|||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_radarr_on_tick_first_render() {
|
async fn test_radarr_on_tick_first_render() {
|
||||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.is_first_render = true;
|
||||||
|
|
||||||
app.radarr_on_tick(ActiveRadarrBlock::Downloads, true).await;
|
app.radarr_on_tick(ActiveRadarrBlock::Downloads).await;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -551,6 +588,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert!(app.is_loading);
|
assert!(app.is_loading);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
|
assert!(!app.is_first_render);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -559,26 +597,8 @@ mod tests {
|
|||||||
app.is_routing = true;
|
app.is_routing = true;
|
||||||
app.should_refresh = true;
|
app.should_refresh = true;
|
||||||
|
|
||||||
app
|
app.radarr_on_tick(ActiveRadarrBlock::Downloads).await;
|
||||||
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
sync_network_rx.recv().await.unwrap(),
|
|
||||||
RadarrEvent::GetDownloads.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
sync_network_rx.recv().await.unwrap(),
|
|
||||||
RadarrEvent::GetQualityProfiles.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
sync_network_rx.recv().await.unwrap(),
|
|
||||||
RadarrEvent::GetTags.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
sync_network_rx.recv().await.unwrap(),
|
|
||||||
RadarrEvent::GetRootFolders.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
RadarrEvent::GetDownloads.into()
|
RadarrEvent::GetDownloads.into()
|
||||||
@@ -592,9 +612,7 @@ mod tests {
|
|||||||
app.is_routing = true;
|
app.is_routing = true;
|
||||||
app.should_refresh = false;
|
app.should_refresh = false;
|
||||||
|
|
||||||
app
|
app.radarr_on_tick(ActiveRadarrBlock::Downloads).await;
|
||||||
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert!(app.cancellation_token.is_cancelled());
|
assert!(app.cancellation_token.is_cancelled());
|
||||||
}
|
}
|
||||||
@@ -604,9 +622,7 @@ mod tests {
|
|||||||
let (mut app, mut sync_network_rx) = construct_app_unit();
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
app.should_refresh = true;
|
app.should_refresh = true;
|
||||||
|
|
||||||
app
|
app.radarr_on_tick(ActiveRadarrBlock::Downloads).await;
|
||||||
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -623,9 +639,7 @@ mod tests {
|
|||||||
app.is_routing = true;
|
app.is_routing = true;
|
||||||
app.should_refresh = true;
|
app.should_refresh = true;
|
||||||
|
|
||||||
app
|
app.radarr_on_tick(ActiveRadarrBlock::Downloads).await;
|
||||||
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -643,9 +657,7 @@ mod tests {
|
|||||||
app.tick_count = 2;
|
app.tick_count = 2;
|
||||||
app.tick_until_poll = 2;
|
app.tick_until_poll = 2;
|
||||||
|
|
||||||
app
|
app.radarr_on_tick(ActiveRadarrBlock::Downloads).await;
|
||||||
.radarr_on_tick(ActiveRadarrBlock::Downloads, false)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
sync_network_rx.recv().await.unwrap(),
|
sync_network_rx.recv().await.unwrap(),
|
||||||
@@ -701,6 +713,7 @@ mod tests {
|
|||||||
let mut app = App {
|
let mut app = App {
|
||||||
network_tx: Some(sync_network_tx),
|
network_tx: Some(sync_network_tx),
|
||||||
tick_count: 1,
|
tick_count: 1,
|
||||||
|
is_first_render: false,
|
||||||
..App::default()
|
..App::default()
|
||||||
};
|
};
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|||||||
@@ -0,0 +1,245 @@
|
|||||||
|
use crate::{
|
||||||
|
models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock,
|
||||||
|
network::sonarr_network::SonarrEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::App;
|
||||||
|
|
||||||
|
pub mod sonarr_context_clues;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "sonarr_tests.rs"]
|
||||||
|
mod sonarr_tests;
|
||||||
|
|
||||||
|
impl<'a> App<'a> {
|
||||||
|
pub(super) async fn dispatch_by_sonarr_block(&mut self, active_sonarr_block: &ActiveSonarrBlock) {
|
||||||
|
match active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Series => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetQualityProfiles.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetLanguageProfiles.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetTags.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::ListSeries.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::SeriesDetails => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::ListSeries.into())
|
||||||
|
.await;
|
||||||
|
self.is_loading = true;
|
||||||
|
self.populate_seasons_table().await;
|
||||||
|
self.is_loading = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::SeriesHistory => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetSeriesHistory(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::SeasonDetails => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetEpisodes(None).into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetEpisodeFiles(None).into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetDownloads.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::SeasonHistory => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetSeasonHistory(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::ManualSeasonSearch => {
|
||||||
|
match self.data.sonarr_data.season_details_modal.as_ref() {
|
||||||
|
Some(season_details_modal) if season_details_modal.season_releases.is_empty() => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetSeasonReleases(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EpisodeDetails | ActiveSonarrBlock::EpisodeFile => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetEpisodeDetails(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EpisodeHistory => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetEpisodeHistory(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::ManualEpisodeSearch => {
|
||||||
|
if let Some(season_details_modal) = self.data.sonarr_data.season_details_modal.as_ref() {
|
||||||
|
if let Some(episode_details_modal) = season_details_modal.episode_details_modal.as_ref() {
|
||||||
|
if episode_details_modal.episode_releases.is_empty() {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetEpisodeReleases(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::Downloads => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetDownloads.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::Blocklist => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::ListSeries.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetBlocklist.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::History => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetHistory(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::RootFolders => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetRootFolders.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::Indexers => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetTags.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetIndexers.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetAllIndexerSettings.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::TestIndexer => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::TestIndexer(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::TestAllIndexers => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::TestAllIndexers.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::System => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetTasks.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetQueuedEvents.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetLogs(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchResults => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::SearchNewSeries(None).into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::SystemUpdates => {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetUpdates.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
self.check_for_sonarr_prompt_action().await;
|
||||||
|
self.reset_tick_count();
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn check_for_sonarr_prompt_action(&mut self) {
|
||||||
|
if self.data.sonarr_data.prompt_confirm {
|
||||||
|
self.data.sonarr_data.prompt_confirm = false;
|
||||||
|
if let Some(sonarr_event) = &self.data.sonarr_data.prompt_confirm_action {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(sonarr_event.clone().into())
|
||||||
|
.await;
|
||||||
|
self.should_refresh = true;
|
||||||
|
self.data.sonarr_data.prompt_confirm_action = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) async fn sonarr_on_tick(&mut self, active_sonarr_block: ActiveSonarrBlock) {
|
||||||
|
if self.is_first_render {
|
||||||
|
self.refresh_sonarr_metadata().await;
|
||||||
|
self.dispatch_by_sonarr_block(&active_sonarr_block).await;
|
||||||
|
self.is_first_render = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.should_refresh {
|
||||||
|
self.dispatch_by_sonarr_block(&active_sonarr_block).await;
|
||||||
|
self.refresh_sonarr_metadata().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.is_routing {
|
||||||
|
if !self.should_refresh {
|
||||||
|
self.cancellation_token.cancel();
|
||||||
|
} else {
|
||||||
|
self.dispatch_by_sonarr_block(&active_sonarr_block).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.tick_count % self.tick_until_poll == 0 {
|
||||||
|
self.refresh_sonarr_metadata().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn refresh_sonarr_metadata(&mut self) {
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetQualityProfiles.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetLanguageProfiles.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetTags.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetRootFolders.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetDownloads.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetDiskSpace.into())
|
||||||
|
.await;
|
||||||
|
self
|
||||||
|
.dispatch_network_event(SonarrEvent::GetStatus.into())
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn populate_seasons_table(&mut self) {
|
||||||
|
let seasons = self
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.series
|
||||||
|
.current_selection()
|
||||||
|
.clone()
|
||||||
|
.seasons
|
||||||
|
.unwrap_or_default()
|
||||||
|
.into_iter()
|
||||||
|
.map(|mut season| {
|
||||||
|
season.title = Some(format!("Season {}", season.season_number));
|
||||||
|
season
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
self.data.sonarr_data.seasons.set_items(seasons);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,159 @@
|
|||||||
|
use crate::app::{context_clues::ContextClue, key_binding::DEFAULT_KEYBINDINGS};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "sonarr_context_clues_tests.rs"]
|
||||||
|
mod sonarr_context_clues_tests;
|
||||||
|
|
||||||
|
pub static ADD_SERIES_SEARCH_RESULTS_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "edit search"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SERIES_CONTEXT_CLUES: [ContextClue; 10] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.add, DEFAULT_KEYBINDINGS.add.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, DEFAULT_KEYBINDINGS.delete.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, "update all"),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SERIES_DETAILS_CONTEXT_CLUES: [ContextClue; 8] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "season details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static HISTORY_CONTEXT_CLUES: [ContextClue; 6] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SERIES_HISTORY_CONTEXT_CLUES: [ContextClue; 9] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.edit, DEFAULT_KEYBINDINGS.edit.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.update, DEFAULT_KEYBINDINGS.update.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SEASON_DETAILS_CONTEXTUAL_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "episode details"),
|
||||||
|
(DEFAULT_KEYBINDINGS.delete, "delete episode"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SEASON_DETAILS_CONTEXT_CLUES: [ContextClue; 5] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring,
|
||||||
|
DEFAULT_KEYBINDINGS.toggle_monitoring.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SEASON_HISTORY_CONTEXT_CLUES: [ContextClue; 6] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.search, DEFAULT_KEYBINDINGS.search.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.filter, DEFAULT_KEYBINDINGS.filter.desc),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, "cancel filter/close"),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static MANUAL_SEASON_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static MANUAL_EPISODE_SEARCH_CONTEXT_CLUES: [ContextClue; 4] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.sort, DEFAULT_KEYBINDINGS.sort.desc),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static DETAILS_CONTEXTUAL_CONTEXT_CLUES: [ContextClue; 1] =
|
||||||
|
[(DEFAULT_KEYBINDINGS.submit, "details")];
|
||||||
|
|
||||||
|
pub static EPISODE_DETAILS_CONTEXT_CLUES: [ContextClue; 3] = [
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh,
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.desc,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search,
|
||||||
|
DEFAULT_KEYBINDINGS.auto_search.desc,
|
||||||
|
),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
|
|
||||||
|
pub static SYSTEM_TASKS_CONTEXT_CLUES: [ContextClue; 2] = [
|
||||||
|
(DEFAULT_KEYBINDINGS.submit, "start task"),
|
||||||
|
(DEFAULT_KEYBINDINGS.esc, DEFAULT_KEYBINDINGS.esc.desc),
|
||||||
|
];
|
||||||
@@ -0,0 +1,402 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
|
||||||
|
use crate::app::{
|
||||||
|
key_binding::DEFAULT_KEYBINDINGS,
|
||||||
|
sonarr::sonarr_context_clues::{
|
||||||
|
ADD_SERIES_SEARCH_RESULTS_CONTEXT_CLUES, DETAILS_CONTEXTUAL_CONTEXT_CLUES,
|
||||||
|
EPISODE_DETAILS_CONTEXT_CLUES, HISTORY_CONTEXT_CLUES, MANUAL_EPISODE_SEARCH_CONTEXT_CLUES,
|
||||||
|
MANUAL_SEASON_SEARCH_CONTEXT_CLUES, SEASON_DETAILS_CONTEXTUAL_CONTEXT_CLUES,
|
||||||
|
SEASON_DETAILS_CONTEXT_CLUES, SEASON_HISTORY_CONTEXT_CLUES, SERIES_CONTEXT_CLUES,
|
||||||
|
SERIES_DETAILS_CONTEXT_CLUES, SERIES_HISTORY_CONTEXT_CLUES, SYSTEM_TASKS_CONTEXT_CLUES,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_add_series_search_results_context_clues() {
|
||||||
|
let mut add_series_search_results_context_clues_iter =
|
||||||
|
ADD_SERIES_SEARCH_RESULTS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = add_series_search_results_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "details");
|
||||||
|
|
||||||
|
let (key_binding, description) = add_series_search_results_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, "edit search");
|
||||||
|
assert_eq!(add_series_search_results_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_series_context_clues() {
|
||||||
|
let mut series_context_clues_iter = SERIES_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.add);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.add.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.delete.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.filter);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.filter.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
||||||
|
assert_str_eq!(*description, "update all");
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "details");
|
||||||
|
|
||||||
|
let (key_binding, description) = series_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, "cancel filter");
|
||||||
|
assert_eq!(series_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_series_history_context_clues() {
|
||||||
|
let mut series_history_context_clues_iter = SERIES_HISTORY_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "details");
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.filter);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.filter.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.update.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, "cancel filter/close");
|
||||||
|
assert_eq!(series_history_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_context_clues() {
|
||||||
|
let mut history_context_clues_iter = HISTORY_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "details");
|
||||||
|
|
||||||
|
let (key_binding, description) = history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.filter);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.filter.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, "cancel filter");
|
||||||
|
assert_eq!(history_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_series_details_context_clues() {
|
||||||
|
let mut series_details_context_clues_iter = SERIES_DETAILS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.edit);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.edit.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.toggle_monitoring);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.toggle_monitoring.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "season details");
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.update);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.update.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = series_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
|
assert_eq!(series_details_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_season_details_context_clues() {
|
||||||
|
let mut season_details_context_clues_iter = SEASON_DETAILS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = season_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.toggle_monitoring);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.toggle_monitoring.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
|
assert_eq!(season_details_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_season_details_contextual_context_clues() {
|
||||||
|
let mut season_details_contextual_context_clues_iter =
|
||||||
|
SEASON_DETAILS_CONTEXTUAL_CONTEXT_CLUES.iter();
|
||||||
|
let (key_binding, description) = season_details_contextual_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "episode details");
|
||||||
|
|
||||||
|
let (key_binding, description) = season_details_contextual_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.delete);
|
||||||
|
assert_str_eq!(*description, "delete episode");
|
||||||
|
assert_eq!(season_details_contextual_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_season_history_context_clues() {
|
||||||
|
let mut season_history_context_clues_iter = SEASON_HISTORY_CONTEXT_CLUES.iter();
|
||||||
|
let (key_binding, description) = season_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.filter);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.filter.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = season_history_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, "cancel filter/close");
|
||||||
|
assert_eq!(season_history_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_manual_season_search_context_clues() {
|
||||||
|
let mut manual_season_search_context_clues_iter = MANUAL_SEASON_SEARCH_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_season_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
|
assert_eq!(manual_season_search_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_manual_episode_search_context_clues() {
|
||||||
|
let mut manual_episode_search_context_clues_iter = MANUAL_EPISODE_SEARCH_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.sort);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.sort.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = manual_episode_search_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
|
assert_eq!(manual_episode_search_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn details_contextual_context_clues() {
|
||||||
|
let mut manual_search_contextual_context_clues_iter = DETAILS_CONTEXTUAL_CONTEXT_CLUES.iter();
|
||||||
|
let (key_binding, description) = manual_search_contextual_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "details");
|
||||||
|
assert_eq!(manual_search_contextual_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_episode_details_context_clues() {
|
||||||
|
let mut episode_details_context_clues_iter = EPISODE_DETAILS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = episode_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.refresh);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.refresh.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = episode_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.auto_search);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.auto_search.desc);
|
||||||
|
|
||||||
|
let (key_binding, description) = episode_details_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
|
assert_eq!(episode_details_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_tasks_context_clues() {
|
||||||
|
let mut system_tasks_context_clues_iter = SYSTEM_TASKS_CONTEXT_CLUES.iter();
|
||||||
|
|
||||||
|
let (key_binding, description) = system_tasks_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.submit);
|
||||||
|
assert_str_eq!(*description, "start task");
|
||||||
|
|
||||||
|
let (key_binding, description) = system_tasks_context_clues_iter.next().unwrap();
|
||||||
|
|
||||||
|
assert_eq!(*key_binding, DEFAULT_KEYBINDINGS.esc);
|
||||||
|
assert_str_eq!(*description, DEFAULT_KEYBINDINGS.esc.desc);
|
||||||
|
assert_eq!(system_tasks_context_clues_iter.next(), None);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,743 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
mod sonarr_tests {
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use tokio::sync::mpsc;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
app::App,
|
||||||
|
models::{
|
||||||
|
servarr_data::sonarr::{
|
||||||
|
modals::{EpisodeDetailsModal, SeasonDetailsModal},
|
||||||
|
sonarr_data::ActiveSonarrBlock,
|
||||||
|
},
|
||||||
|
sonarr_models::{Season, Series, SonarrRelease},
|
||||||
|
},
|
||||||
|
network::{sonarr_network::SonarrEvent, NetworkEvent},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_blocklist_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::Blocklist)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::ListSeries.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetBlocklist.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_series_history_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::SeriesHistory)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetSeriesHistory(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_series_details_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app.data.sonarr_data.series.set_items(vec![Series {
|
||||||
|
seasons: Some(vec![Season::default()]),
|
||||||
|
..Series::default()
|
||||||
|
}]);
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::SeriesDetails)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(!app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::ListSeries.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.seasons.items.is_empty());
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_season_details_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::SeasonDetails)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetEpisodes(None).into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetEpisodeFiles(None).into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_season_history_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::SeasonHistory)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetSeasonHistory(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_manual_season_search_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.data.sonarr_data.season_details_modal = Some(SeasonDetailsModal::default());
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::ManualSeasonSearch)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetSeasonReleases(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_manual_season_search_block_is_loading() {
|
||||||
|
let mut app = App {
|
||||||
|
is_loading: true,
|
||||||
|
..App::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::ManualSeasonSearch)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_manual_season_search_block_season_releases_non_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
let mut season_details_modal = SeasonDetailsModal::default();
|
||||||
|
season_details_modal
|
||||||
|
.season_releases
|
||||||
|
.set_items(vec![SonarrRelease::default()]);
|
||||||
|
app.data.sonarr_data.season_details_modal = Some(season_details_modal);
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::ManualSeasonSearch)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(!app.is_loading);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_episode_details_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeDetails)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetEpisodeDetails(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_episode_file_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeFile)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetEpisodeDetails(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_episode_history_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::EpisodeHistory)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetEpisodeHistory(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_manual_episode_search_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
let season_details_modal = SeasonDetailsModal {
|
||||||
|
episode_details_modal: Some(EpisodeDetailsModal::default()),
|
||||||
|
..SeasonDetailsModal::default()
|
||||||
|
};
|
||||||
|
app.data.sonarr_data.season_details_modal = Some(season_details_modal);
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::ManualEpisodeSearch)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetEpisodeReleases(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_manual_episode_search_block_is_loading() {
|
||||||
|
let mut app = App {
|
||||||
|
is_loading: true,
|
||||||
|
..App::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::ManualEpisodeSearch)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_manual_episode_search_block_episode_releases_non_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
let mut episode_details_modal = EpisodeDetailsModal::default();
|
||||||
|
episode_details_modal
|
||||||
|
.episode_releases
|
||||||
|
.set_items(vec![SonarrRelease::default()]);
|
||||||
|
let season_details_modal = SeasonDetailsModal {
|
||||||
|
episode_details_modal: Some(episode_details_modal),
|
||||||
|
..SeasonDetailsModal::default()
|
||||||
|
};
|
||||||
|
app.data.sonarr_data.season_details_modal = Some(season_details_modal);
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::ManualEpisodeSearch)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(!app.is_loading);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_history_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::History)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetHistory(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_downloads_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::Downloads)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_root_folders_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::RootFolders)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetRootFolders.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_series_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::Series)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetLanguageProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::ListSeries.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_indexers_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::Indexers)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetIndexers.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_all_indexer_settings_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::AllIndexerSettingsPrompt)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetAllIndexerSettings.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_test_indexer_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::TestIndexer)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::TestIndexer(None).into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_test_all_indexers_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::TestAllIndexers)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::TestAllIndexers.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_system_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::System)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetTasks.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetQueuedEvents.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetLogs(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_system_updates_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::SystemUpdates)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetUpdates.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_dispatch_by_add_series_search_results_block() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
|
||||||
|
app
|
||||||
|
.dispatch_by_sonarr_block(&ActiveSonarrBlock::AddSeriesSearchResults)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::SearchNewSeries(None).into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.tick_count, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_check_for_sonarr_prompt_action_no_prompt_confirm() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
|
||||||
|
app.check_for_sonarr_prompt_action().await;
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_check_for_sonarr_prompt_action() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::GetStatus);
|
||||||
|
|
||||||
|
app.check_for_sonarr_prompt_action().await;
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetStatus.into()
|
||||||
|
);
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_refresh_metadata() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.is_routing = true;
|
||||||
|
|
||||||
|
app.refresh_sonarr_metadata().await;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetLanguageProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetRootFolders.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDiskSpace.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetStatus.into()
|
||||||
|
);
|
||||||
|
assert!(app.is_loading);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_on_tick_first_render() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.is_first_render = true;
|
||||||
|
|
||||||
|
app.sonarr_on_tick(ActiveSonarrBlock::Downloads).await;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetLanguageProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetRootFolders.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDiskSpace.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetStatus.into()
|
||||||
|
);
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(!app.is_first_render);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_on_tick_routing() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.is_routing = true;
|
||||||
|
app.should_refresh = true;
|
||||||
|
|
||||||
|
app.sonarr_on_tick(ActiveSonarrBlock::Downloads).await;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_on_tick_routing_while_long_request_is_running_should_cancel_request() {
|
||||||
|
let (mut app, _) = construct_app_unit();
|
||||||
|
app.is_routing = true;
|
||||||
|
app.should_refresh = false;
|
||||||
|
|
||||||
|
app.sonarr_on_tick(ActiveSonarrBlock::Downloads).await;
|
||||||
|
|
||||||
|
assert!(app.cancellation_token.is_cancelled());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_on_tick_should_refresh() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.should_refresh = true;
|
||||||
|
|
||||||
|
app.sonarr_on_tick(ActiveSonarrBlock::Downloads).await;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_on_tick_should_refresh_does_not_cancel_prompt_requests() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.is_routing = true;
|
||||||
|
app.should_refresh = true;
|
||||||
|
|
||||||
|
app.sonarr_on_tick(ActiveSonarrBlock::Downloads).await;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert!(app.is_loading);
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(!app.cancellation_token.is_cancelled());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_sonarr_on_tick_network_tick_frequency() {
|
||||||
|
let (mut app, mut sync_network_rx) = construct_app_unit();
|
||||||
|
app.tick_count = 2;
|
||||||
|
app.tick_until_poll = 2;
|
||||||
|
|
||||||
|
app.sonarr_on_tick(ActiveSonarrBlock::Downloads).await;
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetQualityProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetLanguageProfiles.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetTags.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetRootFolders.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
sync_network_rx.recv().await.unwrap(),
|
||||||
|
SonarrEvent::GetDownloads.into()
|
||||||
|
);
|
||||||
|
assert!(app.is_loading);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_populate_seasons_table_unfiltered() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.series.set_items(vec![Series {
|
||||||
|
seasons: Some(vec![Season::default()]),
|
||||||
|
..Series::default()
|
||||||
|
}]);
|
||||||
|
|
||||||
|
app.populate_seasons_table().await;
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.seasons.items.is_empty());
|
||||||
|
assert_str_eq!(
|
||||||
|
app.data.sonarr_data.seasons.items[0]
|
||||||
|
.title
|
||||||
|
.as_ref()
|
||||||
|
.unwrap(),
|
||||||
|
"Season 0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_populate_seasons_table_filtered() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.series.set_filtered_items(vec![Series {
|
||||||
|
seasons: Some(vec![Season::default()]),
|
||||||
|
..Series::default()
|
||||||
|
}]);
|
||||||
|
|
||||||
|
app.populate_seasons_table().await;
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.seasons.items.is_empty());
|
||||||
|
assert_str_eq!(
|
||||||
|
app.data.sonarr_data.seasons.items[0]
|
||||||
|
.title
|
||||||
|
.as_ref()
|
||||||
|
.unwrap(),
|
||||||
|
"Season 0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn construct_app_unit<'a>() -> (App<'a>, mpsc::Receiver<NetworkEvent>) {
|
||||||
|
let (sync_network_tx, sync_network_rx) = mpsc::channel::<NetworkEvent>(500);
|
||||||
|
let mut app = App {
|
||||||
|
network_tx: Some(sync_network_tx),
|
||||||
|
tick_count: 1,
|
||||||
|
is_first_render: false,
|
||||||
|
..App::default()
|
||||||
|
};
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
(app, sync_network_rx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,6 +33,15 @@ pub enum SonarrListCommand {
|
|||||||
)]
|
)]
|
||||||
series_id: i64,
|
series_id: i64,
|
||||||
},
|
},
|
||||||
|
#[command(about = "List the episode files for the series with the given ID")]
|
||||||
|
EpisodeFiles {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Sonarr ID of the series whose episode files you wish to fetch",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
series_id: i64,
|
||||||
|
},
|
||||||
#[command(about = "Fetch all history events for the episode with the given ID")]
|
#[command(about = "Fetch all history events for the episode with the given ID")]
|
||||||
EpisodeHistory {
|
EpisodeHistory {
|
||||||
#[arg(
|
#[arg(
|
||||||
@@ -67,6 +76,23 @@ pub enum SonarrListCommand {
|
|||||||
QueuedEvents,
|
QueuedEvents,
|
||||||
#[command(about = "List all root folders in Sonarr")]
|
#[command(about = "List all root folders in Sonarr")]
|
||||||
RootFolders,
|
RootFolders,
|
||||||
|
#[command(
|
||||||
|
about = "Fetch all history events for the given season corresponding to the series with the given ID."
|
||||||
|
)]
|
||||||
|
SeasonHistory {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Sonarr ID of the series whose history you wish to fetch and list",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
series_id: i64,
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The season number to fetch history events for",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
season_number: i64,
|
||||||
|
},
|
||||||
#[command(about = "List all series in your Sonarr library")]
|
#[command(about = "List all series in your Sonarr library")]
|
||||||
Series,
|
Series,
|
||||||
#[command(about = "Fetch all history events for the series with the given ID")]
|
#[command(about = "Fetch all history events for the series with the given ID")]
|
||||||
@@ -141,6 +167,13 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrListCommand> for SonarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
SonarrListCommand::EpisodeFiles { series_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(SonarrEvent::GetEpisodeFiles(Some(series_id)).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
SonarrListCommand::EpisodeHistory { episode_id } => {
|
SonarrListCommand::EpisodeHistory { episode_id } => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
@@ -207,6 +240,18 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrListCommand> for SonarrListCommandH
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
SonarrListCommand::SeasonHistory {
|
||||||
|
series_id,
|
||||||
|
season_number,
|
||||||
|
} => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(
|
||||||
|
SonarrEvent::GetSeasonHistory(Some((series_id, season_number))).into(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
SonarrListCommand::Series => {
|
SonarrListCommand::Series => {
|
||||||
let resp = self
|
let resp = self
|
||||||
.network
|
.network
|
||||||
|
|||||||
@@ -57,6 +57,18 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_episode_files_requires_series_id() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "list", "episode-files"]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_episode_history_requires_series_id() {
|
fn test_list_episode_history_requires_series_id() {
|
||||||
let result =
|
let result =
|
||||||
@@ -149,6 +161,79 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_list_episode_files_success() {
|
||||||
|
let expected_args = SonarrListCommand::EpisodeFiles { series_id: 1 };
|
||||||
|
let result = Cli::try_parse_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"list",
|
||||||
|
"episode-files",
|
||||||
|
"--series-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
|
||||||
|
if let Some(Command::Sonarr(SonarrCommand::List(episode_files_command))) =
|
||||||
|
result.unwrap().command
|
||||||
|
{
|
||||||
|
assert_eq!(episode_files_command, expected_args);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_season_history_requires_series_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"list",
|
||||||
|
"season-history",
|
||||||
|
"--season-number",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_season_history_requires_season_number() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"list",
|
||||||
|
"season-history",
|
||||||
|
"--series-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_season_history_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"list",
|
||||||
|
"season-history",
|
||||||
|
"--series-id",
|
||||||
|
"1",
|
||||||
|
"--season-number",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_list_series_history_requires_series_id() {
|
fn test_list_series_history_requires_series_id() {
|
||||||
let result =
|
let result =
|
||||||
@@ -263,6 +348,32 @@ mod tests {
|
|||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_handle_list_episode_files_command() {
|
||||||
|
let expected_series_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
SonarrEvent::GetEpisodeFiles(Some(expected_series_id)).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
|
let list_episode_files_command = SonarrListCommand::EpisodeFiles { series_id: 1 };
|
||||||
|
|
||||||
|
let result =
|
||||||
|
SonarrListCommandHandler::with(&app_arc, list_episode_files_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn test_handle_list_history_command() {
|
async fn test_handle_list_history_command() {
|
||||||
let expected_events = 1000;
|
let expected_events = 1000;
|
||||||
@@ -368,5 +479,35 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_list_season_history_command() {
|
||||||
|
let expected_series_id = 1;
|
||||||
|
let expected_season_number = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
SonarrEvent::GetSeasonHistory(Some((expected_series_id, expected_season_number))).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
|
let list_season_history_command = SonarrListCommand::SeasonHistory {
|
||||||
|
series_id: 1,
|
||||||
|
season_number: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result =
|
||||||
|
SonarrListCommandHandler::with(&app_arc, list_season_history_command, &mut mock_network)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -120,6 +120,32 @@ pub enum SonarrCommand {
|
|||||||
},
|
},
|
||||||
#[command(about = "Test all Sonarr indexers")]
|
#[command(about = "Test all Sonarr indexers")]
|
||||||
TestAllIndexers,
|
TestAllIndexers,
|
||||||
|
#[command(about = "Toggle monitoring for the specified episode")]
|
||||||
|
ToggleEpisodeMonitoring {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Sonarr ID of the episode to toggle monitoring on",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
episode_id: i64,
|
||||||
|
},
|
||||||
|
#[command(
|
||||||
|
about = "Toggle monitoring for the specified season that corresponds to the specified series ID"
|
||||||
|
)]
|
||||||
|
ToggleSeasonMonitoring {
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The Sonarr ID of the series that the season belongs to",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
series_id: i64,
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "The season number to toggle monitoring for",
|
||||||
|
required = true
|
||||||
|
)]
|
||||||
|
season_number: i64,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SonarrCommand> for Command {
|
impl From<SonarrCommand> for Command {
|
||||||
@@ -245,6 +271,25 @@ impl<'a, 'b> CliCommandHandler<'a, 'b, SonarrCommand> for SonarrCliHandler<'a, '
|
|||||||
.await?;
|
.await?;
|
||||||
serde_json::to_string_pretty(&resp)?
|
serde_json::to_string_pretty(&resp)?
|
||||||
}
|
}
|
||||||
|
SonarrCommand::ToggleEpisodeMonitoring { episode_id } => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(SonarrEvent::ToggleEpisodeMonitoring(Some(episode_id)).into())
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
|
SonarrCommand::ToggleSeasonMonitoring {
|
||||||
|
series_id,
|
||||||
|
season_number,
|
||||||
|
} => {
|
||||||
|
let resp = self
|
||||||
|
.network
|
||||||
|
.handle_network_event(
|
||||||
|
SonarrEvent::ToggleSeasonMonitoring(Some((series_id, season_number))).into(),
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
serde_json::to_string_pretty(&resp)?
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
|
|||||||
@@ -142,6 +142,80 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_episode_monitoring_requires_episode_id() {
|
||||||
|
let result =
|
||||||
|
Cli::command().try_get_matches_from(["managarr", "sonarr", "toggle-episode-monitoring"]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_episode_monitoring_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"toggle-episode-monitoring",
|
||||||
|
"--episode-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_season_monitoring_requires_series_id() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"toggle-season-monitoring",
|
||||||
|
"--season-number",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_season_monitoring_requires_season_number() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"toggle-season-monitoring",
|
||||||
|
"--series-id",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.unwrap_err().kind(),
|
||||||
|
ErrorKind::MissingRequiredArgument
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_toggle_season_monitoring_requirements_satisfied() {
|
||||||
|
let result = Cli::command().try_get_matches_from([
|
||||||
|
"managarr",
|
||||||
|
"sonarr",
|
||||||
|
"toggle-season-monitoring",
|
||||||
|
"--series-id",
|
||||||
|
"1",
|
||||||
|
"--season-number",
|
||||||
|
"1",
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod handler {
|
mod handler {
|
||||||
@@ -616,5 +690,69 @@ mod tests {
|
|||||||
|
|
||||||
assert!(result.is_ok());
|
assert!(result.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_list_toggle_episode_monitoring_command() {
|
||||||
|
let expected_episode_id = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
SonarrEvent::ToggleEpisodeMonitoring(Some(expected_episode_id)).into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
|
let toggle_episode_monitoring_command =
|
||||||
|
SonarrCommand::ToggleEpisodeMonitoring { episode_id: 1 };
|
||||||
|
|
||||||
|
let result = SonarrCliHandler::with(
|
||||||
|
&app_arc,
|
||||||
|
toggle_episode_monitoring_command,
|
||||||
|
&mut mock_network,
|
||||||
|
)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_list_toggle_season_monitoring_command() {
|
||||||
|
let expected_series_id = 1;
|
||||||
|
let expected_season_number = 1;
|
||||||
|
let mut mock_network = MockNetworkTrait::new();
|
||||||
|
mock_network
|
||||||
|
.expect_handle_network_event()
|
||||||
|
.with(eq::<NetworkEvent>(
|
||||||
|
SonarrEvent::ToggleSeasonMonitoring(Some((expected_series_id, expected_season_number)))
|
||||||
|
.into(),
|
||||||
|
))
|
||||||
|
.times(1)
|
||||||
|
.returning(|_| {
|
||||||
|
Ok(Serdeable::Sonarr(SonarrSerdeable::Value(
|
||||||
|
json!({"testResponse": "response"}),
|
||||||
|
)))
|
||||||
|
});
|
||||||
|
let app_arc = Arc::new(Mutex::new(App::default()));
|
||||||
|
let toggle_season_monitoring_command = SonarrCommand::ToggleSeasonMonitoring {
|
||||||
|
series_id: 1,
|
||||||
|
season_number: 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = SonarrCliHandler::with(
|
||||||
|
&app_arc,
|
||||||
|
toggle_season_monitoring_command,
|
||||||
|
&mut mock_network,
|
||||||
|
)
|
||||||
|
.handle()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
assert!(result.is_ok());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub enum Key {
|
|||||||
Home,
|
Home,
|
||||||
End,
|
End,
|
||||||
Tab,
|
Tab,
|
||||||
|
BackTab,
|
||||||
Delete,
|
Delete,
|
||||||
Ctrl(char),
|
Ctrl(char),
|
||||||
Char(char),
|
Char(char),
|
||||||
@@ -40,6 +41,7 @@ impl Display for Key {
|
|||||||
Key::Home => write!(f, "<home>"),
|
Key::Home => write!(f, "<home>"),
|
||||||
Key::End => write!(f, "<end>"),
|
Key::End => write!(f, "<end>"),
|
||||||
Key::Tab => write!(f, "<tab>"),
|
Key::Tab => write!(f, "<tab>"),
|
||||||
|
Key::BackTab => write!(f, "<shift-tab>"),
|
||||||
Key::Delete => write!(f, "<del>"),
|
Key::Delete => write!(f, "<del>"),
|
||||||
_ => write!(f, "<{self:?}>"),
|
_ => write!(f, "<{self:?}>"),
|
||||||
}
|
}
|
||||||
@@ -75,6 +77,11 @@ impl From<KeyEvent> for Key {
|
|||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::End, ..
|
code: KeyCode::End, ..
|
||||||
} => Key::End,
|
} => Key::End,
|
||||||
|
KeyEvent {
|
||||||
|
code: KeyCode::BackTab,
|
||||||
|
modifiers: KeyModifiers::SHIFT,
|
||||||
|
..
|
||||||
|
} => Key::BackTab,
|
||||||
KeyEvent {
|
KeyEvent {
|
||||||
code: KeyCode::Tab, ..
|
code: KeyCode::Tab, ..
|
||||||
} => Key::Tab,
|
} => Key::Tab,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ mod tests {
|
|||||||
#[case(Key::Home, "home")]
|
#[case(Key::Home, "home")]
|
||||||
#[case(Key::End, "end")]
|
#[case(Key::End, "end")]
|
||||||
#[case(Key::Tab, "tab")]
|
#[case(Key::Tab, "tab")]
|
||||||
|
#[case(Key::BackTab, "shift-tab")]
|
||||||
#[case(Key::Delete, "del")]
|
#[case(Key::Delete, "del")]
|
||||||
#[case(Key::Char('q'), "q")]
|
#[case(Key::Char('q'), "q")]
|
||||||
#[case(Key::Ctrl('q'), "ctrl-q")]
|
#[case(Key::Ctrl('q'), "ctrl-q")]
|
||||||
@@ -67,6 +68,19 @@ mod tests {
|
|||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Tab)), Key::Tab);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Tab)), Key::Tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_key_from_back_tab() {
|
||||||
|
assert_eq!(
|
||||||
|
Key::from(KeyEvent {
|
||||||
|
code: KeyCode::BackTab,
|
||||||
|
modifiers: KeyModifiers::SHIFT,
|
||||||
|
kind: KeyEventKind::Press,
|
||||||
|
state: KeyEventState::NONE
|
||||||
|
}),
|
||||||
|
Key::BackTab
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_key_from_delete() {
|
fn test_key_from_delete() {
|
||||||
assert_eq!(Key::from(KeyEvent::from(KeyCode::Delete)), Key::Delete);
|
assert_eq!(Key::from(KeyEvent::from(KeyCode::Delete)), Key::Delete);
|
||||||
|
|||||||
@@ -99,86 +99,96 @@ mod test_utils {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! test_iterable_scroll {
|
macro_rules! test_iterable_scroll {
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack($block.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(&key, &mut app, &$block, &$context).handle();
|
||||||
|
|
||||||
assert_str_eq!(app.data.radarr_data.$data_ref.current_selection(), "Test 2");
|
pretty_assertions::assert_str_eq!(
|
||||||
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
|
"Test 2"
|
||||||
|
);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(&key, &mut app, &$block, &$context).handle();
|
||||||
|
|
||||||
assert_str_eq!(app.data.radarr_data.$data_ref.current_selection(), "Test 1");
|
pretty_assertions::assert_str_eq!(
|
||||||
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
|
"Test 1"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack($block.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.set_items(simple_stateful_iterable_vec!($items));
|
.set_items(simple_stateful_iterable_vec!($items));
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.$data_ref.set_items($items);
|
app.push_navigation_stack($block.into());
|
||||||
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
fn $func(#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.$data_ref.set_items($items);
|
app.push_navigation_stack($block.into());
|
||||||
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.$field
|
.$field
|
||||||
@@ -186,12 +196,12 @@ mod test_utils {
|
|||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&key, &mut app, &$block, &$context).handle();
|
$handler::with(key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.$field
|
.$field
|
||||||
@@ -204,86 +214,96 @@ mod test_utils {
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! test_iterable_home_and_end {
|
macro_rules! test_iterable_home_and_end {
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $block:expr, $context:expr) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.$data_ref.set_items(vec![
|
app.push_navigation_stack($block.into());
|
||||||
|
app.data.$servarr_data.$data_ref.set_items(vec![
|
||||||
"Test 1".to_owned(),
|
"Test 1".to_owned(),
|
||||||
"Test 2".to_owned(),
|
"Test 2".to_owned(),
|
||||||
"Test 3".to_owned(),
|
"Test 3".to_owned(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.end.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(app.data.radarr_data.$data_ref.current_selection(), "Test 3");
|
pretty_assertions::assert_str_eq!(
|
||||||
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
|
"Test 3"
|
||||||
|
);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.home.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(app.data.radarr_data.$data_ref.current_selection(), "Test 1");
|
pretty_assertions::assert_str_eq!(
|
||||||
|
app.data.$servarr_data.$data_ref.current_selection(),
|
||||||
|
"Test 1"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:ident, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack($block.into());
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.set_items(extended_stateful_iterable_vec!($items));
|
.set_items(extended_stateful_iterable_vec!($items));
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.end.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.home.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.$data_ref.set_items($items);
|
app.push_navigation_stack($block.into());
|
||||||
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.end.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.home.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app.data.radarr_data.$data_ref.current_selection().$field,
|
app.data.$servarr_data.$data_ref.current_selection().$field,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($func:ident, $handler:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
($func:ident, $handler:ident, $servarr_data:ident, $data_ref:ident, $items:expr, $block:expr, $context:expr, $field:ident, $conversion_fn:ident) => {
|
||||||
#[test]
|
#[test]
|
||||||
fn $func() {
|
fn $func() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.$data_ref.set_items($items);
|
app.push_navigation_stack($block.into());
|
||||||
|
app.data.$servarr_data.$data_ref.set_items($items);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.end.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.end.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.$field
|
.$field
|
||||||
@@ -291,12 +311,12 @@ mod test_utils {
|
|||||||
"Test 3"
|
"Test 3"
|
||||||
);
|
);
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.home.key, &mut app, &$block, &$context).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.home.key, &mut app, $block, $context).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
pretty_assertions::assert_str_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.$servarr_data
|
||||||
.$data_ref
|
.$data_ref
|
||||||
.current_selection()
|
.current_selection()
|
||||||
.$field
|
.$field
|
||||||
@@ -311,18 +331,125 @@ mod test_utils {
|
|||||||
macro_rules! test_handler_delegation {
|
macro_rules! test_handler_delegation {
|
||||||
($handler:ident, $base:expr, $active_block:expr) => {
|
($handler:ident, $base:expr, $active_block:expr) => {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.push_navigation_stack($base.clone().into());
|
app.data.sonarr_data.history.set_items(vec![
|
||||||
app.push_navigation_stack($active_block.clone().into());
|
$crate::models::sonarr_models::SonarrHistoryItem::default(),
|
||||||
|
]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.root_folders
|
||||||
|
.set_items(vec![$crate::models::servarr_models::RootFolder::default()]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![$crate::models::servarr_models::Indexer::default()]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.blocklist
|
||||||
|
.set_items(vec![$crate::models::sonarr_models::BlocklistItem::default()]);
|
||||||
|
app.data.sonarr_data.add_searched_series =
|
||||||
|
Some($crate::models::stateful_table::StatefulTable::default());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movies
|
||||||
|
.set_items(vec![$crate::models::radarr_models::Movie::default()]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.collections
|
||||||
|
.set_items(vec![$crate::models::radarr_models::Collection::default()]);
|
||||||
|
app.data.radarr_data.collection_movies.set_items(vec![
|
||||||
|
$crate::models::radarr_models::CollectionMovie::default(),
|
||||||
|
]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![$crate::models::servarr_models::Indexer::default()]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.root_folders
|
||||||
|
.set_items(vec![$crate::models::servarr_models::RootFolder::default()]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.blocklist
|
||||||
|
.set_items(vec![$crate::models::radarr_models::BlocklistItem::default()]);
|
||||||
|
app.data.radarr_data.add_searched_movies =
|
||||||
|
Some($crate::models::stateful_table::StatefulTable::default());
|
||||||
|
let mut movie_details_modal =
|
||||||
|
$crate::models::servarr_data::radarr::modals::MovieDetailsModal::default();
|
||||||
|
movie_details_modal.movie_history.set_items(vec![
|
||||||
|
$crate::models::radarr_models::MovieHistoryItem::default(),
|
||||||
|
]);
|
||||||
|
movie_details_modal
|
||||||
|
.movie_cast
|
||||||
|
.set_items(vec![$crate::models::radarr_models::Credit::default()]);
|
||||||
|
movie_details_modal
|
||||||
|
.movie_crew
|
||||||
|
.set_items(vec![$crate::models::radarr_models::Credit::default()]);
|
||||||
|
movie_details_modal
|
||||||
|
.movie_releases
|
||||||
|
.set_items(vec![$crate::models::radarr_models::RadarrRelease::default()]);
|
||||||
|
app.data.radarr_data.movie_details_modal = Some(movie_details_modal);
|
||||||
|
let mut season_details_modal =
|
||||||
|
$crate::models::servarr_data::sonarr::modals::SeasonDetailsModal::default();
|
||||||
|
season_details_modal.season_history.set_items(vec![
|
||||||
|
$crate::models::sonarr_models::SonarrHistoryItem::default(),
|
||||||
|
]);
|
||||||
|
season_details_modal.episode_details_modal =
|
||||||
|
Some($crate::models::servarr_data::sonarr::modals::EpisodeDetailsModal::default());
|
||||||
|
app.data.sonarr_data.season_details_modal = Some(season_details_modal);
|
||||||
|
let mut series_history = $crate::models::stateful_table::StatefulTable::default();
|
||||||
|
series_history.set_items(vec![
|
||||||
|
$crate::models::sonarr_models::SonarrHistoryItem::default(),
|
||||||
|
]);
|
||||||
|
app.data.sonarr_data.series_history = Some(series_history);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.series
|
||||||
|
.set_items(vec![$crate::models::sonarr_models::Series::default()]);
|
||||||
|
app.push_navigation_stack($base.into());
|
||||||
|
app.push_navigation_stack($active_block.into());
|
||||||
|
|
||||||
$handler::with(
|
$handler::with(DEFAULT_KEYBINDINGS.esc.key, &mut app, $active_block, None).handle();
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
|
||||||
&mut app,
|
|
||||||
&$active_block,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &$base.into());
|
pretty_assertions::assert_eq!(app.get_current_route(), $base.into());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_delete_prompt {
|
||||||
|
($handler:ident, $block:expr, $expected_block:expr) => {
|
||||||
|
let mut app = App::default();
|
||||||
|
|
||||||
|
$handler::with(DELETE_KEY, &mut app, $block, None).handle();
|
||||||
|
|
||||||
|
pretty_assertions::assert_eq!(app.get_current_route(), $expected_block.into());
|
||||||
|
};
|
||||||
|
|
||||||
|
($handler:ident, $app:expr, $block:expr, $expected_block:expr) => {
|
||||||
|
$handler::with(DELETE_KEY, &mut $app, $block, None).handle();
|
||||||
|
|
||||||
|
pretty_assertions::assert_eq!($app.get_current_route(), $expected_block.into());
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! assert_refresh_key {
|
||||||
|
($handler:ident, $block:expr) => {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack($block.into());
|
||||||
|
|
||||||
|
$handler::with(DEFAULT_KEYBINDINGS.refresh.key, &mut app, $block, None).handle();
|
||||||
|
|
||||||
|
pretty_assertions::assert_eq!(app.get_current_route(), $block.into());
|
||||||
|
assert!(app.should_refresh);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use crate::models::radarr_models::Movie;
|
||||||
|
use crate::models::sonarr_models::Series;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handlers::handle_events;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle};
|
||||||
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
|
use crate::models::HorizontallyScrollableText;
|
||||||
|
use crate::models::Route;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_handle_clear_errors() {
|
fn test_handle_clear_errors() {
|
||||||
@@ -17,17 +26,87 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_handle_prompt_toggle_left_right(#[values(Key::Left, Key::Right)] key: Key) {
|
#[case(ActiveRadarrBlock::Movies.into(), ActiveRadarrBlock::SearchMovie.into())]
|
||||||
|
#[case(ActiveSonarrBlock::Series.into(), ActiveSonarrBlock::SearchSeries.into())]
|
||||||
|
fn test_handle_events(#[case] base_block: Route, #[case] top_block: Route) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(base_block);
|
||||||
|
app.push_navigation_stack(top_block);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.series
|
||||||
|
.set_items(vec![Series::default()]);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movies
|
||||||
|
.set_items(vec![Movie::default()]);
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.esc.key, &mut app);
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), base_block);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(0, ActiveSonarrBlock::Series, ActiveSonarrBlock::Series)]
|
||||||
|
#[case(1, ActiveRadarrBlock::Movies, ActiveRadarrBlock::Movies)]
|
||||||
|
fn test_handle_change_tabs<T>(#[case] index: usize, #[case] left_block: T, #[case] right_block: T)
|
||||||
|
where
|
||||||
|
T: Into<Route> + Copy,
|
||||||
|
{
|
||||||
|
let mut app = App::default();
|
||||||
|
app.error = "Test".into();
|
||||||
|
app.server_tabs.set_index(index);
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.previous_servarr.key, &mut app);
|
||||||
|
|
||||||
|
assert_eq!(app.server_tabs.get_active_route(), left_block.into());
|
||||||
|
assert_eq!(app.get_current_route(), left_block.into());
|
||||||
|
assert!(app.is_first_render);
|
||||||
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
|
|
||||||
|
app.server_tabs.set_index(index);
|
||||||
|
app.is_first_render = false;
|
||||||
|
app.error = "Test".into();
|
||||||
|
|
||||||
|
handle_events(DEFAULT_KEYBINDINGS.next_servarr.key, &mut app);
|
||||||
|
|
||||||
|
assert_eq!(app.server_tabs.get_active_route(), right_block.into());
|
||||||
|
assert_eq!(app.get_current_route(), right_block.into());
|
||||||
|
assert!(app.is_first_render);
|
||||||
|
assert_eq!(app.error, HorizontallyScrollableText::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_handle_prompt_toggle_left_right_radarr(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
handle_prompt_toggle(&mut app, &key);
|
handle_prompt_toggle(&mut app, key);
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
handle_prompt_toggle(&mut app, &key);
|
handle_prompt_toggle(&mut app, key);
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_handle_prompt_toggle_left_right_sonarr(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
handle_prompt_toggle(&mut app, key);
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
handle_prompt_toggle(&mut app, key);
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use radarr_handlers::RadarrHandler;
|
use radarr_handlers::RadarrHandler;
|
||||||
|
use sonarr_handlers::SonarrHandler;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
@@ -6,6 +7,7 @@ use crate::event::Key;
|
|||||||
use crate::models::{HorizontallyScrollableText, Route};
|
use crate::models::{HorizontallyScrollableText, Route};
|
||||||
|
|
||||||
mod radarr_handlers;
|
mod radarr_handlers;
|
||||||
|
mod sonarr_handlers;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "handlers_tests.rs"]
|
#[path = "handlers_tests.rs"]
|
||||||
@@ -14,45 +16,46 @@ mod handlers_tests;
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "handler_test_utils.rs"]
|
#[path = "handler_test_utils.rs"]
|
||||||
pub mod handler_test_utils;
|
pub mod handler_test_utils;
|
||||||
|
mod table_handler;
|
||||||
|
|
||||||
pub trait KeyEventHandler<'a, 'b, T: Into<Route>> {
|
pub trait KeyEventHandler<'a, 'b, T: Into<Route> + Copy> {
|
||||||
fn handle_key_event(&mut self) {
|
fn handle_key_event(&mut self) {
|
||||||
let key = self.get_key();
|
let key = self.get_key();
|
||||||
match key {
|
match key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.up.key => {
|
_ if key == DEFAULT_KEYBINDINGS.up.key => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_scroll_up();
|
self.handle_scroll_up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.down.key => {
|
_ if key == DEFAULT_KEYBINDINGS.down.key => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_scroll_down();
|
self.handle_scroll_down();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.home.key => {
|
_ if key == DEFAULT_KEYBINDINGS.home.key => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_home();
|
self.handle_home();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.end.key => {
|
_ if key == DEFAULT_KEYBINDINGS.end.key => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_end();
|
self.handle_end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.delete.key => {
|
_ if key == DEFAULT_KEYBINDINGS.delete.key => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_delete();
|
self.handle_delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.left.key || *key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if key == DEFAULT_KEYBINDINGS.left.key || key == DEFAULT_KEYBINDINGS.right.key => {
|
||||||
self.handle_left_right_action()
|
self.handle_left_right_action()
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.submit.key => {
|
_ if key == DEFAULT_KEYBINDINGS.submit.key => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_submit();
|
self.handle_submit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.esc.key => self.handle_esc(),
|
_ if key == DEFAULT_KEYBINDINGS.esc.key => self.handle_esc(),
|
||||||
_ => {
|
_ => {
|
||||||
if self.is_ready() {
|
if self.is_ready() {
|
||||||
self.handle_char_key_event();
|
self.handle_char_key_event();
|
||||||
@@ -65,9 +68,9 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route>> {
|
|||||||
self.handle_key_event();
|
self.handle_key_event();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(active_block: &'a T) -> bool;
|
fn accepts(active_block: T) -> bool;
|
||||||
fn with(key: &'a Key, app: &'a mut App<'b>, active_block: &'a T, context: &'a Option<T>) -> Self;
|
fn with(key: Key, app: &'a mut App<'b>, active_block: T, context: Option<T>) -> Self;
|
||||||
fn get_key(&self) -> &Key;
|
fn get_key(&self) -> Key;
|
||||||
fn is_ready(&self) -> bool;
|
fn is_ready(&self) -> bool;
|
||||||
fn handle_scroll_up(&mut self);
|
fn handle_scroll_up(&mut self);
|
||||||
fn handle_scroll_down(&mut self);
|
fn handle_scroll_down(&mut self);
|
||||||
@@ -81,8 +84,24 @@ pub trait KeyEventHandler<'a, 'b, T: Into<Route>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_events(key: Key, app: &mut App<'_>) {
|
pub fn handle_events(key: Key, app: &mut App<'_>) {
|
||||||
if let Route::Radarr(active_radarr_block, context) = *app.get_current_route() {
|
if key == DEFAULT_KEYBINDINGS.next_servarr.key {
|
||||||
RadarrHandler::with(&key, app, &active_radarr_block, &context).handle()
|
app.reset();
|
||||||
|
app.server_tabs.next();
|
||||||
|
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
|
||||||
|
} else if key == DEFAULT_KEYBINDINGS.previous_servarr.key {
|
||||||
|
app.reset();
|
||||||
|
app.server_tabs.previous();
|
||||||
|
app.pop_and_push_navigation_stack(app.server_tabs.get_active_route());
|
||||||
|
} else {
|
||||||
|
match app.get_current_route() {
|
||||||
|
Route::Radarr(active_radarr_block, context) => {
|
||||||
|
RadarrHandler::with(key, app, active_radarr_block, context).handle()
|
||||||
|
}
|
||||||
|
Route::Sonarr(active_sonarr_block, context) => {
|
||||||
|
SonarrHandler::with(key, app, active_sonarr_block, context).handle()
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,11 +111,17 @@ fn handle_clear_errors(app: &mut App<'_>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_prompt_toggle(app: &mut App<'_>, key: &Key) {
|
fn handle_prompt_toggle(app: &mut App<'_>, key: Key) {
|
||||||
match key {
|
match key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.left.key || *key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if key == DEFAULT_KEYBINDINGS.left.key || key == DEFAULT_KEYBINDINGS.right.key => {
|
||||||
if let Route::Radarr(_, _) = *app.get_current_route() {
|
match app.get_current_route() {
|
||||||
app.data.radarr_data.prompt_confirm = !app.data.radarr_data.prompt_confirm;
|
Route::Radarr(_, _) => {
|
||||||
|
app.data.radarr_data.prompt_confirm = !app.data.radarr_data.prompt_confirm
|
||||||
|
}
|
||||||
|
Route::Sonarr(_, _) => {
|
||||||
|
app.data.sonarr_data.prompt_confirm = !app.data.sonarr_data.prompt_confirm
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -107,10 +132,10 @@ fn handle_prompt_toggle(app: &mut App<'_>, key: &Key) {
|
|||||||
macro_rules! handle_text_box_left_right_keys {
|
macro_rules! handle_text_box_left_right_keys {
|
||||||
($self:expr, $key:expr, $input:expr) => {
|
($self:expr, $key:expr, $input:expr) => {
|
||||||
match $self.key {
|
match $self.key {
|
||||||
_ if *$key == DEFAULT_KEYBINDINGS.left.key => {
|
_ if $key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key => {
|
||||||
$input.scroll_left();
|
$input.scroll_left();
|
||||||
}
|
}
|
||||||
_ if *$key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if $key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.right.key => {
|
||||||
$input.scroll_right();
|
$input.scroll_right();
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -122,13 +147,26 @@ macro_rules! handle_text_box_left_right_keys {
|
|||||||
macro_rules! handle_text_box_keys {
|
macro_rules! handle_text_box_keys {
|
||||||
($self:expr, $key:expr, $input:expr) => {
|
($self:expr, $key:expr, $input:expr) => {
|
||||||
match $self.key {
|
match $self.key {
|
||||||
_ if *$key == DEFAULT_KEYBINDINGS.backspace.key => {
|
_ if $key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.backspace.key => {
|
||||||
$input.pop();
|
$input.pop();
|
||||||
}
|
}
|
||||||
Key::Char(character) => {
|
Key::Char(character) => {
|
||||||
$input.push(*character);
|
$input.push(character);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! handle_prompt_left_right_keys {
|
||||||
|
($self:expr, $confirm_prompt:expr, $data:ident) => {
|
||||||
|
if $self.app.data.$data.selected_block.get_active_block() == $confirm_prompt {
|
||||||
|
handle_prompt_toggle($self.app, $self.key);
|
||||||
|
} else if $self.key == $crate::app::key_binding::DEFAULT_KEYBINDINGS.left.key {
|
||||||
|
$self.app.data.$data.selected_block.left();
|
||||||
|
} else {
|
||||||
|
$self.app.data.$data.selected_block.right();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,246 +14,6 @@ mod tests {
|
|||||||
use crate::models::radarr_models::{BlocklistItem, BlocklistItemMovie};
|
use crate::models::radarr_models::{BlocklistItem, BlocklistItemMovie};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
||||||
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
||||||
use crate::models::stateful_table::SortOption;
|
|
||||||
|
|
||||||
mod test_handle_scroll_up_and_down {
|
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::models::radarr_models::BlocklistItem;
|
|
||||||
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_scroll!(
|
|
||||||
test_blocklist_scroll,
|
|
||||||
BlocklistHandler,
|
|
||||||
blocklist,
|
|
||||||
simple_stateful_iterable_vec!(BlocklistItem, String, source_title),
|
|
||||||
ActiveRadarrBlock::Blocklist,
|
|
||||||
None,
|
|
||||||
source_title,
|
|
||||||
to_string
|
|
||||||
);
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_blocklist_scroll_no_op_when_not_ready(
|
|
||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.set_items(simple_stateful_iterable_vec!(
|
|
||||||
BlocklistItem,
|
|
||||||
String,
|
|
||||||
source_title
|
|
||||||
));
|
|
||||||
|
|
||||||
BlocklistHandler::with(&key, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.current_selection()
|
|
||||||
.source_title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
BlocklistHandler::with(&key, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.current_selection()
|
|
||||||
.source_title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_blocklist_sort_scroll(
|
|
||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
|
||||||
) {
|
|
||||||
let blocklist_field_vec = sort_options();
|
|
||||||
let mut app = App::default();
|
|
||||||
app.data.radarr_data.blocklist.sorting(sort_options());
|
|
||||||
|
|
||||||
if key == Key::Up {
|
|
||||||
for i in (0..blocklist_field_vec.len()).rev() {
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection(),
|
|
||||||
&blocklist_field_vec[i]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in 0..blocklist_field_vec.len() {
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection(),
|
|
||||||
&blocklist_field_vec[(i + 1) % blocklist_field_vec.len()]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_home_end {
|
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
|
||||||
|
|
||||||
use crate::models::radarr_models::BlocklistItem;
|
|
||||||
use crate::{extended_stateful_iterable_vec, test_iterable_home_and_end};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_home_and_end!(
|
|
||||||
test_blocklist_home_and_end,
|
|
||||||
BlocklistHandler,
|
|
||||||
blocklist,
|
|
||||||
extended_stateful_iterable_vec!(BlocklistItem, String, source_title),
|
|
||||||
ActiveRadarrBlock::Blocklist,
|
|
||||||
None,
|
|
||||||
source_title,
|
|
||||||
to_string
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_blocklist_home_and_end_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.set_items(extended_stateful_iterable_vec!(
|
|
||||||
BlocklistItem,
|
|
||||||
String,
|
|
||||||
source_title
|
|
||||||
));
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Blocklist,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.current_selection()
|
|
||||||
.source_title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Blocklist,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.current_selection()
|
|
||||||
.source_title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_blocklist_sort_home_end() {
|
|
||||||
let blocklist_field_vec = sort_options();
|
|
||||||
let mut app = App::default();
|
|
||||||
app.data.radarr_data.blocklist.sorting(sort_options());
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection(),
|
|
||||||
&blocklist_field_vec[blocklist_field_vec.len() - 1]
|
|
||||||
);
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection(),
|
|
||||||
&blocklist_field_vec[0]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_delete {
|
mod test_handle_delete {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
@@ -267,11 +27,11 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
BlocklistHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::DeleteBlocklistItemPrompt.into()
|
ActiveRadarrBlock::DeleteBlocklistItemPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,12 +42,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
BlocklistHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,21 +61,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(3);
|
app.data.radarr_data.main_tabs.set_index(3);
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
ActiveRadarrBlock::Downloads.into()
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -328,20 +82,20 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(3);
|
app.data.radarr_data.main_tabs.set_index(3);
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,11 +110,11 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
BlocklistHandler::with(&key, &mut app, &active_radarr_block, &None).handle();
|
BlocklistHandler::with(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
BlocklistHandler::with(&key, &mut app, &active_radarr_block, &None).handle();
|
BlocklistHandler::with(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -382,11 +136,11 @@ mod tests {
|
|||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(&SUBMIT_KEY, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::BlocklistItemDetails.into()
|
ActiveRadarrBlock::BlocklistItemDetails.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -397,12 +151,9 @@ mod tests {
|
|||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(&SUBMIT_KEY, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -427,14 +178,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
BlocklistHandler::with(&SUBMIT_KEY, &mut app, &prompt_block, &None).handle();
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &base_route.into());
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -450,42 +201,11 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
BlocklistHandler::with(&SUBMIT_KEY, &mut app, &prompt_block, &None).handle();
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_blocklist_sort_prompt_submit() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.data.radarr_data.blocklist.sort_asc = true;
|
|
||||||
app.data.radarr_data.blocklist.sorting(sort_options());
|
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::BlocklistSortPrompt.into());
|
|
||||||
|
|
||||||
let mut expected_vec = blocklist_vec();
|
|
||||||
expected_vec.sort_by(|a, b| a.id.cmp(&b.id));
|
|
||||||
expected_vec.reverse();
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&SUBMIT_KEY,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
assert_eq!(app.data.radarr_data.blocklist.items, expected_vec);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,9 +237,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
BlocklistHandler::with(&ESC_KEY, &mut app, &prompt_block, &None).handle();
|
BlocklistHandler::with(ESC_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &base_block.into());
|
assert_eq!(app.get_current_route(), base_block.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,37 +250,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::BlocklistItemDetails.into());
|
app.push_navigation_stack(ActiveRadarrBlock::BlocklistItemDetails.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::BlocklistItemDetails,
|
ActiveRadarrBlock::BlocklistItemDetails,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_blocklist_sort_prompt_block_esc() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::BlocklistSortPrompt.into());
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&ESC_KEY,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -571,12 +268,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
DownloadsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::Blocklist, &None).handle();
|
DownloadsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
assert!(app.error.text.is_empty());
|
assert!(app.error.text.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -596,17 +290,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,17 +309,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -638,16 +326,16 @@ mod tests {
|
|||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.clear.key,
|
DEFAULT_KEYBINDINGS.clear.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into()
|
ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -659,64 +347,14 @@ mod tests {
|
|||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.clear.key,
|
DEFAULT_KEYBINDINGS.clear.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sort_key() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.sort.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Blocklist,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::BlocklistSortPrompt.into()
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
app.data.radarr_data.blocklist.sort.as_ref().unwrap().items,
|
|
||||||
blocklist_sorting_options()
|
|
||||||
);
|
|
||||||
assert!(!app.data.radarr_data.blocklist.sort_asc);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_sort_key_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Blocklist.into());
|
|
||||||
app.data.radarr_data.blocklist.set_items(blocklist_vec());
|
|
||||||
|
|
||||||
BlocklistHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.sort.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Blocklist,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
|
||||||
assert!(app.data.radarr_data.blocklist.sort.is_none());
|
|
||||||
assert!(!app.data.radarr_data.blocklist.sort_asc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -741,10 +379,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
BlocklistHandler::with(
|
BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&prompt_block,
|
prompt_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -753,7 +391,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &base_route.into());
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -896,9 +534,9 @@ mod tests {
|
|||||||
fn test_blocklist_handler_accepts() {
|
fn test_blocklist_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if BLOCKLIST_BLOCKS.contains(&active_radarr_block) {
|
if BLOCKLIST_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(BlocklistHandler::accepts(&active_radarr_block));
|
assert!(BlocklistHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!BlocklistHandler::accepts(&active_radarr_block));
|
assert!(!BlocklistHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -909,10 +547,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = BlocklistHandler::with(
|
let handler = BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -924,10 +562,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = BlocklistHandler::with(
|
let handler = BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -944,10 +582,10 @@ mod tests {
|
|||||||
.set_items(vec![BlocklistItem::default()]);
|
.set_items(vec![BlocklistItem::default()]);
|
||||||
|
|
||||||
let handler = BlocklistHandler::with(
|
let handler = BlocklistHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Blocklist,
|
ActiveRadarrBlock::Blocklist,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
@@ -1029,15 +667,4 @@ mod tests {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sort_options() -> Vec<SortOption<BlocklistItem>> {
|
|
||||||
vec![SortOption {
|
|
||||||
name: "Test 1",
|
|
||||||
cmp_fn: Some(|a, b| {
|
|
||||||
b.source_title
|
|
||||||
.to_lowercase()
|
|
||||||
.cmp(&a.source_title.to_lowercase())
|
|
||||||
}),
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
use crate::models::radarr_models::BlocklistItem;
|
use crate::models::radarr_models::BlocklistItem;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, BLOCKLIST_BLOCKS};
|
||||||
use crate::models::stateful_table::SortOption;
|
use crate::models::stateful_table::SortOption;
|
||||||
use crate::models::Scrollable;
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -14,22 +15,43 @@ use crate::network::radarr_network::RadarrEvent;
|
|||||||
mod blocklist_handler_tests;
|
mod blocklist_handler_tests;
|
||||||
|
|
||||||
pub(super) struct BlocklistHandler<'a, 'b> {
|
pub(super) struct BlocklistHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> BlocklistHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
blocklist,
|
||||||
|
self.app.data.radarr_data.blocklist,
|
||||||
|
BlocklistItem
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
BLOCKLIST_BLOCKS.contains(active_block)
|
let blocklist_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::Blocklist.into())
|
||||||
|
.sorting_block(ActiveRadarrBlock::BlocklistSortPrompt.into())
|
||||||
|
.sort_by_fn(|a: &BlocklistItem, b: &BlocklistItem| a.id.cmp(&b.id))
|
||||||
|
.sort_options(blocklist_sorting_options());
|
||||||
|
|
||||||
|
if !self.handle_blocklist_table_events(blocklist_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
BLOCKLIST_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
BlocklistHandler {
|
BlocklistHandler {
|
||||||
key,
|
key,
|
||||||
@@ -39,7 +61,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,72 +69,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.blocklist.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.blocklist.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Blocklist => self.app.data.radarr_data.blocklist.scroll_up(),
|
|
||||||
ActiveRadarrBlock::BlocklistSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_up(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Blocklist => self.app.data.radarr_data.blocklist.scroll_down(),
|
|
||||||
ActiveRadarrBlock::BlocklistSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_down(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Blocklist => self.app.data.radarr_data.blocklist.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::BlocklistSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_top(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Blocklist => self.app.data.radarr_data.blocklist.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::BlocklistSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {
|
fn handle_delete(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Blocklist {
|
if self.active_radarr_block == ActiveRadarrBlock::Blocklist {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::DeleteBlocklistItemPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::DeleteBlocklistItemPrompt.into());
|
||||||
@@ -145,18 +111,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::BlocklistSortPrompt => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.items
|
|
||||||
.sort_by(|a, b| a.id.cmp(&b.id));
|
|
||||||
self.app.data.radarr_data.blocklist.apply_sorting();
|
|
||||||
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::Blocklist => {
|
ActiveRadarrBlock::Blocklist => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
@@ -173,7 +127,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.prompt_confirm = false;
|
self.app.data.radarr_data.prompt_confirm = false;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::BlocklistItemDetails | ActiveRadarrBlock::BlocklistSortPrompt => {
|
ActiveRadarrBlock::BlocklistItemDetails => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
_ => handle_clear_errors(self.app),
|
_ => handle_clear_errors(self.app),
|
||||||
@@ -184,29 +138,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Blocklist => match self.key {
|
ActiveRadarrBlock::Blocklist => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.clear.key => {
|
_ if key == DEFAULT_KEYBINDINGS.clear.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::BlocklistClearAllItemsPrompt.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.sort.key => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.blocklist
|
|
||||||
.sorting(blocklist_sorting_options());
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::BlocklistSortPrompt.into());
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
|
ActiveRadarrBlock::DeleteBlocklistItemPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
self.app.data.radarr_data.prompt_confirm_action =
|
||||||
Some(RadarrEvent::DeleteBlocklistItem(None));
|
Some(RadarrEvent::DeleteBlocklistItem(None));
|
||||||
@@ -215,7 +158,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for BlocklistHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::BlocklistClearAllItemsPrompt => {
|
ActiveRadarrBlock::BlocklistClearAllItemsPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::ClearBlocklist);
|
||||||
|
|
||||||
|
|||||||
@@ -1,35 +1,56 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::radarr_models::CollectionMovie;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, ADD_MOVIE_SELECTION_BLOCKS, COLLECTION_DETAILS_BLOCKS,
|
ActiveRadarrBlock, ADD_MOVIE_SELECTION_BLOCKS, COLLECTION_DETAILS_BLOCKS,
|
||||||
EDIT_COLLECTION_SELECTION_BLOCKS,
|
EDIT_COLLECTION_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::stateful_table::StatefulTable;
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use crate::models::{BlockSelectionState, Scrollable};
|
use crate::models::BlockSelectionState;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "collection_details_handler_tests.rs"]
|
#[path = "collection_details_handler_tests.rs"]
|
||||||
mod collection_details_handler_tests;
|
mod collection_details_handler_tests;
|
||||||
|
|
||||||
pub(super) struct CollectionDetailsHandler<'a, 'b> {
|
pub(super) struct CollectionDetailsHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> CollectionDetailsHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
collection_movies,
|
||||||
|
self.app.data.radarr_data.collection_movies,
|
||||||
|
CollectionMovie
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
COLLECTION_DETAILS_BLOCKS.contains(active_block)
|
let collection_movies_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::CollectionDetails.into());
|
||||||
|
|
||||||
|
if !self.handle_collection_movies_table_events(collection_movies_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
COLLECTION_DETAILS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> CollectionDetailsHandler<'a, 'b> {
|
) -> CollectionDetailsHandler<'a, 'b> {
|
||||||
CollectionDetailsHandler {
|
CollectionDetailsHandler {
|
||||||
key,
|
key,
|
||||||
@@ -39,7 +60,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,41 +68,20 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.collection_movies.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.collection_movies.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
if ActiveRadarrBlock::CollectionDetails == *self.active_radarr_block {
|
|
||||||
self.app.data.radarr_data.collection_movies.scroll_up()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
if ActiveRadarrBlock::CollectionDetails == *self.active_radarr_block {
|
|
||||||
self.app.data.radarr_data.collection_movies.scroll_down()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
if ActiveRadarrBlock::CollectionDetails == *self.active_radarr_block {
|
|
||||||
self.app.data.radarr_data.collection_movies.scroll_to_top();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
if ActiveRadarrBlock::CollectionDetails == *self.active_radarr_block {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.scroll_to_bottom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {}
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
fn handle_left_right_action(&mut self) {}
|
fn handle_left_right_action(&mut self) {}
|
||||||
|
|
||||||
fn handle_submit(&mut self) {
|
fn handle_submit(&mut self) {
|
||||||
if ActiveRadarrBlock::CollectionDetails == *self.active_radarr_block {
|
if ActiveRadarrBlock::CollectionDetails == self.active_radarr_block {
|
||||||
let tmdb_id = self
|
let tmdb_id = self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -111,7 +111,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
|
BlockSelectionState::new(ADD_MOVIE_SELECTION_BLOCKS);
|
||||||
self.app.data.radarr_data.add_movie_modal = Some((&self.app.data.radarr_data).into());
|
self.app.data.radarr_data.add_movie_modal = Some((&self.app.data.radarr_data).into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,19 +129,19 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionDetailsHan
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_char_key_event(&mut self) {
|
fn handle_char_key_event(&mut self) {
|
||||||
if *self.active_radarr_block == ActiveRadarrBlock::CollectionDetails
|
if self.active_radarr_block == ActiveRadarrBlock::CollectionDetails
|
||||||
&& *self.key == DEFAULT_KEYBINDINGS.edit.key
|
&& self.key == DEFAULT_KEYBINDINGS.edit.key
|
||||||
{
|
{
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
Some(*self.active_radarr_block),
|
Some(self.active_radarr_block),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
self.app.data.radarr_data.edit_collection_modal = Some((&self.app.data.radarr_data).into());
|
self.app.data.radarr_data.edit_collection_modal = Some((&self.app.data.radarr_data).into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,142 +12,6 @@ mod tests {
|
|||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
|
ActiveRadarrBlock, COLLECTION_DETAILS_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::HorizontallyScrollableText;
|
|
||||||
|
|
||||||
mod test_handle_scroll_up_and_down {
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_scroll!(
|
|
||||||
test_collection_details_scroll,
|
|
||||||
CollectionDetailsHandler,
|
|
||||||
collection_movies,
|
|
||||||
simple_stateful_iterable_vec!(CollectionMovie, HorizontallyScrollableText),
|
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
|
||||||
None,
|
|
||||||
title,
|
|
||||||
to_string
|
|
||||||
);
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_collection_details_scroll_no_op_when_not_ready(
|
|
||||||
#[values(
|
|
||||||
DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key
|
|
||||||
)]
|
|
||||||
key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.set_items(simple_stateful_iterable_vec!(
|
|
||||||
CollectionMovie,
|
|
||||||
HorizontallyScrollableText
|
|
||||||
));
|
|
||||||
|
|
||||||
CollectionDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::CollectionDetails, &None)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.current_selection()
|
|
||||||
.title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
CollectionDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::CollectionDetails, &None)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.current_selection()
|
|
||||||
.title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_home_end {
|
|
||||||
use crate::{extended_stateful_iterable_vec, test_iterable_home_and_end};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_home_and_end!(
|
|
||||||
test_collection_details_home_end,
|
|
||||||
CollectionDetailsHandler,
|
|
||||||
collection_movies,
|
|
||||||
extended_stateful_iterable_vec!(CollectionMovie, HorizontallyScrollableText),
|
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
|
||||||
None,
|
|
||||||
title,
|
|
||||||
to_string
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_collection_details_home_end_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.set_items(extended_stateful_iterable_vec!(
|
|
||||||
CollectionMovie,
|
|
||||||
HorizontallyScrollableText
|
|
||||||
));
|
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.current_selection()
|
|
||||||
.title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collection_movies
|
|
||||||
.current_selection()
|
|
||||||
.title
|
|
||||||
.to_string(),
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_submit {
|
mod test_handle_submit {
|
||||||
use bimap::BiMap;
|
use bimap::BiMap;
|
||||||
@@ -171,24 +35,24 @@ mod tests {
|
|||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
app.data.radarr_data.quality_profile_map =
|
app.data.radarr_data.quality_profile_map =
|
||||||
BiMap::from_iter([(1, "B - Test 2".to_owned()), (0, "A - Test 1".to_owned())]);
|
BiMap::from_iter([(1, "B - Test 2".to_owned()), (0, "A - Test 1".to_owned())]);
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(ADD_MOVIE_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, ADD_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&(
|
(
|
||||||
ActiveRadarrBlock::AddMoviePrompt,
|
ActiveRadarrBlock::AddMoviePrompt,
|
||||||
Some(ActiveRadarrBlock::CollectionDetails)
|
Some(ActiveRadarrBlock::CollectionDetails)
|
||||||
)
|
)
|
||||||
@@ -205,7 +69,7 @@ mod tests {
|
|||||||
.is_empty());
|
.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::AddMovieSelectRootFolder
|
ActiveRadarrBlock::AddMovieSelectRootFolder
|
||||||
);
|
);
|
||||||
assert!(!app
|
assert!(!app
|
||||||
.data
|
.data
|
||||||
@@ -250,16 +114,16 @@ mod tests {
|
|||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::CollectionDetails.into()
|
ActiveRadarrBlock::CollectionDetails.into()
|
||||||
);
|
);
|
||||||
assert!(app.data.radarr_data.add_movie_modal.is_none());
|
assert!(app.data.radarr_data.add_movie_modal.is_none());
|
||||||
}
|
}
|
||||||
@@ -279,16 +143,16 @@ mod tests {
|
|||||||
.set_items(vec![Movie::default()]);
|
.set_items(vec![Movie::default()]);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::ViewMovieOverview.into()
|
ActiveRadarrBlock::ViewMovieOverview.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,16 +177,16 @@ mod tests {
|
|||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert!(app.data.radarr_data.collection_movies.items.is_empty());
|
assert!(app.data.radarr_data.collection_movies.items.is_empty());
|
||||||
}
|
}
|
||||||
@@ -334,16 +198,16 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::ViewMovieOverview.into());
|
app.push_navigation_stack(ActiveRadarrBlock::ViewMovieOverview.into());
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::ViewMovieOverview,
|
ActiveRadarrBlock::ViewMovieOverview,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::CollectionDetails.into()
|
ActiveRadarrBlock::CollectionDetails.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -367,7 +231,7 @@ mod tests {
|
|||||||
test_edit_collection_key!(
|
test_edit_collection_key!(
|
||||||
CollectionDetailsHandler,
|
CollectionDetailsHandler,
|
||||||
ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
ActiveRadarrBlock::CollectionDetails
|
Some(ActiveRadarrBlock::CollectionDetails)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -388,16 +252,16 @@ mod tests {
|
|||||||
app.data.radarr_data = radarr_data;
|
app.data.radarr_data = radarr_data;
|
||||||
|
|
||||||
CollectionDetailsHandler::with(
|
CollectionDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.edit.key,
|
DEFAULT_KEYBINDINGS.edit.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::CollectionDetails.into()
|
ActiveRadarrBlock::CollectionDetails.into()
|
||||||
);
|
);
|
||||||
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
assert!(app.data.radarr_data.edit_collection_modal.is_none());
|
||||||
}
|
}
|
||||||
@@ -407,9 +271,9 @@ mod tests {
|
|||||||
fn test_collection_details_handler_accepts() {
|
fn test_collection_details_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if COLLECTION_DETAILS_BLOCKS.contains(&active_radarr_block) {
|
if COLLECTION_DETAILS_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(CollectionDetailsHandler::accepts(&active_radarr_block));
|
assert!(CollectionDetailsHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!CollectionDetailsHandler::accepts(&active_radarr_block));
|
assert!(!CollectionDetailsHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -420,10 +284,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = CollectionDetailsHandler::with(
|
let handler = CollectionDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -435,10 +299,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = CollectionDetailsHandler::with(
|
let handler = CollectionDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -455,10 +319,10 @@ mod tests {
|
|||||||
.set_items(vec![CollectionMovie::default()]);
|
.set_items(vec![CollectionMovie::default()]);
|
||||||
|
|
||||||
let handler = CollectionDetailsHandler::with(
|
let handler = CollectionDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::CollectionDetails,
|
ActiveRadarrBlock::CollectionDetails,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -12,22 +12,22 @@ use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
|||||||
mod edit_collection_handler_tests;
|
mod edit_collection_handler_tests;
|
||||||
|
|
||||||
pub(super) struct EditCollectionHandler<'a, 'b> {
|
pub(super) struct EditCollectionHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
EDIT_COLLECTION_BLOCKS.contains(active_block)
|
EDIT_COLLECTION_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> EditCollectionHandler<'a, 'b> {
|
) -> EditCollectionHandler<'a, 'b> {
|
||||||
EditCollectionHandler {
|
EditCollectionHandler {
|
||||||
key,
|
key,
|
||||||
@@ -37,7 +37,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,9 +65,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
.scroll_up(),
|
.scroll_up(),
|
||||||
ActiveRadarrBlock::EditCollectionPrompt => {
|
ActiveRadarrBlock::EditCollectionPrompt => self.app.data.radarr_data.selected_block.up(),
|
||||||
self.app.data.radarr_data.selected_block.previous()
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -92,7 +90,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
.scroll_down(),
|
.scroll_down(),
|
||||||
ActiveRadarrBlock::EditCollectionPrompt => self.app.data.radarr_data.selected_block.next(),
|
ActiveRadarrBlock::EditCollectionPrompt => self.app.data.radarr_data.selected_block.down(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -203,8 +201,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
|
| ActiveRadarrBlock::EditCollectionSelectQualityProfile => {
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
*self.context,
|
self.context,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
)
|
)
|
||||||
@@ -212,8 +210,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput => {
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
*self.context,
|
self.context,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
@@ -308,8 +306,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditCollectionHandle
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditCollectionPrompt => {
|
ActiveRadarrBlock::EditCollectionPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== &ActiveRadarrBlock::EditCollectionConfirmPrompt
|
== ActiveRadarrBlock::EditCollectionConfirmPrompt
|
||||||
&& *key == DEFAULT_KEYBINDINGS.confirm.key
|
&& key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditCollection(None));
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ mod tests {
|
|||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
for i in (0..minimum_availability_vec.len()).rev() {
|
for i in (0..minimum_availability_vec.len()).rev() {
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -66,10 +66,10 @@ mod tests {
|
|||||||
} else {
|
} else {
|
||||||
for i in 0..minimum_availability_vec.len() {
|
for i in 0..minimum_availability_vec.len() {
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -104,10 +104,10 @@ mod tests {
|
|||||||
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -124,10 +124,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -149,26 +149,21 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.next();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditCollectionToggleMonitored
|
ActiveRadarrBlock::EditCollectionToggleMonitored
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditCollectionSelectQualityProfile
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,20 +176,15 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.next();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -224,10 +214,10 @@ mod tests {
|
|||||||
.set_items(minimum_availability_vec.clone());
|
.set_items(minimum_availability_vec.clone());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -244,10 +234,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
ActiveRadarrBlock::EditCollectionSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -282,10 +272,10 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -302,10 +292,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
ActiveRadarrBlock::EditCollectionSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -331,10 +321,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -352,10 +342,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -386,23 +376,13 @@ mod tests {
|
|||||||
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(key, &mut app, ActiveRadarrBlock::EditCollectionPrompt, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -416,10 +396,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -437,10 +417,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -484,10 +464,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -503,7 +483,7 @@ mod tests {
|
|||||||
.is_empty());
|
.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt.into()
|
ActiveRadarrBlock::EditCollectionPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -514,24 +494,24 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
}
|
}
|
||||||
@@ -544,24 +524,24 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
@@ -579,24 +559,24 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt.into()
|
ActiveRadarrBlock::EditCollectionPrompt.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
@@ -611,18 +591,18 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.push_navigation_stack(current_route);
|
app.push_navigation_stack(current_route);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -635,14 +615,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -664,23 +644,23 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 2);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 2);
|
||||||
app.push_navigation_stack(current_route);
|
app.push_navigation_stack(current_route);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -693,14 +673,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -731,20 +711,20 @@ mod tests {
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(index);
|
app.data.radarr_data.selected_block.set_index(0, index);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&(selected_block, Some(ActiveRadarrBlock::Collections)).into()
|
(selected_block, Some(ActiveRadarrBlock::Collections)).into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
|
|
||||||
@@ -768,16 +748,16 @@ mod tests {
|
|||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&Some(ActiveRadarrBlock::Collections),
|
Some(ActiveRadarrBlock::Collections),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt.into()
|
ActiveRadarrBlock::EditCollectionPrompt.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
if active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
|
if active_radarr_block == ActiveRadarrBlock::EditCollectionRootFolderPathInput {
|
||||||
@@ -806,17 +786,17 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionRootFolderPathInput.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.should_ignore_quit_key);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt.into()
|
ActiveRadarrBlock::EditCollectionPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,16 +808,16 @@ mod tests {
|
|||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
let radarr_data = &app.data.radarr_data;
|
let radarr_data = &app.data.radarr_data;
|
||||||
|
|
||||||
@@ -860,11 +840,11 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditCollectionHandler::with(&ESC_KEY, &mut app, &active_radarr_block, &None).handle();
|
EditCollectionHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -890,10 +870,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.backspace.key,
|
DEFAULT_KEYBINDINGS.backspace.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -916,10 +896,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&Key::Char('h'),
|
Key::Char('h'),
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
ActiveRadarrBlock::EditCollectionRootFolderPathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -943,24 +923,24 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Collections.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditCollectionHandler::with(
|
EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
@@ -974,9 +954,9 @@ mod tests {
|
|||||||
fn test_edit_collection_handler_accepts() {
|
fn test_edit_collection_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if EDIT_COLLECTION_BLOCKS.contains(&active_radarr_block) {
|
if EDIT_COLLECTION_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(EditCollectionHandler::accepts(&active_radarr_block));
|
assert!(EditCollectionHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!EditCollectionHandler::accepts(&active_radarr_block));
|
assert!(!EditCollectionHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -987,10 +967,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = EditCollectionHandler::with(
|
let handler = EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -1002,10 +982,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = EditCollectionHandler::with(
|
let handler = EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -1018,10 +998,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
app.data.radarr_data.edit_collection_modal = Some(EditCollectionModal::default());
|
||||||
|
|
||||||
let handler = EditCollectionHandler::with(
|
let handler = EditCollectionHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditCollectionPrompt,
|
ActiveRadarrBlock::EditCollectionPrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
|
use crate::handlers::radarr_handlers::collections::collection_details_handler::CollectionDetailsHandler;
|
||||||
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
|
use crate::handlers::radarr_handlers::collections::edit_collection_handler::EditCollectionHandler;
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
use crate::models::radarr_models::Collection;
|
use crate::models::radarr_models::Collection;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, COLLECTIONS_BLOCKS, EDIT_COLLECTION_SELECTION_BLOCKS,
|
ActiveRadarrBlock, COLLECTIONS_BLOCKS, EDIT_COLLECTION_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::stateful_table::SortOption;
|
use crate::models::stateful_table::SortOption;
|
||||||
use crate::models::{BlockSelectionState, HorizontallyScrollableText, Scrollable};
|
use crate::models::BlockSelectionState;
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
|
||||||
|
|
||||||
mod collection_details_handler;
|
mod collection_details_handler;
|
||||||
mod edit_collection_handler;
|
mod edit_collection_handler;
|
||||||
@@ -22,38 +23,66 @@ mod edit_collection_handler;
|
|||||||
mod collections_handler_tests;
|
mod collections_handler_tests;
|
||||||
|
|
||||||
pub(super) struct CollectionsHandler<'a, 'b> {
|
pub(super) struct CollectionsHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> CollectionsHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
collections,
|
||||||
|
self.app.data.radarr_data.collections,
|
||||||
|
Collection
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'a, 'b> {
|
||||||
fn handle(&mut self) {
|
fn handle(&mut self) {
|
||||||
match self.active_radarr_block {
|
let collections_table_handling_config =
|
||||||
_ if CollectionDetailsHandler::accepts(self.active_radarr_block) => {
|
TableHandlingConfig::new(ActiveRadarrBlock::Collections.into())
|
||||||
CollectionDetailsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
.sorting_block(ActiveRadarrBlock::CollectionsSortPrompt.into())
|
||||||
|
.sort_by_fn(|a: &Collection, b: &Collection| a.id.cmp(&b.id))
|
||||||
|
.sort_options(collections_sorting_options())
|
||||||
|
.searching_block(ActiveRadarrBlock::SearchCollection.into())
|
||||||
|
.search_error_block(ActiveRadarrBlock::SearchCollectionError.into())
|
||||||
|
.search_field_fn(|collection| &collection.title.text)
|
||||||
|
.filtering_block(ActiveRadarrBlock::FilterCollections.into())
|
||||||
|
.filter_error_block(ActiveRadarrBlock::FilterCollectionsError.into())
|
||||||
|
.filter_field_fn(|collection| &collection.title.text);
|
||||||
|
|
||||||
|
if !self.handle_collections_table_events(collections_table_handling_config) {
|
||||||
|
match self.active_radarr_block {
|
||||||
|
_ if CollectionDetailsHandler::accepts(self.active_radarr_block) => {
|
||||||
|
CollectionDetailsHandler::with(
|
||||||
|
self.key,
|
||||||
|
self.app,
|
||||||
|
self.active_radarr_block,
|
||||||
|
self.context,
|
||||||
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
}
|
||||||
|
_ if EditCollectionHandler::accepts(self.active_radarr_block) => {
|
||||||
|
EditCollectionHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle();
|
||||||
|
}
|
||||||
|
_ => self.handle_key_event(),
|
||||||
}
|
}
|
||||||
_ if EditCollectionHandler::accepts(self.active_radarr_block) => {
|
|
||||||
EditCollectionHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
|
||||||
.handle();
|
|
||||||
}
|
|
||||||
_ => self.handle_key_event(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
CollectionDetailsHandler::accepts(active_block)
|
CollectionDetailsHandler::accepts(active_block)
|
||||||
|| EditCollectionHandler::accepts(active_block)
|
|| EditCollectionHandler::accepts(active_block)
|
||||||
|| COLLECTIONS_BLOCKS.contains(active_block)
|
|| COLLECTIONS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> CollectionsHandler<'a, 'b> {
|
) -> CollectionsHandler<'a, 'b> {
|
||||||
CollectionsHandler {
|
CollectionsHandler {
|
||||||
key,
|
key,
|
||||||
@@ -63,7 +92,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,105 +100,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.collections.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.collections.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Collections => self.app.data.radarr_data.collections.scroll_up(),
|
|
||||||
ActiveRadarrBlock::CollectionsSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_up(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Collections => self.app.data.radarr_data.collections.scroll_down(),
|
|
||||||
ActiveRadarrBlock::CollectionsSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_down(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Collections => self.app.data.radarr_data.collections.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::SearchCollection => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.search
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_home(),
|
|
||||||
ActiveRadarrBlock::FilterCollections => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.filter
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_home(),
|
|
||||||
ActiveRadarrBlock::CollectionsSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_top(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Collections => self.app.data.radarr_data.collections.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::SearchCollection => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.search
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.reset_offset(),
|
|
||||||
ActiveRadarrBlock::FilterCollections => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.filter
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.reset_offset(),
|
|
||||||
ActiveRadarrBlock::CollectionsSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {}
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
@@ -177,34 +114,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Collections => handle_change_tab_left_right_keys(self.app, self.key),
|
ActiveRadarrBlock::Collections => handle_change_tab_left_right_keys(self.app, self.key),
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt => handle_prompt_toggle(self.app, self.key),
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt => handle_prompt_toggle(self.app, self.key),
|
||||||
ActiveRadarrBlock::SearchCollection => {
|
|
||||||
handle_text_box_left_right_keys!(
|
|
||||||
self,
|
|
||||||
self.key,
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.search
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterCollections => {
|
|
||||||
handle_text_box_left_right_keys!(
|
|
||||||
self,
|
|
||||||
self.key,
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.filter
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,44 +123,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
ActiveRadarrBlock::Collections => self
|
ActiveRadarrBlock::Collections => self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into()),
|
.push_navigation_stack(ActiveRadarrBlock::CollectionDetails.into()),
|
||||||
ActiveRadarrBlock::SearchCollection => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
|
|
||||||
if self.app.data.radarr_data.collections.search.is_some() {
|
|
||||||
let has_match = self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.apply_search(|collection| &collection.title.text);
|
|
||||||
|
|
||||||
if !has_match {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SearchCollectionError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterCollections => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
|
|
||||||
if self.app.data.radarr_data.collections.filter.is_some() {
|
|
||||||
let has_matches = self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.apply_filter(|collection| &collection.title.text);
|
|
||||||
|
|
||||||
if !has_matches {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::FilterCollectionsError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
||||||
if self.app.data.radarr_data.prompt_confirm {
|
if self.app.data.radarr_data.prompt_confirm {
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
|
||||||
@@ -259,44 +130,17 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::CollectionsSortPrompt => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.items
|
|
||||||
.sort_by(|a, b| a.id.cmp(&b.id));
|
|
||||||
self.app.data.radarr_data.collections.apply_sorting();
|
|
||||||
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_esc(&mut self) {
|
fn handle_esc(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::FilterCollections | ActiveRadarrBlock::FilterCollectionsError => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.data.radarr_data.collections.reset_filter();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::SearchCollection | ActiveRadarrBlock::SearchCollectionError => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.data.radarr_data.collections.reset_search();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.prompt_confirm = false;
|
self.app.data.radarr_data.prompt_confirm = false;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::CollectionsSortPrompt => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
self.app.data.radarr_data.collections.reset_search();
|
|
||||||
self.app.data.radarr_data.collections.reset_filter();
|
|
||||||
handle_clear_errors(self.app);
|
handle_clear_errors(self.app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -306,87 +150,27 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for CollectionsHandler<'
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Collections => match self.key {
|
ActiveRadarrBlock::Collections => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.search.key => {
|
_ if key == DEFAULT_KEYBINDINGS.edit.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SearchCollection.into());
|
.push_navigation_stack(ActiveRadarrBlock::EditCollectionPrompt.into());
|
||||||
self.app.data.radarr_data.collections.search =
|
|
||||||
Some(HorizontallyScrollableText::default());
|
|
||||||
self.app.should_ignore_quit_key = true;
|
|
||||||
}
|
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.filter.key => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::FilterCollections.into());
|
|
||||||
self.app.data.radarr_data.collections.reset_filter();
|
|
||||||
self.app.data.radarr_data.collections.filter =
|
|
||||||
Some(HorizontallyScrollableText::default());
|
|
||||||
self.app.should_ignore_quit_key = true;
|
|
||||||
}
|
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.edit.key => {
|
|
||||||
self.app.push_navigation_stack(
|
|
||||||
(
|
|
||||||
ActiveRadarrBlock::EditCollectionPrompt,
|
|
||||||
Some(ActiveRadarrBlock::Collections),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
self.app.data.radarr_data.edit_collection_modal =
|
self.app.data.radarr_data.edit_collection_modal =
|
||||||
Some((&self.app.data.radarr_data).into());
|
Some((&self.app.data.radarr_data).into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_COLLECTION_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_COLLECTION_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::UpdateAllCollectionsPrompt.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.sort.key => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.sorting(collections_sorting_options());
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::CollectionsSortPrompt.into());
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::SearchCollection => {
|
|
||||||
handle_text_box_keys!(
|
|
||||||
self,
|
|
||||||
key,
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.search
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterCollections => {
|
|
||||||
handle_text_box_keys!(
|
|
||||||
self,
|
|
||||||
key,
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.collections
|
|
||||||
.filter
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
ActiveRadarrBlock::UpdateAllCollectionsPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateCollections);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_str_eq;
|
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
@@ -11,109 +10,6 @@ mod tests {
|
|||||||
use crate::models::radarr_models::DownloadRecord;
|
use crate::models::radarr_models::DownloadRecord;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
||||||
|
|
||||||
mod test_handle_scroll_up_and_down {
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::models::radarr_models::DownloadRecord;
|
|
||||||
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_scroll!(
|
|
||||||
test_downloads_scroll,
|
|
||||||
DownloadsHandler,
|
|
||||||
downloads,
|
|
||||||
DownloadRecord,
|
|
||||||
ActiveRadarrBlock::Downloads,
|
|
||||||
None,
|
|
||||||
title
|
|
||||||
);
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_downloads_scroll_no_op_when_not_ready(
|
|
||||||
#[values(
|
|
||||||
DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key
|
|
||||||
)]
|
|
||||||
key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.downloads
|
|
||||||
.set_items(simple_stateful_iterable_vec!(DownloadRecord));
|
|
||||||
|
|
||||||
DownloadsHandler::with(&key, &mut app, &ActiveRadarrBlock::Downloads, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.downloads.current_selection().title,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
DownloadsHandler::with(&key, &mut app, &ActiveRadarrBlock::Downloads, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.downloads.current_selection().title,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_home_end {
|
|
||||||
use crate::models::radarr_models::DownloadRecord;
|
|
||||||
use crate::{extended_stateful_iterable_vec, test_iterable_home_and_end};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_home_and_end!(
|
|
||||||
test_downloads_home_end,
|
|
||||||
DownloadsHandler,
|
|
||||||
downloads,
|
|
||||||
DownloadRecord,
|
|
||||||
ActiveRadarrBlock::Downloads,
|
|
||||||
None,
|
|
||||||
title
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_downloads_home_end_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.downloads
|
|
||||||
.set_items(extended_stateful_iterable_vec!(DownloadRecord));
|
|
||||||
|
|
||||||
DownloadsHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Downloads,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.downloads.current_selection().title,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
DownloadsHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Downloads,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.downloads.current_selection().title,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_delete {
|
mod test_handle_delete {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -130,11 +26,11 @@ mod tests {
|
|||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Downloads, &None).handle();
|
DownloadsHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::DeleteDownloadPrompt.into()
|
ActiveRadarrBlock::DeleteDownloadPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,12 +45,9 @@ mod tests {
|
|||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Downloads, &None).handle();
|
DownloadsHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,20 +64,20 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(2);
|
app.data.radarr_data.main_tabs.set_index(2);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::Collections.into()
|
ActiveRadarrBlock::Collections.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,21 +88,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(2);
|
app.data.radarr_data.main_tabs.set_index(2);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
ActiveRadarrBlock::Blocklist.into()
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -223,11 +113,11 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
DownloadsHandler::with(&key, &mut app, &active_radarr_block, &None).handle();
|
DownloadsHandler::with(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
DownloadsHandler::with(&key, &mut app, &active_radarr_block, &None).handle();
|
DownloadsHandler::with(key, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -269,14 +159,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
DownloadsHandler::with(&SUBMIT_KEY, &mut app, &prompt_block, &None).handle();
|
DownloadsHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &base_route.into());
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -295,11 +185,11 @@ mod tests {
|
|||||||
app.push_navigation_stack(base_route.into());
|
app.push_navigation_stack(base_route.into());
|
||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
DownloadsHandler::with(&SUBMIT_KEY, &mut app, &prompt_block, &None).handle();
|
DownloadsHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert_eq!(app.get_current_route(), &base_route.into());
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -323,9 +213,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
DownloadsHandler::with(&ESC_KEY, &mut app, &prompt_block, &None).handle();
|
DownloadsHandler::with(ESC_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &base_block.into());
|
assert_eq!(app.get_current_route(), base_block.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,12 +227,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
DownloadsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::Downloads, &None).handle();
|
DownloadsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
|
||||||
assert!(app.error.text.is_empty());
|
assert!(app.error.text.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -365,16 +252,16 @@ mod tests {
|
|||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::UpdateDownloadsPrompt.into()
|
ActiveRadarrBlock::UpdateDownloadsPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,17 +277,14 @@ mod tests {
|
|||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -414,17 +298,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,17 +321,14 @@ mod tests {
|
|||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Downloads.into());
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Downloads.into()
|
|
||||||
);
|
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -480,10 +358,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(prompt_block.into());
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
DownloadsHandler::with(
|
DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&prompt_block,
|
prompt_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -492,7 +370,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(expected_action)
|
Some(expected_action)
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &base_route.into());
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -500,9 +378,9 @@ mod tests {
|
|||||||
fn test_downloads_handler_accepts() {
|
fn test_downloads_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if DOWNLOADS_BLOCKS.contains(&active_radarr_block) {
|
if DOWNLOADS_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(DownloadsHandler::accepts(&active_radarr_block));
|
assert!(DownloadsHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!DownloadsHandler::accepts(&active_radarr_block));
|
assert!(!DownloadsHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -513,10 +391,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = DownloadsHandler::with(
|
let handler = DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -528,10 +406,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = DownloadsHandler::with(
|
let handler = DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -548,10 +426,10 @@ mod tests {
|
|||||||
.downloads
|
.downloads
|
||||||
.set_items(vec![DownloadRecord::default()]);
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
let handler = DownloadsHandler::with(
|
let handler = DownloadsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Downloads,
|
ActiveRadarrBlock::Downloads,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::radarr_models::DownloadRecord;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, DOWNLOADS_BLOCKS};
|
||||||
use crate::models::Scrollable;
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -12,22 +14,40 @@ use crate::network::radarr_network::RadarrEvent;
|
|||||||
mod downloads_handler_tests;
|
mod downloads_handler_tests;
|
||||||
|
|
||||||
pub(super) struct DownloadsHandler<'a, 'b> {
|
pub(super) struct DownloadsHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> DownloadsHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
downloads,
|
||||||
|
self.app.data.radarr_data.downloads,
|
||||||
|
DownloadRecord
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
DOWNLOADS_BLOCKS.contains(active_block)
|
let downloads_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::Downloads.into());
|
||||||
|
|
||||||
|
if !self.handle_downloads_table_events(downloads_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
DOWNLOADS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> DownloadsHandler<'a, 'b> {
|
) -> DownloadsHandler<'a, 'b> {
|
||||||
DownloadsHandler {
|
DownloadsHandler {
|
||||||
key,
|
key,
|
||||||
@@ -37,7 +57,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,32 +65,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.downloads.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.downloads.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Downloads {
|
|
||||||
self.app.data.radarr_data.downloads.scroll_up()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Downloads {
|
|
||||||
self.app.data.radarr_data.downloads.scroll_down()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Downloads {
|
|
||||||
self.app.data.radarr_data.downloads.scroll_to_top()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Downloads {
|
|
||||||
self.app.data.radarr_data.downloads.scroll_to_bottom()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {
|
fn handle_delete(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Downloads {
|
if self.active_radarr_block == ActiveRadarrBlock::Downloads {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::DeleteDownloadPrompt.into())
|
.push_navigation_stack(ActiveRadarrBlock::DeleteDownloadPrompt.into())
|
||||||
@@ -121,18 +125,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Downloads => match self.key {
|
ActiveRadarrBlock::Downloads => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::UpdateDownloadsPrompt.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::DeleteDownloadPrompt => {
|
ActiveRadarrBlock::DeleteDownloadPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteDownload(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteDownload(None));
|
||||||
|
|
||||||
@@ -140,7 +144,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DownloadsHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::UpdateDownloadsPrompt => {
|
ActiveRadarrBlock::UpdateDownloadsPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateDownloads);
|
||||||
|
|
||||||
|
|||||||
@@ -4,29 +4,29 @@ use crate::event::Key;
|
|||||||
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, EDIT_INDEXER_BLOCKS};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "edit_indexer_handler_tests.rs"]
|
#[path = "edit_indexer_handler_tests.rs"]
|
||||||
mod edit_indexer_handler_tests;
|
mod edit_indexer_handler_tests;
|
||||||
|
|
||||||
pub(super) struct EditIndexerHandler<'a, 'b> {
|
pub(super) struct EditIndexerHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
EDIT_INDEXER_BLOCKS.contains(active_block)
|
EDIT_INDEXER_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> EditIndexerHandler<'a, 'b> {
|
) -> EditIndexerHandler<'a, 'b> {
|
||||||
EditIndexerHandler {
|
EditIndexerHandler {
|
||||||
key,
|
key,
|
||||||
@@ -36,7 +36,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,14 +45,42 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::EditIndexerPrompt {
|
match self.active_radarr_block {
|
||||||
self.app.data.radarr_data.selected_block.previous();
|
ActiveRadarrBlock::EditIndexerPrompt => {
|
||||||
|
self.app.data.radarr_data.selected_block.up();
|
||||||
|
}
|
||||||
|
ActiveRadarrBlock::EditIndexerPriorityInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.priority += 1;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::EditIndexerPrompt {
|
match self.active_radarr_block {
|
||||||
self.app.data.radarr_data.selected_block.next();
|
ActiveRadarrBlock::EditIndexerPrompt => {
|
||||||
|
self.app.data.radarr_data.selected_block.down();
|
||||||
|
}
|
||||||
|
ActiveRadarrBlock::EditIndexerPriorityInput => {
|
||||||
|
let edit_indexer_modal = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
|
if edit_indexer_modal.priority > 0 {
|
||||||
|
edit_indexer_modal.priority -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,15 +211,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
fn handle_left_right_action(&mut self) {
|
fn handle_left_right_action(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::EditIndexerPrompt => {
|
ActiveRadarrBlock::EditIndexerPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
handle_prompt_left_right_keys!(
|
||||||
== &ActiveRadarrBlock::EditIndexerConfirmPrompt
|
self,
|
||||||
{
|
ActiveRadarrBlock::EditIndexerConfirmPrompt,
|
||||||
handle_prompt_toggle(self.app, self.key);
|
radarr_data
|
||||||
} else {
|
);
|
||||||
let len = self.app.data.radarr_data.selected_block.blocks.len();
|
|
||||||
let idx = self.app.data.radarr_data.selected_block.index;
|
|
||||||
self.app.data.radarr_data.selected_block.index = (idx + 5) % len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditIndexerNameInput => {
|
ActiveRadarrBlock::EditIndexerNameInput => {
|
||||||
handle_text_box_left_right_keys!(
|
handle_text_box_left_right_keys!(
|
||||||
@@ -270,7 +294,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
fn handle_submit(&mut self) {
|
fn handle_submit(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::EditIndexerPrompt => {
|
ActiveRadarrBlock::EditIndexerPrompt => {
|
||||||
let selected_block = *self.app.data.radarr_data.selected_block.get_active_block();
|
let selected_block = self.app.data.radarr_data.selected_block.get_active_block();
|
||||||
match selected_block {
|
match selected_block {
|
||||||
ActiveRadarrBlock::EditIndexerConfirmPrompt => {
|
ActiveRadarrBlock::EditIndexerConfirmPrompt => {
|
||||||
let radarr_data = &mut self.app.data.radarr_data;
|
let radarr_data = &mut self.app.data.radarr_data;
|
||||||
@@ -291,6 +315,9 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
self.app.push_navigation_stack(selected_block.into());
|
self.app.push_navigation_stack(selected_block.into());
|
||||||
self.app.should_ignore_quit_key = true;
|
self.app.should_ignore_quit_key = true;
|
||||||
}
|
}
|
||||||
|
ActiveRadarrBlock::EditIndexerPriorityInput => self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveRadarrBlock::EditIndexerPriorityInput.into()),
|
||||||
ActiveRadarrBlock::EditIndexerToggleEnableRss => {
|
ActiveRadarrBlock::EditIndexerToggleEnableRss => {
|
||||||
let indexer = self
|
let indexer = self
|
||||||
.app
|
.app
|
||||||
@@ -334,6 +361,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.should_ignore_quit_key = false;
|
||||||
}
|
}
|
||||||
|
ActiveRadarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,6 +377,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
| ActiveRadarrBlock::EditIndexerUrlInput
|
| ActiveRadarrBlock::EditIndexerUrlInput
|
||||||
| ActiveRadarrBlock::EditIndexerApiKeyInput
|
| ActiveRadarrBlock::EditIndexerApiKeyInput
|
||||||
| ActiveRadarrBlock::EditIndexerSeedRatioInput
|
| ActiveRadarrBlock::EditIndexerSeedRatioInput
|
||||||
|
| ActiveRadarrBlock::EditIndexerPriorityInput
|
||||||
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
| ActiveRadarrBlock::EditIndexerTagsInput => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.should_ignore_quit_key = false;
|
||||||
@@ -431,8 +460,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditIndexerHandler<'
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditIndexerPrompt => {
|
ActiveRadarrBlock::EditIndexerPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== &ActiveRadarrBlock::EditIndexerConfirmPrompt
|
== ActiveRadarrBlock::EditIndexerConfirmPrompt
|
||||||
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditIndexer(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditIndexer(None));
|
||||||
|
|||||||
@@ -6,29 +6,29 @@ use crate::models::servarr_data::radarr::radarr_data::{
|
|||||||
ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS,
|
ActiveRadarrBlock, INDEXER_SETTINGS_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "edit_indexer_settings_handler_tests.rs"]
|
#[path = "edit_indexer_settings_handler_tests.rs"]
|
||||||
mod edit_indexer_settings_handler_tests;
|
mod edit_indexer_settings_handler_tests;
|
||||||
|
|
||||||
pub(super) struct IndexerSettingsHandler<'a, 'b> {
|
pub(super) struct IndexerSettingsHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
INDEXER_SETTINGS_BLOCKS.contains(active_block)
|
INDEXER_SETTINGS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> IndexerSettingsHandler<'a, 'b> {
|
) -> IndexerSettingsHandler<'a, 'b> {
|
||||||
IndexerSettingsHandler {
|
IndexerSettingsHandler {
|
||||||
key,
|
key,
|
||||||
@@ -38,7 +38,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +50,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap();
|
let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap();
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
||||||
self.app.data.radarr_data.selected_block.previous();
|
self.app.data.radarr_data.selected_block.up();
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput => {
|
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput => {
|
||||||
indexer_settings.minimum_age += 1;
|
indexer_settings.minimum_age += 1;
|
||||||
@@ -75,7 +75,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap();
|
let indexer_settings = self.app.data.radarr_data.indexer_settings.as_mut().unwrap();
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
||||||
self.app.data.radarr_data.selected_block.next()
|
self.app.data.radarr_data.selected_block.down()
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput => {
|
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput => {
|
||||||
if indexer_settings.minimum_age > 0 {
|
if indexer_settings.minimum_age > 0 {
|
||||||
@@ -105,7 +105,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput {
|
if self.active_radarr_block == ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -119,7 +119,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput {
|
if self.active_radarr_block == ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -137,15 +137,11 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
fn handle_left_right_action(&mut self) {
|
fn handle_left_right_action(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
handle_prompt_left_right_keys!(
|
||||||
== &ActiveRadarrBlock::IndexerSettingsConfirmPrompt
|
self,
|
||||||
{
|
ActiveRadarrBlock::IndexerSettingsConfirmPrompt,
|
||||||
handle_prompt_toggle(self.app, self.key);
|
radarr_data
|
||||||
} else {
|
);
|
||||||
let len = self.app.data.radarr_data.selected_block.blocks.len();
|
|
||||||
let idx = self.app.data.radarr_data.selected_block.index;
|
|
||||||
self.app.data.radarr_data.selected_block.index = (idx + 5) % len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => {
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput => {
|
||||||
handle_text_box_left_right_keys!(
|
handle_text_box_left_right_keys!(
|
||||||
@@ -187,7 +183,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
| ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput => {
|
| ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput => {
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
@@ -258,8 +254,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexerSettingsHandl
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
ActiveRadarrBlock::AllIndexerSettingsPrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== &ActiveRadarrBlock::IndexerSettingsConfirmPrompt
|
== ActiveRadarrBlock::IndexerSettingsConfirmPrompt
|
||||||
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
self.app.data.radarr_data.prompt_confirm_action =
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(&$key, &mut app, &$block, &None).handle();
|
IndexerSettingsHandler::with($key, &mut app, $block, None).handle();
|
||||||
|
|
||||||
if $key == Key::Up {
|
if $key == Key::Up {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -64,7 +64,7 @@ mod tests {
|
|||||||
0
|
0
|
||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(&Key::Up, &mut app, &$block, &None).handle();
|
IndexerSettingsHandler::with(Key::Up, &mut app, $block, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
@@ -77,7 +77,7 @@ mod tests {
|
|||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(&$key, &mut app, &$block, &None).handle();
|
IndexerSettingsHandler::with($key, &mut app, $block, None).handle();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -98,26 +98,26 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.next();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::IndexerSettingsMinimumAgeInput
|
ActiveRadarrBlock::IndexerSettingsMinimumAgeInput
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::IndexerSettingsMaximumSizeInput
|
ActiveRadarrBlock::IndexerSettingsMaximumSizeInput
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,20 +130,20 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.next();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::IndexerSettingsRetentionInput
|
ActiveRadarrBlock::IndexerSettingsRetentionInput
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,10 +218,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -239,10 +239,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -276,24 +276,24 @@ mod tests {
|
|||||||
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.index = INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1;
|
app.data.radarr_data.selected_block.y = INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1;
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -323,44 +323,44 @@ mod tests {
|
|||||||
)]
|
)]
|
||||||
fn test_left_right_block_toggle(
|
fn test_left_right_block_toggle(
|
||||||
#[values(Key::Left, Key::Right)] key: Key,
|
#[values(Key::Left, Key::Right)] key: Key,
|
||||||
#[case] starting_index: usize,
|
#[case] starting_y_index: usize,
|
||||||
#[case] left_block: ActiveRadarrBlock,
|
#[case] left_block: ActiveRadarrBlock,
|
||||||
#[case] right_block: ActiveRadarrBlock,
|
#[case] right_block: ActiveRadarrBlock,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.index = starting_index;
|
app.data.radarr_data.selected_block.y = starting_y_index;
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&left_block
|
left_block
|
||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&right_block
|
right_block
|
||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&left_block
|
left_block
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -373,10 +373,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -394,10 +394,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -438,23 +438,23 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
assert_eq!(app.data.radarr_data.indexer_settings, None);
|
assert_eq!(app.data.radarr_data.indexer_settings, None);
|
||||||
@@ -466,24 +466,24 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::EditAllIndexerSettings(None))
|
Some(RadarrEvent::EditAllIndexerSettings(None))
|
||||||
@@ -502,71 +502,80 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case(ActiveRadarrBlock::IndexerSettingsMinimumAgeInput, 0)]
|
#[case(ActiveRadarrBlock::IndexerSettingsMinimumAgeInput, 0, 0)]
|
||||||
#[case(ActiveRadarrBlock::IndexerSettingsRetentionInput, 1)]
|
#[case(ActiveRadarrBlock::IndexerSettingsRetentionInput, 1, 0)]
|
||||||
#[case(ActiveRadarrBlock::IndexerSettingsMaximumSizeInput, 2)]
|
#[case(ActiveRadarrBlock::IndexerSettingsMaximumSizeInput, 2, 0)]
|
||||||
#[case(ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput, 5)]
|
#[case(ActiveRadarrBlock::IndexerSettingsAvailabilityDelayInput, 0, 1)]
|
||||||
#[case(ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput, 6)]
|
#[case(ActiveRadarrBlock::IndexerSettingsRssSyncIntervalInput, 1, 1)]
|
||||||
fn test_edit_indexer_settings_prompt_submit_selected_block(
|
fn test_edit_indexer_settings_prompt_submit_selected_block(
|
||||||
#[case] selected_block: ActiveRadarrBlock,
|
#[case] selected_block: ActiveRadarrBlock,
|
||||||
#[case] index: usize,
|
#[case] y_index: usize,
|
||||||
|
#[case] x_index: usize,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(index);
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(x_index, y_index);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &selected_block.into());
|
assert_eq!(app.get_current_route(), selected_block.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_edit_indexer_settings_prompt_submit_selected_block_no_op_when_not_ready(
|
fn test_edit_indexer_settings_prompt_submit_selected_block_no_op_when_not_ready(
|
||||||
#[values(0, 1, 2, 5, 6)] index: usize,
|
#[values((0, 0), (1, 0), (2, 0), (0, 1), (1, 1))] index: (usize, usize),
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(index);
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(index.1, index.0);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -576,20 +585,20 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(7);
|
app.data.radarr_data.selected_block.set_index(1, 2);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into()
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput.into()
|
||||||
);
|
);
|
||||||
assert!(app.should_ignore_quit_key);
|
assert!(app.should_ignore_quit_key);
|
||||||
}
|
}
|
||||||
@@ -599,21 +608,21 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(3);
|
app.data.radarr_data.selected_block.set_index(0, 3);
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
app
|
app
|
||||||
@@ -626,16 +635,16 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!app
|
!app
|
||||||
@@ -653,21 +662,21 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(8);
|
app.data.radarr_data.selected_block.set_index(1, 3);
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
app
|
app
|
||||||
@@ -680,16 +689,16 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
assert!(
|
assert!(
|
||||||
!app
|
!app
|
||||||
@@ -716,10 +725,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -735,7 +744,7 @@ mod tests {
|
|||||||
.is_empty());
|
.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -755,11 +764,11 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(&SUBMIT_KEY, &mut app, &active_radarr_block, &None).handle();
|
IndexerSettingsHandler::with(SUBMIT_KEY, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -783,14 +792,14 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.indexer_settings, None);
|
assert_eq!(app.data.radarr_data.indexer_settings, None);
|
||||||
}
|
}
|
||||||
@@ -806,14 +815,14 @@ mod tests {
|
|||||||
app.should_ignore_quit_key = true;
|
app.should_ignore_quit_key = true;
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.should_ignore_quit_key);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.indexer_settings,
|
app.data.radarr_data.indexer_settings,
|
||||||
@@ -838,9 +847,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(&ESC_KEY, &mut app, &active_radarr_block, &None).handle();
|
IndexerSettingsHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.indexer_settings,
|
app.data.radarr_data.indexer_settings,
|
||||||
Some(IndexerSettings::default())
|
Some(IndexerSettings::default())
|
||||||
@@ -870,10 +879,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.backspace.key,
|
DEFAULT_KEYBINDINGS.backspace.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -896,10 +905,10 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&Key::Char('h'),
|
Key::Char('h'),
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
ActiveRadarrBlock::IndexerSettingsWhitelistedSubtitleTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -922,23 +931,23 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
IndexerSettingsHandler::with(
|
IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::EditAllIndexerSettings(None))
|
Some(RadarrEvent::EditAllIndexerSettings(None))
|
||||||
@@ -952,9 +961,9 @@ mod tests {
|
|||||||
fn test_indexer_settings_handler_accepts() {
|
fn test_indexer_settings_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if INDEXER_SETTINGS_BLOCKS.contains(&active_radarr_block) {
|
if INDEXER_SETTINGS_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(IndexerSettingsHandler::accepts(&active_radarr_block));
|
assert!(IndexerSettingsHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!IndexerSettingsHandler::accepts(&active_radarr_block));
|
assert!(!IndexerSettingsHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -965,10 +974,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = IndexerSettingsHandler::with(
|
let handler = IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -980,10 +989,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = IndexerSettingsHandler::with(
|
let handler = IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -996,10 +1005,10 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
app.data.radarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
let handler = IndexerSettingsHandler::with(
|
let handler = IndexerSettingsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
ActiveRadarrBlock::AllIndexerSettingsPrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::{assert_eq, assert_str_eq};
|
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
@@ -15,107 +14,6 @@ mod tests {
|
|||||||
use crate::models::servarr_models::Indexer;
|
use crate::models::servarr_models::Indexer;
|
||||||
use crate::test_handler_delegation;
|
use crate::test_handler_delegation;
|
||||||
|
|
||||||
mod test_handle_scroll_up_and_down {
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_scroll!(
|
|
||||||
test_indexers_scroll,
|
|
||||||
IndexersHandler,
|
|
||||||
indexers,
|
|
||||||
simple_stateful_iterable_vec!(Indexer, String, protocol),
|
|
||||||
ActiveRadarrBlock::Indexers,
|
|
||||||
None,
|
|
||||||
protocol
|
|
||||||
);
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_indexers_scroll_no_op_when_not_ready(
|
|
||||||
#[values(
|
|
||||||
DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key
|
|
||||||
)]
|
|
||||||
key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexers
|
|
||||||
.set_items(simple_stateful_iterable_vec!(Indexer, String, protocol));
|
|
||||||
|
|
||||||
IndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.indexers.current_selection().protocol,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
IndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.indexers.current_selection().protocol,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_home_end {
|
|
||||||
use crate::{extended_stateful_iterable_vec, test_iterable_home_and_end};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_home_and_end!(
|
|
||||||
test_indexers_home_end,
|
|
||||||
IndexersHandler,
|
|
||||||
indexers,
|
|
||||||
extended_stateful_iterable_vec!(Indexer, String, protocol),
|
|
||||||
ActiveRadarrBlock::Indexers,
|
|
||||||
None,
|
|
||||||
protocol
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_indexers_home_end_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexers
|
|
||||||
.set_items(extended_stateful_iterable_vec!(Indexer, String, protocol));
|
|
||||||
|
|
||||||
IndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Indexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.indexers.current_selection().protocol,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
IndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Indexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.indexers.current_selection().protocol,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_delete {
|
mod test_handle_delete {
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
@@ -132,11 +30,11 @@ mod tests {
|
|||||||
.indexers
|
.indexers
|
||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
IndexersHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt.into()
|
ActiveRadarrBlock::DeleteIndexerPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,9 +49,9 @@ mod tests {
|
|||||||
.indexers
|
.indexers
|
||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(&DELETE_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
IndexersHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,20 +68,20 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(5);
|
app.data.radarr_data.main_tabs.set_index(5);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,18 +92,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(5);
|
app.data.radarr_data.main_tabs.set_index(5);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::System.into()
|
ActiveRadarrBlock::System.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -214,23 +112,11 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(key, &mut app, ActiveRadarrBlock::DeleteIndexerPrompt, None).handle();
|
||||||
&key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(key, &mut app, ActiveRadarrBlock::DeleteIndexerPrompt, None).handle();
|
||||||
&key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -306,11 +192,11 @@ mod tests {
|
|||||||
radarr_data.indexers.set_items(vec![indexer]);
|
radarr_data.indexers.set_items(vec![indexer]);
|
||||||
app.data.radarr_data = radarr_data;
|
app.data.radarr_data = radarr_data;
|
||||||
|
|
||||||
IndexersHandler::with(&SUBMIT_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
IndexersHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditIndexerPrompt.into()
|
ActiveRadarrBlock::EditIndexerPrompt.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.edit_indexer_modal,
|
app.data.radarr_data.edit_indexer_modal,
|
||||||
@@ -323,12 +209,12 @@ mod tests {
|
|||||||
if torrent_protocol {
|
if torrent_protocol {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.blocks,
|
app.data.radarr_data.selected_block.blocks,
|
||||||
&EDIT_INDEXER_TORRENT_SELECTION_BLOCKS
|
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.blocks,
|
app.data.radarr_data.selected_block.blocks,
|
||||||
&EDIT_INDEXER_NZB_SELECTION_BLOCKS
|
EDIT_INDEXER_NZB_SELECTION_BLOCKS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -344,9 +230,9 @@ mod tests {
|
|||||||
.indexers
|
.indexers
|
||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(&SUBMIT_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
IndexersHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert_eq!(app.data.radarr_data.edit_indexer_modal, None);
|
assert_eq!(app.data.radarr_data.edit_indexer_modal, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,10 +249,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt,
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -375,7 +261,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::DeleteIndexer(None))
|
Some(RadarrEvent::DeleteIndexer(None))
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -390,16 +276,16 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt,
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,14 +305,14 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt,
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -434,14 +320,14 @@ mod tests {
|
|||||||
fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) {
|
fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.is_loading = is_ready;
|
app.is_loading = is_ready;
|
||||||
app.data.radarr_data.indexer_test_error = Some("test result".to_owned());
|
app.data.radarr_data.indexer_test_errors = Some("test result".to_owned());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
|
app.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
|
||||||
|
|
||||||
IndexersHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::TestIndexer, &None).handle();
|
IndexersHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::TestIndexer, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert_eq!(app.data.radarr_data.indexer_test_error, None);
|
assert_eq!(app.data.radarr_data.indexer_test_errors, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -452,9 +338,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
|
|
||||||
IndexersHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::Indexers, &None).handle();
|
IndexersHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(app.error.text.is_empty());
|
assert!(app.error.text.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -469,51 +355,6 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_indexer_add() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexers
|
|
||||||
.set_items(vec![Indexer::default()]);
|
|
||||||
|
|
||||||
IndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.add.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Indexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::AddIndexer.into()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_indexer_add_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexers
|
|
||||||
.set_items(vec![Indexer::default()]);
|
|
||||||
|
|
||||||
IndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.add.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::Indexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_refresh_indexers_key() {
|
fn test_refresh_indexers_key() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
@@ -525,14 +366,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,14 +389,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Indexers.into());
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,20 +410,20 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.settings.key,
|
DEFAULT_KEYBINDINGS.settings.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
ActiveRadarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.blocks,
|
app.data.radarr_data.selected_block.blocks,
|
||||||
&INDEXER_SETTINGS_SELECTION_BLOCKS
|
INDEXER_SETTINGS_SELECTION_BLOCKS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,14 +439,14 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.settings.key,
|
DEFAULT_KEYBINDINGS.settings.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -618,16 +459,16 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.test.key,
|
DEFAULT_KEYBINDINGS.test.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::TestIndexer.into()
|
ActiveRadarrBlock::TestIndexer.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -643,14 +484,14 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.test.key,
|
DEFAULT_KEYBINDINGS.test.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -663,16 +504,16 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.test_all.key,
|
DEFAULT_KEYBINDINGS.test_all.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::TestAllIndexers.into()
|
ActiveRadarrBlock::TestAllIndexers.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,14 +529,14 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.test_all.key,
|
DEFAULT_KEYBINDINGS.test_all.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -710,10 +551,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
|
||||||
IndexersHandler::with(
|
IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteIndexerPrompt,
|
ActiveRadarrBlock::DeleteIndexerPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -722,7 +563,7 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::DeleteIndexer(None))
|
Some(RadarrEvent::DeleteIndexer(None))
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,9 +632,9 @@ mod tests {
|
|||||||
|
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if indexers_blocks.contains(&active_radarr_block) {
|
if indexers_blocks.contains(&active_radarr_block) {
|
||||||
assert!(IndexersHandler::accepts(&active_radarr_block));
|
assert!(IndexersHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!IndexersHandler::accepts(&active_radarr_block));
|
assert!(!IndexersHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -804,10 +645,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = IndexersHandler::with(
|
let handler = IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -819,10 +660,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = IndexersHandler::with(
|
let handler = IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -839,10 +680,10 @@ mod tests {
|
|||||||
.set_items(vec![Indexer::default()]);
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
let handler = IndexersHandler::with(
|
let handler = IndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::Indexers,
|
ActiveRadarrBlock::Indexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
|
use crate::handlers::radarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
|
||||||
use crate::handlers::radarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
|
use crate::handlers::radarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
|
||||||
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
ActiveRadarrBlock, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
||||||
INDEXERS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS,
|
INDEXERS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
|
use crate::models::servarr_models::Indexer;
|
||||||
use crate::models::BlockSelectionState;
|
use crate::models::BlockSelectionState;
|
||||||
use crate::models::Scrollable;
|
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
mod edit_indexer_handler;
|
mod edit_indexer_handler;
|
||||||
@@ -23,43 +25,52 @@ mod test_all_indexers_handler;
|
|||||||
mod indexers_handler_tests;
|
mod indexers_handler_tests;
|
||||||
|
|
||||||
pub(super) struct IndexersHandler<'a, 'b> {
|
pub(super) struct IndexersHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> IndexersHandler<'a, 'b> {
|
||||||
|
handle_table_events!(self, indexers, self.app.data.radarr_data.indexers, Indexer);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a, 'b> {
|
||||||
fn handle(&mut self) {
|
fn handle(&mut self) {
|
||||||
match self.active_radarr_block {
|
let indexer_table_handling_config =
|
||||||
_ if EditIndexerHandler::accepts(self.active_radarr_block) => {
|
TableHandlingConfig::new(ActiveRadarrBlock::Indexers.into());
|
||||||
EditIndexerHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
|
||||||
.handle()
|
if !self.handle_indexers_table_events(indexer_table_handling_config) {
|
||||||
|
match self.active_radarr_block {
|
||||||
|
_ if EditIndexerHandler::accepts(self.active_radarr_block) => {
|
||||||
|
EditIndexerHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle()
|
||||||
|
}
|
||||||
|
_ if IndexerSettingsHandler::accepts(self.active_radarr_block) => {
|
||||||
|
IndexerSettingsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle()
|
||||||
|
}
|
||||||
|
_ if TestAllIndexersHandler::accepts(self.active_radarr_block) => {
|
||||||
|
TestAllIndexersHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle()
|
||||||
|
}
|
||||||
|
_ => self.handle_key_event(),
|
||||||
}
|
}
|
||||||
_ if IndexerSettingsHandler::accepts(self.active_radarr_block) => {
|
|
||||||
IndexerSettingsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
|
||||||
.handle()
|
|
||||||
}
|
|
||||||
_ if TestAllIndexersHandler::accepts(self.active_radarr_block) => {
|
|
||||||
TestAllIndexersHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
|
||||||
.handle()
|
|
||||||
}
|
|
||||||
_ => self.handle_key_event(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
EditIndexerHandler::accepts(active_block)
|
EditIndexerHandler::accepts(active_block)
|
||||||
|| IndexerSettingsHandler::accepts(active_block)
|
|| IndexerSettingsHandler::accepts(active_block)
|
||||||
|| TestAllIndexersHandler::accepts(active_block)
|
|| TestAllIndexersHandler::accepts(active_block)
|
||||||
|| INDEXERS_BLOCKS.contains(active_block)
|
|| INDEXERS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> IndexersHandler<'a, 'b> {
|
) -> IndexersHandler<'a, 'b> {
|
||||||
IndexersHandler {
|
IndexersHandler {
|
||||||
key,
|
key,
|
||||||
@@ -69,7 +80,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,32 +88,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.indexers.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.indexers.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Indexers {
|
|
||||||
self.app.data.radarr_data.indexers.scroll_up();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Indexers {
|
|
||||||
self.app.data.radarr_data.indexers.scroll_down();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Indexers {
|
|
||||||
self.app.data.radarr_data.indexers.scroll_to_top();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Indexers {
|
|
||||||
self.app.data.radarr_data.indexers.scroll_to_bottom();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {
|
fn handle_delete(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Indexers {
|
if self.active_radarr_block == ActiveRadarrBlock::Indexers {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::DeleteIndexerPrompt.into());
|
||||||
@@ -141,10 +136,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
|||||||
.protocol;
|
.protocol;
|
||||||
if protocol == "torrent" {
|
if protocol == "torrent" {
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_INDEXER_TORRENT_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_INDEXER_TORRENT_SELECTION_BLOCKS);
|
||||||
} else {
|
} else {
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_INDEXER_NZB_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_INDEXER_NZB_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -159,7 +154,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::TestIndexer => {
|
ActiveRadarrBlock::TestIndexer => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.indexer_test_error = None;
|
self.app.data.radarr_data.indexer_test_errors = None;
|
||||||
}
|
}
|
||||||
_ => handle_clear_errors(self.app),
|
_ => handle_clear_errors(self.app),
|
||||||
}
|
}
|
||||||
@@ -169,35 +164,30 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for IndexersHandler<'a,
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Indexers => match self.key {
|
ActiveRadarrBlock::Indexers => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.add.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::AddIndexer.into());
|
|
||||||
}
|
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.test.key => {
|
_ if key == DEFAULT_KEYBINDINGS.test.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
|
.push_navigation_stack(ActiveRadarrBlock::TestIndexer.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.test_all.key => {
|
_ if key == DEFAULT_KEYBINDINGS.test_all.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into());
|
.push_navigation_stack(ActiveRadarrBlock::TestAllIndexers.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.settings.key => {
|
_ if key == DEFAULT_KEYBINDINGS.settings.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&INDEXER_SETTINGS_SELECTION_BLOCKS);
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::DeleteIndexerPrompt => {
|
ActiveRadarrBlock::DeleteIndexerPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteIndexer(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteIndexer(None));
|
||||||
|
|
||||||
|
|||||||
@@ -1,30 +1,58 @@
|
|||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
use crate::models::servarr_data::radarr::radarr_data::ActiveRadarrBlock;
|
||||||
use crate::models::Scrollable;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "test_all_indexers_handler_tests.rs"]
|
#[path = "test_all_indexers_handler_tests.rs"]
|
||||||
mod test_all_indexers_handler_tests;
|
mod test_all_indexers_handler_tests;
|
||||||
|
|
||||||
pub(super) struct TestAllIndexersHandler<'a, 'b> {
|
pub(super) struct TestAllIndexersHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> TestAllIndexersHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
indexer_test_all_results,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.indexer_test_all_results
|
||||||
|
.as_mut()
|
||||||
|
.unwrap(),
|
||||||
|
IndexerTestResultModalItem
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
active_block == &ActiveRadarrBlock::TestAllIndexers
|
let test_all_indexers_test_results_table_handler_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::TestAllIndexers.into());
|
||||||
|
|
||||||
|
if !self.handle_indexer_test_all_results_table_events(
|
||||||
|
test_all_indexers_test_results_table_handler_config,
|
||||||
|
) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
active_block == ActiveRadarrBlock::TestAllIndexers
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> TestAllIndexersHandler<'a, 'b> {
|
) -> TestAllIndexersHandler<'a, 'b> {
|
||||||
TestAllIndexersHandler {
|
TestAllIndexersHandler {
|
||||||
key,
|
key,
|
||||||
@@ -34,7 +62,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,57 +76,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandl
|
|||||||
!self.app.is_loading && table_is_ready
|
!self.app.is_loading && table_is_ready
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_up()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_down()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_top()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_bottom()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {}
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
@@ -107,7 +91,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for TestAllIndexersHandl
|
|||||||
fn handle_submit(&mut self) {}
|
fn handle_submit(&mut self) {}
|
||||||
|
|
||||||
fn handle_esc(&mut self) {
|
fn handle_esc(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::TestAllIndexers {
|
if self.active_radarr_block == ActiveRadarrBlock::TestAllIndexers {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.indexer_test_all_results = None;
|
self.app.data.radarr_data.indexer_test_all_results = None;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
mod tests {
|
mod tests {
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
|
||||||
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
use crate::handlers::radarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
||||||
use crate::handlers::KeyEventHandler;
|
use crate::handlers::KeyEventHandler;
|
||||||
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
||||||
@@ -10,220 +9,6 @@ mod tests {
|
|||||||
use crate::models::stateful_table::StatefulTable;
|
use crate::models::stateful_table::StatefulTable;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
mod test_handle_scroll_up_and_down {
|
|
||||||
use pretty_assertions::assert_str_eq;
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
|
||||||
use crate::models::stateful_table::StatefulTable;
|
|
||||||
use crate::simple_stateful_iterable_vec;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_test_all_indexers_results_scroll(
|
|
||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
let mut indexer_test_results = StatefulTable::default();
|
|
||||||
indexer_test_results.set_items(simple_stateful_iterable_vec!(
|
|
||||||
IndexerTestResultModalItem,
|
|
||||||
String,
|
|
||||||
name
|
|
||||||
));
|
|
||||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::TestAllIndexers, &None)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 2"
|
|
||||||
);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::TestAllIndexers, &None)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_test_all_indexers_results_scroll_no_op_when_not_ready(
|
|
||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
let mut indexer_test_results = StatefulTable::default();
|
|
||||||
indexer_test_results.set_items(simple_stateful_iterable_vec!(
|
|
||||||
IndexerTestResultModalItem,
|
|
||||||
String,
|
|
||||||
name
|
|
||||||
));
|
|
||||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::TestAllIndexers, &None)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(&key, &mut app, &ActiveRadarrBlock::TestAllIndexers, &None)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_home_end {
|
|
||||||
use crate::extended_stateful_iterable_vec;
|
|
||||||
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
|
||||||
use crate::models::stateful_table::StatefulTable;
|
|
||||||
use pretty_assertions::assert_str_eq;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_test_all_indexers_results_home_end() {
|
|
||||||
let mut app = App::default();
|
|
||||||
let mut indexer_test_results = StatefulTable::default();
|
|
||||||
indexer_test_results.set_items(extended_stateful_iterable_vec!(
|
|
||||||
IndexerTestResultModalItem,
|
|
||||||
String,
|
|
||||||
name
|
|
||||||
));
|
|
||||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 3"
|
|
||||||
);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_test_all_indexers_results_home_end_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
let mut indexer_test_results = StatefulTable::default();
|
|
||||||
indexer_test_results.set_items(extended_stateful_iterable_vec!(
|
|
||||||
IndexerTestResultModalItem,
|
|
||||||
String,
|
|
||||||
name
|
|
||||||
));
|
|
||||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
TestAllIndexersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.indexer_test_all_results
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.current_selection()
|
|
||||||
.name,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_esc {
|
mod test_handle_esc {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::models::stateful_table::StatefulTable;
|
use crate::models::stateful_table::StatefulTable;
|
||||||
@@ -239,14 +24,14 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
app.data.radarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
||||||
|
|
||||||
TestAllIndexersHandler::with(
|
TestAllIndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
ActiveRadarrBlock::TestAllIndexers,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert!(app.data.radarr_data.indexer_test_all_results.is_none());
|
assert!(app.data.radarr_data.indexer_test_all_results.is_none());
|
||||||
}
|
}
|
||||||
@@ -256,9 +41,9 @@ mod tests {
|
|||||||
fn test_test_all_indexers_handler_accepts() {
|
fn test_test_all_indexers_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if active_radarr_block == ActiveRadarrBlock::TestAllIndexers {
|
if active_radarr_block == ActiveRadarrBlock::TestAllIndexers {
|
||||||
assert!(TestAllIndexersHandler::accepts(&active_radarr_block));
|
assert!(TestAllIndexersHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!TestAllIndexersHandler::accepts(&active_radarr_block));
|
assert!(!TestAllIndexersHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -269,10 +54,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = TestAllIndexersHandler::with(
|
let handler = TestAllIndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
ActiveRadarrBlock::TestAllIndexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -284,10 +69,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = TestAllIndexersHandler::with(
|
let handler = TestAllIndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
ActiveRadarrBlock::TestAllIndexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -300,10 +85,10 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
app.data.radarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
||||||
|
|
||||||
let handler = TestAllIndexersHandler::with(
|
let handler = TestAllIndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
ActiveRadarrBlock::TestAllIndexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -318,10 +103,10 @@ mod tests {
|
|||||||
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
app.data.radarr_data.indexer_test_all_results = Some(indexer_test_results);
|
||||||
|
|
||||||
let handler = TestAllIndexersHandler::with(
|
let handler = TestAllIndexersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::TestAllIndexers,
|
ActiveRadarrBlock::TestAllIndexers,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -1,33 +1,59 @@
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::radarr_models::AddMovieSearchResult;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, ADD_MOVIE_BLOCKS, ADD_MOVIE_SELECTION_BLOCKS,
|
ActiveRadarrBlock, ADD_MOVIE_BLOCKS, ADD_MOVIE_SELECTION_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::{BlockSelectionState, Scrollable};
|
use crate::models::{BlockSelectionState, Scrollable};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys, App, Key};
|
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, App, Key};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "add_movie_handler_tests.rs"]
|
#[path = "add_movie_handler_tests.rs"]
|
||||||
mod add_movie_handler_tests;
|
mod add_movie_handler_tests;
|
||||||
|
|
||||||
pub(super) struct AddMovieHandler<'a, 'b> {
|
pub(super) struct AddMovieHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> AddMovieHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
add_movie_search_results,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.add_searched_movies
|
||||||
|
.as_mut()
|
||||||
|
.unwrap(),
|
||||||
|
AddMovieSearchResult
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
ADD_MOVIE_BLOCKS.contains(active_block)
|
let add_movie_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::AddMovieSearchResults.into());
|
||||||
|
|
||||||
|
if !self.handle_add_movie_search_results_table_events(add_movie_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
ADD_MOVIE_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> AddMovieHandler<'a, 'b> {
|
) -> AddMovieHandler<'a, 'b> {
|
||||||
AddMovieHandler {
|
AddMovieHandler {
|
||||||
key,
|
key,
|
||||||
@@ -37,7 +63,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,14 +73,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AddMovieSearchResults => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.add_searched_movies
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_up(),
|
|
||||||
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -91,21 +109,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.root_folder_list
|
.root_folder_list
|
||||||
.scroll_up(),
|
.scroll_up(),
|
||||||
ActiveRadarrBlock::AddMoviePrompt => self.app.data.radarr_data.selected_block.previous(),
|
ActiveRadarrBlock::AddMoviePrompt => self.app.data.radarr_data.selected_block.up(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AddMovieSearchResults => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.add_searched_movies
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_down(),
|
|
||||||
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -142,21 +152,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.root_folder_list
|
.root_folder_list
|
||||||
.scroll_down(),
|
.scroll_down(),
|
||||||
ActiveRadarrBlock::AddMoviePrompt => self.app.data.radarr_data.selected_block.next(),
|
ActiveRadarrBlock::AddMoviePrompt => self.app.data.radarr_data.selected_block.down(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AddMovieSearchResults => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.add_searched_movies
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -216,14 +218,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::AddMovieSearchResults => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.add_searched_movies
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
ActiveRadarrBlock::AddMovieSelectMonitor => self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -313,7 +307,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
|
|
||||||
fn handle_submit(&mut self) {
|
fn handle_submit(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
_ if *self.active_radarr_block == ActiveRadarrBlock::AddMovieSearchInput
|
_ if self.active_radarr_block == ActiveRadarrBlock::AddMovieSearchInput
|
||||||
&& !self
|
&& !self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -329,7 +323,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchResults.into());
|
.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchResults.into());
|
||||||
self.app.should_ignore_quit_key = false;
|
self.app.should_ignore_quit_key = false;
|
||||||
}
|
}
|
||||||
_ if *self.active_radarr_block == ActiveRadarrBlock::AddMovieSearchResults
|
_ if self.active_radarr_block == ActiveRadarrBlock::AddMovieSearchResults
|
||||||
&& self.app.data.radarr_data.add_searched_movies.is_some() =>
|
&& self.app.data.radarr_data.add_searched_movies.is_some() =>
|
||||||
{
|
{
|
||||||
let tmdb_id = self
|
let tmdb_id = self
|
||||||
@@ -360,7 +354,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::AddMoviePrompt.into());
|
||||||
self.app.data.radarr_data.add_movie_modal = Some((&self.app.data.radarr_data).into());
|
self.app.data.radarr_data.add_movie_modal = Some((&self.app.data.radarr_data).into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&ADD_MOVIE_SELECTION_BLOCKS);
|
BlockSelectionState::new(ADD_MOVIE_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::AddMoviePrompt => {
|
ActiveRadarrBlock::AddMoviePrompt => {
|
||||||
@@ -377,16 +371,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
| ActiveRadarrBlock::AddMovieSelectQualityProfile
|
| ActiveRadarrBlock::AddMovieSelectQualityProfile
|
||||||
| ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.push_navigation_stack(
|
| ActiveRadarrBlock::AddMovieSelectRootFolder => self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
*self.context,
|
self.context,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
ActiveRadarrBlock::AddMovieTagsInput => {
|
ActiveRadarrBlock::AddMovieTagsInput => {
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
*self.context,
|
self.context,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
@@ -463,8 +457,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for AddMovieHandler<'a,
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::AddMoviePrompt => {
|
ActiveRadarrBlock::AddMoviePrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== &ActiveRadarrBlock::AddMovieConfirmPrompt
|
== ActiveRadarrBlock::AddMovieConfirmPrompt
|
||||||
&& *key == DEFAULT_KEYBINDINGS.confirm.key
|
&& key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::AddMovie(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::AddMovie(None));
|
||||||
|
|||||||
@@ -10,22 +10,22 @@ use crate::network::radarr_network::RadarrEvent;
|
|||||||
mod delete_movie_handler_tests;
|
mod delete_movie_handler_tests;
|
||||||
|
|
||||||
pub(super) struct DeleteMovieHandler<'a, 'b> {
|
pub(super) struct DeleteMovieHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
DELETE_MOVIE_BLOCKS.contains(active_block)
|
DELETE_MOVIE_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
DeleteMovieHandler {
|
DeleteMovieHandler {
|
||||||
key,
|
key,
|
||||||
@@ -35,7 +35,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,14 +44,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {
|
||||||
if *self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
||||||
self.app.data.radarr_data.selected_block.previous();
|
self.app.data.radarr_data.selected_block.up();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {
|
||||||
if *self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
||||||
self.app.data.radarr_data.selected_block.next();
|
self.app.data.radarr_data.selected_block.down();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,13 +62,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
|
|||||||
fn handle_delete(&mut self) {}
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
fn handle_left_right_action(&mut self) {
|
fn handle_left_right_action(&mut self) {
|
||||||
if *self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
||||||
handle_prompt_toggle(self.app, self.key);
|
handle_prompt_toggle(self.app, self.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_submit(&mut self) {
|
fn handle_submit(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::DeleteMoviePrompt {
|
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
||||||
match self.app.data.radarr_data.selected_block.get_active_block() {
|
match self.app.data.radarr_data.selected_block.get_active_block() {
|
||||||
ActiveRadarrBlock::DeleteMovieConfirmPrompt => {
|
ActiveRadarrBlock::DeleteMovieConfirmPrompt => {
|
||||||
if self.app.data.radarr_data.prompt_confirm {
|
if self.app.data.radarr_data.prompt_confirm {
|
||||||
@@ -94,7 +94,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_esc(&mut self) {
|
fn handle_esc(&mut self) {
|
||||||
if *self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.reset_delete_movie_preferences();
|
self.app.data.radarr_data.reset_delete_movie_preferences();
|
||||||
self.app.data.radarr_data.prompt_confirm = false;
|
self.app.data.radarr_data.prompt_confirm = false;
|
||||||
@@ -102,10 +102,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for DeleteMovieHandler<'
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_char_key_event(&mut self) {
|
fn handle_char_key_event(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::DeleteMoviePrompt
|
if self.active_radarr_block == ActiveRadarrBlock::DeleteMoviePrompt
|
||||||
&& self.app.data.radarr_data.selected_block.get_active_block()
|
&& self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== &ActiveRadarrBlock::DeleteMovieConfirmPrompt
|
== ActiveRadarrBlock::DeleteMovieConfirmPrompt
|
||||||
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteMovie(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DeleteMovie(None));
|
||||||
|
|||||||
@@ -21,22 +21,20 @@ mod tests {
|
|||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_delete_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
fn test_delete_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block = BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block.down();
|
||||||
app.data.radarr_data.selected_block.next();
|
|
||||||
|
|
||||||
DeleteMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::DeleteMoviePrompt, &None)
|
DeleteMovieHandler::with(key, &mut app, ActiveRadarrBlock::DeleteMoviePrompt, None).handle();
|
||||||
.handle();
|
|
||||||
|
|
||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::DeleteMovieToggleDeleteFile
|
ActiveRadarrBlock::DeleteMovieToggleDeleteFile
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::DeleteMovieConfirmPrompt
|
ActiveRadarrBlock::DeleteMovieConfirmPrompt
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,16 +45,14 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block = BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block.down();
|
||||||
app.data.radarr_data.selected_block.next();
|
|
||||||
|
|
||||||
DeleteMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::DeleteMoviePrompt, &None)
|
DeleteMovieHandler::with(key, &mut app, ActiveRadarrBlock::DeleteMoviePrompt, None).handle();
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
|
ActiveRadarrBlock::DeleteMovieToggleAddListExclusion
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -70,13 +66,11 @@ mod tests {
|
|||||||
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
DeleteMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::DeleteMoviePrompt, &None)
|
DeleteMovieHandler::with(key, &mut app, ActiveRadarrBlock::DeleteMoviePrompt, None).handle();
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
DeleteMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::DeleteMoviePrompt, &None)
|
DeleteMovieHandler::with(key, &mut app, ActiveRadarrBlock::DeleteMoviePrompt, None).handle();
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -98,25 +92,24 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block = BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
app.data.radarr_data.delete_movie_files = true;
|
app.data.radarr_data.delete_movie_files = true;
|
||||||
app.data.radarr_data.add_list_exclusion = true;
|
app.data.radarr_data.add_list_exclusion = true;
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert!(!app.data.radarr_data.delete_movie_files);
|
assert!(!app.data.radarr_data.delete_movie_files);
|
||||||
@@ -131,23 +124,22 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
app.data.radarr_data.delete_movie_files = true;
|
app.data.radarr_data.delete_movie_files = true;
|
||||||
app.data.radarr_data.add_list_exclusion = true;
|
app.data.radarr_data.add_list_exclusion = true;
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block = BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::DeleteMovie(None))
|
Some(RadarrEvent::DeleteMovie(None))
|
||||||
@@ -169,16 +161,16 @@ mod tests {
|
|||||||
app.data.radarr_data.add_list_exclusion = true;
|
app.data.radarr_data.add_list_exclusion = true;
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt.into()
|
ActiveRadarrBlock::DeleteMoviePrompt.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
@@ -191,30 +183,29 @@ mod tests {
|
|||||||
fn test_delete_movie_toggle_delete_files_submit() {
|
fn test_delete_movie_toggle_delete_files_submit() {
|
||||||
let current_route = ActiveRadarrBlock::DeleteMoviePrompt.into();
|
let current_route = ActiveRadarrBlock::DeleteMoviePrompt.into();
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block = BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(app.data.radarr_data.delete_movie_files, true);
|
assert_eq!(app.data.radarr_data.delete_movie_files, true);
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(app.data.radarr_data.delete_movie_files, false);
|
assert_eq!(app.data.radarr_data.delete_movie_files, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -236,14 +227,14 @@ mod tests {
|
|||||||
app.data.radarr_data.add_list_exclusion = true;
|
app.data.radarr_data.add_list_exclusion = true;
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
assert!(!app.data.radarr_data.delete_movie_files);
|
assert!(!app.data.radarr_data.delete_movie_files);
|
||||||
assert!(!app.data.radarr_data.add_list_exclusion);
|
assert!(!app.data.radarr_data.add_list_exclusion);
|
||||||
@@ -267,23 +258,22 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
||||||
app.data.radarr_data.delete_movie_files = true;
|
app.data.radarr_data.delete_movie_files = true;
|
||||||
app.data.radarr_data.add_list_exclusion = true;
|
app.data.radarr_data.add_list_exclusion = true;
|
||||||
app.data.radarr_data.selected_block =
|
app.data.radarr_data.selected_block = BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, DELETE_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
DeleteMovieHandler::with(
|
DeleteMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::DeleteMovie(None))
|
Some(RadarrEvent::DeleteMovie(None))
|
||||||
@@ -299,9 +289,9 @@ mod tests {
|
|||||||
fn test_delete_movie_handler_accepts() {
|
fn test_delete_movie_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if DELETE_MOVIE_BLOCKS.contains(&active_radarr_block) {
|
if DELETE_MOVIE_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(DeleteMovieHandler::accepts(&active_radarr_block));
|
assert!(DeleteMovieHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!DeleteMovieHandler::accepts(&active_radarr_block));
|
assert!(!DeleteMovieHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -312,10 +302,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = DeleteMovieHandler::with(
|
let handler = DeleteMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -327,10 +317,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = DeleteMovieHandler::with(
|
let handler = DeleteMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteMoviePrompt,
|
ActiveRadarrBlock::DeleteMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -12,22 +12,22 @@ use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
|||||||
mod edit_movie_handler_tests;
|
mod edit_movie_handler_tests;
|
||||||
|
|
||||||
pub(super) struct EditMovieHandler<'a, 'b> {
|
pub(super) struct EditMovieHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
EDIT_MOVIE_BLOCKS.contains(active_block)
|
EDIT_MOVIE_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> EditMovieHandler<'a, 'b> {
|
) -> EditMovieHandler<'a, 'b> {
|
||||||
EditMovieHandler {
|
EditMovieHandler {
|
||||||
key,
|
key,
|
||||||
@@ -37,7 +37,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
.scroll_up(),
|
.scroll_up(),
|
||||||
ActiveRadarrBlock::EditMoviePrompt => self.app.data.radarr_data.selected_block.previous(),
|
ActiveRadarrBlock::EditMoviePrompt => self.app.data.radarr_data.selected_block.up(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.quality_profile_list
|
.quality_profile_list
|
||||||
.scroll_down(),
|
.scroll_down(),
|
||||||
ActiveRadarrBlock::EditMoviePrompt => self.app.data.radarr_data.selected_block.next(),
|
ActiveRadarrBlock::EditMoviePrompt => self.app.data.radarr_data.selected_block.down(),
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,16 +231,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
|
|||||||
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
|
||||||
| ActiveRadarrBlock::EditMovieSelectQualityProfile => self.app.push_navigation_stack(
|
| ActiveRadarrBlock::EditMovieSelectQualityProfile => self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
*self.context,
|
self.context,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
),
|
),
|
||||||
ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => {
|
ActiveRadarrBlock::EditMoviePathInput | ActiveRadarrBlock::EditMovieTagsInput => {
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
*self.app.data.radarr_data.selected_block.get_active_block(),
|
self.app.data.radarr_data.selected_block.get_active_block(),
|
||||||
*self.context,
|
self.context,
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
@@ -329,8 +329,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for EditMovieHandler<'a,
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::EditMoviePrompt => {
|
ActiveRadarrBlock::EditMoviePrompt => {
|
||||||
if self.app.data.radarr_data.selected_block.get_active_block()
|
if self.app.data.radarr_data.selected_block.get_active_block()
|
||||||
== &ActiveRadarrBlock::EditMovieConfirmPrompt
|
== ActiveRadarrBlock::EditMovieConfirmPrompt
|
||||||
&& *key == DEFAULT_KEYBINDINGS.confirm.key
|
&& key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditMovie(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::EditMovie(None));
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ mod tests {
|
|||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
for i in (0..minimum_availability_vec.len()).rev() {
|
for i in (0..minimum_availability_vec.len()).rev() {
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -64,10 +64,10 @@ mod tests {
|
|||||||
} else {
|
} else {
|
||||||
for i in 0..minimum_availability_vec.len() {
|
for i in 0..minimum_availability_vec.len() {
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -102,10 +102,10 @@ mod tests {
|
|||||||
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
.set_items(vec!["Test 1".to_owned(), "Test 2".to_owned()]);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -122,10 +122,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -146,20 +146,20 @@ mod tests {
|
|||||||
fn test_edit_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
fn test_edit_movie_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.next();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
EditMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::EditMoviePrompt, &None).handle();
|
EditMovieHandler::with(key, &mut app, ActiveRadarrBlock::EditMoviePrompt, None).handle();
|
||||||
|
|
||||||
if key == Key::Up {
|
if key == Key::Up {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditMovieToggleMonitored
|
ActiveRadarrBlock::EditMovieToggleMonitored
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditMovieSelectQualityProfile
|
ActiveRadarrBlock::EditMovieSelectQualityProfile
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,14 +169,14 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.next();
|
app.data.radarr_data.selected_block.down();
|
||||||
|
|
||||||
EditMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::EditMoviePrompt, &None).handle();
|
EditMovieHandler::with(key, &mut app, ActiveRadarrBlock::EditMoviePrompt, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditMovieSelectMinimumAvailability
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -205,10 +205,10 @@ mod tests {
|
|||||||
.set_items(minimum_availability_vec.clone());
|
.set_items(minimum_availability_vec.clone());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -225,10 +225,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
ActiveRadarrBlock::EditMovieSelectMinimumAvailability,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -263,10 +263,10 @@ mod tests {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -283,10 +283,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
ActiveRadarrBlock::EditMovieSelectQualityProfile,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -312,10 +312,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -333,10 +333,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -363,10 +363,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -384,10 +384,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -418,11 +418,11 @@ mod tests {
|
|||||||
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
EditMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::EditMoviePrompt, &None).handle();
|
EditMovieHandler::with(key, &mut app, ActiveRadarrBlock::EditMoviePrompt, None).handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
EditMovieHandler::with(&key, &mut app, &ActiveRadarrBlock::EditMoviePrompt, &None).handle();
|
EditMovieHandler::with(key, &mut app, ActiveRadarrBlock::EditMoviePrompt, None).handle();
|
||||||
|
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -436,10 +436,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -457,10 +457,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -487,10 +487,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -508,10 +508,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -535,9 +535,7 @@ mod tests {
|
|||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
|
||||||
use crate::models::servarr_data::radarr::modals::EditMovieModal;
|
use crate::models::servarr_data::radarr::modals::EditMovieModal;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::EDIT_MOVIE_SELECTION_BLOCKS;
|
||||||
EDIT_COLLECTION_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS,
|
|
||||||
};
|
|
||||||
use crate::models::{BlockSelectionState, Route};
|
use crate::models::{BlockSelectionState, Route};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
|
|
||||||
@@ -557,10 +555,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePathInput.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePathInput.into());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -576,7 +574,7 @@ mod tests {
|
|||||||
.is_empty());
|
.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditMoviePrompt.into()
|
ActiveRadarrBlock::EditMoviePrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -592,10 +590,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePathInput.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePathInput.into());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -611,7 +609,7 @@ mod tests {
|
|||||||
.is_empty());
|
.is_empty());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditMoviePrompt.into()
|
ActiveRadarrBlock::EditMoviePrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,22 +619,22 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -647,22 +645,22 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::EditMovie(None))
|
Some(RadarrEvent::EditMovie(None))
|
||||||
@@ -681,16 +679,16 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditMoviePrompt.into()
|
ActiveRadarrBlock::EditMoviePrompt.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
@@ -704,18 +702,18 @@ mod tests {
|
|||||||
));
|
));
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app.push_navigation_stack(current_route);
|
app.push_navigation_stack(current_route);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&Some(ActiveRadarrBlock::Movies),
|
Some(ActiveRadarrBlock::Movies),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -728,14 +726,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&Some(ActiveRadarrBlock::Movies),
|
Some(ActiveRadarrBlock::Movies),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), ¤t_route);
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
@@ -755,7 +753,7 @@ mod tests {
|
|||||||
#[case(ActiveRadarrBlock::EditMovieTagsInput, 4)]
|
#[case(ActiveRadarrBlock::EditMovieTagsInput, 4)]
|
||||||
fn test_edit_movie_prompt_selected_block_submit(
|
fn test_edit_movie_prompt_selected_block_submit(
|
||||||
#[case] selected_block: ActiveRadarrBlock,
|
#[case] selected_block: ActiveRadarrBlock,
|
||||||
#[case] index: usize,
|
#[case] y_index: usize,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
@@ -766,20 +764,20 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(index);
|
app.data.radarr_data.selected_block.set_index(0, y_index);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&Some(ActiveRadarrBlock::Movies),
|
Some(ActiveRadarrBlock::Movies),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&(selected_block, Some(ActiveRadarrBlock::Movies)).into()
|
(selected_block, Some(ActiveRadarrBlock::Movies)).into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
|
|
||||||
@@ -792,7 +790,7 @@ mod tests {
|
|||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
fn test_edit_movie_prompt_selected_block_submit_no_op_when_not_ready(
|
fn test_edit_movie_prompt_selected_block_submit_no_op_when_not_ready(
|
||||||
#[values(1, 2, 3, 4)] index: usize,
|
#[values(1, 2, 3, 4)] y_index: usize,
|
||||||
) {
|
) {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
@@ -804,20 +802,20 @@ mod tests {
|
|||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app.data.radarr_data.selected_block.set_index(index);
|
app.data.radarr_data.selected_block.set_index(0, y_index);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&Some(ActiveRadarrBlock::Movies),
|
Some(ActiveRadarrBlock::Movies),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&(
|
(
|
||||||
ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
Some(ActiveRadarrBlock::Movies),
|
Some(ActiveRadarrBlock::Movies),
|
||||||
)
|
)
|
||||||
@@ -843,16 +841,16 @@ mod tests {
|
|||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&Some(ActiveRadarrBlock::Movies),
|
Some(ActiveRadarrBlock::Movies),
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditMoviePrompt.into()
|
ActiveRadarrBlock::EditMoviePrompt.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
if active_radarr_block == ActiveRadarrBlock::EditMoviePathInput
|
if active_radarr_block == ActiveRadarrBlock::EditMoviePathInput
|
||||||
@@ -888,12 +886,12 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditMovieHandler::with(&ESC_KEY, &mut app, &active_radarr_block, &None).handle();
|
EditMovieHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.should_ignore_quit_key);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::EditMoviePrompt.into()
|
ActiveRadarrBlock::EditMoviePrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,15 +902,9 @@ mod tests {
|
|||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::EditMoviePrompt, None).handle();
|
||||||
&ESC_KEY,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
|
|
||||||
assert!(app.data.radarr_data.edit_movie_modal.is_none());
|
assert!(app.data.radarr_data.edit_movie_modal.is_none());
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
@@ -932,9 +924,9 @@ mod tests {
|
|||||||
app.data.radarr_data = create_test_radarr_data();
|
app.data.radarr_data = create_test_radarr_data();
|
||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
EditMovieHandler::with(&ESC_KEY, &mut app, &active_radarr_block, &None).handle();
|
EditMovieHandler::with(ESC_KEY, &mut app, active_radarr_block, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -942,10 +934,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
models::{
|
models::{
|
||||||
servarr_data::radarr::{
|
servarr_data::radarr::{modals::EditMovieModal, radarr_data::EDIT_MOVIE_SELECTION_BLOCKS},
|
||||||
modals::EditMovieModal,
|
|
||||||
radarr_data::{EDIT_COLLECTION_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS},
|
|
||||||
},
|
|
||||||
BlockSelectionState,
|
BlockSelectionState,
|
||||||
},
|
},
|
||||||
network::radarr_network::RadarrEvent,
|
network::radarr_network::RadarrEvent,
|
||||||
@@ -960,10 +949,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.backspace.key,
|
DEFAULT_KEYBINDINGS.backspace.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -989,10 +978,10 @@ mod tests {
|
|||||||
});
|
});
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.backspace.key,
|
DEFAULT_KEYBINDINGS.backspace.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -1015,10 +1004,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&Key::Char('h'),
|
Key::Char('h'),
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePathInput,
|
ActiveRadarrBlock::EditMoviePathInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -1041,10 +1030,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&Key::Char('h'),
|
Key::Char('h'),
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMovieTagsInput,
|
ActiveRadarrBlock::EditMovieTagsInput,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -1067,22 +1056,22 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
app.push_navigation_stack(ActiveRadarrBlock::Movies.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::EditMoviePrompt.into());
|
||||||
app.data.radarr_data.selected_block = BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
app.data.radarr_data.selected_block = BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
app
|
app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.selected_block
|
.selected_block
|
||||||
.set_index(EDIT_COLLECTION_SELECTION_BLOCKS.len() - 1);
|
.set_index(0, EDIT_MOVIE_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
EditMovieHandler::with(
|
EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.prompt_confirm_action,
|
app.data.radarr_data.prompt_confirm_action,
|
||||||
Some(RadarrEvent::EditMovie(None))
|
Some(RadarrEvent::EditMovie(None))
|
||||||
@@ -1096,9 +1085,9 @@ mod tests {
|
|||||||
fn test_edit_movie_handler_accepts() {
|
fn test_edit_movie_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if EDIT_MOVIE_BLOCKS.contains(&active_radarr_block) {
|
if EDIT_MOVIE_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(EditMovieHandler::accepts(&active_radarr_block));
|
assert!(EditMovieHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!EditMovieHandler::accepts(&active_radarr_block));
|
assert!(!EditMovieHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -1109,10 +1098,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = EditMovieHandler::with(
|
let handler = EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -1124,10 +1113,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = EditMovieHandler::with(
|
let handler = EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -1140,10 +1129,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
app.data.radarr_data.edit_movie_modal = Some(EditMovieModal::default());
|
||||||
|
|
||||||
let handler = EditMovieHandler::with(
|
let handler = EditMovieHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -8,14 +8,15 @@ use crate::handlers::radarr_handlers::library::edit_movie_handler::EditMovieHand
|
|||||||
use crate::handlers::radarr_handlers::library::movie_details_handler::MovieDetailsHandler;
|
use crate::handlers::radarr_handlers::library::movie_details_handler::MovieDetailsHandler;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
|
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::models::radarr_models::Movie;
|
use crate::models::radarr_models::Movie;
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, DELETE_MOVIE_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS, LIBRARY_BLOCKS,
|
ActiveRadarrBlock, DELETE_MOVIE_SELECTION_BLOCKS, EDIT_MOVIE_SELECTION_BLOCKS, LIBRARY_BLOCKS,
|
||||||
};
|
};
|
||||||
use crate::models::stateful_table::SortOption;
|
use crate::models::stateful_table::SortOption;
|
||||||
use crate::models::{BlockSelectionState, HorizontallyScrollableText, Scrollable};
|
use crate::models::{BlockSelectionState, HorizontallyScrollableText};
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
|
||||||
|
|
||||||
mod add_movie_handler;
|
mod add_movie_handler;
|
||||||
mod delete_movie_handler;
|
mod delete_movie_handler;
|
||||||
@@ -27,46 +28,65 @@ mod movie_details_handler;
|
|||||||
mod library_handler_tests;
|
mod library_handler_tests;
|
||||||
|
|
||||||
pub(super) struct LibraryHandler<'a, 'b> {
|
pub(super) struct LibraryHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> LibraryHandler<'a, 'b> {
|
||||||
|
handle_table_events!(self, movies, self.app.data.radarr_data.movies, Movie);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, 'b> {
|
||||||
fn handle(&mut self) {
|
fn handle(&mut self) {
|
||||||
match self.active_radarr_block {
|
let movie_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Movies.into())
|
||||||
_ if AddMovieHandler::accepts(self.active_radarr_block) => {
|
.sorting_block(ActiveRadarrBlock::MoviesSortPrompt.into())
|
||||||
AddMovieHandler::with(self.key, self.app, self.active_radarr_block, self.context).handle();
|
.sort_by_fn(|a: &Movie, b: &Movie| a.id.cmp(&b.id))
|
||||||
|
.sort_options(movies_sorting_options())
|
||||||
|
.searching_block(ActiveRadarrBlock::SearchMovie.into())
|
||||||
|
.search_error_block(ActiveRadarrBlock::SearchMovieError.into())
|
||||||
|
.search_field_fn(|movie| &movie.title.text)
|
||||||
|
.filtering_block(ActiveRadarrBlock::FilterMovies.into())
|
||||||
|
.filter_error_block(ActiveRadarrBlock::FilterMoviesError.into())
|
||||||
|
.filter_field_fn(|movie| &movie.title.text);
|
||||||
|
|
||||||
|
if !self.handle_movies_table_events(movie_table_handling_config) {
|
||||||
|
match self.active_radarr_block {
|
||||||
|
_ if AddMovieHandler::accepts(self.active_radarr_block) => {
|
||||||
|
AddMovieHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle();
|
||||||
|
}
|
||||||
|
_ if DeleteMovieHandler::accepts(self.active_radarr_block) => {
|
||||||
|
DeleteMovieHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle();
|
||||||
|
}
|
||||||
|
_ if EditMovieHandler::accepts(self.active_radarr_block) => {
|
||||||
|
EditMovieHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle();
|
||||||
|
}
|
||||||
|
_ if MovieDetailsHandler::accepts(self.active_radarr_block) => {
|
||||||
|
MovieDetailsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
||||||
|
.handle();
|
||||||
|
}
|
||||||
|
_ => self.handle_key_event(),
|
||||||
}
|
}
|
||||||
_ if DeleteMovieHandler::accepts(self.active_radarr_block) => {
|
|
||||||
DeleteMovieHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
|
||||||
.handle();
|
|
||||||
}
|
|
||||||
_ if EditMovieHandler::accepts(self.active_radarr_block) => {
|
|
||||||
EditMovieHandler::with(self.key, self.app, self.active_radarr_block, self.context).handle();
|
|
||||||
}
|
|
||||||
_ if MovieDetailsHandler::accepts(self.active_radarr_block) => {
|
|
||||||
MovieDetailsHandler::with(self.key, self.app, self.active_radarr_block, self.context)
|
|
||||||
.handle();
|
|
||||||
}
|
|
||||||
_ => self.handle_key_event(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
AddMovieHandler::accepts(active_block)
|
AddMovieHandler::accepts(active_block)
|
||||||
|| DeleteMovieHandler::accepts(active_block)
|
|| DeleteMovieHandler::accepts(active_block)
|
||||||
|| EditMovieHandler::accepts(active_block)
|
|| EditMovieHandler::accepts(active_block)
|
||||||
|| MovieDetailsHandler::accepts(active_block)
|
|| MovieDetailsHandler::accepts(active_block)
|
||||||
|| LIBRARY_BLOCKS.contains(active_block)
|
|| LIBRARY_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> LibraryHandler<'a, 'b> {
|
) -> LibraryHandler<'a, 'b> {
|
||||||
LibraryHandler {
|
LibraryHandler {
|
||||||
key,
|
key,
|
||||||
@@ -76,7 +96,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,117 +104,21 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.movies.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.movies.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Movies => self.app.data.radarr_data.movies.scroll_up(),
|
|
||||||
ActiveRadarrBlock::MoviesSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_up(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Movies => self.app.data.radarr_data.movies.scroll_down(),
|
|
||||||
ActiveRadarrBlock::MoviesSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_down(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Movies => self.app.data.radarr_data.movies.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::SearchMovie => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.search
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_home();
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterMovies => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.filter
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_home();
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::MoviesSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_top(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {}
|
||||||
match self.active_radarr_block {
|
|
||||||
ActiveRadarrBlock::Movies => self.app.data.radarr_data.movies.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::SearchMovie => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.search
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.reset_offset(),
|
|
||||||
ActiveRadarrBlock::FilterMovies => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.filter
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.reset_offset(),
|
|
||||||
ActiveRadarrBlock::MoviesSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_delete(&mut self) {
|
fn handle_delete(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::Movies {
|
if self.active_radarr_block == ActiveRadarrBlock::Movies {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::DeleteMoviePrompt.into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&DELETE_MOVIE_SELECTION_BLOCKS);
|
BlockSelectionState::new(DELETE_MOVIE_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,20 +126,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Movies => handle_change_tab_left_right_keys(self.app, self.key),
|
ActiveRadarrBlock::Movies => handle_change_tab_left_right_keys(self.app, self.key),
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt => handle_prompt_toggle(self.app, self.key),
|
ActiveRadarrBlock::UpdateAllMoviesPrompt => handle_prompt_toggle(self.app, self.key),
|
||||||
ActiveRadarrBlock::SearchMovie => {
|
|
||||||
handle_text_box_left_right_keys!(
|
|
||||||
self,
|
|
||||||
self.key,
|
|
||||||
self.app.data.radarr_data.movies.search.as_mut().unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterMovies => {
|
|
||||||
handle_text_box_left_right_keys!(
|
|
||||||
self,
|
|
||||||
self.key,
|
|
||||||
self.app.data.radarr_data.movies.filter.as_mut().unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,44 +135,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
ActiveRadarrBlock::Movies => self
|
ActiveRadarrBlock::Movies => self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::MovieDetails.into()),
|
.push_navigation_stack(ActiveRadarrBlock::MovieDetails.into()),
|
||||||
ActiveRadarrBlock::SearchMovie => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
|
|
||||||
if self.app.data.radarr_data.movies.search.is_some() {
|
|
||||||
let has_match = self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.apply_search(|movie| &movie.title.text);
|
|
||||||
|
|
||||||
if !has_match {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SearchMovieError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterMovies => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
|
|
||||||
if self.app.data.radarr_data.movies.filter.is_some() {
|
|
||||||
let has_matches = self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.apply_filter(|movie| &movie.title.text);
|
|
||||||
|
|
||||||
if !has_matches {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::FilterMoviesError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
||||||
if self.app.data.radarr_data.prompt_confirm {
|
if self.app.data.radarr_data.prompt_confirm {
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
|
||||||
@@ -270,44 +142,17 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::MoviesSortPrompt => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.items
|
|
||||||
.sort_by(|a, b| a.id.cmp(&b.id));
|
|
||||||
self.app.data.radarr_data.movies.apply_sorting();
|
|
||||||
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_esc(&mut self) {
|
fn handle_esc(&mut self) {
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::FilterMovies | ActiveRadarrBlock::FilterMoviesError => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.data.radarr_data.movies.reset_filter();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::SearchMovie | ActiveRadarrBlock::SearchMovieError => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
self.app.data.radarr_data.movies.reset_search();
|
|
||||||
self.app.should_ignore_quit_key = false;
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.prompt_confirm = false;
|
self.app.data.radarr_data.prompt_confirm = false;
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::MoviesSortPrompt => {
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
}
|
|
||||||
_ => {
|
_ => {
|
||||||
self.app.data.radarr_data.movies.reset_search();
|
|
||||||
self.app.data.radarr_data.movies.reset_filter();
|
|
||||||
handle_clear_errors(self.app);
|
handle_clear_errors(self.app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,22 +162,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::Movies => match self.key {
|
ActiveRadarrBlock::Movies => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.search.key => {
|
_ if key == DEFAULT_KEYBINDINGS.edit.key => {
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SearchMovie.into());
|
|
||||||
self.app.data.radarr_data.movies.search = Some(HorizontallyScrollableText::default());
|
|
||||||
self.app.should_ignore_quit_key = true;
|
|
||||||
}
|
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.filter.key => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::FilterMovies.into());
|
|
||||||
self.app.data.radarr_data.movies.reset_filter();
|
|
||||||
self.app.data.radarr_data.movies.filter = Some(HorizontallyScrollableText::default());
|
|
||||||
self.app.should_ignore_quit_key = true;
|
|
||||||
}
|
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.edit.key => {
|
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
@@ -342,52 +172,27 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for LibraryHandler<'a, '
|
|||||||
);
|
);
|
||||||
self.app.data.radarr_data.edit_movie_modal = Some((&self.app.data.radarr_data).into());
|
self.app.data.radarr_data.edit_movie_modal = Some((&self.app.data.radarr_data).into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.add.key => {
|
_ if key == DEFAULT_KEYBINDINGS.add.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into());
|
.push_navigation_stack(ActiveRadarrBlock::AddMovieSearchInput.into());
|
||||||
self.app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default());
|
self.app.data.radarr_data.add_movie_search = Some(HorizontallyScrollableText::default());
|
||||||
self.app.should_ignore_quit_key = true;
|
self.app.should_ignore_quit_key = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::UpdateAllMoviesPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::UpdateAllMoviesPrompt.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.sort.key => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movies
|
|
||||||
.sorting(movies_sorting_options());
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::MoviesSortPrompt.into());
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::SearchMovie => {
|
|
||||||
handle_text_box_keys!(
|
|
||||||
self,
|
|
||||||
key,
|
|
||||||
self.app.data.radarr_data.movies.search.as_mut().unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::FilterMovies => {
|
|
||||||
handle_text_box_keys!(
|
|
||||||
self,
|
|
||||||
key,
|
|
||||||
self.app.data.radarr_data.movies.filter.as_mut().unwrap()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
ActiveRadarrBlock::UpdateAllMoviesPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAllMovies);
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ use serde_json::Number;
|
|||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
use crate::models::radarr_models::RadarrRelease;
|
use crate::models::radarr_models::{Credit, MovieHistoryItem, RadarrRelease};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{
|
use crate::models::servarr_data::radarr::radarr_data::{
|
||||||
ActiveRadarrBlock, EDIT_MOVIE_SELECTION_BLOCKS, MOVIE_DETAILS_BLOCKS,
|
ActiveRadarrBlock, EDIT_MOVIE_SELECTION_BLOCKS, MOVIE_DETAILS_BLOCKS,
|
||||||
};
|
};
|
||||||
@@ -18,22 +20,96 @@ use crate::network::radarr_network::RadarrEvent;
|
|||||||
mod movie_details_handler_tests;
|
mod movie_details_handler_tests;
|
||||||
|
|
||||||
pub(super) struct MovieDetailsHandler<'a, 'b> {
|
pub(super) struct MovieDetailsHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> MovieDetailsHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
movie_releases,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.movie_releases,
|
||||||
|
RadarrRelease
|
||||||
|
);
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
movie_history,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.movie_history,
|
||||||
|
MovieHistoryItem
|
||||||
|
);
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
movie_cast,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.movie_cast,
|
||||||
|
Credit
|
||||||
|
);
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
movie_crew,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.movie_details_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.movie_crew,
|
||||||
|
Credit
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
MOVIE_DETAILS_BLOCKS.contains(active_block)
|
let movie_history_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::MovieHistory.into());
|
||||||
|
let movie_releases_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::ManualSearch.into())
|
||||||
|
.sorting_block(ActiveRadarrBlock::ManualSearchSortPrompt.into())
|
||||||
|
.sort_options(releases_sorting_options());
|
||||||
|
let movie_cast_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Cast.into());
|
||||||
|
let movie_crew_table_handling_config = TableHandlingConfig::new(ActiveRadarrBlock::Crew.into());
|
||||||
|
|
||||||
|
if !self.handle_movie_history_table_events(movie_history_table_handling_config)
|
||||||
|
&& !self.handle_movie_releases_table_events(movie_releases_table_handling_config)
|
||||||
|
&& !self.handle_movie_cast_table_events(movie_cast_table_handling_config)
|
||||||
|
&& !self.handle_movie_crew_table_events(movie_crew_table_handling_config)
|
||||||
|
{
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
MOVIE_DETAILS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> MovieDetailsHandler<'a, 'b> {
|
) -> MovieDetailsHandler<'a, 'b> {
|
||||||
MovieDetailsHandler {
|
MovieDetailsHandler {
|
||||||
key,
|
key,
|
||||||
@@ -43,7 +119,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,8 +149,8 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {
|
||||||
match self.active_radarr_block {
|
if self.active_radarr_block == ActiveRadarrBlock::MovieDetails {
|
||||||
ActiveRadarrBlock::MovieDetails => self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -82,62 +158,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.movie_details
|
.movie_details
|
||||||
.scroll_up(),
|
.scroll_up()
|
||||||
ActiveRadarrBlock::MovieHistory => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_history
|
|
||||||
.scroll_up(),
|
|
||||||
ActiveRadarrBlock::Cast => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_cast
|
|
||||||
.scroll_up(),
|
|
||||||
ActiveRadarrBlock::Crew => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_crew
|
|
||||||
.scroll_up(),
|
|
||||||
ActiveRadarrBlock::ManualSearch => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.scroll_up(),
|
|
||||||
ActiveRadarrBlock::ManualSearchSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_up(),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {
|
||||||
match self.active_radarr_block {
|
if self.active_radarr_block == ActiveRadarrBlock::MovieDetails {
|
||||||
ActiveRadarrBlock::MovieDetails => self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -145,62 +172,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.movie_details
|
.movie_details
|
||||||
.scroll_down(),
|
.scroll_down()
|
||||||
ActiveRadarrBlock::MovieHistory => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_history
|
|
||||||
.scroll_down(),
|
|
||||||
ActiveRadarrBlock::Cast => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_cast
|
|
||||||
.scroll_down(),
|
|
||||||
ActiveRadarrBlock::Crew => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_crew
|
|
||||||
.scroll_down(),
|
|
||||||
ActiveRadarrBlock::ManualSearch => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.scroll_down(),
|
|
||||||
ActiveRadarrBlock::ManualSearchSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_down(),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {
|
||||||
match self.active_radarr_block {
|
if self.active_radarr_block == ActiveRadarrBlock::MovieDetails {
|
||||||
ActiveRadarrBlock::MovieDetails => self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -208,62 +186,13 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.movie_details
|
.movie_details
|
||||||
.scroll_to_top(),
|
.scroll_to_top()
|
||||||
ActiveRadarrBlock::MovieHistory => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_history
|
|
||||||
.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::Cast => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_cast
|
|
||||||
.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::Crew => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_crew
|
|
||||||
.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::ManualSearch => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.scroll_to_top(),
|
|
||||||
ActiveRadarrBlock::ManualSearchSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_top(),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {
|
||||||
match self.active_radarr_block {
|
if let ActiveRadarrBlock::MovieDetails = self.active_radarr_block {
|
||||||
ActiveRadarrBlock::MovieDetails => self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
@@ -271,56 +200,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.movie_details
|
.movie_details
|
||||||
.scroll_to_bottom(),
|
.scroll_to_bottom()
|
||||||
ActiveRadarrBlock::MovieHistory => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_history
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::Cast => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_cast
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::Crew => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_crew
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::ManualSearch => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
ActiveRadarrBlock::ManualSearchSortPrompt => self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.sort
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.scroll_to_bottom(),
|
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,16 +214,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
| ActiveRadarrBlock::Cast
|
| ActiveRadarrBlock::Cast
|
||||||
| ActiveRadarrBlock::Crew
|
| ActiveRadarrBlock::Crew
|
||||||
| ActiveRadarrBlock::ManualSearch => match self.key {
|
| ActiveRadarrBlock::ManualSearch => match self.key {
|
||||||
_ if *self.key == DEFAULT_KEYBINDINGS.left.key => {
|
_ if self.key == DEFAULT_KEYBINDINGS.left.key => {
|
||||||
self.app.data.radarr_data.movie_info_tabs.previous();
|
self.app.data.radarr_data.movie_info_tabs.previous();
|
||||||
self.app.pop_and_push_navigation_stack(
|
self.app.pop_and_push_navigation_stack(
|
||||||
*self.app.data.radarr_data.movie_info_tabs.get_active_route(),
|
self.app.data.radarr_data.movie_info_tabs.get_active_route(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ if *self.key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if self.key == DEFAULT_KEYBINDINGS.right.key => {
|
||||||
self.app.data.radarr_data.movie_info_tabs.next();
|
self.app.data.radarr_data.movie_info_tabs.next();
|
||||||
self.app.pop_and_push_navigation_stack(
|
self.app.pop_and_push_navigation_stack(
|
||||||
*self.app.data.radarr_data.movie_info_tabs.get_active_route(),
|
self.app.data.radarr_data.movie_info_tabs.get_active_route(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -385,18 +265,6 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::ManualSearchSortPrompt => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.apply_sorting();
|
|
||||||
self.app.pop_navigation_stack();
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -414,8 +282,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
}
|
}
|
||||||
ActiveRadarrBlock::AutomaticallySearchMoviePrompt
|
ActiveRadarrBlock::AutomaticallySearchMoviePrompt
|
||||||
| ActiveRadarrBlock::UpdateAndScanPrompt
|
| ActiveRadarrBlock::UpdateAndScanPrompt
|
||||||
| ActiveRadarrBlock::ManualSearchConfirmPrompt
|
| ActiveRadarrBlock::ManualSearchConfirmPrompt => {
|
||||||
| ActiveRadarrBlock::ManualSearchSortPrompt => {
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
self.app.data.radarr_data.prompt_confirm = false;
|
self.app.data.radarr_data.prompt_confirm = false;
|
||||||
}
|
}
|
||||||
@@ -425,81 +292,62 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for MovieDetailsHandler<
|
|||||||
|
|
||||||
fn handle_char_key_event(&mut self) {
|
fn handle_char_key_event(&mut self) {
|
||||||
let key = self.key;
|
let key = self.key;
|
||||||
match *self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::MovieDetails
|
ActiveRadarrBlock::MovieDetails
|
||||||
| ActiveRadarrBlock::MovieHistory
|
| ActiveRadarrBlock::MovieHistory
|
||||||
| ActiveRadarrBlock::FileInfo
|
| ActiveRadarrBlock::FileInfo
|
||||||
| ActiveRadarrBlock::Cast
|
| ActiveRadarrBlock::Cast
|
||||||
| ActiveRadarrBlock::Crew
|
| ActiveRadarrBlock::Crew
|
||||||
| ActiveRadarrBlock::ManualSearch => match self.key {
|
| ActiveRadarrBlock::ManualSearch => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.search.key => {
|
_ if key == DEFAULT_KEYBINDINGS.auto_search.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::AutomaticallySearchMoviePrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::AutomaticallySearchMoviePrompt.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.edit.key => {
|
_ if key == DEFAULT_KEYBINDINGS.edit.key => {
|
||||||
self.app.push_navigation_stack(
|
self.app.push_navigation_stack(
|
||||||
(
|
(
|
||||||
ActiveRadarrBlock::EditMoviePrompt,
|
ActiveRadarrBlock::EditMoviePrompt,
|
||||||
Some(*self.active_radarr_block),
|
Some(self.active_radarr_block),
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
self.app.data.radarr_data.edit_movie_modal = Some((&self.app.data.radarr_data).into());
|
self.app.data.radarr_data.edit_movie_modal = Some((&self.app.data.radarr_data).into());
|
||||||
self.app.data.radarr_data.selected_block =
|
self.app.data.radarr_data.selected_block =
|
||||||
BlockSelectionState::new(&EDIT_MOVIE_SELECTION_BLOCKS);
|
BlockSelectionState::new(EDIT_MOVIE_SELECTION_BLOCKS);
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::UpdateAndScanPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::UpdateAndScanPrompt.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.pop_and_push_navigation_stack((*self.active_radarr_block).into());
|
.pop_and_push_navigation_stack(self.active_radarr_block.into());
|
||||||
}
|
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.sort.key => {
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.movie_details_modal
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.movie_releases
|
|
||||||
.sorting(releases_sorting_options());
|
|
||||||
self
|
|
||||||
.app
|
|
||||||
.push_navigation_stack(ActiveRadarrBlock::ManualSearchSortPrompt.into());
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
},
|
},
|
||||||
ActiveRadarrBlock::AutomaticallySearchMoviePrompt => {
|
ActiveRadarrBlock::AutomaticallySearchMoviePrompt
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key =>
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
Some(RadarrEvent::TriggerAutomaticSearch(None));
|
self.app.data.radarr_data.prompt_confirm_action =
|
||||||
|
Some(RadarrEvent::TriggerAutomaticSearch(None));
|
||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::UpdateAndScanPrompt => {
|
ActiveRadarrBlock::UpdateAndScanPrompt if key == DEFAULT_KEYBINDINGS.confirm.key => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAndScan(None));
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::UpdateAndScan(None));
|
|
||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::ManualSearchConfirmPrompt => {
|
ActiveRadarrBlock::ManualSearchConfirmPrompt if key == DEFAULT_KEYBINDINGS.confirm.key => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::DownloadRelease(None));
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
|
||||||
Some(RadarrEvent::DownloadRelease(None));
|
|
||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ mod radarr_handler_tests;
|
|||||||
mod radarr_handler_test_utils;
|
mod radarr_handler_test_utils;
|
||||||
|
|
||||||
pub(super) struct RadarrHandler<'a, 'b> {
|
pub(super) struct RadarrHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b> {
|
||||||
@@ -63,15 +63,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(_active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(_active_block: ActiveRadarrBlock) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> RadarrHandler<'a, 'b> {
|
) -> RadarrHandler<'a, 'b> {
|
||||||
RadarrHandler {
|
RadarrHandler {
|
||||||
key,
|
key,
|
||||||
@@ -81,7 +81,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,16 +108,16 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RadarrHandler<'a, 'b
|
|||||||
fn handle_char_key_event(&mut self) {}
|
fn handle_char_key_event(&mut self) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_change_tab_left_right_keys(app: &mut App<'_>, key: &Key) {
|
pub fn handle_change_tab_left_right_keys(app: &mut App<'_>, key: Key) {
|
||||||
let key_ref = key;
|
let key_ref = key;
|
||||||
match key_ref {
|
match key_ref {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.left.key => {
|
_ if key == DEFAULT_KEYBINDINGS.left.key => {
|
||||||
app.data.radarr_data.main_tabs.previous();
|
app.data.radarr_data.main_tabs.previous();
|
||||||
app.pop_and_push_navigation_stack(*app.data.radarr_data.main_tabs.get_active_route());
|
app.pop_and_push_navigation_stack(app.data.radarr_data.main_tabs.get_active_route());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if key == DEFAULT_KEYBINDINGS.right.key => {
|
||||||
app.data.radarr_data.main_tabs.next();
|
app.data.radarr_data.main_tabs.next();
|
||||||
app.pop_and_push_navigation_stack(*app.data.radarr_data.main_tabs.get_active_route());
|
app.pop_and_push_navigation_stack(app.data.radarr_data.main_tabs.get_active_route());
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,15 @@ mod utils {
|
|||||||
}]);
|
}]);
|
||||||
app.data.radarr_data = radarr_data;
|
app.data.radarr_data = radarr_data;
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.edit.key, &mut app, &$block, &None).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.edit.key, &mut app, $block, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&(ActiveRadarrBlock::EditMoviePrompt, Some($context)).into()
|
(ActiveRadarrBlock::EditMoviePrompt, Some($context)).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditMovieToggleMonitored
|
ActiveRadarrBlock::EditMovieToggleMonitored
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
@@ -111,7 +111,7 @@ mod utils {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.blocks,
|
app.data.radarr_data.selected_block.blocks,
|
||||||
&EDIT_MOVIE_SELECTION_BLOCKS
|
EDIT_MOVIE_SELECTION_BLOCKS
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -137,15 +137,15 @@ mod utils {
|
|||||||
}]);
|
}]);
|
||||||
app.data.radarr_data = radarr_data;
|
app.data.radarr_data = radarr_data;
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.edit.key, &mut app, &$block, &None).handle();
|
$handler::with(DEFAULT_KEYBINDINGS.edit.key, &mut app, $block, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&(ActiveRadarrBlock::EditCollectionPrompt, Some($context)).into()
|
(ActiveRadarrBlock::EditCollectionPrompt, $context).into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.get_active_block(),
|
app.data.radarr_data.selected_block.get_active_block(),
|
||||||
&ActiveRadarrBlock::EditCollectionToggleMonitored
|
ActiveRadarrBlock::EditCollectionToggleMonitored
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app
|
app
|
||||||
@@ -224,52 +224,8 @@ mod utils {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.selected_block.blocks,
|
app.data.radarr_data.selected_block.blocks,
|
||||||
&EDIT_COLLECTION_SELECTION_BLOCKS
|
EDIT_COLLECTION_SELECTION_BLOCKS
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! assert_delete_prompt {
|
|
||||||
($block:expr, $expected_block:expr) => {
|
|
||||||
let mut app = App::default();
|
|
||||||
|
|
||||||
RadarrHandler::with(&DELETE_KEY, &mut app, &$block, &None).handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &$expected_block.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
($handler:ident, $block:expr, $expected_block:expr) => {
|
|
||||||
let mut app = App::default();
|
|
||||||
|
|
||||||
$handler::with(&DELETE_KEY, &mut app, &$block, &None).handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &$expected_block.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
($app:expr, $block:expr, $expected_block:expr) => {
|
|
||||||
RadarrHandler::with(&DELETE_KEY, &mut $app, &$block, &None).handle();
|
|
||||||
|
|
||||||
assert_eq!($app.get_current_route(), &$expected_block.into());
|
|
||||||
};
|
|
||||||
|
|
||||||
($handler:ident, $app:expr, $block:expr, $expected_block:expr) => {
|
|
||||||
$handler::with(&DELETE_KEY, &mut $app, &$block, &None).handle();
|
|
||||||
|
|
||||||
assert_eq!($app.get_current_route(), &$expected_block.into());
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! assert_refresh_key {
|
|
||||||
($handler:ident, $block:expr) => {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.push_navigation_stack($block.into());
|
|
||||||
|
|
||||||
$handler::with(&DEFAULT_KEYBINDINGS.refresh.key, &mut app, &$block, &None).handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &$block.into());
|
|
||||||
assert!(app.should_refresh);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,23 +27,23 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.main_tabs.set_index(index);
|
app.data.radarr_data.main_tabs.set_index(index);
|
||||||
|
|
||||||
handle_change_tab_left_right_keys(&mut app, &DEFAULT_KEYBINDINGS.left.key);
|
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.key);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&left_block.into()
|
left_block.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &left_block.into());
|
assert_eq!(app.get_current_route(), left_block.into());
|
||||||
|
|
||||||
app.data.radarr_data.main_tabs.set_index(index);
|
app.data.radarr_data.main_tabs.set_index(index);
|
||||||
|
|
||||||
handle_change_tab_left_right_keys(&mut app, &DEFAULT_KEYBINDINGS.right.key);
|
handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.key);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&right_block.into()
|
right_block.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &right_block.into());
|
assert_eq!(app.get_current_route(), right_block.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -213,7 +213,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_radarr_handler_accepts() {
|
fn test_radarr_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
assert!(RadarrHandler::accepts(&active_radarr_block));
|
assert!(RadarrHandler::accepts(active_radarr_block));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,10 +223,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = RadarrHandler::with(
|
let handler = RadarrHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -2,33 +2,53 @@ use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
|||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
use crate::event::Key;
|
use crate::event::Key;
|
||||||
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
use crate::handlers::radarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ROOT_FOLDERS_BLOCKS};
|
use crate::models::servarr_data::radarr::radarr_data::{ActiveRadarrBlock, ROOT_FOLDERS_BLOCKS};
|
||||||
use crate::models::{HorizontallyScrollableText, Scrollable};
|
use crate::models::servarr_models::RootFolder;
|
||||||
|
use crate::models::HorizontallyScrollableText;
|
||||||
use crate::network::radarr_network::RadarrEvent;
|
use crate::network::radarr_network::RadarrEvent;
|
||||||
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys};
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[path = "root_folders_handler_tests.rs"]
|
#[path = "root_folders_handler_tests.rs"]
|
||||||
mod root_folders_handler_tests;
|
mod root_folders_handler_tests;
|
||||||
|
|
||||||
pub(super) struct RootFoldersHandler<'a, 'b> {
|
pub(super) struct RootFoldersHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> RootFoldersHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
root_folders,
|
||||||
|
self.app.data.radarr_data.root_folders,
|
||||||
|
RootFolder
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn handle(&mut self) {
|
||||||
ROOT_FOLDERS_BLOCKS.contains(active_block)
|
let root_folder_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveRadarrBlock::RootFolders.into());
|
||||||
|
|
||||||
|
if !self.handle_root_folders_table_events(root_folder_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
|
ROOT_FOLDERS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
) -> RootFoldersHandler<'a, 'b> {
|
) -> RootFoldersHandler<'a, 'b> {
|
||||||
RootFoldersHandler {
|
RootFoldersHandler {
|
||||||
key,
|
key,
|
||||||
@@ -38,7 +58,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,50 +66,38 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
|
|||||||
!self.app.is_loading && !self.app.data.radarr_data.root_folders.is_empty()
|
!self.app.is_loading && !self.app.data.radarr_data.root_folders.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_scroll_up(&mut self) {
|
fn handle_scroll_up(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::RootFolders {
|
|
||||||
self.app.data.radarr_data.root_folders.scroll_up()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_scroll_down(&mut self) {
|
fn handle_scroll_down(&mut self) {}
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::RootFolders {
|
|
||||||
self.app.data.radarr_data.root_folders.scroll_down()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn handle_home(&mut self) {
|
fn handle_home(&mut self) {
|
||||||
match self.active_radarr_block {
|
if self.active_radarr_block == ActiveRadarrBlock::AddRootFolderPrompt {
|
||||||
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_to_top(),
|
self
|
||||||
ActiveRadarrBlock::AddRootFolderPrompt => self
|
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.edit_root_folder
|
.edit_root_folder
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.scroll_home(),
|
.scroll_home()
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_end(&mut self) {
|
fn handle_end(&mut self) {
|
||||||
match self.active_radarr_block {
|
if self.active_radarr_block == ActiveRadarrBlock::AddRootFolderPrompt {
|
||||||
ActiveRadarrBlock::RootFolders => self.app.data.radarr_data.root_folders.scroll_to_bottom(),
|
self
|
||||||
ActiveRadarrBlock::AddRootFolderPrompt => self
|
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
.radarr_data
|
.radarr_data
|
||||||
.edit_root_folder
|
.edit_root_folder
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.reset_offset(),
|
.reset_offset()
|
||||||
_ => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_delete(&mut self) {
|
fn handle_delete(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::RootFolders {
|
if self.active_radarr_block == ActiveRadarrBlock::RootFolders {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into())
|
.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into())
|
||||||
@@ -121,7 +129,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
|
|||||||
|
|
||||||
self.app.pop_navigation_stack();
|
self.app.pop_navigation_stack();
|
||||||
}
|
}
|
||||||
_ if *self.active_radarr_block == ActiveRadarrBlock::AddRootFolderPrompt
|
_ if self.active_radarr_block == ActiveRadarrBlock::AddRootFolderPrompt
|
||||||
&& !self
|
&& !self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -161,10 +169,10 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
|
|||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::RootFolders => match self.key {
|
ActiveRadarrBlock::RootFolders => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.add.key => {
|
_ if key == DEFAULT_KEYBINDINGS.add.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
|
.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
|
||||||
@@ -181,7 +189,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for RootFoldersHandler<'
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
ActiveRadarrBlock::DeleteRootFolderPrompt => {
|
ActiveRadarrBlock::DeleteRootFolderPrompt => {
|
||||||
if *key == DEFAULT_KEYBINDINGS.confirm.key {
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action =
|
self.app.data.radarr_data.prompt_confirm_action =
|
||||||
Some(RadarrEvent::DeleteRootFolder(None));
|
Some(RadarrEvent::DeleteRootFolder(None));
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_str_eq;
|
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
@@ -12,108 +11,12 @@ mod tests {
|
|||||||
use crate::models::servarr_models::RootFolder;
|
use crate::models::servarr_models::RootFolder;
|
||||||
use crate::models::HorizontallyScrollableText;
|
use crate::models::HorizontallyScrollableText;
|
||||||
|
|
||||||
mod test_handle_scroll_up_and_down {
|
|
||||||
use rstest::rstest;
|
|
||||||
|
|
||||||
use crate::models::servarr_models::RootFolder;
|
|
||||||
use crate::{simple_stateful_iterable_vec, test_iterable_scroll};
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
test_iterable_scroll!(
|
|
||||||
test_root_folders_scroll,
|
|
||||||
RootFoldersHandler,
|
|
||||||
root_folders,
|
|
||||||
simple_stateful_iterable_vec!(RootFolder, String, path),
|
|
||||||
ActiveRadarrBlock::RootFolders,
|
|
||||||
None,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
|
|
||||||
#[rstest]
|
|
||||||
fn test_root_folders_scroll_no_op_when_not_ready(
|
|
||||||
#[values(DEFAULT_KEYBINDINGS.up.key, DEFAULT_KEYBINDINGS.down.key)] key: Key,
|
|
||||||
) {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.root_folders
|
|
||||||
.set_items(simple_stateful_iterable_vec!(RootFolder, String, path));
|
|
||||||
|
|
||||||
RootFoldersHandler::with(&key, &mut app, &ActiveRadarrBlock::RootFolders, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.root_folders.current_selection().path,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
RootFoldersHandler::with(&key, &mut app, &ActiveRadarrBlock::RootFolders, &None).handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.root_folders.current_selection().path,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mod test_handle_home_end {
|
mod test_handle_home_end {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
use std::sync::atomic::Ordering;
|
use std::sync::atomic::Ordering;
|
||||||
|
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
|
|
||||||
use crate::models::servarr_models::RootFolder;
|
|
||||||
use crate::{extended_stateful_iterable_vec, test_iterable_home_and_end};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::models::servarr_models::RootFolder;
|
||||||
test_iterable_home_and_end!(
|
|
||||||
test_root_folders_home_end,
|
|
||||||
RootFoldersHandler,
|
|
||||||
root_folders,
|
|
||||||
extended_stateful_iterable_vec!(RootFolder, String, path),
|
|
||||||
ActiveRadarrBlock::RootFolders,
|
|
||||||
None,
|
|
||||||
path
|
|
||||||
);
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_root_folders_home_end_no_op_when_not_ready() {
|
|
||||||
let mut app = App::default();
|
|
||||||
app.is_loading = true;
|
|
||||||
app
|
|
||||||
.data
|
|
||||||
.radarr_data
|
|
||||||
.root_folders
|
|
||||||
.set_items(extended_stateful_iterable_vec!(RootFolder, String, path));
|
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::RootFolders,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.root_folders.current_selection().path,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::RootFolders,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
|
||||||
app.data.radarr_data.root_folders.current_selection().path,
|
|
||||||
"Test 1"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_add_root_folder_prompt_home_end_keys() {
|
fn test_add_root_folder_prompt_home_end_keys() {
|
||||||
@@ -126,10 +29,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_root_folder = Some("Test".into());
|
app.data.radarr_data.edit_root_folder = Some("Test".into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -146,10 +49,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -183,17 +86,11 @@ mod tests {
|
|||||||
.root_folders
|
.root_folders
|
||||||
.set_items(vec![RootFolder::default()]);
|
.set_items(vec![RootFolder::default()]);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::RootFolders, None).handle();
|
||||||
&DELETE_KEY,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::RootFolders,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt.into()
|
ActiveRadarrBlock::DeleteRootFolderPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,17 +105,11 @@ mod tests {
|
|||||||
.root_folders
|
.root_folders
|
||||||
.set_items(vec![RootFolder::default()]);
|
.set_items(vec![RootFolder::default()]);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(DELETE_KEY, &mut app, ActiveRadarrBlock::RootFolders, None).handle();
|
||||||
&DELETE_KEY,
|
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::RootFolders,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,21 +129,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(4);
|
app.data.radarr_data.main_tabs.set_index(4);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
ActiveRadarrBlock::Blocklist.into()
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
app.get_current_route(),
|
|
||||||
&ActiveRadarrBlock::Blocklist.into()
|
|
||||||
);
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Blocklist.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -262,18 +150,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(4);
|
app.data.radarr_data.main_tabs.set_index(4);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Indexers.into()
|
ActiveRadarrBlock::Indexers.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -283,20 +171,20 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -309,10 +197,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_root_folder = Some("Test".into());
|
app.data.radarr_data.edit_root_folder = Some("Test".into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -329,10 +217,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -374,10 +262,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -389,7 +277,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,10 +291,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::AddRootFolderPrompt.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -415,7 +303,7 @@ mod tests {
|
|||||||
assert!(app.data.radarr_data.prompt_confirm_action.is_none());
|
assert!(app.data.radarr_data.prompt_confirm_action.is_none());
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt.into()
|
ActiveRadarrBlock::AddRootFolderPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -432,10 +320,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -446,7 +334,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,10 +350,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -473,7 +361,7 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,16 +381,16 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -516,16 +404,16 @@ mod tests {
|
|||||||
app.should_ignore_quit_key = true;
|
app.should_ignore_quit_key = true;
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(app.data.radarr_data.edit_root_folder.is_none());
|
assert!(app.data.radarr_data.edit_root_folder.is_none());
|
||||||
@@ -541,11 +429,11 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::RootFolders, &None).handle();
|
RootFoldersHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::RootFolders, None).handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert!(app.error.text.is_empty());
|
assert!(app.error.text.is_empty());
|
||||||
}
|
}
|
||||||
@@ -568,16 +456,16 @@ mod tests {
|
|||||||
.set_items(vec![RootFolder::default()]);
|
.set_items(vec![RootFolder::default()]);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.add.key,
|
DEFAULT_KEYBINDINGS.add.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt.into()
|
ActiveRadarrBlock::AddRootFolderPrompt.into()
|
||||||
);
|
);
|
||||||
assert!(app.should_ignore_quit_key);
|
assert!(app.should_ignore_quit_key);
|
||||||
assert!(app.data.radarr_data.edit_root_folder.is_some());
|
assert!(app.data.radarr_data.edit_root_folder.is_some());
|
||||||
@@ -595,16 +483,16 @@ mod tests {
|
|||||||
.set_items(vec![RootFolder::default()]);
|
.set_items(vec![RootFolder::default()]);
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.add.key,
|
DEFAULT_KEYBINDINGS.add.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert!(!app.should_ignore_quit_key);
|
assert!(!app.should_ignore_quit_key);
|
||||||
assert!(app.data.radarr_data.edit_root_folder.is_none());
|
assert!(app.data.radarr_data.edit_root_folder.is_none());
|
||||||
@@ -621,16 +509,16 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
@@ -647,16 +535,16 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
app.push_navigation_stack(ActiveRadarrBlock::RootFolders.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
@@ -672,10 +560,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_root_folder = Some("/nfs/test".into());
|
app.data.radarr_data.edit_root_folder = Some("/nfs/test".into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.backspace.key,
|
DEFAULT_KEYBINDINGS.backspace.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -696,10 +584,10 @@ mod tests {
|
|||||||
app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
|
app.data.radarr_data.edit_root_folder = Some(HorizontallyScrollableText::default());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&Key::Char('h'),
|
Key::Char('h'),
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::AddRootFolderPrompt,
|
ActiveRadarrBlock::AddRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -721,10 +609,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::DeleteRootFolderPrompt.into());
|
||||||
|
|
||||||
RootFoldersHandler::with(
|
RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::DeleteRootFolderPrompt,
|
ActiveRadarrBlock::DeleteRootFolderPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -735,7 +623,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::RootFolders.into()
|
ActiveRadarrBlock::RootFolders.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -744,9 +632,9 @@ mod tests {
|
|||||||
fn test_root_folders_handler_accepts() {
|
fn test_root_folders_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if ROOT_FOLDERS_BLOCKS.contains(&active_radarr_block) {
|
if ROOT_FOLDERS_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(RootFoldersHandler::accepts(&active_radarr_block));
|
assert!(RootFoldersHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!RootFoldersHandler::accepts(&active_radarr_block));
|
assert!(!RootFoldersHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -757,10 +645,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = RootFoldersHandler::with(
|
let handler = RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -772,10 +660,10 @@ mod tests {
|
|||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = RootFoldersHandler::with(
|
let handler = RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -792,10 +680,10 @@ mod tests {
|
|||||||
.root_folders
|
.root_folders
|
||||||
.set_items(vec![RootFolder::default()]);
|
.set_items(vec![RootFolder::default()]);
|
||||||
let handler = RootFoldersHandler::with(
|
let handler = RootFoldersHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::RootFolders,
|
ActiveRadarrBlock::RootFolders,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -14,10 +14,10 @@ mod system_details_handler;
|
|||||||
mod system_handler_tests;
|
mod system_handler_tests;
|
||||||
|
|
||||||
pub(super) struct SystemHandler<'a, 'b> {
|
pub(super) struct SystemHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b> {
|
||||||
@@ -31,15 +31,15 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
SystemDetailsHandler::accepts(active_block) || active_block == &ActiveRadarrBlock::System
|
SystemDetailsHandler::accepts(active_block) || active_block == ActiveRadarrBlock::System
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> SystemHandler<'a, 'b> {
|
) -> SystemHandler<'a, 'b> {
|
||||||
SystemHandler {
|
SystemHandler {
|
||||||
key,
|
key,
|
||||||
@@ -49,7 +49,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
|
|||||||
fn handle_delete(&mut self) {}
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
fn handle_left_right_action(&mut self) {
|
fn handle_left_right_action(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::System {
|
if self.active_radarr_block == ActiveRadarrBlock::System {
|
||||||
handle_change_tab_left_right_keys(self.app, self.key);
|
handle_change_tab_left_right_keys(self.app, self.key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,18 +83,18 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_char_key_event(&mut self) {
|
fn handle_char_key_event(&mut self) {
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::System {
|
if self.active_radarr_block == ActiveRadarrBlock::System {
|
||||||
let key = self.key;
|
let key = self.key;
|
||||||
match self.key {
|
match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.refresh.key => {
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.events.key => {
|
_ if key == DEFAULT_KEYBINDINGS.events.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SystemQueuedEvents.into());
|
.push_navigation_stack(ActiveRadarrBlock::SystemQueuedEvents.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.logs.key => {
|
_ if key == DEFAULT_KEYBINDINGS.logs.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SystemLogs.into());
|
.push_navigation_stack(ActiveRadarrBlock::SystemLogs.into());
|
||||||
@@ -106,12 +106,12 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemHandler<'a, 'b
|
|||||||
.set_items(self.app.data.radarr_data.logs.items.to_vec());
|
.set_items(self.app.data.radarr_data.logs.items.to_vec());
|
||||||
self.app.data.radarr_data.log_details.scroll_to_bottom();
|
self.app.data.radarr_data.log_details.scroll_to_bottom();
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.tasks.key => {
|
_ if key == DEFAULT_KEYBINDINGS.tasks.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
|
.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.update.key => {
|
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.push_navigation_stack(ActiveRadarrBlock::SystemUpdates.into());
|
.push_navigation_stack(ActiveRadarrBlock::SystemUpdates.into());
|
||||||
|
|||||||
@@ -12,22 +12,22 @@ use crate::network::radarr_network::RadarrEvent;
|
|||||||
mod system_details_handler_tests;
|
mod system_details_handler_tests;
|
||||||
|
|
||||||
pub(super) struct SystemDetailsHandler<'a, 'b> {
|
pub(super) struct SystemDetailsHandler<'a, 'b> {
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_radarr_block: &'a ActiveRadarrBlock,
|
active_radarr_block: ActiveRadarrBlock,
|
||||||
_context: &'a Option<ActiveRadarrBlock>,
|
_context: Option<ActiveRadarrBlock>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler<'a, 'b> {
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler<'a, 'b> {
|
||||||
fn accepts(active_block: &'a ActiveRadarrBlock) -> bool {
|
fn accepts(active_block: ActiveRadarrBlock) -> bool {
|
||||||
SYSTEM_DETAILS_BLOCKS.contains(active_block)
|
SYSTEM_DETAILS_BLOCKS.contains(&active_block)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with(
|
fn with(
|
||||||
key: &'a Key,
|
key: Key,
|
||||||
app: &'a mut App<'b>,
|
app: &'a mut App<'b>,
|
||||||
active_block: &'a ActiveRadarrBlock,
|
active_block: ActiveRadarrBlock,
|
||||||
context: &'a Option<ActiveRadarrBlock>,
|
context: Option<ActiveRadarrBlock>,
|
||||||
) -> SystemDetailsHandler<'a, 'b> {
|
) -> SystemDetailsHandler<'a, 'b> {
|
||||||
SystemDetailsHandler {
|
SystemDetailsHandler {
|
||||||
key,
|
key,
|
||||||
@@ -37,13 +37,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_key(&self) -> &Key {
|
fn get_key(&self) -> Key {
|
||||||
self.key
|
self.key
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_ready(&self) -> bool {
|
fn is_ready(&self) -> bool {
|
||||||
!self.app.is_loading
|
!self.app.is_loading
|
||||||
&& (!self.app.data.radarr_data.log_details.is_empty()
|
&& (!self.app.data.radarr_data.log_details.is_empty()
|
||||||
|
|| !self.app.data.radarr_data.tasks.is_empty()
|
||||||
|| !self.app.data.radarr_data.updates.is_empty())
|
|| !self.app.data.radarr_data.updates.is_empty())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
|
|||||||
|
|
||||||
match self.active_radarr_block {
|
match self.active_radarr_block {
|
||||||
ActiveRadarrBlock::SystemLogs => match self.key {
|
ActiveRadarrBlock::SystemLogs => match self.key {
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.left.key => {
|
_ if key == DEFAULT_KEYBINDINGS.left.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -110,7 +111,7 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
|
|||||||
.iter()
|
.iter()
|
||||||
.for_each(|log| log.scroll_right());
|
.for_each(|log| log.scroll_right());
|
||||||
}
|
}
|
||||||
_ if *key == DEFAULT_KEYBINDINGS.right.key => {
|
_ if key == DEFAULT_KEYBINDINGS.right.key => {
|
||||||
self
|
self
|
||||||
.app
|
.app
|
||||||
.data
|
.data
|
||||||
@@ -163,14 +164,14 @@ impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveRadarrBlock> for SystemDetailsHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_char_key_event(&mut self) {
|
fn handle_char_key_event(&mut self) {
|
||||||
if SYSTEM_DETAILS_BLOCKS.contains(self.active_radarr_block)
|
if SYSTEM_DETAILS_BLOCKS.contains(&self.active_radarr_block)
|
||||||
&& self.key == &DEFAULT_KEYBINDINGS.refresh.key
|
&& self.key == DEFAULT_KEYBINDINGS.refresh.key
|
||||||
{
|
{
|
||||||
self.app.should_refresh = true;
|
self.app.should_refresh = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.active_radarr_block == &ActiveRadarrBlock::SystemTaskStartConfirmPrompt
|
if self.active_radarr_block == ActiveRadarrBlock::SystemTaskStartConfirmPrompt
|
||||||
&& *self.key == DEFAULT_KEYBINDINGS.confirm.key
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
{
|
{
|
||||||
self.app.data.radarr_data.prompt_confirm = true;
|
self.app.data.radarr_data.prompt_confirm = true;
|
||||||
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::StartTask(None));
|
self.app.data.radarr_data.prompt_confirm_action = Some(RadarrEvent::StartTask(None));
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ mod tests {
|
|||||||
test_iterable_scroll!(
|
test_iterable_scroll!(
|
||||||
test_log_details_scroll,
|
test_log_details_scroll,
|
||||||
SystemDetailsHandler,
|
SystemDetailsHandler,
|
||||||
|
radarr_data,
|
||||||
log_details,
|
log_details,
|
||||||
simple_stateful_iterable_vec!(HorizontallyScrollableText, String, text),
|
simple_stateful_iterable_vec!(HorizontallyScrollableText, String, text),
|
||||||
ActiveRadarrBlock::SystemLogs,
|
ActiveRadarrBlock::SystemLogs,
|
||||||
@@ -49,14 +50,14 @@ mod tests {
|
|||||||
text
|
text
|
||||||
));
|
));
|
||||||
|
|
||||||
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemLogs, &None).handle();
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemLogs, None).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.log_details.current_selection().text,
|
app.data.radarr_data.log_details.current_selection().text,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemLogs, &None).handle();
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemLogs, None).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.log_details.current_selection().text,
|
app.data.radarr_data.log_details.current_selection().text,
|
||||||
@@ -76,14 +77,14 @@ mod tests {
|
|||||||
.tasks
|
.tasks
|
||||||
.set_items(simple_stateful_iterable_vec!(RadarrTask, String, name));
|
.set_items(simple_stateful_iterable_vec!(RadarrTask, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle();
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemTasks, None).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.tasks.current_selection().name,
|
app.data.radarr_data.tasks.current_selection().name,
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle();
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemTasks, None).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.tasks.current_selection().name,
|
app.data.radarr_data.tasks.current_selection().name,
|
||||||
@@ -104,14 +105,14 @@ mod tests {
|
|||||||
.tasks
|
.tasks
|
||||||
.set_items(simple_stateful_iterable_vec!(RadarrTask, String, name));
|
.set_items(simple_stateful_iterable_vec!(RadarrTask, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle();
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemTasks, None).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.tasks.current_selection().name,
|
app.data.radarr_data.tasks.current_selection().name,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(&key, &mut app, &ActiveRadarrBlock::SystemTasks, &None).handle();
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemTasks, None).handle();
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.tasks.current_selection().name,
|
app.data.radarr_data.tasks.current_selection().name,
|
||||||
@@ -131,26 +132,16 @@ mod tests {
|
|||||||
.queued_events
|
.queued_events
|
||||||
.set_items(simple_stateful_iterable_vec!(QueueEvent, String, name));
|
.set_items(simple_stateful_iterable_vec!(QueueEvent, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemQueuedEvents, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.queued_events.current_selection().name,
|
app.data.radarr_data.queued_events.current_selection().name,
|
||||||
"Test 2"
|
"Test 2"
|
||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemQueuedEvents, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.queued_events.current_selection().name,
|
app.data.radarr_data.queued_events.current_selection().name,
|
||||||
@@ -171,26 +162,16 @@ mod tests {
|
|||||||
.queued_events
|
.queued_events
|
||||||
.set_items(simple_stateful_iterable_vec!(QueueEvent, String, name));
|
.set_items(simple_stateful_iterable_vec!(QueueEvent, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemQueuedEvents, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.queued_events.current_selection().name,
|
app.data.radarr_data.queued_events.current_selection().name,
|
||||||
"Test 1"
|
"Test 1"
|
||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(key, &mut app, ActiveRadarrBlock::SystemQueuedEvents, None)
|
||||||
&key,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_str_eq!(
|
assert_str_eq!(
|
||||||
app.data.radarr_data.queued_events.current_selection().name,
|
app.data.radarr_data.queued_events.current_selection().name,
|
||||||
@@ -204,20 +185,20 @@ mod tests {
|
|||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.up.key,
|
DEFAULT_KEYBINDINGS.up.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.data.radarr_data.updates.offset, 0);
|
assert_eq!(app.data.radarr_data.updates.offset, 0);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.down.key,
|
DEFAULT_KEYBINDINGS.down.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -231,20 +212,20 @@ mod tests {
|
|||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.up.key,
|
DEFAULT_KEYBINDINGS.up.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.data.radarr_data.updates.offset, 0);
|
assert_eq!(app.data.radarr_data.updates.offset, 0);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.down.key,
|
DEFAULT_KEYBINDINGS.down.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -261,6 +242,7 @@ mod tests {
|
|||||||
test_iterable_home_and_end!(
|
test_iterable_home_and_end!(
|
||||||
test_log_details_home_end,
|
test_log_details_home_end,
|
||||||
SystemDetailsHandler,
|
SystemDetailsHandler,
|
||||||
|
radarr_data,
|
||||||
log_details,
|
log_details,
|
||||||
extended_stateful_iterable_vec!(HorizontallyScrollableText, String, text),
|
extended_stateful_iterable_vec!(HorizontallyScrollableText, String, text),
|
||||||
ActiveRadarrBlock::SystemLogs,
|
ActiveRadarrBlock::SystemLogs,
|
||||||
@@ -283,10 +265,10 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemLogs,
|
ActiveRadarrBlock::SystemLogs,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -296,10 +278,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemLogs,
|
ActiveRadarrBlock::SystemLogs,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -321,10 +303,10 @@ mod tests {
|
|||||||
.set_items(extended_stateful_iterable_vec!(RadarrTask, String, name));
|
.set_items(extended_stateful_iterable_vec!(RadarrTask, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTasks,
|
ActiveRadarrBlock::SystemTasks,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -334,10 +316,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTasks,
|
ActiveRadarrBlock::SystemTasks,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -360,10 +342,10 @@ mod tests {
|
|||||||
.set_items(extended_stateful_iterable_vec!(RadarrTask, String, name));
|
.set_items(extended_stateful_iterable_vec!(RadarrTask, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTasks,
|
ActiveRadarrBlock::SystemTasks,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -373,10 +355,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTasks,
|
ActiveRadarrBlock::SystemTasks,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -398,10 +380,10 @@ mod tests {
|
|||||||
.set_items(extended_stateful_iterable_vec!(QueueEvent, String, name));
|
.set_items(extended_stateful_iterable_vec!(QueueEvent, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
ActiveRadarrBlock::SystemQueuedEvents,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -411,10 +393,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
ActiveRadarrBlock::SystemQueuedEvents,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -437,10 +419,10 @@ mod tests {
|
|||||||
.set_items(extended_stateful_iterable_vec!(QueueEvent, String, name));
|
.set_items(extended_stateful_iterable_vec!(QueueEvent, String, name));
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
ActiveRadarrBlock::SystemQueuedEvents,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -450,10 +432,10 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
ActiveRadarrBlock::SystemQueuedEvents,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -469,20 +451,20 @@ mod tests {
|
|||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.data.radarr_data.updates.offset, 1);
|
assert_eq!(app.data.radarr_data.updates.offset, 1);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -496,20 +478,20 @@ mod tests {
|
|||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test 1\nTest 2".to_owned());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.end.key,
|
DEFAULT_KEYBINDINGS.end.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.data.radarr_data.updates.offset, 0);
|
assert_eq!(app.data.radarr_data.updates.offset, 0);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.home.key,
|
DEFAULT_KEYBINDINGS.home.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -534,10 +516,10 @@ mod tests {
|
|||||||
.set_items(vec!["t1".into(), "t22".into()]);
|
.set_items(vec!["t1".into(), "t22".into()]);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -545,10 +527,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "t22");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "t22");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -556,10 +538,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "22");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "22");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -567,10 +549,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "2");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "2");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -578,10 +560,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -589,10 +571,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -600,10 +582,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "2");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "2");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -611,10 +593,10 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "22");
|
assert_eq!(app.data.radarr_data.log_details.items[1].to_string(), "22");
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -629,20 +611,20 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert!(app.data.radarr_data.prompt_confirm);
|
assert!(app.data.radarr_data.prompt_confirm);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&key,
|
key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -664,17 +646,12 @@ mod tests {
|
|||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::SystemTasks, None)
|
||||||
&SUBMIT_KEY,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::SystemTasks,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into()
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -685,17 +662,12 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
|
app.push_navigation_stack(ActiveRadarrBlock::SystemTasks.into());
|
||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(SUBMIT_KEY, &mut app, ActiveRadarrBlock::SystemTasks, None)
|
||||||
&SUBMIT_KEY,
|
.handle();
|
||||||
&mut app,
|
|
||||||
&ActiveRadarrBlock::SystemTasks,
|
|
||||||
&None,
|
|
||||||
)
|
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTasks.into()
|
ActiveRadarrBlock::SystemTasks.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,10 +680,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -722,7 +694,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTasks.into()
|
ActiveRadarrBlock::SystemTasks.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,10 +706,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&SUBMIT_KEY,
|
SUBMIT_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -745,7 +717,7 @@ mod tests {
|
|||||||
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
assert_eq!(app.data.radarr_data.prompt_confirm_action, None);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTasks.into()
|
ActiveRadarrBlock::SystemTasks.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -776,10 +748,9 @@ mod tests {
|
|||||||
.log_details
|
.log_details
|
||||||
.set_items(vec![HorizontallyScrollableText::default()]);
|
.set_items(vec![HorizontallyScrollableText::default()]);
|
||||||
|
|
||||||
SystemDetailsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::SystemLogs, &None)
|
SystemDetailsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::SystemLogs, None).handle();
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
assert!(app.data.radarr_data.log_details.items.is_empty());
|
assert!(app.data.radarr_data.log_details.items.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -795,10 +766,9 @@ mod tests {
|
|||||||
.tasks
|
.tasks
|
||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemDetailsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::SystemTasks, &None)
|
SystemDetailsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::SystemTasks, None).handle();
|
||||||
.handle();
|
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -814,14 +784,14 @@ mod tests {
|
|||||||
.set_items(vec![QueueEvent::default()]);
|
.set_items(vec![QueueEvent::default()]);
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents,
|
ActiveRadarrBlock::SystemQueuedEvents,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -831,10 +801,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::SystemUpdates.into());
|
app.push_navigation_stack(ActiveRadarrBlock::SystemUpdates.into());
|
||||||
|
|
||||||
SystemDetailsHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::SystemUpdates, &None)
|
SystemDetailsHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::SystemUpdates, None)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -845,16 +815,16 @@ mod tests {
|
|||||||
app.data.radarr_data.prompt_confirm = true;
|
app.data.radarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&ESC_KEY,
|
ESC_KEY,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTasks.into()
|
ActiveRadarrBlock::SystemTasks.into()
|
||||||
);
|
);
|
||||||
assert!(!app.data.radarr_data.prompt_confirm);
|
assert!(!app.data.radarr_data.prompt_confirm);
|
||||||
}
|
}
|
||||||
@@ -882,14 +852,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &active_radarr_block.into());
|
assert_eq!(app.get_current_route(), active_radarr_block.into());
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,14 +879,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(active_radarr_block.into());
|
app.push_navigation_stack(active_radarr_block.into());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&active_radarr_block,
|
active_radarr_block,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &active_radarr_block.into());
|
assert_eq!(app.get_current_route(), active_radarr_block.into());
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,10 +898,10 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
|
app.push_navigation_stack(ActiveRadarrBlock::SystemTaskStartConfirmPrompt.into());
|
||||||
|
|
||||||
SystemDetailsHandler::with(
|
SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.confirm.key,
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
ActiveRadarrBlock::SystemTaskStartConfirmPrompt,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
@@ -942,7 +912,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTasks.into()
|
ActiveRadarrBlock::SystemTasks.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -951,9 +921,9 @@ mod tests {
|
|||||||
fn test_system_details_handler_accepts() {
|
fn test_system_details_handler_accepts() {
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if SYSTEM_DETAILS_BLOCKS.contains(&active_radarr_block) {
|
if SYSTEM_DETAILS_BLOCKS.contains(&active_radarr_block) {
|
||||||
assert!(SystemDetailsHandler::accepts(&active_radarr_block));
|
assert!(SystemDetailsHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!SystemDetailsHandler::accepts(&active_radarr_block));
|
assert!(!SystemDetailsHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -964,25 +934,25 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let handler = SystemDetailsHandler::with(
|
let handler = SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_system_details_handler_not_ready_when_both_log_details_and_updates_are_empty() {
|
fn test_system_details_handler_not_ready_when_log_details_and_updates_and_tasks_are_empty() {
|
||||||
let mut app = App::default();
|
let mut app = App::default();
|
||||||
app.is_loading = false;
|
app.is_loading = false;
|
||||||
|
|
||||||
let handler = SystemDetailsHandler::with(
|
let handler = SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!handler.is_ready());
|
assert!(!handler.is_ready());
|
||||||
@@ -999,10 +969,30 @@ mod tests {
|
|||||||
.set_items(vec![HorizontallyScrollableText::default()]);
|
.set_items(vec![HorizontallyScrollableText::default()]);
|
||||||
|
|
||||||
let handler = SystemDetailsHandler::with(
|
let handler = SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_system_details_handler_ready_when_not_loading_and_tasks_is_not_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = false;
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.radarr_data
|
||||||
|
.tasks
|
||||||
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
|
let handler = SystemDetailsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveRadarrBlock::SystemTasks,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
@@ -1015,10 +1005,10 @@ mod tests {
|
|||||||
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
|
app.data.radarr_data.updates = ScrollableText::with_string("Test".to_owned());
|
||||||
|
|
||||||
let handler = SystemDetailsHandler::with(
|
let handler = SystemDetailsHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.esc.key,
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::SystemUpdates,
|
ActiveRadarrBlock::SystemUpdates,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(handler.is_ready());
|
assert!(handler.is_ready());
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use pretty_assertions::assert_eq;
|
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
use strum::IntoEnumIterator;
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
@@ -28,18 +27,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(6);
|
app.data.radarr_data.main_tabs.set_index(6);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.left.key,
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Indexers.into()
|
ActiveRadarrBlock::Indexers.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Indexers.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Indexers.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@@ -49,18 +48,18 @@ mod tests {
|
|||||||
app.data.radarr_data.main_tabs.set_index(6);
|
app.data.radarr_data.main_tabs.set_index(6);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.right.key,
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.main_tabs.get_active_route(),
|
app.data.radarr_data.main_tabs.get_active_route(),
|
||||||
&ActiveRadarrBlock::Movies.into()
|
ActiveRadarrBlock::Movies.into()
|
||||||
);
|
);
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::Movies.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::Movies.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,9 +78,9 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
||||||
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
||||||
|
|
||||||
SystemHandler::with(&ESC_KEY, &mut app, &ActiveRadarrBlock::System, &None).handle();
|
SystemHandler::with(ESC_KEY, &mut app, ActiveRadarrBlock::System, None).handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
assert!(app.error.text.is_empty());
|
assert!(app.error.text.is_empty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,16 +111,16 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemUpdates.into()
|
ActiveRadarrBlock::SystemUpdates.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,14 +145,14 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -175,16 +174,16 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.events.key,
|
DEFAULT_KEYBINDINGS.events.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemQueuedEvents.into()
|
ActiveRadarrBlock::SystemQueuedEvents.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,14 +208,14 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.events.key,
|
DEFAULT_KEYBINDINGS.events.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -239,14 +238,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
assert!(app.should_refresh);
|
assert!(app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,14 +271,14 @@ mod tests {
|
|||||||
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
app.push_navigation_stack(ActiveRadarrBlock::System.into());
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.refresh.key,
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
assert!(!app.should_refresh);
|
assert!(!app.should_refresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -302,16 +301,16 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.logs.key,
|
DEFAULT_KEYBINDINGS.logs.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemLogs.into()
|
ActiveRadarrBlock::SystemLogs.into()
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.data.radarr_data.log_details.items,
|
app.data.radarr_data.log_details.items,
|
||||||
@@ -344,14 +343,14 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.logs.key,
|
DEFAULT_KEYBINDINGS.logs.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
assert!(app.data.radarr_data.log_details.is_empty());
|
assert!(app.data.radarr_data.log_details.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,16 +373,16 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.tasks.key,
|
DEFAULT_KEYBINDINGS.tasks.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.get_current_route(),
|
app.get_current_route(),
|
||||||
&ActiveRadarrBlock::SystemTasks.into()
|
ActiveRadarrBlock::SystemTasks.into()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,14 +407,14 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
SystemHandler::with(
|
SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.tasks.key,
|
DEFAULT_KEYBINDINGS.tasks.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
)
|
)
|
||||||
.handle();
|
.handle();
|
||||||
|
|
||||||
assert_eq!(app.get_current_route(), &ActiveRadarrBlock::System.into());
|
assert_eq!(app.get_current_route(), ActiveRadarrBlock::System.into());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -444,9 +443,9 @@ mod tests {
|
|||||||
|
|
||||||
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
ActiveRadarrBlock::iter().for_each(|active_radarr_block| {
|
||||||
if system_blocks.contains(&active_radarr_block) {
|
if system_blocks.contains(&active_radarr_block) {
|
||||||
assert!(SystemHandler::accepts(&active_radarr_block));
|
assert!(SystemHandler::accepts(active_radarr_block));
|
||||||
} else {
|
} else {
|
||||||
assert!(!SystemHandler::accepts(&active_radarr_block));
|
assert!(!SystemHandler::accepts(active_radarr_block));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -457,10 +456,10 @@ mod tests {
|
|||||||
app.is_loading = true;
|
app.is_loading = true;
|
||||||
|
|
||||||
let system_handler = SystemHandler::with(
|
let system_handler = SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!system_handler.is_ready());
|
assert!(!system_handler.is_ready());
|
||||||
@@ -482,10 +481,10 @@ mod tests {
|
|||||||
.set_items(vec![QueueEvent::default()]);
|
.set_items(vec![QueueEvent::default()]);
|
||||||
|
|
||||||
let system_handler = SystemHandler::with(
|
let system_handler = SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!system_handler.is_ready());
|
assert!(!system_handler.is_ready());
|
||||||
@@ -503,10 +502,10 @@ mod tests {
|
|||||||
.set_items(vec![QueueEvent::default()]);
|
.set_items(vec![QueueEvent::default()]);
|
||||||
|
|
||||||
let system_handler = SystemHandler::with(
|
let system_handler = SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!system_handler.is_ready());
|
assert!(!system_handler.is_ready());
|
||||||
@@ -524,10 +523,10 @@ mod tests {
|
|||||||
.set_items(vec![RadarrTask::default()]);
|
.set_items(vec![RadarrTask::default()]);
|
||||||
|
|
||||||
let system_handler = SystemHandler::with(
|
let system_handler = SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(!system_handler.is_ready());
|
assert!(!system_handler.is_ready());
|
||||||
@@ -550,10 +549,10 @@ mod tests {
|
|||||||
.set_items(vec![QueueEvent::default()]);
|
.set_items(vec![QueueEvent::default()]);
|
||||||
|
|
||||||
let system_handler = SystemHandler::with(
|
let system_handler = SystemHandler::with(
|
||||||
&DEFAULT_KEYBINDINGS.update.key,
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
&mut app,
|
&mut app,
|
||||||
&ActiveRadarrBlock::System,
|
ActiveRadarrBlock::System,
|
||||||
&None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(system_handler.is_ready());
|
assert!(system_handler.is_ready());
|
||||||
|
|||||||
@@ -0,0 +1,621 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use chrono::DateTime;
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::sonarr_handlers::blocklist::{blocklist_sorting_options, BlocklistHandler};
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, BLOCKLIST_BLOCKS};
|
||||||
|
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
||||||
|
use crate::models::sonarr_models::BlocklistItem;
|
||||||
|
|
||||||
|
mod test_handle_delete {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const DELETE_KEY: Key = DEFAULT_KEYBINDINGS.delete.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_blocklist_item_prompt() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
|
BlocklistHandler::with(DELETE_KEY, &mut app, ActiveSonarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_blocklist_item_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
|
BlocklistHandler::with(DELETE_KEY, &mut app, ActiveSonarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_left_right_action {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(2);
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::Downloads.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Downloads.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(2);
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::History.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::History.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_left_right_prompt_toggle(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt,
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt
|
||||||
|
)]
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(key, &mut app, active_sonarr_block, None).handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
BlocklistHandler::with(key, &mut app, active_sonarr_block, None).handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_submit {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, ActiveSonarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::BlocklistItemDetails.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_submit_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, ActiveSonarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt,
|
||||||
|
SonarrEvent::DeleteBlocklistItem(None)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt,
|
||||||
|
SonarrEvent::ClearBlocklist
|
||||||
|
)]
|
||||||
|
fn test_blocklist_prompt_confirm_submit(
|
||||||
|
#[case] base_route: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
#[case] expected_action: SonarrEvent,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
app.push_navigation_stack(base_route.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(expected_action)
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_blocklist_prompt_decline_submit(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt,
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt
|
||||||
|
)]
|
||||||
|
prompt_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt
|
||||||
|
)]
|
||||||
|
fn test_blocklist_prompt_blocks_esc(
|
||||||
|
#[case] base_block: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(base_block.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
BlocklistHandler::with(ESC_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), base_block.into());
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_esc_blocklist_item_details() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::BlocklistItemDetails.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
ESC_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::BlocklistItemDetails,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.error = "test error".to_owned().into();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::Blocklist, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
assert!(app.error.text.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_key_char {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_blocklist_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_blocklist_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear_blocklist_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.clear.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear_blocklist_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.clear.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt,
|
||||||
|
SonarrEvent::DeleteBlocklistItem(None)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt,
|
||||||
|
SonarrEvent::ClearBlocklist
|
||||||
|
)]
|
||||||
|
fn test_blocklist_prompt_confirm(
|
||||||
|
#[case] base_route: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
#[case] expected_action: SonarrEvent,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.blocklist.set_items(blocklist_vec());
|
||||||
|
app.push_navigation_stack(base_route.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
|
BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
|
&mut app,
|
||||||
|
prompt_block,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(expected_action)
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_sorting_options_series_title() {
|
||||||
|
let expected_cmp_fn: fn(&BlocklistItem, &BlocklistItem) -> Ordering = |a, b| {
|
||||||
|
a.series_title
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&String::new())
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(
|
||||||
|
&b.series_title
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&String::new())
|
||||||
|
.to_lowercase(),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let mut expected_blocklist_vec = blocklist_vec();
|
||||||
|
expected_blocklist_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = blocklist_sorting_options()[0].clone();
|
||||||
|
let mut sorted_blocklist_vec = blocklist_vec();
|
||||||
|
sorted_blocklist_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_blocklist_vec, expected_blocklist_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Series Title");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_sorting_options_source_title() {
|
||||||
|
let expected_cmp_fn: fn(&BlocklistItem, &BlocklistItem) -> Ordering = |a, b| {
|
||||||
|
a.source_title
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.source_title.to_lowercase())
|
||||||
|
};
|
||||||
|
let mut expected_blocklist_vec = blocklist_vec();
|
||||||
|
expected_blocklist_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = blocklist_sorting_options()[1].clone();
|
||||||
|
let mut sorted_blocklist_vec = blocklist_vec();
|
||||||
|
sorted_blocklist_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_blocklist_vec, expected_blocklist_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Source Title");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_sorting_options_language() {
|
||||||
|
let expected_cmp_fn: fn(&BlocklistItem, &BlocklistItem) -> Ordering = |a, b| {
|
||||||
|
let a_languages = a
|
||||||
|
.languages
|
||||||
|
.iter()
|
||||||
|
.map(|lang| lang.name.to_lowercase())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ");
|
||||||
|
let b_languages = b
|
||||||
|
.languages
|
||||||
|
.iter()
|
||||||
|
.map(|lang| lang.name.to_lowercase())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
a_languages.cmp(&b_languages)
|
||||||
|
};
|
||||||
|
let mut expected_blocklist_vec = blocklist_vec();
|
||||||
|
expected_blocklist_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = blocklist_sorting_options()[2].clone();
|
||||||
|
let mut sorted_blocklist_vec = blocklist_vec();
|
||||||
|
sorted_blocklist_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_blocklist_vec, expected_blocklist_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Language");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_sorting_options_quality() {
|
||||||
|
let expected_cmp_fn: fn(&BlocklistItem, &BlocklistItem) -> Ordering = |a, b| {
|
||||||
|
a.quality
|
||||||
|
.quality
|
||||||
|
.name
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.quality.quality.name.to_lowercase())
|
||||||
|
};
|
||||||
|
let mut expected_blocklist_vec = blocklist_vec();
|
||||||
|
expected_blocklist_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = blocklist_sorting_options()[3].clone();
|
||||||
|
let mut sorted_blocklist_vec = blocklist_vec();
|
||||||
|
sorted_blocklist_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_blocklist_vec, expected_blocklist_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Quality");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_sorting_options_date() {
|
||||||
|
let expected_cmp_fn: fn(&BlocklistItem, &BlocklistItem) -> Ordering =
|
||||||
|
|a, b| a.date.cmp(&b.date);
|
||||||
|
let mut expected_blocklist_vec = blocklist_vec();
|
||||||
|
expected_blocklist_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = blocklist_sorting_options()[4].clone();
|
||||||
|
let mut sorted_blocklist_vec = blocklist_vec();
|
||||||
|
sorted_blocklist_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_blocklist_vec, expected_blocklist_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Date");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_handler_accepts() {
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if BLOCKLIST_BLOCKS.contains(&active_sonarr_block) {
|
||||||
|
assert!(BlocklistHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!BlocklistHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_handler_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_handler_not_ready_when_blocklist_is_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_blocklist_handler_ready_when_not_loading_and_blocklist_is_not_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Blocklist.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.blocklist
|
||||||
|
.set_items(vec![BlocklistItem::default()]);
|
||||||
|
|
||||||
|
let handler = BlocklistHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Blocklist,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blocklist_vec() -> Vec<BlocklistItem> {
|
||||||
|
vec![
|
||||||
|
BlocklistItem {
|
||||||
|
id: 3,
|
||||||
|
source_title: "test 1".to_owned(),
|
||||||
|
languages: vec![Language {
|
||||||
|
id: 1,
|
||||||
|
name: "telgu".to_owned(),
|
||||||
|
}],
|
||||||
|
quality: QualityWrapper {
|
||||||
|
quality: Quality {
|
||||||
|
name: "HD - 1080p".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
date: DateTime::from(DateTime::parse_from_rfc3339("2024-01-10T07:28:45Z").unwrap()),
|
||||||
|
series_title: Some("test 3".into()),
|
||||||
|
..BlocklistItem::default()
|
||||||
|
},
|
||||||
|
BlocklistItem {
|
||||||
|
id: 2,
|
||||||
|
source_title: "test 2".to_owned(),
|
||||||
|
languages: vec![Language {
|
||||||
|
id: 3,
|
||||||
|
name: "chinese".to_owned(),
|
||||||
|
}],
|
||||||
|
quality: QualityWrapper {
|
||||||
|
quality: Quality {
|
||||||
|
name: "SD - 720p".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
date: DateTime::from(DateTime::parse_from_rfc3339("2024-02-10T07:28:45Z").unwrap()),
|
||||||
|
series_title: Some("test 2".into()),
|
||||||
|
..BlocklistItem::default()
|
||||||
|
},
|
||||||
|
BlocklistItem {
|
||||||
|
id: 1,
|
||||||
|
source_title: "test 3".to_owned(),
|
||||||
|
languages: vec![Language {
|
||||||
|
id: 1,
|
||||||
|
name: "english".to_owned(),
|
||||||
|
}],
|
||||||
|
quality: QualityWrapper {
|
||||||
|
quality: Quality {
|
||||||
|
name: "HD - 1080p".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
date: DateTime::from(DateTime::parse_from_rfc3339("2024-03-10T07:28:45Z").unwrap()),
|
||||||
|
series_title: None,
|
||||||
|
..BlocklistItem::default()
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,232 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, BLOCKLIST_BLOCKS};
|
||||||
|
use crate::models::sonarr_models::BlocklistItem;
|
||||||
|
use crate::models::stateful_table::SortOption;
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "blocklist_handler_tests.rs"]
|
||||||
|
mod blocklist_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct BlocklistHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> BlocklistHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
blocklist,
|
||||||
|
self.app.data.sonarr_data.blocklist,
|
||||||
|
BlocklistItem
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for BlocklistHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let blocklist_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveSonarrBlock::Blocklist.into())
|
||||||
|
.sorting_block(ActiveSonarrBlock::BlocklistSortPrompt.into())
|
||||||
|
.sort_by_fn(|a: &BlocklistItem, b: &BlocklistItem| a.id.cmp(&b.id))
|
||||||
|
.sort_options(blocklist_sorting_options());
|
||||||
|
|
||||||
|
if !self.handle_blocklist_table_events(blocklist_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
BLOCKLIST_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> Self {
|
||||||
|
BlocklistHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context: context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && !self.app.data.sonarr_data.blocklist.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::Blocklist {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::DeleteBlocklistItemPrompt.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Blocklist => handle_change_tab_left_right_keys(self.app, self.key),
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt
|
||||||
|
| ActiveSonarrBlock::BlocklistClearAllItemsPrompt => handle_prompt_toggle(self.app, self.key),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action =
|
||||||
|
Some(SonarrEvent::DeleteBlocklistItem(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::ClearBlocklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::Blocklist => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::BlocklistItemDetails.into());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt
|
||||||
|
| ActiveSonarrBlock::BlocklistClearAllItemsPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::BlocklistItemDetails | ActiveSonarrBlock::BlocklistSortPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
_ => handle_clear_errors(self.app),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
let key = self.key;
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Blocklist => match self.key {
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
}
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.clear.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::BlocklistClearAllItemsPrompt.into());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
ActiveSonarrBlock::DeleteBlocklistItemPrompt => {
|
||||||
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action =
|
||||||
|
Some(SonarrEvent::DeleteBlocklistItem(None));
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::BlocklistClearAllItemsPrompt => {
|
||||||
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::ClearBlocklist);
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blocklist_sorting_options() -> Vec<SortOption<BlocklistItem>> {
|
||||||
|
vec![
|
||||||
|
SortOption {
|
||||||
|
name: "Series Title",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.series_title
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&String::new())
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(
|
||||||
|
&b.series_title
|
||||||
|
.as_ref()
|
||||||
|
.unwrap_or(&String::new())
|
||||||
|
.to_lowercase(),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Source Title",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.source_title
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.source_title.to_lowercase())
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Language",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
let a_languages = a
|
||||||
|
.languages
|
||||||
|
.iter()
|
||||||
|
.map(|lang| lang.name.to_lowercase())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ");
|
||||||
|
let b_languages = b
|
||||||
|
.languages
|
||||||
|
.iter()
|
||||||
|
.map(|lang| lang.name.to_lowercase())
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
a_languages.cmp(&b_languages)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Quality",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.quality
|
||||||
|
.quality
|
||||||
|
.name
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.quality.quality.name.to_lowercase())
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Date",
|
||||||
|
cmp_fn: Some(|a, b| a.date.cmp(&b.date)),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,442 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::sonarr_handlers::downloads::DownloadsHandler;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DOWNLOADS_BLOCKS};
|
||||||
|
use crate::models::sonarr_models::DownloadRecord;
|
||||||
|
|
||||||
|
mod test_handle_delete {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const DELETE_KEY: Key = DEFAULT_KEYBINDINGS.delete.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_download_prompt() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
|
DownloadsHandler::with(DELETE_KEY, &mut app, ActiveSonarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_download_prompt_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
|
DownloadsHandler::with(DELETE_KEY, &mut app, ActiveSonarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Downloads.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_left_right_action {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_downloads_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(1);
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::Series.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_downloads_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(1);
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::Blocklist.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_downloads_left_right_prompt_toggle(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt,
|
||||||
|
ActiveSonarrBlock::UpdateDownloadsPrompt
|
||||||
|
)]
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
|
||||||
|
DownloadsHandler::with(key, &mut app, active_sonarr_block, None).handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
DownloadsHandler::with(key, &mut app, active_sonarr_block, None).handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_submit {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt,
|
||||||
|
SonarrEvent::DeleteDownload(None)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
ActiveSonarrBlock::UpdateDownloadsPrompt,
|
||||||
|
SonarrEvent::UpdateDownloads
|
||||||
|
)]
|
||||||
|
fn test_downloads_prompt_confirm_submit(
|
||||||
|
#[case] base_route: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
#[case] expected_action: SonarrEvent,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
app.push_navigation_stack(base_route.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
|
DownloadsHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(expected_action)
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(ActiveSonarrBlock::Downloads, ActiveSonarrBlock::DeleteDownloadPrompt)]
|
||||||
|
#[case(ActiveSonarrBlock::Downloads, ActiveSonarrBlock::UpdateDownloadsPrompt)]
|
||||||
|
fn test_downloads_prompt_decline_submit(
|
||||||
|
#[case] base_route: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
app.push_navigation_stack(base_route.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
|
DownloadsHandler::with(SUBMIT_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(ActiveSonarrBlock::Downloads, ActiveSonarrBlock::DeleteDownloadPrompt)]
|
||||||
|
#[case(ActiveSonarrBlock::Downloads, ActiveSonarrBlock::UpdateDownloadsPrompt)]
|
||||||
|
fn test_downloads_prompt_blocks_esc(
|
||||||
|
#[case] base_block: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(base_block.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
DownloadsHandler::with(ESC_KEY, &mut app, prompt_block, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), base_block.into());
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.error = "test error".to_owned().into();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
|
||||||
|
DownloadsHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::Downloads, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Downloads.into());
|
||||||
|
assert!(app.error.text.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_key_char {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_downloads_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::UpdateDownloadsPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_update_downloads_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.update.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Downloads.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_downloads_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Downloads.into());
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_downloads_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Downloads.into());
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt,
|
||||||
|
SonarrEvent::DeleteDownload(None)
|
||||||
|
)]
|
||||||
|
#[case(
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
ActiveSonarrBlock::UpdateDownloadsPrompt,
|
||||||
|
SonarrEvent::UpdateDownloads
|
||||||
|
)]
|
||||||
|
fn test_downloads_prompt_confirm_submit(
|
||||||
|
#[case] base_route: ActiveSonarrBlock,
|
||||||
|
#[case] prompt_block: ActiveSonarrBlock,
|
||||||
|
#[case] expected_action: SonarrEvent,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
app.push_navigation_stack(base_route.into());
|
||||||
|
app.push_navigation_stack(prompt_block.into());
|
||||||
|
|
||||||
|
DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
|
&mut app,
|
||||||
|
prompt_block,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(expected_action)
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), base_route.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_downloads_handler_accepts() {
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if DOWNLOADS_BLOCKS.contains(&active_sonarr_block) {
|
||||||
|
assert!(DownloadsHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!DownloadsHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_downloads_handler_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_downloads_handler_not_ready_when_downloads_is_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_downloads_handler_ready_when_not_loading_and_downloads_is_not_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Downloads.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.downloads
|
||||||
|
.set_items(vec![DownloadRecord::default()]);
|
||||||
|
let handler = DownloadsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Downloads,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DOWNLOADS_BLOCKS};
|
||||||
|
use crate::models::sonarr_models::DownloadRecord;
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "downloads_handler_tests.rs"]
|
||||||
|
mod downloads_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct DownloadsHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> DownloadsHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
downloads,
|
||||||
|
self.app.data.sonarr_data.downloads,
|
||||||
|
DownloadRecord
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DownloadsHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let download_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveSonarrBlock::Downloads.into());
|
||||||
|
|
||||||
|
if !self.handle_downloads_table_events(download_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
DOWNLOADS_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> DownloadsHandler<'a, 'b> {
|
||||||
|
DownloadsHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && !self.app.data.sonarr_data.downloads.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::Downloads {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::DeleteDownloadPrompt.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Downloads => handle_change_tab_left_right_keys(self.app, self.key),
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt | ActiveSonarrBlock::UpdateDownloadsPrompt => {
|
||||||
|
handle_prompt_toggle(self.app, self.key)
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteDownload(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::UpdateDownloadsPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::UpdateDownloads);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt | ActiveSonarrBlock::UpdateDownloadsPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
}
|
||||||
|
_ => handle_clear_errors(self.app),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
let key = self.key;
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Downloads => match self.key {
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.update.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::UpdateDownloadsPrompt.into());
|
||||||
|
}
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
ActiveSonarrBlock::DeleteDownloadPrompt => {
|
||||||
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteDownload(None));
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::UpdateDownloadsPrompt => {
|
||||||
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::UpdateDownloads);
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,414 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
|
||||||
|
use chrono::DateTime;
|
||||||
|
use pretty_assertions::{assert_eq, assert_str_eq};
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::sonarr_handlers::history::{history_sorting_options, HistoryHandler};
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTORY_BLOCKS};
|
||||||
|
use crate::models::servarr_models::{Language, Quality, QualityWrapper};
|
||||||
|
use crate::models::sonarr_models::{SonarrHistoryEventType, SonarrHistoryItem};
|
||||||
|
|
||||||
|
mod test_handle_left_right_action {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_history_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(3);
|
||||||
|
|
||||||
|
HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::Blocklist.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Blocklist.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_history_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(3);
|
||||||
|
|
||||||
|
HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::RootFolders.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::RootFolders.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_submit {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.history.set_items(history_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
|
||||||
|
HistoryHandler::with(SUBMIT_KEY, &mut app, ActiveSonarrBlock::History, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::HistoryItemDetails.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_submit_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.history.set_items(history_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
|
||||||
|
HistoryHandler::with(SUBMIT_KEY, &mut app, ActiveSonarrBlock::History, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::History.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::sonarr_test_utils::utils::create_test_sonarr_data;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_esc_history_item_details() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.history
|
||||||
|
.set_items(vec![SonarrHistoryItem::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::HistoryItemDetails.into());
|
||||||
|
|
||||||
|
HistoryHandler::with(
|
||||||
|
ESC_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::HistoryItemDetails,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::History.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.error = "test error".to_owned().into();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.data.sonarr_data = create_test_sonarr_data();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.history
|
||||||
|
.set_items(vec![SonarrHistoryItem::default()]);
|
||||||
|
|
||||||
|
HistoryHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::History, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::History.into());
|
||||||
|
assert!(app.error.text.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_key_char {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_history_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.history.set_items(history_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
|
||||||
|
HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::History.into());
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_history_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.history.set_items(history_vec());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
|
||||||
|
HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::History.into());
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_sorting_options_source_title() {
|
||||||
|
let expected_cmp_fn: fn(&SonarrHistoryItem, &SonarrHistoryItem) -> Ordering = |a, b| {
|
||||||
|
a.source_title
|
||||||
|
.text
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.source_title.text.to_lowercase())
|
||||||
|
};
|
||||||
|
let mut expected_history_vec = history_vec();
|
||||||
|
expected_history_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = history_sorting_options()[0].clone();
|
||||||
|
let mut sorted_history_vec = history_vec();
|
||||||
|
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Source Title");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_sorting_options_event_type() {
|
||||||
|
let expected_cmp_fn: fn(&SonarrHistoryItem, &SonarrHistoryItem) -> Ordering = |a, b| {
|
||||||
|
a.event_type
|
||||||
|
.to_string()
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.event_type.to_string().to_lowercase())
|
||||||
|
};
|
||||||
|
let mut expected_history_vec = history_vec();
|
||||||
|
expected_history_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = history_sorting_options()[1].clone();
|
||||||
|
let mut sorted_history_vec = history_vec();
|
||||||
|
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Event Type");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_sorting_options_language() {
|
||||||
|
let expected_cmp_fn: fn(&SonarrHistoryItem, &SonarrHistoryItem) -> Ordering = |a, b| {
|
||||||
|
let default_language = Language {
|
||||||
|
id: 1,
|
||||||
|
name: "_".to_owned(),
|
||||||
|
};
|
||||||
|
let language_a = &a.languages.first().unwrap_or(&default_language);
|
||||||
|
let language_b = &b.languages.first().unwrap_or(&default_language);
|
||||||
|
|
||||||
|
language_a.cmp(language_b)
|
||||||
|
};
|
||||||
|
let mut expected_history_vec = history_vec();
|
||||||
|
expected_history_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = history_sorting_options()[2].clone();
|
||||||
|
let mut sorted_history_vec = history_vec();
|
||||||
|
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Language");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_sorting_options_quality() {
|
||||||
|
let expected_cmp_fn: fn(&SonarrHistoryItem, &SonarrHistoryItem) -> Ordering = |a, b| {
|
||||||
|
a.quality
|
||||||
|
.quality
|
||||||
|
.name
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.quality.quality.name.to_lowercase())
|
||||||
|
};
|
||||||
|
let mut expected_history_vec = history_vec();
|
||||||
|
expected_history_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = history_sorting_options()[3].clone();
|
||||||
|
let mut sorted_history_vec = history_vec();
|
||||||
|
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Quality");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_sorting_options_date() {
|
||||||
|
let expected_cmp_fn: fn(&SonarrHistoryItem, &SonarrHistoryItem) -> Ordering =
|
||||||
|
|a, b| a.date.cmp(&b.date);
|
||||||
|
let mut expected_history_vec = history_vec();
|
||||||
|
expected_history_vec.sort_by(expected_cmp_fn);
|
||||||
|
|
||||||
|
let sort_option = history_sorting_options()[4].clone();
|
||||||
|
let mut sorted_history_vec = history_vec();
|
||||||
|
sorted_history_vec.sort_by(sort_option.cmp_fn.unwrap());
|
||||||
|
|
||||||
|
assert_eq!(sorted_history_vec, expected_history_vec);
|
||||||
|
assert_str_eq!(sort_option.name, "Date");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_handler_accepts() {
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if HISTORY_BLOCKS.contains(&active_sonarr_block) {
|
||||||
|
assert!(HistoryHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!HistoryHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_handler_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_handler_not_ready_when_history_is_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_history_handler_ready_when_not_loading_and_history_is_not_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::History.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.history
|
||||||
|
.set_items(vec![SonarrHistoryItem::default()]);
|
||||||
|
|
||||||
|
let handler = HistoryHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::History,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn history_vec() -> Vec<SonarrHistoryItem> {
|
||||||
|
vec![
|
||||||
|
SonarrHistoryItem {
|
||||||
|
id: 3,
|
||||||
|
source_title: "test 1".into(),
|
||||||
|
event_type: SonarrHistoryEventType::Grabbed,
|
||||||
|
languages: vec![Language {
|
||||||
|
id: 1,
|
||||||
|
name: "telgu".to_owned(),
|
||||||
|
}],
|
||||||
|
quality: QualityWrapper {
|
||||||
|
quality: Quality {
|
||||||
|
name: "HD - 1080p".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
date: DateTime::from(DateTime::parse_from_rfc3339("2024-01-10T07:28:45Z").unwrap()),
|
||||||
|
..SonarrHistoryItem::default()
|
||||||
|
},
|
||||||
|
SonarrHistoryItem {
|
||||||
|
id: 2,
|
||||||
|
source_title: "test 2".into(),
|
||||||
|
event_type: SonarrHistoryEventType::DownloadFolderImported,
|
||||||
|
languages: vec![Language {
|
||||||
|
id: 3,
|
||||||
|
name: "chinese".to_owned(),
|
||||||
|
}],
|
||||||
|
quality: QualityWrapper {
|
||||||
|
quality: Quality {
|
||||||
|
name: "SD - 720p".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
date: DateTime::from(DateTime::parse_from_rfc3339("2024-02-10T07:28:45Z").unwrap()),
|
||||||
|
..SonarrHistoryItem::default()
|
||||||
|
},
|
||||||
|
SonarrHistoryItem {
|
||||||
|
id: 1,
|
||||||
|
source_title: "test 3".into(),
|
||||||
|
event_type: SonarrHistoryEventType::EpisodeFileDeleted,
|
||||||
|
languages: vec![Language {
|
||||||
|
id: 1,
|
||||||
|
name: "english".to_owned(),
|
||||||
|
}],
|
||||||
|
quality: QualityWrapper {
|
||||||
|
quality: Quality {
|
||||||
|
name: "HD - 1080p".to_owned(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
date: DateTime::from(DateTime::parse_from_rfc3339("2024-03-10T07:28:45Z").unwrap()),
|
||||||
|
..SonarrHistoryItem::default()
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,171 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
|
use crate::handlers::{handle_clear_errors, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, HISTORY_BLOCKS};
|
||||||
|
use crate::models::servarr_models::Language;
|
||||||
|
use crate::models::sonarr_models::SonarrHistoryItem;
|
||||||
|
use crate::models::stateful_table::SortOption;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "history_handler_tests.rs"]
|
||||||
|
mod history_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct HistoryHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> HistoryHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
history,
|
||||||
|
self.app.data.sonarr_data.history,
|
||||||
|
SonarrHistoryItem
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for HistoryHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let history_table_handling_config = TableHandlingConfig::new(ActiveSonarrBlock::History.into())
|
||||||
|
.sorting_block(ActiveSonarrBlock::HistorySortPrompt.into())
|
||||||
|
.sort_by_fn(|a: &SonarrHistoryItem, b: &SonarrHistoryItem| a.id.cmp(&b.id))
|
||||||
|
.sort_options(history_sorting_options())
|
||||||
|
.searching_block(ActiveSonarrBlock::SearchHistory.into())
|
||||||
|
.search_error_block(ActiveSonarrBlock::SearchHistoryError.into())
|
||||||
|
.search_field_fn(|history| &history.source_title.text)
|
||||||
|
.filtering_block(ActiveSonarrBlock::FilterHistory.into())
|
||||||
|
.filter_error_block(ActiveSonarrBlock::FilterHistoryError.into())
|
||||||
|
.filter_field_fn(|history| &history.source_title.text);
|
||||||
|
|
||||||
|
if !self.handle_history_table_events(history_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
HISTORY_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> Self {
|
||||||
|
HistoryHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context: context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && !self.app.data.sonarr_data.history.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::History {
|
||||||
|
handle_change_tab_left_right_keys(self.app, self.key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::History {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::HistoryItemDetails.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::HistoryItemDetails {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
} else {
|
||||||
|
handle_clear_errors(self.app);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
let key = self.key;
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::History {
|
||||||
|
match self.key {
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(in crate::handlers::sonarr_handlers) fn history_sorting_options(
|
||||||
|
) -> Vec<SortOption<SonarrHistoryItem>> {
|
||||||
|
vec![
|
||||||
|
SortOption {
|
||||||
|
name: "Source Title",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.source_title
|
||||||
|
.text
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.source_title.text.to_lowercase())
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Event Type",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.event_type
|
||||||
|
.to_string()
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.event_type.to_string().to_lowercase())
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Language",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
let default_language = Language {
|
||||||
|
id: 1,
|
||||||
|
name: "_".to_owned(),
|
||||||
|
};
|
||||||
|
let language_a = &a.languages.first().unwrap_or(&default_language);
|
||||||
|
let language_b = &b.languages.first().unwrap_or(&default_language);
|
||||||
|
|
||||||
|
language_a.cmp(language_b)
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Quality",
|
||||||
|
cmp_fn: Some(|a, b| {
|
||||||
|
a.quality
|
||||||
|
.quality
|
||||||
|
.name
|
||||||
|
.to_lowercase()
|
||||||
|
.cmp(&b.quality.quality.name.to_lowercase())
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
SortOption {
|
||||||
|
name: "Date",
|
||||||
|
cmp_fn: Some(|a, b| a.date.cmp(&b.date)),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,476 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_INDEXER_BLOCKS};
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
use crate::{handle_prompt_left_right_keys, handle_text_box_keys, handle_text_box_left_right_keys};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "edit_indexer_handler_tests.rs"]
|
||||||
|
mod edit_indexer_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct EditIndexerHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditIndexerHandler<'a, 'b> {
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
EDIT_INDEXER_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> EditIndexerHandler<'a, 'b> {
|
||||||
|
EditIndexerHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && self.app.data.sonarr_data.edit_indexer_modal.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt => {
|
||||||
|
self.app.data.sonarr_data.selected_block.up();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerPriorityInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.priority += 1;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt => {
|
||||||
|
self.app.data.sonarr_data.selected_block.down();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerPriorityInput => {
|
||||||
|
let edit_indexer_modal = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
|
if edit_indexer_modal.priority > 0 {
|
||||||
|
edit_indexer_modal.priority -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.scroll_home();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerUrlInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.url
|
||||||
|
.scroll_home();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerApiKeyInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.api_key
|
||||||
|
.scroll_home();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerSeedRatioInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.seed_ratio
|
||||||
|
.scroll_home();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.scroll_home();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
.reset_offset();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerUrlInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.url
|
||||||
|
.reset_offset();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerApiKeyInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.api_key
|
||||||
|
.reset_offset();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerSeedRatioInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.seed_ratio
|
||||||
|
.reset_offset();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.reset_offset();
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt => {
|
||||||
|
handle_prompt_left_right_keys!(
|
||||||
|
self,
|
||||||
|
ActiveSonarrBlock::EditIndexerConfirmPrompt,
|
||||||
|
sonarr_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerUrlInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerApiKeyInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.api_key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerSeedRatioInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.seed_ratio
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt => {
|
||||||
|
let selected_block = self.app.data.sonarr_data.selected_block.get_active_block();
|
||||||
|
match selected_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerConfirmPrompt => {
|
||||||
|
let sonarr_data = &mut self.app.data.sonarr_data;
|
||||||
|
if sonarr_data.prompt_confirm {
|
||||||
|
sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditIndexer(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
} else {
|
||||||
|
sonarr_data.edit_indexer_modal = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerUrlInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerApiKeyInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerSeedRatioInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
self.app.push_navigation_stack(selected_block.into());
|
||||||
|
self.app.should_ignore_quit_key = true;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerPriorityInput => self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::EditIndexerPriorityInput.into()),
|
||||||
|
ActiveSonarrBlock::EditIndexerToggleEnableRss => {
|
||||||
|
let indexer = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
|
indexer.enable_rss = Some(!indexer.enable_rss.unwrap_or_default());
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerToggleEnableAutomaticSearch => {
|
||||||
|
let indexer = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
|
indexer.enable_automatic_search =
|
||||||
|
Some(!indexer.enable_automatic_search.unwrap_or_default());
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerToggleEnableInteractiveSearch => {
|
||||||
|
let indexer = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap();
|
||||||
|
indexer.enable_interactive_search =
|
||||||
|
Some(!indexer.enable_interactive_search.unwrap_or_default());
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerUrlInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerApiKeyInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerSeedRatioInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerPriorityInput => self.app.pop_navigation_stack(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
self.app.data.sonarr_data.edit_indexer_modal = None;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerUrlInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerApiKeyInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerSeedRatioInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerPriorityInput
|
||||||
|
| ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
_ => self.app.pop_navigation_stack(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerUrlInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerApiKeyInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.api_key
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerSeedRatioInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.seed_ratio
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerTagsInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_indexer_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt => {
|
||||||
|
if self.app.data.sonarr_data.selected_block.get_active_block()
|
||||||
|
== ActiveSonarrBlock::EditIndexerConfirmPrompt
|
||||||
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
|
{
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditIndexer(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handle_prompt_left_right_keys;
|
||||||
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
ActiveSonarrBlock, INDEXER_SETTINGS_BLOCKS,
|
||||||
|
};
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "edit_indexer_settings_handler_tests.rs"]
|
||||||
|
mod edit_indexer_settings_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct IndexerSettingsHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexerSettingsHandler<'a, 'b> {
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
INDEXER_SETTINGS_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> IndexerSettingsHandler<'a, 'b> {
|
||||||
|
IndexerSettingsHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && self.app.data.sonarr_data.indexer_settings.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {
|
||||||
|
let indexer_settings = self.app.data.sonarr_data.indexer_settings.as_mut().unwrap();
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt => {
|
||||||
|
self.app.data.sonarr_data.selected_block.up();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput => {
|
||||||
|
indexer_settings.minimum_age += 1;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput => {
|
||||||
|
indexer_settings.retention += 1;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput => {
|
||||||
|
indexer_settings.maximum_size += 1;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput => {
|
||||||
|
indexer_settings.rss_sync_interval += 1;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {
|
||||||
|
let indexer_settings = self.app.data.sonarr_data.indexer_settings.as_mut().unwrap();
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt => {
|
||||||
|
self.app.data.sonarr_data.selected_block.down()
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput => {
|
||||||
|
if indexer_settings.minimum_age > 0 {
|
||||||
|
indexer_settings.minimum_age -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput => {
|
||||||
|
if indexer_settings.retention > 0 {
|
||||||
|
indexer_settings.retention -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput => {
|
||||||
|
if indexer_settings.maximum_size > 0 {
|
||||||
|
indexer_settings.maximum_size -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput => {
|
||||||
|
if indexer_settings.rss_sync_interval > 0 {
|
||||||
|
indexer_settings.rss_sync_interval -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::AllIndexerSettingsPrompt {
|
||||||
|
handle_prompt_left_right_keys!(
|
||||||
|
self,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsConfirmPrompt,
|
||||||
|
sonarr_data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt => {
|
||||||
|
match self.app.data.sonarr_data.selected_block.get_active_block() {
|
||||||
|
ActiveSonarrBlock::IndexerSettingsConfirmPrompt => {
|
||||||
|
let sonarr_data = &mut self.app.data.sonarr_data;
|
||||||
|
if sonarr_data.prompt_confirm {
|
||||||
|
sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditAllIndexerSettings(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
} else {
|
||||||
|
sonarr_data.indexer_settings = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput
|
||||||
|
| ActiveSonarrBlock::IndexerSettingsRetentionInput
|
||||||
|
| ActiveSonarrBlock::IndexerSettingsMaximumSizeInput
|
||||||
|
| ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput => {
|
||||||
|
self.app.push_navigation_stack(
|
||||||
|
(
|
||||||
|
self.app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput
|
||||||
|
| ActiveSonarrBlock::IndexerSettingsRetentionInput
|
||||||
|
| ActiveSonarrBlock::IndexerSettingsMaximumSizeInput
|
||||||
|
| ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput => self.app.pop_navigation_stack(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
self.app.data.sonarr_data.indexer_settings = None;
|
||||||
|
}
|
||||||
|
_ => self.app.pop_navigation_stack(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::AllIndexerSettingsPrompt
|
||||||
|
&& self.app.data.sonarr_data.selected_block.get_active_block()
|
||||||
|
== ActiveSonarrBlock::IndexerSettingsConfirmPrompt
|
||||||
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
|
{
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action =
|
||||||
|
Some(SonarrEvent::EditAllIndexerSettings(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,570 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::sonarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
ActiveSonarrBlock, INDEXER_SETTINGS_BLOCKS,
|
||||||
|
};
|
||||||
|
use crate::models::sonarr_models::IndexerSettings;
|
||||||
|
|
||||||
|
mod test_handle_scroll_up_and_down {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS;
|
||||||
|
use crate::models::sonarr_models::IndexerSettings;
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
macro_rules! test_i64_counter_scroll_value {
|
||||||
|
($block:expr, $key:expr, $data_ref:ident, $negatives:literal) => {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with($key, &mut app, $block, None).handle();
|
||||||
|
|
||||||
|
if $key == Key::Up {
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.$data_ref,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if $negatives {
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.$data_ref,
|
||||||
|
-1
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.$data_ref,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(Key::Up, &mut app, $block, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.$data_ref,
|
||||||
|
1
|
||||||
|
);
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with($key, &mut app, $block, None).handle();
|
||||||
|
assert_eq!(
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexer_settings
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.$data_ref,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.down();
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
if key == Key::Up {
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_prompt_scroll_no_op_when_not_ready(
|
||||||
|
#[values(Key::Up, Key::Down)] key: Key,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.down();
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_minimum_age_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
|
test_i64_counter_scroll_value!(
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput,
|
||||||
|
key,
|
||||||
|
minimum_age,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_retention_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
|
test_i64_counter_scroll_value!(
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput,
|
||||||
|
key,
|
||||||
|
retention,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_maximum_size_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
|
test_i64_counter_scroll_value!(
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput,
|
||||||
|
key,
|
||||||
|
maximum_size,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_rss_sync_interval_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
|
test_i64_counter_scroll_value!(
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput,
|
||||||
|
key,
|
||||||
|
rss_sync_interval,
|
||||||
|
false
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_left_right_action {
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS;
|
||||||
|
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.y = INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1;
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_submit {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
models::{
|
||||||
|
servarr_data::sonarr::sonarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS,
|
||||||
|
sonarr_models::IndexerSettings, BlockSelectionState,
|
||||||
|
},
|
||||||
|
network::sonarr_network::SonarrEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_prompt_prompt_decline_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(0, INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
assert_eq!(app.data.sonarr_data.indexer_settings, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_prompt_prompt_confirmation_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(0, INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(SonarrEvent::EditAllIndexerSettings(None))
|
||||||
|
);
|
||||||
|
assert!(app.data.sonarr_data.indexer_settings.is_some());
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_prompt_prompt_confirmation_submit_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
|
);
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case(ActiveSonarrBlock::IndexerSettingsMinimumAgeInput, 0)]
|
||||||
|
#[case(ActiveSonarrBlock::IndexerSettingsRetentionInput, 1)]
|
||||||
|
#[case(ActiveSonarrBlock::IndexerSettingsMaximumSizeInput, 2)]
|
||||||
|
#[case(ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput, 3)]
|
||||||
|
fn test_edit_indexer_settings_prompt_submit_selected_block(
|
||||||
|
#[case] selected_block: ActiveSonarrBlock,
|
||||||
|
#[case] y_index: usize,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.set_index(0, y_index);
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), selected_block.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_prompt_submit_selected_block_no_op_when_not_ready(
|
||||||
|
#[values(0, 1, 2, 3, 4)] y_index: usize,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.set_index(0, y_index);
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_selected_block_submit(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput
|
||||||
|
)]
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.push_navigation_stack(active_sonarr_block.into());
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(SUBMIT_KEY, &mut app, active_sonarr_block, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::models::sonarr_models::IndexerSettings;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_prompt_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
ESC_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.data.sonarr_data.indexer_settings, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_settings_selected_blocks_esc(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput
|
||||||
|
)]
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(active_sonarr_block.into());
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(ESC_KEY, &mut app, active_sonarr_block, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.indexer_settings,
|
||||||
|
Some(IndexerSettings::default())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_key_char {
|
||||||
|
use crate::{
|
||||||
|
models::{
|
||||||
|
servarr_data::sonarr::sonarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS,
|
||||||
|
sonarr_models::IndexerSettings, BlockSelectionState,
|
||||||
|
},
|
||||||
|
network::sonarr_network::SonarrEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_prompt_prompt_confirmation_confirm() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(0, INDEXER_SETTINGS_SELECTION_BLOCKS.len() - 1);
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
|
IndexerSettingsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(SonarrEvent::EditAllIndexerSettings(None))
|
||||||
|
);
|
||||||
|
assert!(app.data.sonarr_data.indexer_settings.is_some());
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexer_settings_handler_accepts() {
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if INDEXER_SETTINGS_BLOCKS.contains(&active_sonarr_block) {
|
||||||
|
assert!(IndexerSettingsHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!IndexerSettingsHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_handler_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = IndexerSettingsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_handler_not_ready_when_indexer_settings_is_none() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = IndexerSettingsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_settings_handler_ready_when_not_loading_and_indexer_settings_is_some() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
app.data.sonarr_data.indexer_settings = Some(IndexerSettings::default());
|
||||||
|
|
||||||
|
let handler = IndexerSettingsHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,704 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use rstest::rstest;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::sonarr_handlers::indexers::IndexersHandler;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
ActiveSonarrBlock, EDIT_INDEXER_BLOCKS, INDEXERS_BLOCKS, INDEXER_SETTINGS_BLOCKS,
|
||||||
|
};
|
||||||
|
use crate::models::servarr_models::Indexer;
|
||||||
|
use crate::test_handler_delegation;
|
||||||
|
|
||||||
|
mod test_handle_delete {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const DELETE_KEY: Key = DEFAULT_KEYBINDINGS.delete.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_indexer_prompt() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(DELETE_KEY, &mut app, ActiveSonarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_indexer_prompt_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(DELETE_KEY, &mut app, ActiveSonarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_left_right_action {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_indexers_tab_left(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(5);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.left.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::RootFolders.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::RootFolders.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_indexers_tab_right(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.main_tabs.set_index(5);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.right.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.main_tabs.get_active_route(),
|
||||||
|
ActiveSonarrBlock::System.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::System.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_left_right_delete_indexer_prompt_toggle(
|
||||||
|
#[values(DEFAULT_KEYBINDINGS.left.key, DEFAULT_KEYBINDINGS.right.key)] key: Key,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(key, &mut app, ActiveSonarrBlock::DeleteIndexerPrompt, None).handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
IndexersHandler::with(key, &mut app, ActiveSonarrBlock::DeleteIndexerPrompt, None).handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_submit {
|
||||||
|
use crate::models::servarr_data::modals::EditIndexerModal;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
SonarrData, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
||||||
|
};
|
||||||
|
use crate::models::servarr_models::{Indexer, IndexerField};
|
||||||
|
use bimap::BiMap;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use serde_json::{Number, Value};
|
||||||
|
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_edit_indexer_submit(#[values(true, false)] torrent_protocol: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
let protocol = if torrent_protocol {
|
||||||
|
"torrent".to_owned()
|
||||||
|
} else {
|
||||||
|
"usenet".to_owned()
|
||||||
|
};
|
||||||
|
let mut expected_edit_indexer_modal = EditIndexerModal {
|
||||||
|
name: "Test".into(),
|
||||||
|
enable_rss: Some(true),
|
||||||
|
enable_automatic_search: Some(true),
|
||||||
|
enable_interactive_search: Some(true),
|
||||||
|
url: "https://test.com".into(),
|
||||||
|
api_key: "1234".into(),
|
||||||
|
tags: "usenet, test".into(),
|
||||||
|
..EditIndexerModal::default()
|
||||||
|
};
|
||||||
|
let mut sonarr_data = SonarrData {
|
||||||
|
tags_map: BiMap::from_iter([(1, "usenet".to_owned()), (2, "test".to_owned())]),
|
||||||
|
..SonarrData::default()
|
||||||
|
};
|
||||||
|
let mut fields = vec![
|
||||||
|
IndexerField {
|
||||||
|
name: Some("baseUrl".to_owned()),
|
||||||
|
value: Some(Value::String("https://test.com".to_owned())),
|
||||||
|
},
|
||||||
|
IndexerField {
|
||||||
|
name: Some("apiKey".to_owned()),
|
||||||
|
value: Some(Value::String("1234".to_owned())),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if torrent_protocol {
|
||||||
|
fields.push(IndexerField {
|
||||||
|
name: Some("seedCriteria.seedRatio".to_owned()),
|
||||||
|
value: Some(Value::from(1.2f64)),
|
||||||
|
});
|
||||||
|
expected_edit_indexer_modal.seed_ratio = "1.2".into();
|
||||||
|
}
|
||||||
|
|
||||||
|
let indexer = Indexer {
|
||||||
|
name: Some("Test".to_owned()),
|
||||||
|
enable_rss: true,
|
||||||
|
enable_automatic_search: true,
|
||||||
|
enable_interactive_search: true,
|
||||||
|
protocol,
|
||||||
|
tags: vec![Number::from(1), Number::from(2)],
|
||||||
|
fields: Some(fields),
|
||||||
|
..Indexer::default()
|
||||||
|
};
|
||||||
|
sonarr_data.indexers.set_items(vec![indexer]);
|
||||||
|
app.data.sonarr_data = sonarr_data;
|
||||||
|
|
||||||
|
IndexersHandler::with(SUBMIT_KEY, &mut app, ActiveSonarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.edit_indexer_modal,
|
||||||
|
Some((&app.data.sonarr_data).into())
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.edit_indexer_modal,
|
||||||
|
Some(expected_edit_indexer_modal)
|
||||||
|
);
|
||||||
|
if torrent_protocol {
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.blocks,
|
||||||
|
EDIT_INDEXER_TORRENT_SELECTION_BLOCKS
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.blocks,
|
||||||
|
EDIT_INDEXER_NZB_SELECTION_BLOCKS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_edit_indexer_submit_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(SUBMIT_KEY, &mut app, ActiveSonarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert_eq!(app.data.sonarr_data.edit_indexer_modal, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_indexer_prompt_confirm_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(SonarrEvent::DeleteIndexer(None))
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_prompt_decline_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delete_indexer_prompt_block_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
ESC_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_test_indexer_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.data.sonarr_data.indexer_test_errors = Some("test result".to_owned());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::TestIndexer.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::TestIndexer, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert_eq!(app.data.sonarr_data.indexer_test_errors, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_default_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.error = "test error".to_owned().into();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(ESC_KEY, &mut app, ActiveSonarrBlock::Indexers, None).handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert!(app.error.text.is_empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_key_char {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
models::servarr_data::sonarr::sonarr_data::INDEXER_SETTINGS_SELECTION_BLOCKS,
|
||||||
|
network::sonarr_network::SonarrEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_indexers_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_refresh_indexers_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.refresh.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexer_settings_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.settings.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt.into()
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.blocks,
|
||||||
|
INDEXER_SETTINGS_SELECTION_BLOCKS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexer_settings_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.settings.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.test.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::TestIndexer.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.test.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_key() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.test_all.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::TestAllIndexers.into()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_key_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.test_all.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_indexer_prompt_confirm() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
|
||||||
|
IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(SonarrEvent::DeleteIndexer(None))
|
||||||
|
);
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delegates_edit_indexer_blocks_to_edit_indexer_handler(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::EditIndexerPrompt,
|
||||||
|
ActiveSonarrBlock::EditIndexerConfirmPrompt,
|
||||||
|
ActiveSonarrBlock::EditIndexerApiKeyInput,
|
||||||
|
ActiveSonarrBlock::EditIndexerNameInput,
|
||||||
|
ActiveSonarrBlock::EditIndexerSeedRatioInput,
|
||||||
|
ActiveSonarrBlock::EditIndexerToggleEnableRss,
|
||||||
|
ActiveSonarrBlock::EditIndexerToggleEnableAutomaticSearch,
|
||||||
|
ActiveSonarrBlock::EditIndexerToggleEnableInteractiveSearch,
|
||||||
|
ActiveSonarrBlock::EditIndexerUrlInput,
|
||||||
|
ActiveSonarrBlock::EditIndexerTagsInput
|
||||||
|
)]
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
test_handler_delegation!(
|
||||||
|
IndexersHandler,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
active_sonarr_block
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delegates_indexer_settings_blocks_to_indexer_settings_handler(
|
||||||
|
#[values(
|
||||||
|
ActiveSonarrBlock::AllIndexerSettingsPrompt,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsConfirmPrompt,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMaximumSizeInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsMinimumAgeInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRetentionInput,
|
||||||
|
ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput
|
||||||
|
)]
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
) {
|
||||||
|
test_handler_delegation!(
|
||||||
|
IndexersHandler,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
active_sonarr_block
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delegates_test_all_indexers_block_to_test_all_indexers_handler() {
|
||||||
|
test_handler_delegation!(
|
||||||
|
IndexersHandler,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
ActiveSonarrBlock::TestAllIndexers
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexers_handler_accepts() {
|
||||||
|
let mut indexers_blocks = Vec::new();
|
||||||
|
indexers_blocks.extend(INDEXERS_BLOCKS);
|
||||||
|
indexers_blocks.extend(INDEXER_SETTINGS_BLOCKS);
|
||||||
|
indexers_blocks.extend(EDIT_INDEXER_BLOCKS);
|
||||||
|
indexers_blocks.push(ActiveSonarrBlock::TestAllIndexers);
|
||||||
|
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if indexers_blocks.contains(&active_sonarr_block) {
|
||||||
|
assert!(IndexersHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!IndexersHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexers_handler_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexers_handler_not_ready_when_indexers_is_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_indexers_handler_ready_when_not_loading_and_indexers_is_not_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.set_items(vec![Indexer::default()]);
|
||||||
|
|
||||||
|
let handler = IndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::Indexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
|
||||||
|
use crate::handlers::sonarr_handlers::indexers::edit_indexer_handler::EditIndexerHandler;
|
||||||
|
use crate::handlers::sonarr_handlers::indexers::edit_indexer_settings_handler::IndexerSettingsHandler;
|
||||||
|
use crate::handlers::sonarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
|
use crate::handlers::{handle_clear_errors, handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
ActiveSonarrBlock, EDIT_INDEXER_NZB_SELECTION_BLOCKS, EDIT_INDEXER_TORRENT_SELECTION_BLOCKS,
|
||||||
|
INDEXERS_BLOCKS, INDEXER_SETTINGS_SELECTION_BLOCKS,
|
||||||
|
};
|
||||||
|
use crate::models::servarr_models::Indexer;
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
mod edit_indexer_handler;
|
||||||
|
mod edit_indexer_settings_handler;
|
||||||
|
mod test_all_indexers_handler;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "indexers_handler_tests.rs"]
|
||||||
|
mod indexers_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct IndexersHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> IndexersHandler<'a, 'b> {
|
||||||
|
handle_table_events!(self, indexers, self.app.data.sonarr_data.indexers, Indexer);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for IndexersHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let indexers_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveSonarrBlock::Indexers.into());
|
||||||
|
|
||||||
|
if !self.handle_indexers_table_events(indexers_table_handling_config) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
_ if EditIndexerHandler::accepts(self.active_sonarr_block) => {
|
||||||
|
EditIndexerHandler::with(self.key, self.app, self.active_sonarr_block, self.context)
|
||||||
|
.handle()
|
||||||
|
}
|
||||||
|
_ if IndexerSettingsHandler::accepts(self.active_sonarr_block) => {
|
||||||
|
IndexerSettingsHandler::with(self.key, self.app, self.active_sonarr_block, self.context)
|
||||||
|
.handle()
|
||||||
|
}
|
||||||
|
_ if TestAllIndexersHandler::accepts(self.active_sonarr_block) => {
|
||||||
|
TestAllIndexersHandler::with(self.key, self.app, self.active_sonarr_block, self.context)
|
||||||
|
.handle()
|
||||||
|
}
|
||||||
|
_ => self.handle_key_event(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
EditIndexerHandler::accepts(active_block)
|
||||||
|
|| IndexerSettingsHandler::accepts(active_block)
|
||||||
|
|| TestAllIndexersHandler::accepts(active_block)
|
||||||
|
|| INDEXERS_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> IndexersHandler<'a, 'b> {
|
||||||
|
IndexersHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && !self.app.data.sonarr_data.indexers.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::Indexers {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::DeleteIndexerPrompt.into());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Indexers => handle_change_tab_left_right_keys(self.app, self.key),
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt => handle_prompt_toggle(self.app, self.key),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt => {
|
||||||
|
let sonarr_data = &mut self.app.data.sonarr_data;
|
||||||
|
if sonarr_data.prompt_confirm {
|
||||||
|
sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteIndexer(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::Indexers => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::EditIndexerPrompt.into());
|
||||||
|
self.app.data.sonarr_data.edit_indexer_modal = Some((&self.app.data.sonarr_data).into());
|
||||||
|
let protocol = &self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexers
|
||||||
|
.current_selection()
|
||||||
|
.protocol;
|
||||||
|
if protocol == "torrent" {
|
||||||
|
self.app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(EDIT_INDEXER_TORRENT_SELECTION_BLOCKS);
|
||||||
|
} else {
|
||||||
|
self.app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(EDIT_INDEXER_NZB_SELECTION_BLOCKS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::TestIndexer => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.indexer_test_errors = None;
|
||||||
|
}
|
||||||
|
_ => handle_clear_errors(self.app),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
let key = self.key;
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::Indexers => match self.key {
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.refresh.key => {
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
}
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.test.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::TestIndexer.into());
|
||||||
|
}
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.test_all.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::TestAllIndexers.into());
|
||||||
|
}
|
||||||
|
_ if key == DEFAULT_KEYBINDINGS.settings.key => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::AllIndexerSettingsPrompt.into());
|
||||||
|
self.app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(INDEXER_SETTINGS_SELECTION_BLOCKS);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
ActiveSonarrBlock::DeleteIndexerPrompt => {
|
||||||
|
if key == DEFAULT_KEYBINDINGS.confirm.key {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteIndexer(None));
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handle_table_events;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "test_all_indexers_handler_tests.rs"]
|
||||||
|
mod test_all_indexers_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct TestAllIndexersHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> TestAllIndexersHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
indexer_test_all_results,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.indexer_test_all_results
|
||||||
|
.as_mut()
|
||||||
|
.unwrap(),
|
||||||
|
IndexerTestResultModalItem
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for TestAllIndexersHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let indexer_test_all_results_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveSonarrBlock::TestAllIndexers.into());
|
||||||
|
|
||||||
|
if !self
|
||||||
|
.handle_indexer_test_all_results_table_events(indexer_test_all_results_table_handling_config)
|
||||||
|
{
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
active_block == ActiveSonarrBlock::TestAllIndexers
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> TestAllIndexersHandler<'a, 'b> {
|
||||||
|
TestAllIndexersHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
let table_is_ready = if let Some(table) = &self.app.data.sonarr_data.indexer_test_all_results {
|
||||||
|
!table.is_empty()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
!self.app.is_loading && table_is_ready
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::TestAllIndexers {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.indexer_test_all_results = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::handlers::sonarr_handlers::indexers::test_all_indexers_handler::TestAllIndexersHandler;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::modals::IndexerTestResultModalItem;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use super::*;
|
||||||
|
use crate::models::stateful_table::StatefulTable;
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_test_all_indexers_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::TestAllIndexers.into());
|
||||||
|
app.data.sonarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
||||||
|
|
||||||
|
TestAllIndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::TestAllIndexers,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Indexers.into());
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(app.data.sonarr_data.indexer_test_all_results.is_none());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_indexers_handler_accepts() {
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if active_sonarr_block == ActiveSonarrBlock::TestAllIndexers {
|
||||||
|
assert!(TestAllIndexersHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!TestAllIndexersHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_indexers_handler_is_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = TestAllIndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::TestAllIndexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_indexers_handler_is_not_ready_when_results_is_none() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = TestAllIndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::TestAllIndexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_indexers_handler_is_not_ready_when_results_is_empty() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
app.data.sonarr_data.indexer_test_all_results = Some(StatefulTable::default());
|
||||||
|
|
||||||
|
let handler = TestAllIndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::TestAllIndexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_test_all_indexers_handler_is_ready_when_results_is_not_empty_and_is_loaded() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Indexers.into());
|
||||||
|
app.is_loading = false;
|
||||||
|
let mut indexer_test_results = StatefulTable::default();
|
||||||
|
indexer_test_results.set_items(vec![IndexerTestResultModalItem::default()]);
|
||||||
|
app.data.sonarr_data.indexer_test_all_results = Some(indexer_test_results);
|
||||||
|
|
||||||
|
let handler = TestAllIndexersHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::TestAllIndexers,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,544 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::handlers::table_handler::TableHandlingConfig;
|
||||||
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{
|
||||||
|
ActiveSonarrBlock, ADD_SERIES_BLOCKS, ADD_SERIES_SELECTION_BLOCKS,
|
||||||
|
};
|
||||||
|
use crate::models::sonarr_models::AddSeriesSearchResult;
|
||||||
|
use crate::models::{BlockSelectionState, Scrollable};
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
use crate::{handle_table_events, handle_text_box_keys, handle_text_box_left_right_keys, App, Key};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "add_series_handler_tests.rs"]
|
||||||
|
mod add_series_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct AddSeriesHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> AddSeriesHandler<'a, 'b> {
|
||||||
|
handle_table_events!(
|
||||||
|
self,
|
||||||
|
add_searched_series,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_searched_series
|
||||||
|
.as_mut()
|
||||||
|
.unwrap(),
|
||||||
|
AddSeriesSearchResult
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for AddSeriesHandler<'a, 'b> {
|
||||||
|
fn handle(&mut self) {
|
||||||
|
let add_series_table_handling_config =
|
||||||
|
TableHandlingConfig::new(ActiveSonarrBlock::AddSeriesSearchResults.into());
|
||||||
|
|
||||||
|
if !self.handle_add_searched_series_table_events(add_series_table_handling_config) {
|
||||||
|
self.handle_key_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
ADD_SERIES_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> AddSeriesHandler<'a, 'b> {
|
||||||
|
AddSeriesHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.monitor_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectRootFolder => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.root_folder_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt => self.app.data.sonarr_data.selected_block.up(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.monitor_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectRootFolder => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.root_folder_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt => self.app.data.sonarr_data.selected_block.down(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.monitor_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectRootFolder => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.root_folder_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_search
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.scroll_home(),
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.scroll_home(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.monitor_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectRootFolder => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.root_folder_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_search
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.reset_offset(),
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.reset_offset(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt => handle_prompt_toggle(self.app, self.key),
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_search
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
_ if self.active_sonarr_block == ActiveSonarrBlock::AddSeriesSearchInput
|
||||||
|
&& !self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_search
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.text
|
||||||
|
.is_empty() =>
|
||||||
|
{
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::AddSeriesSearchResults.into());
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
_ if self.active_sonarr_block == ActiveSonarrBlock::AddSeriesSearchResults
|
||||||
|
&& self.app.data.sonarr_data.add_searched_series.is_some() =>
|
||||||
|
{
|
||||||
|
let tvdb_id = self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_searched_series
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.current_selection()
|
||||||
|
.tvdb_id;
|
||||||
|
|
||||||
|
if self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.series
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.any(|series| series.tvdb_id == tvdb_id)
|
||||||
|
{
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::AddSeriesAlreadyInLibrary.into());
|
||||||
|
} else {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.push_navigation_stack(ActiveSonarrBlock::AddSeriesPrompt.into());
|
||||||
|
self.app.data.sonarr_data.add_series_modal = Some((&self.app.data.sonarr_data).into());
|
||||||
|
self.app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(ADD_SERIES_SELECTION_BLOCKS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt => {
|
||||||
|
match self.app.data.sonarr_data.selected_block.get_active_block() {
|
||||||
|
ActiveSonarrBlock::AddSeriesConfirmPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::AddSeries(None));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectLanguageProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.push_navigation_stack(
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.get_active_block()
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => {
|
||||||
|
self.app.push_navigation_stack(
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.get_active_block()
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
self.app.should_ignore_quit_key = true;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesToggleUseSeasonFolder => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.use_season_folder = !self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.use_season_folder;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectLanguageProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.pop_navigation_stack(),
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.add_series_search = None;
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchResults
|
||||||
|
| ActiveSonarrBlock::AddSeriesEmptySearchResults => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.add_searched_series = None;
|
||||||
|
self.app.should_ignore_quit_key = true;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.add_series_modal = None;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesSelectMonitor
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectLanguageProfile
|
||||||
|
| ActiveSonarrBlock::AddSeriesAlreadyInLibrary
|
||||||
|
| ActiveSonarrBlock::AddSeriesSelectRootFolder => self.app.pop_navigation_stack(),
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
let key = self.key;
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::AddSeriesSearchInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_search
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesTagsInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.add_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::AddSeriesPrompt => {
|
||||||
|
if self.app.data.sonarr_data.selected_block.get_active_block()
|
||||||
|
== ActiveSonarrBlock::AddSeriesConfirmPrompt
|
||||||
|
&& key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
|
{
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::AddSeries(None));
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
use crate::{
|
||||||
|
app::{key_binding::DEFAULT_KEYBINDINGS, App},
|
||||||
|
event::Key,
|
||||||
|
handlers::{handle_prompt_toggle, KeyEventHandler},
|
||||||
|
models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DELETE_SERIES_BLOCKS},
|
||||||
|
network::sonarr_network::SonarrEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "delete_series_handler_tests.rs"]
|
||||||
|
mod delete_series_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct DeleteSeriesHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for DeleteSeriesHandler<'a, 'b> {
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
DELETE_SERIES_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
_context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> Self {
|
||||||
|
DeleteSeriesHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
_context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt {
|
||||||
|
self.app.data.sonarr_data.selected_block.up();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt {
|
||||||
|
self.app.data.sonarr_data.selected_block.down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt {
|
||||||
|
handle_prompt_toggle(self.app, self.key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt {
|
||||||
|
match self.app.data.sonarr_data.selected_block.get_active_block() {
|
||||||
|
ActiveSonarrBlock::DeleteSeriesConfirmPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteSeries(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
} else {
|
||||||
|
self.app.data.sonarr_data.reset_delete_series_preferences();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::DeleteSeriesToggleDeleteFile => {
|
||||||
|
self.app.data.sonarr_data.delete_series_files =
|
||||||
|
!self.app.data.sonarr_data.delete_series_files;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::DeleteSeriesToggleAddListExclusion => {
|
||||||
|
self.app.data.sonarr_data.add_list_exclusion =
|
||||||
|
!self.app.data.sonarr_data.add_list_exclusion;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.reset_delete_series_preferences();
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
if self.active_sonarr_block == ActiveSonarrBlock::DeleteSeriesPrompt
|
||||||
|
&& self.app.data.sonarr_data.selected_block.get_active_block()
|
||||||
|
== ActiveSonarrBlock::DeleteSeriesConfirmPrompt
|
||||||
|
&& self.key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
|
{
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::DeleteSeries(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,339 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use strum::IntoEnumIterator;
|
||||||
|
|
||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::sonarr_handlers::library::delete_series_handler::DeleteSeriesHandler;
|
||||||
|
use crate::handlers::KeyEventHandler;
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, DELETE_SERIES_BLOCKS};
|
||||||
|
|
||||||
|
mod test_handle_scroll_up_and_down {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::DELETE_SERIES_SELECTION_BLOCKS;
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delete_series_prompt_scroll(#[values(Key::Up, Key::Down)] key: Key) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(DELETE_SERIES_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.down();
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(key, &mut app, ActiveSonarrBlock::DeleteSeriesPrompt, None)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
if key == Key::Up {
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
ActiveSonarrBlock::DeleteSeriesToggleDeleteFile
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
ActiveSonarrBlock::DeleteSeriesConfirmPrompt
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delete_series_prompt_scroll_no_op_when_not_ready(
|
||||||
|
#[values(Key::Up, Key::Down)] key: Key,
|
||||||
|
) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(DELETE_SERIES_SELECTION_BLOCKS);
|
||||||
|
app.data.sonarr_data.selected_block.down();
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(key, &mut app, ActiveSonarrBlock::DeleteSeriesPrompt, None)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
ActiveSonarrBlock::DeleteSeriesToggleAddListExclusion
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_left_right_action {
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_left_right_prompt_toggle(#[values(Key::Left, Key::Right)] key: Key) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(key, &mut app, ActiveSonarrBlock::DeleteSeriesPrompt, None)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(key, &mut app, ActiveSonarrBlock::DeleteSeriesPrompt, None)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_submit {
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::DELETE_SERIES_SELECTION_BLOCKS;
|
||||||
|
use crate::models::BlockSelectionState;
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SUBMIT_KEY: Key = DEFAULT_KEYBINDINGS.submit.key;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_prompt_prompt_decline_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(DELETE_SERIES_SELECTION_BLOCKS);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(0, DELETE_SERIES_SELECTION_BLOCKS.len() - 1);
|
||||||
|
app.data.sonarr_data.delete_series_files = true;
|
||||||
|
app.data.sonarr_data.add_list_exclusion = true;
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(!app.data.sonarr_data.delete_series_files);
|
||||||
|
assert!(!app.data.sonarr_data.add_list_exclusion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_confirm_prompt_prompt_confirmation_submit() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
app.data.sonarr_data.delete_series_files = true;
|
||||||
|
app.data.sonarr_data.add_list_exclusion = true;
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(DELETE_SERIES_SELECTION_BLOCKS);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(0, DELETE_SERIES_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(SonarrEvent::DeleteSeries(None))
|
||||||
|
);
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(app.data.sonarr_data.delete_series_files);
|
||||||
|
assert!(app.data.sonarr_data.add_list_exclusion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_confirm_prompt_prompt_confirmation_submit_no_op_when_not_ready() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
app.data.sonarr_data.delete_series_files = true;
|
||||||
|
app.data.sonarr_data.add_list_exclusion = true;
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.get_current_route(),
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt.into()
|
||||||
|
);
|
||||||
|
assert_eq!(app.data.sonarr_data.prompt_confirm_action, None);
|
||||||
|
assert!(!app.should_refresh);
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(app.data.sonarr_data.delete_series_files);
|
||||||
|
assert!(app.data.sonarr_data.add_list_exclusion);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_toggle_delete_files_submit() {
|
||||||
|
let current_route = ActiveSonarrBlock::DeleteSeriesPrompt.into();
|
||||||
|
let mut app = App::default();
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(DELETE_SERIES_SELECTION_BLOCKS);
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
|
assert_eq!(app.data.sonarr_data.delete_series_files, true);
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
SUBMIT_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), current_route);
|
||||||
|
assert_eq!(app.data.sonarr_data.delete_series_files, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_esc {
|
||||||
|
use super::*;
|
||||||
|
use rstest::rstest;
|
||||||
|
|
||||||
|
const ESC_KEY: Key = DEFAULT_KEYBINDINGS.esc.key;
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
fn test_delete_series_prompt_esc(#[values(true, false)] is_ready: bool) {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = is_ready;
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
app.data.sonarr_data.delete_series_files = true;
|
||||||
|
app.data.sonarr_data.add_list_exclusion = true;
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
ESC_KEY,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
|
||||||
|
assert!(!app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(!app.data.sonarr_data.delete_series_files);
|
||||||
|
assert!(!app.data.sonarr_data.add_list_exclusion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod test_handle_key_char {
|
||||||
|
use crate::{
|
||||||
|
models::{
|
||||||
|
servarr_data::sonarr::sonarr_data::DELETE_SERIES_SELECTION_BLOCKS, BlockSelectionState,
|
||||||
|
},
|
||||||
|
network::sonarr_network::SonarrEvent,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_confirm_prompt_prompt_confirm() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::Series.into());
|
||||||
|
app.push_navigation_stack(ActiveSonarrBlock::DeleteSeriesPrompt.into());
|
||||||
|
app.data.sonarr_data.delete_series_files = true;
|
||||||
|
app.data.sonarr_data.add_list_exclusion = true;
|
||||||
|
app.data.sonarr_data.selected_block =
|
||||||
|
BlockSelectionState::new(DELETE_SERIES_SELECTION_BLOCKS);
|
||||||
|
app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.selected_block
|
||||||
|
.set_index(0, DELETE_SERIES_SELECTION_BLOCKS.len() - 1);
|
||||||
|
|
||||||
|
DeleteSeriesHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.confirm.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
.handle();
|
||||||
|
|
||||||
|
assert_eq!(app.get_current_route(), ActiveSonarrBlock::Series.into());
|
||||||
|
assert_eq!(
|
||||||
|
app.data.sonarr_data.prompt_confirm_action,
|
||||||
|
Some(SonarrEvent::DeleteSeries(None))
|
||||||
|
);
|
||||||
|
assert!(app.should_refresh);
|
||||||
|
assert!(app.data.sonarr_data.prompt_confirm);
|
||||||
|
assert!(app.data.sonarr_data.delete_series_files);
|
||||||
|
assert!(app.data.sonarr_data.add_list_exclusion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_handler_accepts() {
|
||||||
|
ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
|
||||||
|
if DELETE_SERIES_BLOCKS.contains(&active_sonarr_block) {
|
||||||
|
assert!(DeleteSeriesHandler::accepts(active_sonarr_block));
|
||||||
|
} else {
|
||||||
|
assert!(!DeleteSeriesHandler::accepts(active_sonarr_block));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_handler_not_ready_when_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = true;
|
||||||
|
|
||||||
|
let handler = DeleteSeriesHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(!handler.is_ready());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_delete_series_handler_ready_when_not_loading() {
|
||||||
|
let mut app = App::default();
|
||||||
|
app.is_loading = false;
|
||||||
|
|
||||||
|
let handler = DeleteSeriesHandler::with(
|
||||||
|
DEFAULT_KEYBINDINGS.esc.key,
|
||||||
|
&mut app,
|
||||||
|
ActiveSonarrBlock::DeleteSeriesPrompt,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert!(handler.is_ready());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,404 @@
|
|||||||
|
use crate::app::key_binding::DEFAULT_KEYBINDINGS;
|
||||||
|
use crate::app::App;
|
||||||
|
use crate::event::Key;
|
||||||
|
use crate::handlers::{handle_prompt_toggle, KeyEventHandler};
|
||||||
|
use crate::models::servarr_data::sonarr::sonarr_data::{ActiveSonarrBlock, EDIT_SERIES_BLOCKS};
|
||||||
|
use crate::models::Scrollable;
|
||||||
|
use crate::network::sonarr_network::SonarrEvent;
|
||||||
|
use crate::{handle_text_box_keys, handle_text_box_left_right_keys};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "edit_series_handler_tests.rs"]
|
||||||
|
mod edit_series_handler_tests;
|
||||||
|
|
||||||
|
pub(super) struct EditSeriesHandler<'a, 'b> {
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_sonarr_block: ActiveSonarrBlock,
|
||||||
|
context: Option<ActiveSonarrBlock>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> KeyEventHandler<'a, 'b, ActiveSonarrBlock> for EditSeriesHandler<'a, 'b> {
|
||||||
|
fn accepts(active_block: ActiveSonarrBlock) -> bool {
|
||||||
|
EDIT_SERIES_BLOCKS.contains(&active_block)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn with(
|
||||||
|
key: Key,
|
||||||
|
app: &'a mut App<'b>,
|
||||||
|
active_block: ActiveSonarrBlock,
|
||||||
|
context: Option<ActiveSonarrBlock>,
|
||||||
|
) -> EditSeriesHandler<'a, 'b> {
|
||||||
|
EditSeriesHandler {
|
||||||
|
key,
|
||||||
|
app,
|
||||||
|
active_sonarr_block: active_block,
|
||||||
|
context,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_key(&self) -> Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_ready(&self) -> bool {
|
||||||
|
!self.app.is_loading && self.app.data.sonarr_data.edit_series_modal.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_up(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_up(),
|
||||||
|
ActiveSonarrBlock::EditSeriesPrompt => self.app.data.sonarr_data.selected_block.up(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_scroll_down(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_down(),
|
||||||
|
ActiveSonarrBlock::EditSeriesPrompt => self.app.data.sonarr_data.selected_block.down(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_home(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_to_top(),
|
||||||
|
ActiveSonarrBlock::EditSeriesPathInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.path
|
||||||
|
.scroll_home(),
|
||||||
|
ActiveSonarrBlock::EditSeriesTagsInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.scroll_home(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_end(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.series_type_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectQualityProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.quality_profile_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.language_profile_list
|
||||||
|
.scroll_to_bottom(),
|
||||||
|
ActiveSonarrBlock::EditSeriesPathInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.path
|
||||||
|
.reset_offset(),
|
||||||
|
ActiveSonarrBlock::EditSeriesTagsInput => self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
.reset_offset(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_delete(&mut self) {}
|
||||||
|
|
||||||
|
fn handle_left_right_action(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesPrompt => handle_prompt_toggle(self.app, self.key),
|
||||||
|
ActiveSonarrBlock::EditSeriesPathInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesTagsInput => {
|
||||||
|
handle_text_box_left_right_keys!(
|
||||||
|
self,
|
||||||
|
self.key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_submit(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesPrompt => {
|
||||||
|
match self.app.data.sonarr_data.selected_block.get_active_block() {
|
||||||
|
ActiveSonarrBlock::EditSeriesConfirmPrompt => {
|
||||||
|
if self.app.data.sonarr_data.prompt_confirm {
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditSeries(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::EditSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self.app.push_navigation_stack(
|
||||||
|
(
|
||||||
|
self.app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
self.context,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
),
|
||||||
|
ActiveSonarrBlock::EditSeriesPathInput | ActiveSonarrBlock::EditSeriesTagsInput => {
|
||||||
|
self.app.push_navigation_stack(
|
||||||
|
(
|
||||||
|
self.app.data.sonarr_data.selected_block.get_active_block(),
|
||||||
|
self.context,
|
||||||
|
)
|
||||||
|
.into(),
|
||||||
|
);
|
||||||
|
self.app.should_ignore_quit_key = true;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesToggleMonitored => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.monitored = Some(
|
||||||
|
!self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.monitored
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesToggleSeasonFolder => {
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.use_season_folders = Some(
|
||||||
|
!self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.use_season_folders
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::EditSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self.app.pop_navigation_stack(),
|
||||||
|
ActiveSonarrBlock::EditSeriesPathInput | ActiveSonarrBlock::EditSeriesTagsInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_esc(&mut self) {
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesTagsInput | ActiveSonarrBlock::EditSeriesPathInput => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.should_ignore_quit_key = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesPrompt => {
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
self.app.data.sonarr_data.edit_series_modal = None;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = false;
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesSelectSeriesType
|
||||||
|
| ActiveSonarrBlock::EditSeriesSelectQualityProfile
|
||||||
|
| ActiveSonarrBlock::EditSeriesSelectLanguageProfile => self.app.pop_navigation_stack(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_char_key_event(&mut self) {
|
||||||
|
let key = self.key;
|
||||||
|
match self.active_sonarr_block {
|
||||||
|
ActiveSonarrBlock::EditSeriesPathInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.path
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesTagsInput => {
|
||||||
|
handle_text_box_keys!(
|
||||||
|
self,
|
||||||
|
key,
|
||||||
|
self
|
||||||
|
.app
|
||||||
|
.data
|
||||||
|
.sonarr_data
|
||||||
|
.edit_series_modal
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.tags
|
||||||
|
)
|
||||||
|
}
|
||||||
|
ActiveSonarrBlock::EditSeriesPrompt => {
|
||||||
|
if self.app.data.sonarr_data.selected_block.get_active_block()
|
||||||
|
== ActiveSonarrBlock::EditSeriesConfirmPrompt
|
||||||
|
&& key == DEFAULT_KEYBINDINGS.confirm.key
|
||||||
|
{
|
||||||
|
self.app.data.sonarr_data.prompt_confirm = true;
|
||||||
|
self.app.data.sonarr_data.prompt_confirm_action = Some(SonarrEvent::EditSeries(None));
|
||||||
|
self.app.should_refresh = true;
|
||||||
|
|
||||||
|
self.app.pop_navigation_stack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||