Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c48f043f7c | ||
|
|
fbc214d56c | ||
|
|
486ce47c39 | ||
|
|
b9ac324d21 | ||
|
|
5494a4a26b | ||
|
|
174d5440f5 | ||
|
|
62745172dd | ||
|
|
6319f2c270 | ||
|
|
0dd30c6c14 | ||
|
|
06f7cb5c8c | ||
|
|
e1c519adf5 | ||
|
|
ae86f6962a | ||
|
|
4f95404f0b | ||
|
|
0d7e4b5c3a | ||
|
|
ac133fd5b6 | ||
|
|
35c30b8213 | ||
|
|
948b930395 | ||
|
|
a2a7bc6100 | ||
|
|
0c1a9f86d6 | ||
|
|
ab32f01e07 | ||
|
|
07f6919617 | ||
|
|
1d84985a76 | ||
|
|
33d635839f | ||
|
|
abf0cd2359 | ||
|
|
02fc32942a | ||
|
|
ccfca0dd25 | ||
|
|
60f12cc333 | ||
|
|
63737e46eb | ||
|
|
2fb8d34ec1 | ||
|
|
12871ef7d2 | ||
|
|
d317ce6179 | ||
|
|
0c071c0621 | ||
|
|
71c3733363 | ||
|
|
03bfc8fc16 | ||
|
|
56b9a186d4 | ||
|
|
0f46cb3c93 | ||
|
|
08d64bbaaf | ||
|
|
a79c082d45 |
@@ -0,0 +1,179 @@
|
|||||||
|
name: Build and Release Court Pilot
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
CN_APPLICATION: 'trweb/court-pilot'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# Create CrabNebula draft release
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
draft:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Create CrabNebula draft release
|
||||||
|
uses: crabnebula-dev/cloud-release@v0
|
||||||
|
with:
|
||||||
|
command: release draft ${{ env.CN_APPLICATION }} --framework tauri
|
||||||
|
api-key: ${{ secrets.CN_API_KEY }}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# Windows Tauri build
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
windows:
|
||||||
|
needs: draft
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Install Ionic CLI
|
||||||
|
run: npm install -g @ionic/cli
|
||||||
|
|
||||||
|
- name: Build Tauri app
|
||||||
|
env:
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||||
|
run: npm run tauri build
|
||||||
|
|
||||||
|
- name: Upload release assets to CrabNebula
|
||||||
|
uses: crabnebula-dev/cloud-release@v0
|
||||||
|
with:
|
||||||
|
command: release upload ${{ env.CN_APPLICATION }} --framework tauri
|
||||||
|
api-key: ${{ secrets.CN_API_KEY }}
|
||||||
|
path: ./src-tauri
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# Linux Tauri build + Snap
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
snap:
|
||||||
|
needs: draft
|
||||||
|
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 22
|
||||||
|
cache: npm
|
||||||
|
|
||||||
|
- name: Setup Rust
|
||||||
|
uses: actions-rust-lang/setup-rust-toolchain@v1
|
||||||
|
with:
|
||||||
|
toolchain: stable
|
||||||
|
cache: true
|
||||||
|
|
||||||
|
- name: Install Linux dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y \
|
||||||
|
libssl-dev \
|
||||||
|
libxdo-dev \
|
||||||
|
libayatana-appindicator3-dev \
|
||||||
|
librsvg2-dev \
|
||||||
|
libwebkit2gtk-4.1-dev \
|
||||||
|
dpkg
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: Install Ionic CLI
|
||||||
|
run: npm install -g @ionic/cli
|
||||||
|
|
||||||
|
- name: Build Tauri Debian package
|
||||||
|
env:
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
|
||||||
|
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}
|
||||||
|
run: npm run tauri build -- --bundles deb
|
||||||
|
|
||||||
|
- name: Extract Debian package
|
||||||
|
run: |
|
||||||
|
rm -rf snap-root
|
||||||
|
mkdir -p snap-root
|
||||||
|
|
||||||
|
dpkg -x src-tauri/target/release/bundle/deb/*.deb snap-root/
|
||||||
|
|
||||||
|
- name: Show extracted Snap filesystem
|
||||||
|
run: |
|
||||||
|
echo "Snap root:"
|
||||||
|
find snap-root -maxdepth 5 -type f | sort
|
||||||
|
|
||||||
|
- name: Build Snap
|
||||||
|
uses: snapcore/action-build@v1
|
||||||
|
id: snapcraft
|
||||||
|
with:
|
||||||
|
snapcraft-channel: stable
|
||||||
|
|
||||||
|
- name: Show generated Snap
|
||||||
|
run: |
|
||||||
|
echo "Snap created:"
|
||||||
|
echo "${{ steps.snapcraft.outputs.snap }}"
|
||||||
|
|
||||||
|
- name: Upload Snap as GitHub artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: court-pilot-snap
|
||||||
|
path: ${{ steps.snapcraft.outputs.snap }}
|
||||||
|
|
||||||
|
- name: Publish Snap to Snap Store
|
||||||
|
uses: snapcore/action-publish@v1
|
||||||
|
env:
|
||||||
|
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
|
||||||
|
with:
|
||||||
|
snap: ${{ steps.snapcraft.outputs.snap }}
|
||||||
|
release: stable
|
||||||
|
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
# Publish CrabNebula release
|
||||||
|
# ---------------------------------------------------------
|
||||||
|
publish:
|
||||||
|
needs:
|
||||||
|
- windows
|
||||||
|
- snap
|
||||||
|
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Publish CrabNebula release
|
||||||
|
uses: crabnebula-dev/cloud-release@v0
|
||||||
|
with:
|
||||||
|
command: release publish ${{ env.CN_APPLICATION }} --framework tauri
|
||||||
|
api-key: ${{ secrets.CN_API_KEY }}
|
||||||
|
path: ./src-tauri
|
||||||
|
working-directory: ./src-tauri
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 Court Pilot
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import Dexie, { type EntityTable } from 'dexie';
|
||||||
|
|
||||||
|
export interface Umpire {
|
||||||
|
id: number;
|
||||||
|
firstName: string;
|
||||||
|
lastName: string;
|
||||||
|
country: string;
|
||||||
|
gender: string;
|
||||||
|
courtNo?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CourtUmpire {
|
||||||
|
id: number;
|
||||||
|
umpireId: number | null;
|
||||||
|
courtNo: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CourtServiceJudge {
|
||||||
|
id: number;
|
||||||
|
umpireId: number | null;
|
||||||
|
courtNo: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WaitingAsUmpire {
|
||||||
|
id: number;
|
||||||
|
umpireId: number;
|
||||||
|
order: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface WaitingAsServiceJudge {
|
||||||
|
id: number;
|
||||||
|
serviceJudgeId: number;
|
||||||
|
order: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Settings {
|
||||||
|
id: number;
|
||||||
|
withServiceJudge: boolean;
|
||||||
|
numberOfCourts: number;
|
||||||
|
showAlert: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const db = new Dexie('CourtPilot') as Dexie & {
|
||||||
|
umpires: EntityTable<Umpire, 'id'>;
|
||||||
|
courtUmpires: EntityTable<CourtUmpire, 'id'>;
|
||||||
|
courtServiceJudges: EntityTable<CourtServiceJudge, 'id'>;
|
||||||
|
settings: EntityTable<Settings, 'id'>;
|
||||||
|
waitingUmpires: EntityTable<WaitingAsUmpire, 'id'>;
|
||||||
|
waitingServiceJudges: EntityTable<WaitingAsServiceJudge, 'id'>;
|
||||||
|
};
|
||||||
|
|
||||||
|
db.version(1).stores({
|
||||||
|
umpires: '++id, lastName',
|
||||||
|
courtUmpires: '++id, courtNo, umpireId',
|
||||||
|
courtServiceJudges: '++id, courtNo, umpireId',
|
||||||
|
settings: '++id',
|
||||||
|
waitingUmpires: '++id, order, umpireId',
|
||||||
|
waitingServiceJudges: '++id, order, serviceJudgeId'
|
||||||
|
});
|
||||||
|
|
||||||
|
export { db };
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "court-pilot",
|
"name": "court-pilot",
|
||||||
"version": "0.0.1",
|
"version": "1.1.3",
|
||||||
"author": "Ionic Framework",
|
"author": "Ionic Framework",
|
||||||
"homepage": "https://ionicframework.com/",
|
"homepage": "https://ionicframework.com/",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -9,39 +9,45 @@
|
|||||||
"build": "ng build",
|
"build": "ng build",
|
||||||
"watch": "ng build --watch --configuration development",
|
"watch": "ng build --watch --configuration development",
|
||||||
"test": "ng test",
|
"test": "ng test",
|
||||||
"lint": "ng lint"
|
"lint": "ng lint",
|
||||||
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^20.0.0",
|
"@angular/animations": "^20.3.28",
|
||||||
"@angular/common": "^20.0.0",
|
"@angular/cdk": "^20.2.14",
|
||||||
"@angular/compiler": "^20.0.0",
|
"@angular/common": "^20.3.28",
|
||||||
"@angular/core": "^20.0.0",
|
"@angular/compiler": "^20.3.28",
|
||||||
"@angular/forms": "^20.0.0",
|
"@angular/core": "^20.3.28",
|
||||||
"@angular/platform-browser": "^20.0.0",
|
"@angular/forms": "^20.3.28",
|
||||||
"@angular/platform-browser-dynamic": "^20.0.0",
|
"@angular/platform-browser": "^20.3.28",
|
||||||
"@angular/router": "^20.0.0",
|
"@angular/platform-browser-dynamic": "^20.3.28",
|
||||||
|
"@angular/router": "^20.3.28",
|
||||||
"@capacitor/app": "8.1.0",
|
"@capacitor/app": "8.1.0",
|
||||||
"@capacitor/core": "8.3.4",
|
"@capacitor/core": "8.3.4",
|
||||||
"@capacitor/haptics": "8.0.2",
|
"@capacitor/haptics": "8.0.2",
|
||||||
"@capacitor/keyboard": "8.0.3",
|
"@capacitor/keyboard": "8.0.3",
|
||||||
"@capacitor/status-bar": "8.0.2",
|
"@capacitor/status-bar": "8.0.2",
|
||||||
"@ionic/angular": "^8.0.0",
|
"@ionic/angular": "^8.0.0",
|
||||||
|
"@tauri-apps/plugin-os": "^2.3.2",
|
||||||
|
"@tauri-apps/plugin-process": "^2.3.1",
|
||||||
|
"@tauri-apps/plugin-updater": "^2.10.1",
|
||||||
|
"dexie": "^4.4.2",
|
||||||
"ionicons": "^7.0.0",
|
"ionicons": "^7.0.0",
|
||||||
"rxjs": "~7.8.0",
|
"rxjs": "~7.8.0",
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"zone.js": "~0.15.0"
|
"zone.js": "~0.15.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^20.0.0",
|
"@angular-devkit/build-angular": "^20.3.34",
|
||||||
"@angular-eslint/builder": "^20.0.0",
|
"@angular-eslint/builder": "^20.3.0",
|
||||||
"@angular-eslint/eslint-plugin": "^20.0.0",
|
"@angular-eslint/eslint-plugin": "^20.3.0",
|
||||||
"@angular-eslint/eslint-plugin-template": "^20.0.0",
|
"@angular-eslint/eslint-plugin-template": "^20.3.0",
|
||||||
"@angular-eslint/schematics": "^20.0.0",
|
"@angular-eslint/schematics": "^20.3.0",
|
||||||
"@angular-eslint/template-parser": "^20.0.0",
|
"@angular-eslint/template-parser": "^20.3.0",
|
||||||
"@angular/cli": "^20.0.0",
|
"@angular/cli": "^20.3.34",
|
||||||
"@angular/compiler-cli": "^20.0.0",
|
"@angular/compiler-cli": "^20.3.28",
|
||||||
"@angular/language-service": "^20.0.0",
|
"@angular/language-service": "^20.3.28",
|
||||||
"@capacitor/cli": "8.3.4",
|
"@capacitor/cli": "8.3.4",
|
||||||
"@ionic/angular-toolkit": "^12.0.0",
|
"@ionic/angular-toolkit": "^12.0.0",
|
||||||
"@tauri-apps/cli": "^2.11.2",
|
"@tauri-apps/cli": "^2.11.2",
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Desktop Entry]
|
||||||
|
Categories=
|
||||||
|
Comment=Court Pilot
|
||||||
|
Exec=court-pilot
|
||||||
|
StartupWMClass=court-pilot
|
||||||
|
Icon=${SNAP}/meta/gui/court-pilot.png
|
||||||
|
Name=court-pilot
|
||||||
|
Terminal=false
|
||||||
|
Type=Application
|
||||||
|
After Width: | Height: | Size: 44 KiB |
@@ -0,0 +1,48 @@
|
|||||||
|
name: court-pilot
|
||||||
|
title: Court Pilot
|
||||||
|
contact:
|
||||||
|
- toth.richard@trweb.hu
|
||||||
|
issues:
|
||||||
|
- https://github.com/tricsusz/court-pilot/issues
|
||||||
|
source-code:
|
||||||
|
- https://github.com/tricsusz/court-pilot
|
||||||
|
website:
|
||||||
|
- https://github.com/tricsusz/court-pilot
|
||||||
|
license: MIT
|
||||||
|
base: core24
|
||||||
|
icon: snap/gui/court-pilot.png
|
||||||
|
|
||||||
|
version: '1.1.4'
|
||||||
|
|
||||||
|
summary: Badminton umpire rotation application
|
||||||
|
|
||||||
|
description: |
|
||||||
|
Court Pilot is a desktop application for managing badminton
|
||||||
|
umpire rotations and court assignments.
|
||||||
|
|
||||||
|
grade: stable
|
||||||
|
confinement: strict
|
||||||
|
|
||||||
|
apps:
|
||||||
|
court-pilot:
|
||||||
|
command: usr/bin/court-pilot
|
||||||
|
desktop: usr/share/applications/court-pilot.desktop
|
||||||
|
|
||||||
|
extensions:
|
||||||
|
- gnome
|
||||||
|
|
||||||
|
plugs:
|
||||||
|
- network
|
||||||
|
- home
|
||||||
|
|
||||||
|
environment:
|
||||||
|
LD_LIBRARY_PATH: $SNAP_DESKTOP_RUNTIME/usr/lib/x86_64-linux-gnu:$LD_LIBRARY_PATH
|
||||||
|
|
||||||
|
parts:
|
||||||
|
court-pilot:
|
||||||
|
plugin: dump
|
||||||
|
source: snap-root
|
||||||
|
|
||||||
|
stage-packages:
|
||||||
|
- libwebkit2gtk-4.1-0
|
||||||
|
- libayatana-appindicator3-1
|
||||||
@@ -76,15 +76,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "app"
|
name = "arbitrary"
|
||||||
version = "0.1.0"
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"derive_arbitrary",
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tauri",
|
|
||||||
"tauri-build",
|
|
||||||
"tauri-plugin-log",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -503,6 +500,21 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "court-pilot"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"log",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tauri",
|
||||||
|
"tauri-build",
|
||||||
|
"tauri-plugin-log",
|
||||||
|
"tauri-plugin-os",
|
||||||
|
"tauri-plugin-process",
|
||||||
|
"tauri-plugin-updater",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cpufeatures"
|
name = "cpufeatures"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -640,6 +652,17 @@ dependencies = [
|
|||||||
"serde_core",
|
"serde_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "derive_arbitrary"
|
||||||
|
version = "1.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "derive_more"
|
name = "derive_more"
|
||||||
version = "2.1.1"
|
version = "2.1.1"
|
||||||
@@ -851,6 +874,16 @@ dependencies = [
|
|||||||
"typeid",
|
"typeid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "errno"
|
||||||
|
version = "0.3.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.4.1"
|
version = "2.4.1"
|
||||||
@@ -885,6 +918,16 @@ dependencies = [
|
|||||||
"rustc_version",
|
"rustc_version",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "filetime"
|
||||||
|
version = "0.2.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.9"
|
||||||
@@ -1141,6 +1184,16 @@ dependencies = [
|
|||||||
"version_check",
|
"version_check",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "gethostname"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8"
|
||||||
|
dependencies = [
|
||||||
|
"rustix",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "getrandom"
|
name = "getrandom"
|
||||||
version = "0.2.17"
|
version = "0.2.17"
|
||||||
@@ -1436,6 +1489,21 @@ dependencies = [
|
|||||||
"want",
|
"want",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hyper-rustls"
|
||||||
|
version = "0.27.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f"
|
||||||
|
dependencies = [
|
||||||
|
"http",
|
||||||
|
"hyper",
|
||||||
|
"hyper-util",
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
|
"tower-service",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-util"
|
name = "hyper-util"
|
||||||
version = "0.1.20"
|
version = "0.1.20"
|
||||||
@@ -1691,6 +1759,36 @@ dependencies = [
|
|||||||
"windows-sys 0.45.0",
|
"windows-sys 0.45.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5efd9a482cf3a427f00d6b35f14332adc7902ce91efb778580e180ff90fa3498"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"combine",
|
||||||
|
"jni-macros",
|
||||||
|
"jni-sys 0.4.1",
|
||||||
|
"log",
|
||||||
|
"simd_cesu8",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"walkdir",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jni-macros"
|
||||||
|
version = "0.22.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a00109accc170f0bdb141fed3e393c565b6f5e072365c3bd58f5b062591560a3"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustc_version",
|
||||||
|
"simd_cesu8",
|
||||||
|
"syn 2.0.117",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "jni-sys"
|
name = "jni-sys"
|
||||||
version = "0.3.1"
|
version = "0.3.1"
|
||||||
@@ -1828,6 +1926,12 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linux-raw-sys"
|
||||||
|
version = "0.12.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "litemap"
|
name = "litemap"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -1884,6 +1988,12 @@ version = "0.3.17"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minisign-verify"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22f9645cb765ea72b8111f36c522475d2daa0d22c957a9826437e97534bc4e9e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.9"
|
version = "0.8.9"
|
||||||
@@ -1956,6 +2066,18 @@ version = "1.0.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.31.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"cfg-if",
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-conv"
|
name = "num-conv"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -2125,6 +2247,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.1",
|
"bitflags 2.11.1",
|
||||||
"block2",
|
"block2",
|
||||||
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
@@ -2140,6 +2263,18 @@ dependencies = [
|
|||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "objc2-osa-kit"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f112d1746737b0da274ef79a23aac283376f335f4095a083a267a082f21db0c0"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"objc2",
|
||||||
|
"objc2-app-kit",
|
||||||
|
"objc2-foundation",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2-quartz-core"
|
name = "objc2-quartz-core"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@@ -2203,12 +2338,48 @@ version = "1.21.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-probe"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "option-ext"
|
name = "option-ext"
|
||||||
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 = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "os_info"
|
||||||
|
version = "3.15.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9cf20a545b305cf1da722b236b5155c9bb35f1d5ceb28c048bd96ca842f41b5b"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"log",
|
||||||
|
"nix",
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-ui-kit",
|
||||||
|
"serde",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "osakit"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "732c71caeaa72c065bb69d7ea08717bd3f4863a4f451402fc9513e29dbd5261b"
|
||||||
|
dependencies = [
|
||||||
|
"objc2",
|
||||||
|
"objc2-foundation",
|
||||||
|
"objc2-osa-kit",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pango"
|
name = "pango"
|
||||||
version = "0.18.3"
|
version = "0.18.3"
|
||||||
@@ -2653,15 +2824,20 @@ dependencies = [
|
|||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
|
"hyper-rustls",
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-platform-verifier",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
@@ -2673,6 +2849,20 @@ dependencies = [
|
|||||||
"web-sys",
|
"web-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ring"
|
||||||
|
version = "0.17.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"getrandom 0.2.17",
|
||||||
|
"libc",
|
||||||
|
"untrusted",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rkyv"
|
name = "rkyv"
|
||||||
version = "0.7.46"
|
version = "0.7.46"
|
||||||
@@ -2734,6 +2924,92 @@ dependencies = [
|
|||||||
"semver",
|
"semver",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustix"
|
||||||
|
version = "1.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"errno",
|
||||||
|
"libc",
|
||||||
|
"linux-raw-sys",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls"
|
||||||
|
version = "0.23.43"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"rustls-webpki",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-native-certs"
|
||||||
|
version = "0.8.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dab5152771c58876a2146916e53e35057e1a4dfa2b9df0f0305b07f611fdea4d"
|
||||||
|
dependencies = [
|
||||||
|
"openssl-probe",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"schannel",
|
||||||
|
"security-framework",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-pki-types"
|
||||||
|
version = "1.15.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96"
|
||||||
|
dependencies = [
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-platform-verifier"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"jni 0.22.4",
|
||||||
|
"log",
|
||||||
|
"once_cell",
|
||||||
|
"rustls",
|
||||||
|
"rustls-native-certs",
|
||||||
|
"rustls-platform-verifier-android",
|
||||||
|
"rustls-webpki",
|
||||||
|
"security-framework",
|
||||||
|
"security-framework-sys",
|
||||||
|
"webpki-root-certs",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-platform-verifier-android"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustls-webpki"
|
||||||
|
version = "0.103.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2"
|
||||||
|
dependencies = [
|
||||||
|
"ring",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"untrusted",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.22"
|
version = "1.0.22"
|
||||||
@@ -2749,6 +3025,15 @@ dependencies = [
|
|||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "schannel"
|
||||||
|
version = "0.1.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
|
||||||
|
dependencies = [
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schemars"
|
name = "schemars"
|
||||||
version = "0.8.22"
|
version = "0.8.22"
|
||||||
@@ -2812,6 +3097,29 @@ version = "4.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "3.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"core-foundation",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework-sys"
|
||||||
|
version = "2.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3"
|
||||||
|
dependencies = [
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "selectors"
|
name = "selectors"
|
||||||
version = "0.36.1"
|
version = "0.36.1"
|
||||||
@@ -3022,6 +3330,16 @@ version = "0.3.9"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "simd_cesu8"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520"
|
||||||
|
dependencies = [
|
||||||
|
"rustc_version",
|
||||||
|
"simdutf8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "simdutf8"
|
name = "simdutf8"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
@@ -3140,6 +3458,12 @@ version = "0.11.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "subtle"
|
||||||
|
version = "2.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "swift-rs"
|
name = "swift-rs"
|
||||||
version = "1.0.7"
|
version = "1.0.7"
|
||||||
@@ -3193,6 +3517,15 @@ dependencies = [
|
|||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sys-locale"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "system-deps"
|
name = "system-deps"
|
||||||
version = "6.2.2"
|
version = "6.2.2"
|
||||||
@@ -3224,7 +3557,7 @@ dependencies = [
|
|||||||
"gdkwayland-sys",
|
"gdkwayland-sys",
|
||||||
"gdkx11-sys",
|
"gdkx11-sys",
|
||||||
"gtk",
|
"gtk",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"ndk",
|
"ndk",
|
||||||
@@ -3263,6 +3596,17 @@ version = "1.0.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tar"
|
||||||
|
version = "0.4.46"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840"
|
||||||
|
dependencies = [
|
||||||
|
"filetime",
|
||||||
|
"libc",
|
||||||
|
"xattr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "target-lexicon"
|
name = "target-lexicon"
|
||||||
version = "0.12.16"
|
version = "0.12.16"
|
||||||
@@ -3286,7 +3630,7 @@ dependencies = [
|
|||||||
"gtk",
|
"gtk",
|
||||||
"heck 0.5.0",
|
"heck 0.5.0",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
"mime",
|
||||||
@@ -3420,6 +3764,67 @@ dependencies = [
|
|||||||
"time",
|
"time",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-os"
|
||||||
|
version = "2.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d8f08346c8deb39e96f86973da0e2d76cbb933d7ac9b750f6dc4daf955a6f997"
|
||||||
|
dependencies = [
|
||||||
|
"gethostname",
|
||||||
|
"log",
|
||||||
|
"os_info",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serialize-to-javascript",
|
||||||
|
"sys-locale",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-process"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d55511a7bf6cd70c8767b02c97bf8134fa434daf3926cfc1be0a0f94132d165a"
|
||||||
|
dependencies = [
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tauri-plugin-updater"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.22.1",
|
||||||
|
"dirs",
|
||||||
|
"flate2",
|
||||||
|
"futures-util",
|
||||||
|
"http",
|
||||||
|
"infer",
|
||||||
|
"log",
|
||||||
|
"minisign-verify",
|
||||||
|
"osakit",
|
||||||
|
"percent-encoding",
|
||||||
|
"reqwest",
|
||||||
|
"rustls",
|
||||||
|
"semver",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tar",
|
||||||
|
"tauri",
|
||||||
|
"tauri-plugin",
|
||||||
|
"tempfile",
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
"time",
|
||||||
|
"tokio",
|
||||||
|
"url",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
"zip",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tauri-runtime"
|
name = "tauri-runtime"
|
||||||
version = "2.11.2"
|
version = "2.11.2"
|
||||||
@@ -3430,7 +3835,7 @@ dependencies = [
|
|||||||
"dpi",
|
"dpi",
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-ui-kit",
|
"objc2-ui-kit",
|
||||||
"objc2-web-kit",
|
"objc2-web-kit",
|
||||||
@@ -3453,7 +3858,7 @@ checksum = "b83849ee63ecb27a8e8d0fe51915ca215076914aca43f96db1179f0f415f6cd9"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"log",
|
"log",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
@@ -3520,6 +3925,19 @@ dependencies = [
|
|||||||
"toml 1.1.2+spec-1.1.0",
|
"toml 1.1.2+spec-1.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tempfile"
|
||||||
|
version = "3.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
|
||||||
|
dependencies = [
|
||||||
|
"fastrand",
|
||||||
|
"getrandom 0.4.2",
|
||||||
|
"once_cell",
|
||||||
|
"rustix",
|
||||||
|
"windows-sys 0.61.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tendril"
|
name = "tendril"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@@ -3642,6 +4060,16 @@ dependencies = [
|
|||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tokio-rustls"
|
||||||
|
version = "0.26.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61"
|
||||||
|
dependencies = [
|
||||||
|
"rustls",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-util"
|
name = "tokio-util"
|
||||||
version = "0.7.18"
|
version = "0.7.18"
|
||||||
@@ -3938,6 +4366,12 @@ version = "0.2.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "untrusted"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "2.5.8"
|
version = "2.5.8"
|
||||||
@@ -4242,6 +4676,15 @@ dependencies = [
|
|||||||
"system-deps",
|
"system-deps",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-root-certs"
|
||||||
|
version = "1.0.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b96554aa2acc8ccdb7e1c9a58a7a68dd5d13bccc69cd124cb09406db612a1c9b"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "webview2-com"
|
name = "webview2-com"
|
||||||
version = "0.38.2"
|
version = "0.38.2"
|
||||||
@@ -4472,6 +4915,15 @@ dependencies = [
|
|||||||
"windows-targets 0.42.2",
|
"windows-targets 0.42.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.52.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.59.0"
|
version = "0.59.0"
|
||||||
@@ -4481,6 +4933,15 @@ dependencies = [
|
|||||||
"windows-targets 0.52.6",
|
"windows-targets 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-sys"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.53.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.61.2"
|
version = "0.61.2"
|
||||||
@@ -4514,13 +4975,30 @@ dependencies = [
|
|||||||
"windows_aarch64_gnullvm 0.52.6",
|
"windows_aarch64_gnullvm 0.52.6",
|
||||||
"windows_aarch64_msvc 0.52.6",
|
"windows_aarch64_msvc 0.52.6",
|
||||||
"windows_i686_gnu 0.52.6",
|
"windows_i686_gnu 0.52.6",
|
||||||
"windows_i686_gnullvm",
|
"windows_i686_gnullvm 0.52.6",
|
||||||
"windows_i686_msvc 0.52.6",
|
"windows_i686_msvc 0.52.6",
|
||||||
"windows_x86_64_gnu 0.52.6",
|
"windows_x86_64_gnu 0.52.6",
|
||||||
"windows_x86_64_gnullvm 0.52.6",
|
"windows_x86_64_gnullvm 0.52.6",
|
||||||
"windows_x86_64_msvc 0.52.6",
|
"windows_x86_64_msvc 0.52.6",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-targets"
|
||||||
|
version = "0.53.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
"windows_aarch64_gnullvm 0.53.1",
|
||||||
|
"windows_aarch64_msvc 0.53.1",
|
||||||
|
"windows_i686_gnu 0.53.1",
|
||||||
|
"windows_i686_gnullvm 0.53.1",
|
||||||
|
"windows_i686_msvc 0.53.1",
|
||||||
|
"windows_x86_64_gnu 0.53.1",
|
||||||
|
"windows_x86_64_gnullvm 0.53.1",
|
||||||
|
"windows_x86_64_msvc 0.53.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-threading"
|
name = "windows-threading"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@@ -4551,6 +5029,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -4563,6 +5047,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -4575,12 +5065,24 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnullvm"
|
name = "windows_i686_gnullvm"
|
||||||
version = "0.52.6"
|
version = "0.52.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -4593,6 +5095,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -4605,6 +5113,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -4617,6 +5131,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnullvm"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.2"
|
version = "0.42.2"
|
||||||
@@ -4629,6 +5149,12 @@ version = "0.52.6"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.53.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.5.40"
|
version = "0.5.40"
|
||||||
@@ -4781,7 +5307,7 @@ dependencies = [
|
|||||||
"gtk",
|
"gtk",
|
||||||
"http",
|
"http",
|
||||||
"javascriptcore-rs",
|
"javascriptcore-rs",
|
||||||
"jni",
|
"jni 0.21.1",
|
||||||
"libc",
|
"libc",
|
||||||
"ndk",
|
"ndk",
|
||||||
"objc2",
|
"objc2",
|
||||||
@@ -4837,6 +5363,16 @@ dependencies = [
|
|||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xattr"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"rustix",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yoke"
|
name = "yoke"
|
||||||
version = "0.8.2"
|
version = "0.8.2"
|
||||||
@@ -4901,6 +5437,12 @@ dependencies = [
|
|||||||
"synstructure",
|
"synstructure",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zeroize"
|
||||||
|
version = "1.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerotrie"
|
name = "zerotrie"
|
||||||
version = "0.2.4"
|
version = "0.2.4"
|
||||||
@@ -4934,6 +5476,18 @@ dependencies = [
|
|||||||
"syn 2.0.117",
|
"syn 2.0.117",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zip"
|
||||||
|
version = "4.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "caa8cd6af31c3b31c6631b8f483848b91589021b28fffe50adada48d4f4d2ed1"
|
||||||
|
dependencies = [
|
||||||
|
"arbitrary",
|
||||||
|
"crc32fast",
|
||||||
|
"indexmap 2.14.0",
|
||||||
|
"memchr",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zmij"
|
name = "zmij"
|
||||||
version = "1.0.21"
|
version = "1.0.21"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "app"
|
name = "court-pilot"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
description = "A Tauri App"
|
description = "Court Pilot"
|
||||||
authors = ["you"]
|
authors = ["Richard Toth"]
|
||||||
license = ""
|
license = "MIT"
|
||||||
repository = ""
|
repository = "https://github.com/tricsusz/court-pilot"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
rust-version = "1.77.2"
|
rust-version = "1.77.2"
|
||||||
|
|
||||||
@@ -23,3 +23,8 @@ serde = { version = "1.0", features = ["derive"] }
|
|||||||
log = "0.4"
|
log = "0.4"
|
||||||
tauri = { version = "2.11.2", features = [] }
|
tauri = { version = "2.11.2", features = [] }
|
||||||
tauri-plugin-log = "2"
|
tauri-plugin-log = "2"
|
||||||
|
tauri-plugin-process = "2"
|
||||||
|
tauri-plugin-os = "2"
|
||||||
|
|
||||||
|
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||||
|
tauri-plugin-updater = "2"
|
||||||
|
|||||||
@@ -6,6 +6,8 @@
|
|||||||
"main"
|
"main"
|
||||||
],
|
],
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"core:default"
|
"core:default",
|
||||||
|
"process:default",
|
||||||
|
"os:default"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"identifier": "desktop-capability",
|
||||||
|
"platforms": [
|
||||||
|
"macOS",
|
||||||
|
"windows",
|
||||||
|
"linux"
|
||||||
|
],
|
||||||
|
"windows": [
|
||||||
|
"main"
|
||||||
|
],
|
||||||
|
"permissions": [
|
||||||
|
"updater:default",
|
||||||
|
"os:default"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 838 B |
|
After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 5.1 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 790 B |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 2.9 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 6.0 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 8.4 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#fff</color>
|
||||||
|
</resources>
|
||||||
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 513 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 751 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
@@ -1,6 +1,9 @@
|
|||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.plugin(tauri_plugin_os::init())
|
||||||
|
.plugin(tauri_plugin_process::init())
|
||||||
|
.plugin(tauri_plugin_updater::Builder::new().build())
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
app.handle().plugin(
|
app.handle().plugin(
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
{
|
{
|
||||||
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
|
||||||
"productName": "court-pilot",
|
"productName": "court-pilot",
|
||||||
"version": "0.1.0",
|
"mainBinaryName": "Court Pilot",
|
||||||
"identifier": "com.tauri.dev",
|
"version": "1.1.4",
|
||||||
|
"identifier": "com.courtpilot.dev",
|
||||||
"build": {
|
"build": {
|
||||||
"frontendDist": "../wwww",
|
"frontendDist": "../www",
|
||||||
"devUrl": "http://localhost:8103",
|
"devUrl": "http://localhost:8103",
|
||||||
"beforeDevCommand": "npm start",
|
"beforeDevCommand": "npm start",
|
||||||
"beforeBuildCommand": "ionic build"
|
"beforeBuildCommand": "ionic build"
|
||||||
@@ -12,11 +13,14 @@
|
|||||||
"app": {
|
"app": {
|
||||||
"windows": [
|
"windows": [
|
||||||
{
|
{
|
||||||
|
"minHeight": 600,
|
||||||
|
"minWidth": 800,
|
||||||
"title": "Court Pilot",
|
"title": "Court Pilot",
|
||||||
"width": 800,
|
"width": 800,
|
||||||
"height": 600,
|
"height": 600,
|
||||||
"resizable": true,
|
"resizable": true,
|
||||||
"fullscreen": false
|
"fullscreen": false,
|
||||||
|
"center": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"security": {
|
"security": {
|
||||||
@@ -35,6 +39,17 @@
|
|||||||
],
|
],
|
||||||
"android": {
|
"android": {
|
||||||
"debugApplicationIdSuffix": ".debug"
|
"debugApplicationIdSuffix": ".debug"
|
||||||
|
},
|
||||||
|
"createUpdaterArtifacts": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"licenseFile": "../LICENSE"
|
||||||
|
},
|
||||||
|
"plugins": {
|
||||||
|
"updater": {
|
||||||
|
"endpoints": [
|
||||||
|
"https://cdn.crabnebula.app/update/trweb/court-pilot/{{target}}-{{arch}}/{{current_version}}"
|
||||||
|
],
|
||||||
|
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IEY3MDU5NkNDN0Y3QTQ3RDgKUldUWVIzcC96SllGOTduTUFweEUraTE2WUxjczRJNDdoaFFIb1VRT1o5aHdJeFg2RlRlUGoxRTcK"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,123 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { IonApp, IonRouterOutlet } from '@ionic/angular/standalone';
|
import {
|
||||||
|
AlertController,
|
||||||
|
IonApp,
|
||||||
|
IonRouterOutlet,
|
||||||
|
LoadingController
|
||||||
|
} from '@ionic/angular/standalone';
|
||||||
|
import { check, DownloadEvent } from '@tauri-apps/plugin-updater';
|
||||||
|
import { isTauri } from '@tauri-apps/api/core';
|
||||||
|
import { platform } from '@tauri-apps/plugin-os';
|
||||||
|
import { relaunch } from '@tauri-apps/plugin-process';
|
||||||
|
import { TranslationService } from './i18n/translation.service';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: 'app.component.html',
|
templateUrl: 'app.component.html',
|
||||||
imports: [IonApp, IonRouterOutlet],
|
imports: [IonApp, IonRouterOutlet]
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
constructor() {}
|
readonly alertController: AlertController = inject(AlertController);
|
||||||
|
readonly loadingController: LoadingController = inject(LoadingController);
|
||||||
|
readonly translationService: TranslationService = inject(TranslationService);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.checkForUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkForUpdates(): Promise<void> {
|
||||||
|
if (!isTauri()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Snap handles updates on Linux.
|
||||||
|
if (platform() === 'linux') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const update = await check();
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
const alert = await this.alertController.create({
|
||||||
|
header: this.translationService.translate('updateAvailable'),
|
||||||
|
message: this.translationService.translate('newVersion', {
|
||||||
|
version: update.version
|
||||||
|
}),
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: 'OK',
|
||||||
|
handler: async () => {
|
||||||
|
const loading = await this.loadingController.create({
|
||||||
|
message:
|
||||||
|
this.translationService.translate('updateDownloading'),
|
||||||
|
spinner: 'crescent',
|
||||||
|
backdropDismiss: false
|
||||||
|
});
|
||||||
|
|
||||||
|
await loading.present();
|
||||||
|
|
||||||
|
let downloaded = 0;
|
||||||
|
let total = 0;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await update.downloadAndInstall((event: DownloadEvent) => {
|
||||||
|
switch (event.event) {
|
||||||
|
case 'Started':
|
||||||
|
total = event.data.contentLength ?? 0;
|
||||||
|
downloaded = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Progress':
|
||||||
|
downloaded += event.data.chunkLength;
|
||||||
|
|
||||||
|
if (total > 0) {
|
||||||
|
const percent = Math.min(
|
||||||
|
100,
|
||||||
|
Math.round((downloaded / total) * 100)
|
||||||
|
);
|
||||||
|
|
||||||
|
loading.message = `${this.translationService.translate('updateDownloading')} ${percent}%`;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Finished':
|
||||||
|
loading.message =
|
||||||
|
this.translationService.translate('updateInstalling');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await loading.dismiss();
|
||||||
|
await relaunch();
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to install update:', error);
|
||||||
|
|
||||||
|
await loading.dismiss();
|
||||||
|
|
||||||
|
const errorAlert = await this.alertController.create({
|
||||||
|
header: this.translationService.translate('updateFailed'),
|
||||||
|
message: String(error),
|
||||||
|
buttons: ['OK']
|
||||||
|
});
|
||||||
|
|
||||||
|
await errorAlert.present();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('No updates available.');
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to check for updates:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<div id="container">
|
|
||||||
<strong>{{ name }}</strong>
|
|
||||||
<p>
|
|
||||||
Explore
|
|
||||||
<a
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
href="https://ionicframework.com/docs/components"
|
|
||||||
>UI Components</a
|
|
||||||
>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#container {
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
#container strong {
|
|
||||||
font-size: 20px;
|
|
||||||
line-height: 26px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container p {
|
|
||||||
font-size: 16px;
|
|
||||||
line-height: 22px;
|
|
||||||
|
|
||||||
color: #8c8c8c;
|
|
||||||
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#container a {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
||||||
|
|
||||||
import { ExploreContainerComponent } from './explore-container.component';
|
|
||||||
|
|
||||||
describe('ExploreContainerComponent', () => {
|
|
||||||
let component: ExploreContainerComponent;
|
|
||||||
let fixture: ComponentFixture<ExploreContainerComponent>;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
fixture = TestBed.createComponent(ExploreContainerComponent);
|
|
||||||
component = fixture.componentInstance;
|
|
||||||
fixture.detectChanges();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create', () => {
|
|
||||||
expect(component).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'app-explore-container',
|
|
||||||
templateUrl: './explore-container.component.html',
|
|
||||||
styleUrls: ['./explore-container.component.scss'],
|
|
||||||
})
|
|
||||||
export class ExploreContainerComponent {
|
|
||||||
@Input() name?: string;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import { FullnamePipe } from './fullname-pipe';
|
||||||
|
|
||||||
|
describe('FullnamePipePipe', () => {
|
||||||
|
it('create an instance', () => {
|
||||||
|
const pipe = new FullnamePipe();
|
||||||
|
expect(pipe).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
import { inject, Pipe, PipeTransform } from '@angular/core';
|
||||||
|
import { Umpire } from 'db';
|
||||||
|
import { TranslationService } from './i18n/translation.service';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'fullname',
|
||||||
|
standalone: true,
|
||||||
|
pure: false
|
||||||
|
})
|
||||||
|
export class FullnamePipe implements PipeTransform {
|
||||||
|
readonly translationService = inject(TranslationService);
|
||||||
|
|
||||||
|
transform(value: Umpire | undefined, ...args: unknown[]): string {
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.translationService.language() === 'en') {
|
||||||
|
return value.firstName + ' ' + value.lastName;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value.lastName + ' ' + value.firstName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Pipe, PipeTransform, inject } from '@angular/core';
|
||||||
|
import { TranslationKey, TranslationParams } from './translations';
|
||||||
|
import { TranslationService } from './translation.service';
|
||||||
|
|
||||||
|
@Pipe({
|
||||||
|
name: 'translate',
|
||||||
|
standalone: true,
|
||||||
|
pure: false
|
||||||
|
})
|
||||||
|
export class TranslatePipe implements PipeTransform {
|
||||||
|
private readonly translationService = inject(TranslationService);
|
||||||
|
|
||||||
|
transform(key: TranslationKey, params: TranslationParams = {}): string {
|
||||||
|
return this.translationService.translate(key, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Injectable, signal } from '@angular/core';
|
||||||
|
import {
|
||||||
|
translations,
|
||||||
|
Language,
|
||||||
|
TranslationKey,
|
||||||
|
TranslationParams
|
||||||
|
} from './translations';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class TranslationService {
|
||||||
|
private readonly storageKey = 'language';
|
||||||
|
|
||||||
|
readonly language = signal<Language>(this.getInitialLanguage());
|
||||||
|
|
||||||
|
setLanguage(language: Language): void {
|
||||||
|
this.language.set(language);
|
||||||
|
localStorage.setItem(this.storageKey, language);
|
||||||
|
}
|
||||||
|
|
||||||
|
translate(key: TranslationKey, params: TranslationParams = {}): string {
|
||||||
|
let text: string = translations[this.language()][key];
|
||||||
|
|
||||||
|
for (const [param, value] of Object.entries(params)) {
|
||||||
|
text = text.replaceAll(`{${param}}`, String(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private getInitialLanguage(): Language {
|
||||||
|
const stored = localStorage.getItem(this.storageKey);
|
||||||
|
|
||||||
|
if (stored && stored in translations) {
|
||||||
|
return stored as Language;
|
||||||
|
}
|
||||||
|
|
||||||
|
const browserLanguage = navigator.language.split('-')[0] as Language;
|
||||||
|
|
||||||
|
if (browserLanguage in translations) {
|
||||||
|
return browserLanguage;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'en';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
import { language, male, settings } from 'ionicons/icons';
|
||||||
|
import { noop } from 'rxjs';
|
||||||
|
|
||||||
|
export const translations = {
|
||||||
|
en: {
|
||||||
|
courts: 'Courts',
|
||||||
|
numberOfCourts: 'Number of Courts',
|
||||||
|
showAlerts: 'Show alerts on quick buttons',
|
||||||
|
serviceJudge: 'Service Judge',
|
||||||
|
language: 'Language',
|
||||||
|
settings: 'Settings',
|
||||||
|
courtOfficials: 'Court Officials',
|
||||||
|
add: 'Add',
|
||||||
|
noCourtOfficials: 'No court officials',
|
||||||
|
newCourtOfficial: 'New Court Official',
|
||||||
|
cancel: 'Cancel',
|
||||||
|
save: 'Save',
|
||||||
|
firstName: 'First Name',
|
||||||
|
lastName: 'Last Name',
|
||||||
|
country: 'Country',
|
||||||
|
gender: 'Gender',
|
||||||
|
male: 'Male',
|
||||||
|
female: 'Female',
|
||||||
|
confirmation: 'Confirmation',
|
||||||
|
confirmDeleteUmpire: 'Do you really want to delete this court official?',
|
||||||
|
no: 'No',
|
||||||
|
yes: 'Yes',
|
||||||
|
umpires: 'Umpires',
|
||||||
|
serviceJudges: 'Service Judges',
|
||||||
|
notOnDuty: 'Not on Duty',
|
||||||
|
shortCourtName: 'C',
|
||||||
|
court: 'Court',
|
||||||
|
umpire: 'Umpire',
|
||||||
|
removeUmpireFromCourt:
|
||||||
|
'Are you sure you want to remove them from the court?',
|
||||||
|
removeUmpiresFromCourt:
|
||||||
|
'Are you sure you want to remove them from the court?',
|
||||||
|
courtConfirm: 'Court {courtNo}',
|
||||||
|
sendUmpireToCourt: 'Are you sure you want to send them to the court?',
|
||||||
|
sendUmpiresToCourt: 'Are you sure you want to send them to the court?',
|
||||||
|
sendUmpireMessage: '{umpire}',
|
||||||
|
sendUmpiresMessage: '{umpire} - {serviceJudge}',
|
||||||
|
version: 'Version',
|
||||||
|
updateAvailable: 'Update available',
|
||||||
|
newVersion:
|
||||||
|
'A new version {version} is available. The application will restart to install the update.',
|
||||||
|
english: 'English',
|
||||||
|
hungarian: 'Hungarian',
|
||||||
|
updateDownloading: 'Downloading update...',
|
||||||
|
updateInstalling: 'Installing update...',
|
||||||
|
updateFailed: 'Failed to install the update. Please try again.'
|
||||||
|
},
|
||||||
|
|
||||||
|
hu: {
|
||||||
|
courts: 'Pályák',
|
||||||
|
numberOfCourts: 'Pályák száma',
|
||||||
|
showAlerts: 'Figyelmeztetések megjelenítése a gyors gomboknál',
|
||||||
|
serviceJudge: 'Adogatásbíró',
|
||||||
|
language: 'Nyelv',
|
||||||
|
settings: 'Beállítások',
|
||||||
|
courtOfficials: 'Tisztségviselők',
|
||||||
|
add: 'Hozzáadás',
|
||||||
|
noCourtOfficials: 'Nincsenek tisztségviselők',
|
||||||
|
newCourtOfficial: 'Új Tisztségviselő',
|
||||||
|
cancel: 'Mégse',
|
||||||
|
save: 'Mentés',
|
||||||
|
firstName: 'Keresztnév',
|
||||||
|
lastName: 'Vezetéknév',
|
||||||
|
country: 'Ország',
|
||||||
|
gender: 'Nem',
|
||||||
|
male: 'Férfi',
|
||||||
|
female: 'Nő',
|
||||||
|
confirmation: 'Megerősítés',
|
||||||
|
confirmDeleteUmpire: 'Biztosan törölni szeretnéd ezt a tisztségviselőt?',
|
||||||
|
no: 'Nem',
|
||||||
|
yes: 'Igen',
|
||||||
|
umpires: 'Játékvezetők',
|
||||||
|
serviceJudges: 'Adogatásbírók',
|
||||||
|
notOnDuty: 'Pihenő',
|
||||||
|
shortCourtName: 'P',
|
||||||
|
court: 'Pálya',
|
||||||
|
umpire: 'Játékvezető',
|
||||||
|
removeUmpireFromCourt: 'Biztos leveszed őt a pályáról?',
|
||||||
|
removeUmpiresFromCourt: 'Biztos leveszed őket a pályáról?',
|
||||||
|
courtConfirm: 'Pálya {courtNo}',
|
||||||
|
sendUmpireToCourt: 'Biztos pályára küldöd őt?',
|
||||||
|
sendUmpiresToCourt: 'Biztos pályára küldöd őket?',
|
||||||
|
sendUmpireMessage: '{umpire}',
|
||||||
|
sendUmpiresMessage: '{umpire} - {serviceJudge}',
|
||||||
|
version: 'Verzió',
|
||||||
|
updateAvailable: 'Új verzió elérhető',
|
||||||
|
newVersion:
|
||||||
|
'Új elérhető verzió: {version}. A frissítések telepítése után az alkalmazás újraindul.',
|
||||||
|
english: 'Angol',
|
||||||
|
hungarian: 'Magyar',
|
||||||
|
updateDownloading: 'Frissítés letöltése...',
|
||||||
|
updateFailed: 'Frissítés sikertelen. Kérlek próbáld újra.',
|
||||||
|
updateInstalling: 'Frissítés telepítése...'
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type Language = keyof typeof translations;
|
||||||
|
export type TranslationKey = keyof typeof translations.en;
|
||||||
|
export type TranslationParams = Record<string, string | number>;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CourtServiceJudgeService } from './court.service.judge.service';
|
||||||
|
|
||||||
|
describe('CourtServiceJudgeService', () => {
|
||||||
|
let service: CourtServiceJudgeService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(CourtServiceJudgeService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
import { CourtServiceJudge, db } from 'db';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
import { from } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CourtServiceJudgeService {
|
||||||
|
/**
|
||||||
|
* All service judges (reactive)
|
||||||
|
*/
|
||||||
|
readonly umpires = toSignal(
|
||||||
|
from(liveQuery(() => db.courtServiceJudges.orderBy('courtNo').toArray())),
|
||||||
|
{ initialValue: [] }
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get by court number (reactive)
|
||||||
|
*/
|
||||||
|
getByCourtNo(courtNo: number) {
|
||||||
|
return toSignal<CourtServiceJudge | undefined>(
|
||||||
|
liveQuery(() =>
|
||||||
|
db.courtServiceJudges.where('courtNo').equals(courtNo).first()
|
||||||
|
),
|
||||||
|
{ initialValue: undefined }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create / update
|
||||||
|
*/
|
||||||
|
async save(item: Omit<CourtServiceJudge, 'id'>): Promise<number> {
|
||||||
|
return db.courtServiceJudges.add(item as CourtServiceJudge);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(
|
||||||
|
id: number,
|
||||||
|
changes: Partial<CourtServiceJudge>
|
||||||
|
): Promise<number> {
|
||||||
|
return db.courtServiceJudges.update(id, changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: number): Promise<void> {
|
||||||
|
await db.courtServiceJudges.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeByUmpireId(umpireId: number): Promise<void> {
|
||||||
|
const item = await db.courtServiceJudges
|
||||||
|
.where('umpireId')
|
||||||
|
.equals(umpireId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!item?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.courtServiceJudges.delete(item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { CourtUmpireService } from './court.umpire.service';
|
||||||
|
|
||||||
|
describe('CourtUmpireService', () => {
|
||||||
|
let service: CourtUmpireService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(CourtUmpireService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
import { CourtUmpire, db } from 'db';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
import { from } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class CourtUmpireService {
|
||||||
|
/**
|
||||||
|
* All court umpires (reactive)
|
||||||
|
*/
|
||||||
|
readonly umpires = toSignal(
|
||||||
|
from(liveQuery(() => db.courtUmpires.orderBy('courtNo').toArray())),
|
||||||
|
{ initialValue: [] }
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get by court number (reactive single)
|
||||||
|
*/
|
||||||
|
getByCourtNo(courtNo: number) {
|
||||||
|
return toSignal<CourtUmpire | undefined>(
|
||||||
|
liveQuery(() => db.courtUmpires.where('courtNo').equals(courtNo).first()),
|
||||||
|
{ initialValue: undefined }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create / update
|
||||||
|
*/
|
||||||
|
async save(item: Omit<CourtUmpire, 'id'>): Promise<number> {
|
||||||
|
return db.courtUmpires.add(item as CourtUmpire);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: number, changes: Partial<CourtUmpire>): Promise<number> {
|
||||||
|
return db.courtUmpires.update(id, changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: number): Promise<void> {
|
||||||
|
await db.courtUmpires.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeByUmpireId(umpireId: number): Promise<void> {
|
||||||
|
const item = await db.courtUmpires
|
||||||
|
.where('umpireId')
|
||||||
|
.equals(umpireId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!item?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.courtUmpires.delete(item.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { SettingsService } from './settings-service';
|
||||||
|
|
||||||
|
describe('SettingsService', () => {
|
||||||
|
let service: SettingsService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(SettingsService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
import { db, Settings } from 'db';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class SettingsService {
|
||||||
|
constructor() {
|
||||||
|
void this.ensureSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reactive settings signal
|
||||||
|
*/
|
||||||
|
readonly settings = toSignal<Settings | undefined>(
|
||||||
|
liveQuery(() => db.settings.get(1)),
|
||||||
|
{ initialValue: undefined }
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update settings
|
||||||
|
*/
|
||||||
|
async update(changes: Partial<Omit<Settings, 'id'>>): Promise<void> {
|
||||||
|
const current = await db.settings.get(1);
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.settings.update(1, changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async ensureSettings() {
|
||||||
|
const existing = await db.settings.get(1);
|
||||||
|
|
||||||
|
if (!existing) {
|
||||||
|
await db.settings.put({
|
||||||
|
id: 1,
|
||||||
|
numberOfCourts: 5,
|
||||||
|
withServiceJudge: true,
|
||||||
|
showAlert: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { UmpireService } from './umpire.service';
|
||||||
|
|
||||||
|
describe('Umpire', () => {
|
||||||
|
let service: UmpireService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(UmpireService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { db } from 'db';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
import { from } from 'rxjs';
|
||||||
|
import { Umpire } from '../../../db';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class UmpireService {
|
||||||
|
/**
|
||||||
|
* Reactive signal with all umpires
|
||||||
|
*/
|
||||||
|
readonly umpires = toSignal(
|
||||||
|
from(liveQuery(() => db.umpires.orderBy('lastName').toArray())),
|
||||||
|
{
|
||||||
|
initialValue: []
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create
|
||||||
|
*/
|
||||||
|
async create(umpire: Omit<Umpire, 'id'>): Promise<number> {
|
||||||
|
return await db.umpires.add({
|
||||||
|
...umpire
|
||||||
|
} as Umpire);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read one
|
||||||
|
*/
|
||||||
|
async getById(id: number): Promise<Umpire | undefined> {
|
||||||
|
return await db.umpires.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update
|
||||||
|
*/
|
||||||
|
async update(
|
||||||
|
id: number,
|
||||||
|
changes: Partial<Omit<Umpire, 'id'>>
|
||||||
|
): Promise<number> {
|
||||||
|
return await db.umpires.update(id, changes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete
|
||||||
|
*/
|
||||||
|
async delete(id: number): Promise<void> {
|
||||||
|
await db.umpires.delete(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete all
|
||||||
|
*/
|
||||||
|
async clear(): Promise<void> {
|
||||||
|
await db.umpires.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { WaitingServiceJudgesService } from './waiting-service-judges.service';
|
||||||
|
|
||||||
|
describe('WaitingServiceJudgesService', () => {
|
||||||
|
let service: WaitingServiceJudgesService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(WaitingServiceJudgesService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
import { db, Umpire } from 'db';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
import { from } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class WaitingServiceJudgesService {
|
||||||
|
/**
|
||||||
|
* Reactive list sorted by order
|
||||||
|
*/
|
||||||
|
readonly waitingServiceJudges = toSignal(
|
||||||
|
from(liveQuery(() => db.waitingServiceJudges.orderBy('order').toArray())),
|
||||||
|
{
|
||||||
|
initialValue: []
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new umpire to queue with max(order) + 1
|
||||||
|
*/
|
||||||
|
async add(serviceJudgeId: number, toPosition?: number): Promise<number> {
|
||||||
|
const id = await db.transaction('rw', db.waitingServiceJudges, async () => {
|
||||||
|
const last = await db.waitingServiceJudges.orderBy('order').last();
|
||||||
|
|
||||||
|
const nextOrder = last ? last.order + 1 : 1;
|
||||||
|
|
||||||
|
return db.waitingServiceJudges.add({
|
||||||
|
serviceJudgeId,
|
||||||
|
order: nextOrder
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (toPosition !== undefined) {
|
||||||
|
await this.moveToPosition(serviceJudgeId, toPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove from queue
|
||||||
|
*/
|
||||||
|
async remove(id: number): Promise<void> {
|
||||||
|
await db.waitingServiceJudges.delete(id);
|
||||||
|
|
||||||
|
await this.reinitOrders();
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeByUmpireId(umpireId: number): Promise<void> {
|
||||||
|
const item = await db.waitingServiceJudges
|
||||||
|
.where('serviceJudgeId')
|
||||||
|
.equals(umpireId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!item?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.remove(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorder (optional helper)
|
||||||
|
*/
|
||||||
|
async updateOrder(id: number, order: number): Promise<void> {
|
||||||
|
await db.waitingServiceJudges.update(id, { order });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear queue
|
||||||
|
*/
|
||||||
|
async clear(): Promise<void> {
|
||||||
|
await db.waitingServiceJudges.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
async moveToPosition(umpireId: number, newOrder: number): Promise<void> {
|
||||||
|
await db.transaction('rw', db.waitingServiceJudges, async () => {
|
||||||
|
const current = await db.waitingServiceJudges
|
||||||
|
.where('serviceJudgeId')
|
||||||
|
.equals(umpireId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldOrder = current.order;
|
||||||
|
|
||||||
|
if (oldOrder === newOrder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newOrder < oldOrder) {
|
||||||
|
// Moving up: shift affected records down
|
||||||
|
|
||||||
|
const affected = await db.waitingServiceJudges
|
||||||
|
.filter(
|
||||||
|
(item) =>
|
||||||
|
item.order >= newOrder &&
|
||||||
|
item.order < oldOrder &&
|
||||||
|
item.id !== current.id
|
||||||
|
)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
for (const item of affected) {
|
||||||
|
await db.waitingServiceJudges.update(item.id!, {
|
||||||
|
order: item.order + 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Moving down: shift affected records up
|
||||||
|
|
||||||
|
const affected = await db.waitingServiceJudges
|
||||||
|
.filter(
|
||||||
|
(item) =>
|
||||||
|
item.order > oldOrder &&
|
||||||
|
item.order <= newOrder &&
|
||||||
|
item.id !== current.id
|
||||||
|
)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
for (const item of affected) {
|
||||||
|
await db.waitingServiceJudges.update(item.id!, {
|
||||||
|
order: item.order - 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.waitingServiceJudges.update(current.id!, {
|
||||||
|
order: newOrder
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async reinitOrders(): Promise<void> {
|
||||||
|
await db.transaction('rw', db.waitingServiceJudges, async () => {
|
||||||
|
const items = await db.waitingServiceJudges.orderBy('order').toArray();
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i];
|
||||||
|
|
||||||
|
const expectedOrder = i + 1;
|
||||||
|
|
||||||
|
if (item.order !== expectedOrder) {
|
||||||
|
await db.waitingServiceJudges.update(item.id!, {
|
||||||
|
order: expectedOrder
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentUmpire(): Promise<Umpire | undefined> {
|
||||||
|
const item = await db.waitingServiceJudges.where('order').equals(1).first();
|
||||||
|
|
||||||
|
return item ? db.umpires.get(item.serviceJudgeId) : undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { WaitingUmpiresService } from './waiting-umpires.service';
|
||||||
|
|
||||||
|
describe('WaitingUmpiresService', () => {
|
||||||
|
let service: WaitingUmpiresService;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
TestBed.configureTestingModule({});
|
||||||
|
service = TestBed.inject(WaitingUmpiresService);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be created', () => {
|
||||||
|
expect(service).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,161 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { toSignal } from '@angular/core/rxjs-interop';
|
||||||
|
import { db, Umpire } from 'db';
|
||||||
|
import { liveQuery } from 'dexie';
|
||||||
|
import { from } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root'
|
||||||
|
})
|
||||||
|
export class WaitingUmpiresService {
|
||||||
|
/**
|
||||||
|
* Reactive list sorted by order
|
||||||
|
*/
|
||||||
|
readonly waitingUmpires = toSignal(
|
||||||
|
from(liveQuery(() => db.waitingUmpires.orderBy('order').toArray())),
|
||||||
|
{
|
||||||
|
initialValue: []
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add new umpire to queue with max(order) + 1
|
||||||
|
*/
|
||||||
|
async add(umpireId: number, toPosition?: number): Promise<number> {
|
||||||
|
const id = await db.transaction('rw', db.waitingUmpires, async () => {
|
||||||
|
const last = await db.waitingUmpires.orderBy('order').last();
|
||||||
|
|
||||||
|
const nextOrder = last ? last.order + 1 : 1;
|
||||||
|
|
||||||
|
return db.waitingUmpires.add({
|
||||||
|
umpireId,
|
||||||
|
order: nextOrder
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (toPosition !== undefined) {
|
||||||
|
await this.moveToPosition(umpireId, toPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove from queue
|
||||||
|
*/
|
||||||
|
async remove(id: number): Promise<void> {
|
||||||
|
await db.waitingUmpires.delete(id);
|
||||||
|
|
||||||
|
await this.reinitOrders();
|
||||||
|
}
|
||||||
|
|
||||||
|
async removeByUmpireId(umpireId: number): Promise<void> {
|
||||||
|
const item = await db.waitingUmpires
|
||||||
|
.where('umpireId')
|
||||||
|
.equals(umpireId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!item?.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.remove(item.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reorder (optional helper)
|
||||||
|
*/
|
||||||
|
async updateOrder(id: number, order: number): Promise<void> {
|
||||||
|
await db.waitingUmpires.update(id, { order });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear queue
|
||||||
|
*/
|
||||||
|
async clear(): Promise<void> {
|
||||||
|
await db.waitingUmpires.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
async moveToPosition(umpireId: number, newOrder: number): Promise<void> {
|
||||||
|
await db.transaction('rw', db.waitingUmpires, async () => {
|
||||||
|
const current = await db.waitingUmpires
|
||||||
|
.where('umpireId')
|
||||||
|
.equals(umpireId)
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!current) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const oldOrder = current.order;
|
||||||
|
|
||||||
|
if (oldOrder === newOrder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newOrder < oldOrder) {
|
||||||
|
// Moving up: shift affected records down
|
||||||
|
|
||||||
|
const affected = await db.waitingUmpires
|
||||||
|
.filter(
|
||||||
|
(item) =>
|
||||||
|
item.order >= newOrder &&
|
||||||
|
item.order < oldOrder &&
|
||||||
|
item.id !== current.id
|
||||||
|
)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
for (const item of affected) {
|
||||||
|
await db.waitingUmpires.update(item.id!, {
|
||||||
|
order: item.order + 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Moving down: shift affected records up
|
||||||
|
|
||||||
|
const affected = await db.waitingUmpires
|
||||||
|
.filter(
|
||||||
|
(item) =>
|
||||||
|
item.order > oldOrder &&
|
||||||
|
item.order <= newOrder &&
|
||||||
|
item.id !== current.id
|
||||||
|
)
|
||||||
|
.toArray();
|
||||||
|
|
||||||
|
for (const item of affected) {
|
||||||
|
await db.waitingUmpires.update(item.id!, {
|
||||||
|
order: item.order - 1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await db.waitingUmpires.update(current.id!, {
|
||||||
|
order: newOrder
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async reinitOrders(): Promise<void> {
|
||||||
|
await db.transaction('rw', db.waitingUmpires, async () => {
|
||||||
|
const items = await db.waitingUmpires.orderBy('order').toArray();
|
||||||
|
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
const item = items[i];
|
||||||
|
|
||||||
|
const expectedOrder = i + 1;
|
||||||
|
|
||||||
|
if (item.order !== expectedOrder) {
|
||||||
|
await db.waitingUmpires.update(item.id!, {
|
||||||
|
order: expectedOrder
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentUmpire(): Promise<Umpire | undefined> {
|
||||||
|
const item = await db.waitingUmpires.where('order').equals(1).first();
|
||||||
|
|
||||||
|
return item ? db.umpires.get(item.umpireId) : undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,17 +1,195 @@
|
|||||||
<ion-header [translucent]="true">
|
<ion-header [translucent]="true">
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title>
|
<ion-title> {{ 'courts' | translate }} </ion-title>
|
||||||
Tab 1
|
|
||||||
</ion-title>
|
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content [fullscreen]="true">
|
<ion-content [fullscreen]="true" cdkDropListGroup>
|
||||||
<ion-header collapse="condense">
|
<ion-header collapse="condense">
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title size="large">Tab 1</ion-title>
|
<ion-title size="large">{{ 'courts' | translate }}</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<app-explore-container name="Tab 1 page"></app-explore-container>
|
<ion-grid [fixed]="'fixed'" class="bottom-lists">
|
||||||
|
<ion-row>
|
||||||
|
<ion-col [size]="1" class="ion-display-none ion-display-xl-block">
|
||||||
|
<ion-item [lines]="'none'">{{ 'court' | translate }}</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col [size]="1" class="ion-display-xl-none">
|
||||||
|
<ion-item [lines]="'none'">{{ 'shortCourtName' | translate }}</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col>
|
||||||
|
<ion-item [lines]="'none'">
|
||||||
|
<ion-label class="ion-text-center"> {{ 'umpire' | translate }} </ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
@if (serviceJudgeEnabled()) {
|
||||||
|
<ion-col>
|
||||||
|
<ion-item [lines]="'none'">
|
||||||
|
<ion-label class="ion-text-center"> {{ 'serviceJudge' | translate }} </ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
}
|
||||||
|
<ion-col size="2" sizeLg="1"></ion-col>
|
||||||
|
</ion-row>
|
||||||
|
@for (item of [].constructor(settings()?.numberOfCourts); track $index) {
|
||||||
|
<ion-row>
|
||||||
|
<ion-col [size]="1">
|
||||||
|
<ion-list>
|
||||||
|
<ion-item [lines]="'none'"> {{ $index + 1 }}. </ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
<ion-col>
|
||||||
|
<ion-list
|
||||||
|
[lines]="'none'"
|
||||||
|
cdkDropList
|
||||||
|
[id]="`court-umpire-${$index + 1}`"
|
||||||
|
[cdkDropListData]="umpireByCourt().get($index + 1) ? [umpireByCourt().get($index + 1)] : []"
|
||||||
|
[cdkDropListEnterPredicate]="canDropUmpire"
|
||||||
|
(cdkDropListDropped)="dropToUmpire($event, $index + 1)">
|
||||||
|
@if (umpireByCourt().get($index + 1); as umpire) {
|
||||||
|
|
||||||
|
<div class="custom-ion-item" cdkDrag [cdkDragData]="umpire">
|
||||||
|
<div *cdkDragPlaceholder class="custom-ion-item primary">
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
@if (serviceJudgeEnabled()) {
|
||||||
|
<ion-col>
|
||||||
|
<ion-list
|
||||||
|
[lines]="'none'"
|
||||||
|
cdkDropList
|
||||||
|
[id]="`court-service-judge-${$index + 1}`"
|
||||||
|
[cdkDropListData]="serviceJudgeByCourt().get($index + 1) ? [serviceJudgeByCourt().get($index + 1)] : []"
|
||||||
|
(cdkDropListDropped)="dropToServiceJudge($event, $index + 1)">
|
||||||
|
@if (serviceJudgeByCourt().get($index + 1); as umpire) {
|
||||||
|
|
||||||
|
<div class="custom-ion-item" cdkDrag [cdkDragData]="umpire">
|
||||||
|
<div *cdkDragPlaceholder class="custom-ion-item primary">
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
}
|
||||||
|
<ion-col size="2" sizeLg="1">
|
||||||
|
<ion-list>
|
||||||
|
<ion-item lines="none">
|
||||||
|
@if ( (umpireByCourt().get($index + 1) &&
|
||||||
|
serviceJudgeByCourt().get($index + 1)) ||
|
||||||
|
(umpireByCourt().get($index + 1) && !serviceJudgeEnabled()) ) {
|
||||||
|
<ion-button
|
||||||
|
[color]="'danger'"
|
||||||
|
(click)="showRemoveConfirmation($index + 1)">
|
||||||
|
<ion-icon
|
||||||
|
slot="icon-only"
|
||||||
|
size="large"
|
||||||
|
name="exit-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
} @else if ((!umpireByCourt().get($index + 1) &&
|
||||||
|
!serviceJudgeByCourt().get($index + 1) && waitingUmpires().length &&
|
||||||
|
waitingServiceJudges().length) || (!umpireByCourt().get($index + 1)
|
||||||
|
&& waitingUmpires().length && !serviceJudgeEnabled())) {
|
||||||
|
<ion-button
|
||||||
|
[color]="'success'"
|
||||||
|
[disabled]=""
|
||||||
|
(click)="showAddConfirmation($index + 1)">
|
||||||
|
<ion-icon
|
||||||
|
slot="icon-only"
|
||||||
|
size="large"
|
||||||
|
name="enter-outline"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
}
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
}
|
||||||
|
</ion-grid>
|
||||||
|
<ion-grid [fixed]="'fixed'" class="ion-margin-top bottom-lists">
|
||||||
|
<ion-row>
|
||||||
|
<ion-col [size]="!serviceJudgeEnabled() ? 6 : 4">
|
||||||
|
<ion-item color="primary">
|
||||||
|
<ion-label class="ion-text-center"> {{ 'umpires' | translate }} </ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
@if (serviceJudgeEnabled()) {
|
||||||
|
<ion-col [size]="4">
|
||||||
|
<ion-item color="primary">
|
||||||
|
<ion-label class="ion-text-center"> {{ 'serviceJudges' | translate }} </ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
}
|
||||||
|
<ion-col [size]="!serviceJudgeEnabled() ? 6 : 4">
|
||||||
|
<ion-item color="medium">
|
||||||
|
<ion-label class="ion-text-center"> {{ 'notOnDuty' | translate }} </ion-label>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col>
|
||||||
|
<ion-list
|
||||||
|
[lines]="'none'"
|
||||||
|
cdkDropList
|
||||||
|
id="list-waiting-umpires"
|
||||||
|
[cdkDropListData]="waitingUmpires()"
|
||||||
|
(cdkDropListDropped)="dropToWaitingUmpire($event)">
|
||||||
|
@for (umpire of waitingUmpires(); track umpire.id) {
|
||||||
|
<div class="custom-ion-item" cdkDrag [cdkDragData]="umpire">
|
||||||
|
<div *cdkDragPlaceholder class="custom-ion-item primary">
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
@if (serviceJudgeEnabled()) {
|
||||||
|
<ion-col>
|
||||||
|
<ion-list
|
||||||
|
[lines]="'none'"
|
||||||
|
cdkDropList
|
||||||
|
id="list-waiting-service-judges"
|
||||||
|
[cdkDropListData]="waitingServiceJudges()"
|
||||||
|
(cdkDropListDropped)="dropToWaitingServiceJudge($event)">
|
||||||
|
@for (umpire of waitingServiceJudges(); track umpire.id) {
|
||||||
|
<div class="custom-ion-item" cdkDrag [cdkDragData]="umpire">
|
||||||
|
<div *cdkDragPlaceholder class="custom-ion-item primary">
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
}
|
||||||
|
<ion-col>
|
||||||
|
<ion-list
|
||||||
|
[lines]="'none'"
|
||||||
|
cdkDropList
|
||||||
|
cdkDropListSortingDisabled
|
||||||
|
id="list-on-rest"
|
||||||
|
(cdkDropListDropped)="dropToRest($event)"
|
||||||
|
[cdkDropListData]="onRest()">
|
||||||
|
@for (umpire of onRest(); track umpire.id) {
|
||||||
|
<div class="custom-ion-item" cdkDrag [cdkDragData]="umpire">
|
||||||
|
<div *cdkDragPlaceholder class="custom-ion-item primary">
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
<ion-label>{{ umpire|fullname }}</ion-label>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
.bottom-lists ion-list {
|
||||||
|
min-height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-ion-item {
|
||||||
|
cursor: move;
|
||||||
|
padding: 10px 15px;
|
||||||
|
|
||||||
|
&.primary {
|
||||||
|
background-color: var(--ion-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,13 +1,554 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, computed, inject } from '@angular/core';
|
||||||
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
|
import {
|
||||||
import { ExploreContainerComponent } from '../explore-container/explore-container.component';
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
IonGrid,
|
||||||
|
IonCol,
|
||||||
|
IonRow,
|
||||||
|
IonList,
|
||||||
|
IonItem,
|
||||||
|
IonLabel,
|
||||||
|
IonIcon,
|
||||||
|
IonButton,
|
||||||
|
AlertController
|
||||||
|
} from '@ionic/angular/standalone';
|
||||||
|
import { SettingsService } from '../services/settings-service';
|
||||||
|
import { UmpireService } from '../services/umpire.service';
|
||||||
|
import { Umpire } from 'db';
|
||||||
|
import { WaitingUmpiresService } from '../services/waiting-umpires.service';
|
||||||
|
import { WaitingServiceJudgesService } from '../services/waiting-service-judges.service';
|
||||||
|
import { FullnamePipe } from '../fullname-pipe';
|
||||||
|
import {
|
||||||
|
CdkDrag,
|
||||||
|
CdkDragDrop,
|
||||||
|
CdkDragPlaceholder,
|
||||||
|
CdkDropList,
|
||||||
|
CdkDropListGroup
|
||||||
|
} from '@angular/cdk/drag-drop';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { CourtUmpireService } from '../services/court.umpire.service';
|
||||||
|
import { CourtServiceJudgeService } from '../services/court.service.judge.service';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
import { enterOutline, exitOutline } from 'ionicons/icons';
|
||||||
|
import { TranslatePipe } from '../i18n/translation.pipe';
|
||||||
|
import { TranslationService } from '../i18n/translation.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tab1',
|
selector: 'app-tab1',
|
||||||
templateUrl: 'tab1.page.html',
|
templateUrl: 'tab1.page.html',
|
||||||
styleUrls: ['tab1.page.scss'],
|
styleUrls: ['tab1.page.scss'],
|
||||||
imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent],
|
providers: [FullnamePipe],
|
||||||
|
imports: [
|
||||||
|
IonButton,
|
||||||
|
IonIcon,
|
||||||
|
IonLabel,
|
||||||
|
IonItem,
|
||||||
|
IonList,
|
||||||
|
IonRow,
|
||||||
|
IonCol,
|
||||||
|
IonGrid,
|
||||||
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
FullnamePipe,
|
||||||
|
CdkDropList,
|
||||||
|
CdkDrag,
|
||||||
|
CommonModule,
|
||||||
|
CdkDragPlaceholder,
|
||||||
|
CdkDropListGroup,
|
||||||
|
TranslatePipe
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class Tab1Page {
|
export class Tab1Page {
|
||||||
constructor() {}
|
constructor() {
|
||||||
|
addIcons({ exitOutline, enterOutline });
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly settingsService = inject(SettingsService);
|
||||||
|
readonly umpireService = inject(UmpireService);
|
||||||
|
readonly waitingUmpireService = inject(WaitingUmpiresService);
|
||||||
|
readonly waitingServiceJudgeService = inject(WaitingServiceJudgesService);
|
||||||
|
readonly courtUmpireService = inject(CourtUmpireService);
|
||||||
|
readonly courtServiceJudgeService = inject(CourtServiceJudgeService);
|
||||||
|
readonly translationService = inject(TranslationService);
|
||||||
|
|
||||||
|
private alertController = inject(AlertController);
|
||||||
|
private fullnamePipe = inject(FullnamePipe);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw signals from services
|
||||||
|
*/
|
||||||
|
readonly settings = this.settingsService.settings;
|
||||||
|
|
||||||
|
readonly _umpires = this.umpireService.umpires;
|
||||||
|
|
||||||
|
readonly _waitingUmpires = this.waitingUmpireService.waitingUmpires;
|
||||||
|
|
||||||
|
readonly _waitingServiceJudges =
|
||||||
|
this.waitingServiceJudgeService.waitingServiceJudges;
|
||||||
|
|
||||||
|
readonly _courtUmpires = this.courtUmpireService.umpires;
|
||||||
|
|
||||||
|
readonly _courtServiceJudges = this.courtServiceJudgeService.umpires;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fast O(1) umpire lookup
|
||||||
|
*/
|
||||||
|
readonly umpireMap = computed(() => {
|
||||||
|
return new Map<number, Umpire>(this._umpires().map((u) => [u.id, u]));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waiting umpire IDs
|
||||||
|
*/
|
||||||
|
readonly waitingUmpireIds = computed(() => {
|
||||||
|
return new Set(this._waitingUmpires().map((w) => w.umpireId));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waiting service judge IDs
|
||||||
|
*/
|
||||||
|
readonly waitingServiceJudgeIds = computed(() => {
|
||||||
|
return new Set(this._waitingServiceJudges().map((w) => w.serviceJudgeId));
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court umpire IDs
|
||||||
|
*/
|
||||||
|
readonly courtUmpireIds = computed(() => {
|
||||||
|
return new Set(
|
||||||
|
this._courtUmpires()
|
||||||
|
.map((c) => c.umpireId)
|
||||||
|
.filter((id): id is number => id !== null)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court service judge IDs
|
||||||
|
*/
|
||||||
|
readonly courtServiceJudgeIds = computed(() => {
|
||||||
|
return new Set(
|
||||||
|
this._courtServiceJudges()
|
||||||
|
.map((c) => c.umpireId)
|
||||||
|
.filter((id): id is number => id !== null)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Umpires waiting as umpire
|
||||||
|
*/
|
||||||
|
readonly waitingUmpires = computed(() => {
|
||||||
|
const umpireMap = this.umpireMap();
|
||||||
|
|
||||||
|
return this._waitingUmpires()
|
||||||
|
.map((wu) => umpireMap.get(wu.umpireId))
|
||||||
|
.filter((u): u is Umpire => !!u);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Umpires waiting as service judge
|
||||||
|
*/
|
||||||
|
readonly waitingServiceJudges = computed(() => {
|
||||||
|
const umpireMap = this.umpireMap();
|
||||||
|
|
||||||
|
return this._waitingServiceJudges()
|
||||||
|
.map((wsj) => umpireMap.get(wsj.serviceJudgeId))
|
||||||
|
.filter((u): u is Umpire => !!u);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court umpires
|
||||||
|
*/
|
||||||
|
readonly courtUmpires = computed(() => {
|
||||||
|
const umpireMap = this.umpireMap();
|
||||||
|
|
||||||
|
return this._courtUmpires()
|
||||||
|
.map((cu) => {
|
||||||
|
if (cu.umpireId == null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return umpireMap.get(cu.umpireId);
|
||||||
|
})
|
||||||
|
.filter((u): u is Umpire => !!u);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court service judges
|
||||||
|
*/
|
||||||
|
readonly courtServiceJudges = computed(() => {
|
||||||
|
const umpireMap = this.umpireMap();
|
||||||
|
|
||||||
|
return this._courtServiceJudges()
|
||||||
|
.map((csj) => {
|
||||||
|
if (csj.umpireId == null) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return umpireMap.get(csj.umpireId);
|
||||||
|
})
|
||||||
|
.filter((u): u is Umpire => !!u);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Umpires resting
|
||||||
|
*/
|
||||||
|
readonly onRest = computed(() => {
|
||||||
|
const waitingUmpireIds = this.waitingUmpireIds();
|
||||||
|
|
||||||
|
const waitingServiceJudgeIds = this.waitingServiceJudgeIds();
|
||||||
|
|
||||||
|
const courtUmpireIds = this.courtUmpireIds();
|
||||||
|
|
||||||
|
const courtServiceJudgeIds = this.courtServiceJudgeIds();
|
||||||
|
|
||||||
|
return this._umpires().filter((umpire) => {
|
||||||
|
return (
|
||||||
|
!waitingUmpireIds.has(umpire.id) &&
|
||||||
|
!waitingServiceJudgeIds.has(umpire.id) &&
|
||||||
|
!courtUmpireIds.has(umpire.id) &&
|
||||||
|
!courtServiceJudgeIds.has(umpire.id)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court -> umpire map
|
||||||
|
*/
|
||||||
|
readonly umpireByCourt = computed(() => {
|
||||||
|
const map = new Map<number, Umpire>();
|
||||||
|
|
||||||
|
const umpireMap = this.umpireMap();
|
||||||
|
|
||||||
|
for (const item of this._courtUmpires()) {
|
||||||
|
if (item.umpireId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const umpire = umpireMap.get(item.umpireId);
|
||||||
|
|
||||||
|
if (!umpire) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.set(item.courtNo, umpire);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court -> service judge map
|
||||||
|
*/
|
||||||
|
readonly serviceJudgeByCourt = computed(() => {
|
||||||
|
const map = new Map<number, Umpire>();
|
||||||
|
|
||||||
|
const umpireMap = this.umpireMap();
|
||||||
|
|
||||||
|
for (const item of this._courtServiceJudges()) {
|
||||||
|
if (item.umpireId == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const umpire = umpireMap.get(item.umpireId);
|
||||||
|
|
||||||
|
if (!umpire) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
map.set(item.courtNo, umpire);
|
||||||
|
}
|
||||||
|
|
||||||
|
return map;
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Court indexes for template
|
||||||
|
*/
|
||||||
|
readonly courtIndexes = computed(() => {
|
||||||
|
const count = this.settings()?.numberOfCourts ?? 0;
|
||||||
|
|
||||||
|
return Array.from({ length: count }, (_, i) => i + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is service judge functionality enabled in settings.
|
||||||
|
*/
|
||||||
|
readonly serviceJudgeEnabled = computed(() => {
|
||||||
|
return this.settings()?.withServiceJudge ?? false;
|
||||||
|
});
|
||||||
|
|
||||||
|
dropToRest(event: CdkDragDrop<Umpire[]>) {
|
||||||
|
if (event.previousContainer === event.container) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const comingFrom = event.previousContainer.id;
|
||||||
|
const umpireToMove = event.item.data;
|
||||||
|
this.removeFromOriginalPlace(umpireToMove, comingFrom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dropToWaitingServiceJudge(event: CdkDragDrop<Umpire[]>) {
|
||||||
|
const umpireToMove = event.item.data;
|
||||||
|
if (event.previousContainer === event.container) {
|
||||||
|
this.waitingServiceJudgeService.moveToPosition(
|
||||||
|
umpireToMove.id,
|
||||||
|
event.currentIndex + 1
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const comingFrom = event.previousContainer.id;
|
||||||
|
|
||||||
|
this.waitingServiceJudgeService.add(
|
||||||
|
umpireToMove.id,
|
||||||
|
event.currentIndex + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
this.removeFromOriginalPlace(umpireToMove, comingFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropToWaitingUmpire(event: CdkDragDrop<Umpire[]>) {
|
||||||
|
const umpireToMove = event.item.data;
|
||||||
|
if (event.previousContainer === event.container) {
|
||||||
|
this.waitingUmpireService.moveToPosition(
|
||||||
|
umpireToMove.id,
|
||||||
|
event.currentIndex + 1
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const comingFrom = event.previousContainer.id;
|
||||||
|
this.waitingUmpireService.add(umpireToMove.id, event.currentIndex + 1);
|
||||||
|
|
||||||
|
this.removeFromOriginalPlace(umpireToMove, comingFrom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dropToUmpire(event: CdkDragDrop<(Umpire | undefined)[]>, courtNo: number) {
|
||||||
|
const targetUmpires = event.container.data;
|
||||||
|
|
||||||
|
if (targetUmpires.length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const comingFrom = event.previousContainer.id;
|
||||||
|
const umpireToMove = event.item.data;
|
||||||
|
this.courtUmpireService.save({ umpireId: umpireToMove.id, courtNo });
|
||||||
|
|
||||||
|
this.removeFromOriginalPlace(umpireToMove, comingFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
dropToServiceJudge(
|
||||||
|
event: CdkDragDrop<(Umpire | undefined)[]>,
|
||||||
|
courtNo: number
|
||||||
|
) {
|
||||||
|
const targetUmpires = event.container.data;
|
||||||
|
|
||||||
|
if (targetUmpires.length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const comingFrom = event.previousContainer.id;
|
||||||
|
const umpireToMove = event.item.data;
|
||||||
|
this.courtServiceJudgeService.save({ umpireId: umpireToMove.id, courtNo });
|
||||||
|
|
||||||
|
this.removeFromOriginalPlace(umpireToMove, comingFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeFromOriginalPlace(
|
||||||
|
umpireToMove: Umpire,
|
||||||
|
comingFrom: string
|
||||||
|
): void {
|
||||||
|
if ('list-waiting-service-judges' === comingFrom) {
|
||||||
|
this.waitingServiceJudgeService.removeByUmpireId(umpireToMove.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('list-waiting-umpires' === comingFrom) {
|
||||||
|
this.waitingUmpireService.removeByUmpireId(umpireToMove.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comingFrom.startsWith('court-umpire')) {
|
||||||
|
this.courtUmpireService.removeByUmpireId(umpireToMove.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (comingFrom.startsWith('court-service-judge')) {
|
||||||
|
this.courtServiceJudgeService.removeByUmpireId(umpireToMove.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canDropUmpire = (
|
||||||
|
drag: CdkDrag<Umpire>,
|
||||||
|
drop: CdkDropList<Umpire[]>
|
||||||
|
): boolean => {
|
||||||
|
return drop.data.length === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
public async showRemoveConfirmation(courtNo: number) {
|
||||||
|
const umpire = this.umpireByCourt().get(courtNo);
|
||||||
|
const serviceJudge = this.serviceJudgeByCourt().get(courtNo);
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof umpire === 'undefined' ||
|
||||||
|
(typeof serviceJudge === 'undefined' && this.serviceJudgeEnabled())
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.settings()?.showAlert) {
|
||||||
|
this.removeUmpiresFromCourt(courtNo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const alert = await this.alertController.create({
|
||||||
|
header: this.translationService.translate('courtConfirm', {
|
||||||
|
courtNo
|
||||||
|
}),
|
||||||
|
|
||||||
|
subHeader: this.translationService.translate(
|
||||||
|
serviceJudge ? 'removeUmpiresFromCourt' : 'removeUmpireFromCourt'
|
||||||
|
),
|
||||||
|
|
||||||
|
cssClass: 'wide',
|
||||||
|
|
||||||
|
message: `${this.fullnamePipe.transform(umpire)}${
|
||||||
|
serviceJudge ? ' - ' : ''
|
||||||
|
}${this.fullnamePipe.transform(serviceJudge)}`,
|
||||||
|
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: this.translationService.translate('no'),
|
||||||
|
role: 'cancel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translationService.translate('yes'),
|
||||||
|
role: 'confirm',
|
||||||
|
handler: () => {
|
||||||
|
if (this.serviceJudgeEnabled()) {
|
||||||
|
this.removeUmpiresFromCourt(courtNo);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.removeUmpireFromCourt(courtNo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is for removing both umpire and service judge from the court (when service judge is enabled).
|
||||||
|
*/
|
||||||
|
private async removeUmpiresFromCourt(courtNo: number) {
|
||||||
|
const umpire = this.umpireByCourt().get(courtNo);
|
||||||
|
const serviceJudge = this.serviceJudgeByCourt().get(courtNo);
|
||||||
|
|
||||||
|
if (typeof umpire === 'undefined' || typeof serviceJudge === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.courtUmpireService.removeByUmpireId(umpire.id);
|
||||||
|
await this.courtServiceJudgeService.removeByUmpireId(serviceJudge.id);
|
||||||
|
await this.waitingUmpireService.add(serviceJudge.id);
|
||||||
|
await this.waitingServiceJudgeService.add(umpire.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is for removing 1 umpire only (when service judge is not enabled).
|
||||||
|
*/
|
||||||
|
private async removeUmpireFromCourt(courtNo: number) {
|
||||||
|
const umpire = this.umpireByCourt().get(courtNo);
|
||||||
|
|
||||||
|
if (typeof umpire === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.courtUmpireService.removeByUmpireId(umpire.id);
|
||||||
|
await this.waitingUmpireService.add(umpire.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async showAddConfirmation(courtNo: number) {
|
||||||
|
const umpire = await this.waitingUmpireService.getCurrentUmpire();
|
||||||
|
const serviceJudge =
|
||||||
|
await this.waitingServiceJudgeService.getCurrentUmpire();
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof umpire === 'undefined' ||
|
||||||
|
(typeof serviceJudge === 'undefined' && this.serviceJudgeEnabled())
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.settings()?.showAlert) {
|
||||||
|
if (this.serviceJudgeEnabled() && serviceJudge) {
|
||||||
|
this.addUmpiresToCourt(courtNo, umpire, serviceJudge);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.addUmpireToCourt(courtNo, umpire);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const alert = await this.alertController.create({
|
||||||
|
header: this.translationService.translate('court', {
|
||||||
|
courtNo
|
||||||
|
}),
|
||||||
|
|
||||||
|
cssClass: 'wide',
|
||||||
|
|
||||||
|
subHeader: this.translationService.translate(
|
||||||
|
serviceJudge ? 'sendUmpiresToCourt' : 'sendUmpireToCourt'
|
||||||
|
),
|
||||||
|
|
||||||
|
message: this.translationService.translate(
|
||||||
|
serviceJudge ? 'sendUmpiresMessage' : 'sendUmpireMessage',
|
||||||
|
{
|
||||||
|
umpire: this.fullnamePipe.transform(umpire),
|
||||||
|
serviceJudge: this.fullnamePipe.transform(serviceJudge)
|
||||||
|
}
|
||||||
|
),
|
||||||
|
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: this.translationService.translate('no'),
|
||||||
|
role: 'cancel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translationService.translate('yes'),
|
||||||
|
role: 'confirm',
|
||||||
|
handler: () => {
|
||||||
|
if (this.serviceJudgeEnabled() && serviceJudge) {
|
||||||
|
this.addUmpiresToCourt(courtNo, umpire, serviceJudge);
|
||||||
|
} else {
|
||||||
|
this.addUmpireToCourt(courtNo, umpire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async addUmpiresToCourt(
|
||||||
|
courtNo: number,
|
||||||
|
umpire: Umpire,
|
||||||
|
serviceJudge: Umpire
|
||||||
|
) {
|
||||||
|
await this.courtUmpireService.save({ courtNo, umpireId: umpire.id });
|
||||||
|
await this.courtServiceJudgeService.save({
|
||||||
|
courtNo,
|
||||||
|
umpireId: serviceJudge.id
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.waitingUmpireService.removeByUmpireId(umpire.id);
|
||||||
|
await this.waitingServiceJudgeService.removeByUmpireId(serviceJudge.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async addUmpireToCourt(courtNo: number, umpire: Umpire) {
|
||||||
|
await this.courtUmpireService.save({ courtNo, umpireId: umpire.id });
|
||||||
|
await this.waitingUmpireService.removeByUmpireId(umpire.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,104 @@
|
|||||||
<ion-header [translucent]="true">
|
<ion-header [translucent]="true">
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title>
|
<ion-title> {{ 'courtOfficials' | translate }} </ion-title>
|
||||||
Tab 2
|
<ion-buttons [slot]="'end'">
|
||||||
</ion-title>
|
<ion-button [color]="'primary'" [fill]="'solid'" id="open-modal">
|
||||||
|
<ion-icon slot="start" name="add"></ion-icon>
|
||||||
|
{{ 'add' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content [fullscreen]="true">
|
<ion-content [fullscreen]="true">
|
||||||
<ion-header collapse="condense">
|
<ion-header collapse="condense">
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title size="large">Tab 2</ion-title>
|
<ion-title size="large">Játékvezetők</ion-title>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<app-explore-container name="Tab 2 page"></app-explore-container>
|
<ion-grid>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col size="12" sizeMd="6" pushMd="3">
|
||||||
|
<ion-list>
|
||||||
|
@for (umpire of umpires(); track umpire.id) {
|
||||||
|
<ion-item>
|
||||||
|
<ion-label> {{ umpire | fullname }} </ion-label>
|
||||||
|
<ion-button
|
||||||
|
[color]="'danger'"
|
||||||
|
slot="end"
|
||||||
|
(click)="showDeleteConfirmation(umpire)">
|
||||||
|
<ion-icon slot="icon-only" name="trash"></ion-icon>
|
||||||
|
</ion-button>
|
||||||
|
</ion-item>
|
||||||
|
} @empty {
|
||||||
|
<ion-item> {{ 'noCourtOfficials' | translate }} </ion-item>
|
||||||
|
}
|
||||||
|
</ion-list>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
|
|
||||||
|
<ion-modal trigger="open-modal" (willDismiss)="onWillDismiss($event)">
|
||||||
|
<ng-template>
|
||||||
|
<ion-header>
|
||||||
|
<ion-toolbar>
|
||||||
|
<ion-buttons slot="start">
|
||||||
|
<ion-button (click)="cancel()"
|
||||||
|
>{{ 'cancel' | translate }}</ion-button
|
||||||
|
>
|
||||||
|
</ion-buttons>
|
||||||
|
<ion-title>{{ 'newCourtOfficial' | translate }}</ion-title>
|
||||||
|
<ion-buttons slot="end">
|
||||||
|
<ion-button
|
||||||
|
[disabled]="!isValidUmpire()"
|
||||||
|
(click)="confirm()"
|
||||||
|
[strong]="true">
|
||||||
|
{{ 'save' | translate }}
|
||||||
|
</ion-button>
|
||||||
|
</ion-buttons>
|
||||||
|
</ion-toolbar>
|
||||||
|
</ion-header>
|
||||||
|
<ion-content class="ion-padding">
|
||||||
|
<ion-list>
|
||||||
|
<ion-item>
|
||||||
|
<ion-input
|
||||||
|
[label]="'lastName' | translate"
|
||||||
|
labelPlacement="stacked"
|
||||||
|
type="text"
|
||||||
|
placeholder="{{ 'lastName' | translate }}"
|
||||||
|
[(ngModel)]="lastName" />
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-input
|
||||||
|
[label]="'firstName' | translate"
|
||||||
|
labelPlacement="stacked"
|
||||||
|
type="text"
|
||||||
|
placeholder="{{ 'firstName' | translate }}"
|
||||||
|
[(ngModel)]="firstName" />
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-input
|
||||||
|
[label]="'country' | translate"
|
||||||
|
labelPlacement="stacked"
|
||||||
|
type="text"
|
||||||
|
placeholder="{{ 'country' | translate }}"
|
||||||
|
[(ngModel)]="country" />
|
||||||
|
</ion-item>
|
||||||
|
<ion-item>
|
||||||
|
<ion-select
|
||||||
|
[label]="'gender' | translate"
|
||||||
|
placeholder="{{ 'gender' | translate }}"
|
||||||
|
[(ngModel)]="gender">
|
||||||
|
@for (item of genders; track item.code) {
|
||||||
|
<ion-select-option [value]="item.code">
|
||||||
|
{{item.label | translate }}
|
||||||
|
</ion-select-option>
|
||||||
|
}
|
||||||
|
</ion-select>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
</ion-content>
|
||||||
|
</ng-template>
|
||||||
|
</ion-modal>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -1,15 +1,153 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, inject, ViewChild } from '@angular/core';
|
||||||
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
|
import {
|
||||||
import { ExploreContainerComponent } from '../explore-container/explore-container.component';
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
IonButtons,
|
||||||
|
IonButton,
|
||||||
|
IonIcon,
|
||||||
|
IonModal,
|
||||||
|
IonItem,
|
||||||
|
IonInput,
|
||||||
|
IonSelect,
|
||||||
|
IonSelectOption,
|
||||||
|
IonList,
|
||||||
|
IonGrid,
|
||||||
|
IonRow,
|
||||||
|
IonCol,
|
||||||
|
IonLabel,
|
||||||
|
AlertController
|
||||||
|
} from '@ionic/angular/standalone';
|
||||||
|
import { UmpireService } from '../services/umpire.service';
|
||||||
|
import { Umpire } from 'db';
|
||||||
|
import { addIcons } from 'ionicons';
|
||||||
|
import { add, trash } from 'ionicons/icons';
|
||||||
|
import { OverlayEventDetail } from '@ionic/core/components';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { FullnamePipe } from '../fullname-pipe';
|
||||||
|
import { TranslatePipe } from '../i18n/translation.pipe';
|
||||||
|
import { TranslationKey } from '../i18n/translations';
|
||||||
|
import { TranslationService } from '../i18n/translation.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tab2',
|
selector: 'app-tab2',
|
||||||
templateUrl: 'tab2.page.html',
|
templateUrl: 'tab2.page.html',
|
||||||
styleUrls: ['tab2.page.scss'],
|
styleUrls: ['tab2.page.scss'],
|
||||||
imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent]
|
providers: [FullnamePipe],
|
||||||
|
imports: [
|
||||||
|
IonLabel,
|
||||||
|
IonCol,
|
||||||
|
IonRow,
|
||||||
|
IonGrid,
|
||||||
|
IonInput,
|
||||||
|
IonItem,
|
||||||
|
IonModal,
|
||||||
|
IonIcon,
|
||||||
|
IonButton,
|
||||||
|
IonButtons,
|
||||||
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
FormsModule,
|
||||||
|
IonSelect,
|
||||||
|
IonSelectOption,
|
||||||
|
IonList,
|
||||||
|
FullnamePipe,
|
||||||
|
TranslatePipe
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class Tab2Page {
|
export class Tab2Page {
|
||||||
|
readonly translationService = inject(TranslationService);
|
||||||
|
|
||||||
constructor() {}
|
@ViewChild(IonModal) modal!: IonModal;
|
||||||
|
|
||||||
|
public readonly umpireService = inject(UmpireService);
|
||||||
|
public readonly fullnamePipe = inject(FullnamePipe);
|
||||||
|
public readonly alertController = inject(AlertController);
|
||||||
|
|
||||||
|
public readonly umpires = this.umpireService.umpires;
|
||||||
|
|
||||||
|
public lastName: string = '';
|
||||||
|
public firstName: string = '';
|
||||||
|
public country: string = '';
|
||||||
|
public gender: string = '';
|
||||||
|
|
||||||
|
public genders: { label: TranslationKey; code: string }[] = [
|
||||||
|
{ label: 'male', code: 'M' },
|
||||||
|
{ label: 'female', code: 'W' }
|
||||||
|
];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
addIcons({ add, trash });
|
||||||
|
}
|
||||||
|
|
||||||
|
public async onWillDismiss(event: CustomEvent<OverlayEventDetail>) {
|
||||||
|
if (event.detail.role !== 'confirm') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newUmpire: Umpire = event.detail.data;
|
||||||
|
|
||||||
|
await this.umpireService.create({
|
||||||
|
firstName: newUmpire.firstName,
|
||||||
|
lastName: newUmpire.lastName,
|
||||||
|
country: newUmpire.country,
|
||||||
|
gender: newUmpire.gender
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
cancel() {
|
||||||
|
this.modal.dismiss(null, 'cancel');
|
||||||
|
}
|
||||||
|
|
||||||
|
async confirm() {
|
||||||
|
await this.modal.dismiss(
|
||||||
|
{
|
||||||
|
lastName: this.lastName,
|
||||||
|
firstName: this.firstName,
|
||||||
|
country: this.country,
|
||||||
|
gender: this.gender
|
||||||
|
},
|
||||||
|
'confirm'
|
||||||
|
);
|
||||||
|
|
||||||
|
this.lastName = '';
|
||||||
|
this.firstName = '';
|
||||||
|
this.country = '';
|
||||||
|
this.gender = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
isValidUmpire(): boolean {
|
||||||
|
return this.lastName !== '' && this.firstName !== '';
|
||||||
|
}
|
||||||
|
|
||||||
|
public async showDeleteConfirmation(umpire: Umpire): Promise<void> {
|
||||||
|
const alert = await this.alertController.create({
|
||||||
|
header: this.translationService.translate('confirmation'),
|
||||||
|
subHeader: this.translationService.translate('confirmDeleteUmpire'),
|
||||||
|
message: this.fullnamePipe.transform(umpire),
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
text: this.translationService.translate('no'),
|
||||||
|
role: 'cancel'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: this.translationService.translate('yes'),
|
||||||
|
role: 'confirm',
|
||||||
|
handler: () => {
|
||||||
|
// TODO: also remove from first tab
|
||||||
|
this.removeUmpire(umpire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
await alert.present();
|
||||||
|
}
|
||||||
|
|
||||||
|
private removeUmpire(umpire: Umpire): void {
|
||||||
|
this.umpireService.delete(umpire.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,71 @@
|
|||||||
<ion-header [translucent]="true">
|
<ion-header>
|
||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-title>
|
<ion-title>{{ 'settings' | translate }}</ion-title>
|
||||||
Tab 3
|
|
||||||
</ion-title>
|
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content [fullscreen]="true">
|
<ion-content>
|
||||||
<ion-header collapse="condense">
|
<ion-grid [fixed]="true">
|
||||||
<ion-toolbar>
|
<ion-row>
|
||||||
<ion-title size="large">Tab 3</ion-title>
|
<ion-col sizeLg="6" pushLg="3">
|
||||||
</ion-toolbar>
|
@if (settings(); as currentSettings) {
|
||||||
</ion-header>
|
|
||||||
|
|
||||||
<app-explore-container name="Tab 3 page"></app-explore-container>
|
<ion-list>
|
||||||
|
<ion-item>
|
||||||
|
<ion-select
|
||||||
|
[label]="'language' | translate"
|
||||||
|
[value]="translationService.language()"
|
||||||
|
(ionChange)="updateLanguage($event)"
|
||||||
|
interface="popover">
|
||||||
|
<ion-select-option value="en">
|
||||||
|
{{ 'english' | translate }}
|
||||||
|
</ion-select-option>
|
||||||
|
|
||||||
|
<ion-select-option value="hu">
|
||||||
|
{{ 'hungarian' | translate }}
|
||||||
|
</ion-select-option>
|
||||||
|
</ion-select>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-toggle
|
||||||
|
[checked]="currentSettings.withServiceJudge"
|
||||||
|
(ionChange)="updateWithServiceJudge($event)">
|
||||||
|
{{ 'serviceJudge' | translate }}
|
||||||
|
</ion-toggle>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-toggle
|
||||||
|
[checked]="currentSettings.showAlert"
|
||||||
|
(ionChange)="updateShowAlert($event)">
|
||||||
|
{{ 'showAlerts' | translate }}
|
||||||
|
</ion-toggle>
|
||||||
|
</ion-item>
|
||||||
|
|
||||||
|
<ion-item>
|
||||||
|
<ion-input
|
||||||
|
[label]="'numberOfCourts' | translate"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
labelPlacement="floating"
|
||||||
|
[value]="currentSettings.numberOfCourts"
|
||||||
|
(ionInput)="updateNumberOfCourts($event)">
|
||||||
|
</ion-input>
|
||||||
|
</ion-item>
|
||||||
|
</ion-list>
|
||||||
|
|
||||||
|
}
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
<ion-row>
|
||||||
|
<ion-col sizeLg="6" pushLg="3">
|
||||||
|
<ion-item>
|
||||||
|
<ion-label class="ion-text-center"
|
||||||
|
>{{ 'version' | translate }}: 1.1.4</ion-label
|
||||||
|
>
|
||||||
|
</ion-item>
|
||||||
|
</ion-col>
|
||||||
|
</ion-row>
|
||||||
|
</ion-grid>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|||||||
@@ -1,13 +1,107 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, inject } from '@angular/core';
|
||||||
import { IonHeader, IonToolbar, IonTitle, IonContent } from '@ionic/angular/standalone';
|
import {
|
||||||
import { ExploreContainerComponent } from '../explore-container/explore-container.component';
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
IonList,
|
||||||
|
IonItem,
|
||||||
|
IonToggle,
|
||||||
|
IonInput,
|
||||||
|
IonGrid,
|
||||||
|
IonCol,
|
||||||
|
IonRow,
|
||||||
|
IonSelect,
|
||||||
|
IonSelectOption,
|
||||||
|
IonLabel
|
||||||
|
} from '@ionic/angular/standalone';
|
||||||
|
import { SettingsService } from '../services/settings-service';
|
||||||
|
import { CourtUmpireService } from '../services/court.umpire.service';
|
||||||
|
import { CourtServiceJudgeService } from '../services/court.service.judge.service';
|
||||||
|
import { CourtServiceJudge } from 'db';
|
||||||
|
import { WaitingServiceJudgesService } from '../services/waiting-service-judges.service';
|
||||||
|
import { TranslationService } from '../i18n/translation.service';
|
||||||
|
import { Language } from '../i18n/translations';
|
||||||
|
import { TranslatePipe } from '../i18n/translation.pipe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tab3',
|
selector: 'app-tab3',
|
||||||
templateUrl: 'tab3.page.html',
|
templateUrl: 'tab3.page.html',
|
||||||
styleUrls: ['tab3.page.scss'],
|
styleUrls: ['tab3.page.scss'],
|
||||||
imports: [IonHeader, IonToolbar, IonTitle, IonContent, ExploreContainerComponent],
|
imports: [
|
||||||
|
IonRow,
|
||||||
|
IonCol,
|
||||||
|
IonGrid,
|
||||||
|
IonInput,
|
||||||
|
IonToggle,
|
||||||
|
IonItem,
|
||||||
|
IonList,
|
||||||
|
IonHeader,
|
||||||
|
IonToolbar,
|
||||||
|
IonTitle,
|
||||||
|
IonContent,
|
||||||
|
IonSelect,
|
||||||
|
IonSelectOption,
|
||||||
|
TranslatePipe,
|
||||||
|
IonLabel
|
||||||
|
]
|
||||||
})
|
})
|
||||||
export class Tab3Page {
|
export class Tab3Page {
|
||||||
constructor() {}
|
readonly settingsService = inject(SettingsService);
|
||||||
|
readonly courtUmpireService = inject(CourtUmpireService);
|
||||||
|
readonly courtServiceJudgeService = inject(CourtServiceJudgeService);
|
||||||
|
readonly waitingServiceJudgeService = inject(WaitingServiceJudgesService);
|
||||||
|
readonly translationService = inject(TranslationService);
|
||||||
|
|
||||||
|
readonly settings = this.settingsService.settings;
|
||||||
|
|
||||||
|
async updateNumberOfCourts(event: CustomEvent): Promise<void> {
|
||||||
|
this.courtUmpireService
|
||||||
|
.umpires()
|
||||||
|
.filter((cu) => {
|
||||||
|
return cu.courtNo > Number(event.detail.value);
|
||||||
|
})
|
||||||
|
.map((cu) => {
|
||||||
|
this.courtUmpireService.delete(cu.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.courtServiceJudgeService
|
||||||
|
.umpires()
|
||||||
|
.filter((cu) => {
|
||||||
|
return cu.courtNo > Number(event.detail.value);
|
||||||
|
})
|
||||||
|
.map((cu) => {
|
||||||
|
this.courtServiceJudgeService.delete(cu.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.settingsService.update({
|
||||||
|
numberOfCourts: Number(event.detail.value)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateWithServiceJudge(event: CustomEvent): Promise<void> {
|
||||||
|
await this.settingsService.update({
|
||||||
|
withServiceJudge: event.detail.checked
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!event.detail.checked) {
|
||||||
|
this.courtServiceJudgeService.umpires().map((csj: CourtServiceJudge) => {
|
||||||
|
this.courtServiceJudgeService.delete(csj.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.waitingServiceJudgeService.waitingServiceJudges().map((wsj) => {
|
||||||
|
this.waitingServiceJudgeService.remove(wsj.id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateShowAlert(event: CustomEvent): Promise<void> {
|
||||||
|
await this.settingsService.update({
|
||||||
|
showAlert: event.detail.checked
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateLanguage(event: CustomEvent): void {
|
||||||
|
this.translationService.setLanguage(event.detail.value as Language);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
<ion-tabs>
|
<ion-tabs>
|
||||||
<ion-tab-bar slot="bottom">
|
<ion-tab-bar slot="bottom">
|
||||||
<ion-tab-button tab="pilot" href="/tabs/pilot">
|
<ion-tab-button tab="pilot" href="/tabs/pilot">
|
||||||
<ion-icon aria-hidden="true" name="triangle"></ion-icon>
|
<ion-icon aria-hidden="true" name="grid-outline"></ion-icon>
|
||||||
<ion-label>Tab 1</ion-label>
|
<ion-label>{{ 'courts' | translate }}</ion-label>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
|
|
||||||
<ion-tab-button tab="umpires" href="/tabs/umpires">
|
<ion-tab-button tab="umpires" href="/tabs/umpires">
|
||||||
<ion-icon aria-hidden="true" name="ellipse"></ion-icon>
|
<ion-icon aria-hidden="true" name="people-outline"></ion-icon>
|
||||||
<ion-label>Tab 2</ion-label>
|
<ion-label>{{ 'courtOfficials' | translate }}</ion-label>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
|
|
||||||
<ion-tab-button tab="stats" href="/tabs/stats">
|
<ion-tab-button tab="settings" href="/tabs/settings">
|
||||||
<ion-icon aria-hidden="true" name="square"></ion-icon>
|
<ion-icon aria-hidden="true" name="settings-outline"></ion-icon>
|
||||||
<ion-label>Tab 3</ion-label>
|
<ion-label>{{ 'settings' | translate }}</ion-label>
|
||||||
</ion-tab-button>
|
</ion-tab-button>
|
||||||
</ion-tab-bar>
|
</ion-tab-bar>
|
||||||
</ion-tabs>
|
</ion-tabs>
|
||||||
|
|||||||
@@ -1,18 +1,25 @@
|
|||||||
import { Component, EnvironmentInjector, inject } from '@angular/core';
|
import { Component, EnvironmentInjector, inject } from '@angular/core';
|
||||||
import { IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel } from '@ionic/angular/standalone';
|
import {
|
||||||
|
IonTabs,
|
||||||
|
IonTabBar,
|
||||||
|
IonTabButton,
|
||||||
|
IonIcon,
|
||||||
|
IonLabel
|
||||||
|
} from '@ionic/angular/standalone';
|
||||||
import { addIcons } from 'ionicons';
|
import { addIcons } from 'ionicons';
|
||||||
import { triangle, ellipse, square } from 'ionicons/icons';
|
import { gridOutline, peopleOutline, settingsOutline } from 'ionicons/icons';
|
||||||
|
import { TranslatePipe } from '../i18n/translation.pipe';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-tabs',
|
selector: 'app-tabs',
|
||||||
templateUrl: 'tabs.page.html',
|
templateUrl: 'tabs.page.html',
|
||||||
styleUrls: ['tabs.page.scss'],
|
styleUrls: ['tabs.page.scss'],
|
||||||
imports: [IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel],
|
imports: [IonTabs, IonTabBar, IonTabButton, IonIcon, IonLabel, TranslatePipe]
|
||||||
})
|
})
|
||||||
export class TabsPage {
|
export class TabsPage {
|
||||||
public environmentInjector = inject(EnvironmentInjector);
|
public environmentInjector = inject(EnvironmentInjector);
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
addIcons({ triangle, ellipse, square });
|
addIcons({ gridOutline, peopleOutline, settingsOutline });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export const routes: Routes = [
|
|||||||
loadComponent: () => import('../tab2/tab2.page').then((m) => m.Tab2Page)
|
loadComponent: () => import('../tab2/tab2.page').then((m) => m.Tab2Page)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'stats',
|
path: 'settings',
|
||||||
loadComponent: () => import('../tab3/tab3.page').then((m) => m.Tab3Page)
|
loadComponent: () => import('../tab3/tab3.page').then((m) => m.Tab3Page)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
|
After Width: | Height: | Size: 1.3 MiB |
|
After Width: | Height: | Size: 346 B |