first commit
@@ -0,0 +1,31 @@
|
|||||||
|
# Contribuer à Ben-to
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. Ouvrir ou **référencer une issue** GitHub (comportement attendu, contexte, critères d’acceptation).
|
||||||
|
2. Créer une branche depuis `main` : `feat/issue-123-courte-description`, `fix/issue-123-…`, etc.
|
||||||
|
3. Implémenter en respectant la structure **feature-first** (`packages/features/*`, `packages/shared/*`) et les règles du dépôt (`.cursor/rules/`).
|
||||||
|
4. **Scénarios Gherkin** (`specs/features/*.feature`) : tout tag `@int-*` doit apparaître dans un fichier `*.int.test.ts` correspondant (voir `npm run check:gherkin-scenarios`).
|
||||||
|
5. **Imports explicites** : pas de fichier barrel `packages/**/src/index.ts` ; utiliser les sous-chemins documentés dans les `package.json` `exports` et les alias Vite (`@ben-to/.../domain`, etc.).
|
||||||
|
6. Avant la PR : `npm run check:quality` et `npm run test:ci`.
|
||||||
|
7. **Issue GitHub** : la laisser **ouverte** jusqu’au merge de la PR. Inclure dans le **message de commit** (recommandé, dernière ligne) `Closes #N` / `Fixes #N` pour que GitHub ferme l’issue automatiquement au merge ; éviter de fermer l’issue manuellement avant la fusion.
|
||||||
|
|
||||||
|
### Hook pre-commit (tests unitaires)
|
||||||
|
|
||||||
|
Après `npm install`, Husky installe un hook qui exécute `vitest related` sur les fichiers `.ts` / `.tsx` stagés (projet **unit** uniquement).
|
||||||
|
|
||||||
|
Contournement exceptionnel (hotfix documenté en PR) : `git commit --no-verify`.
|
||||||
|
|
||||||
|
## Qualité et couverture
|
||||||
|
|
||||||
|
- Les seuils de couverture Vitest s’appliquent aux sources sous `packages/features/**` et `packages/shared/**` (voir `vitest.config.ts`). Le front web est couvert par les **e2e**, **Axe** et **Lighthouse**.
|
||||||
|
- La CI publie un **commentaire de synthèse** sur les PR (couverture, audit npm, Axe, Lighthouse, timings navigation).
|
||||||
|
|
||||||
|
## GitHub
|
||||||
|
|
||||||
|
- Activez **Code scanning** avec CodeQL si vous voulez les résultats SARIF dans l’onglet Sécurité ; puis retirez `upload: false` dans `.github/workflows/security.yml` (voir [docs/CODE_SCANNING.md](docs/CODE_SCANNING.md)).
|
||||||
|
- Protégez la branche `main` : CI obligatoire, revues si vous travaillez en équipe.
|
||||||
|
|
||||||
|
## Mobile Android
|
||||||
|
|
||||||
|
Les commandes `mobile:*` se lancent depuis la **racine** du monorepo (voir [README.md](README.md)). La CI exécute `assembleDebug` pour détecter les régressions Gradle/Capacitor.
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
FROM node:22-alpine AS build
|
||||||
|
WORKDIR /app
|
||||||
|
ENV CI=1
|
||||||
|
COPY package*.json ./
|
||||||
|
COPY apps/web/package.json apps/web/package.json
|
||||||
|
COPY packages/features/builder/package.json packages/features/builder/package.json
|
||||||
|
COPY packages/features/recipes/package.json packages/features/recipes/package.json
|
||||||
|
COPY packages/shared/i18n/package.json packages/shared/i18n/package.json
|
||||||
|
COPY packages/shared/privacy/package.json packages/shared/privacy/package.json
|
||||||
|
RUN npm ci --no-audit --no-fund
|
||||||
|
COPY . .
|
||||||
|
RUN node scripts/build-recipes.mjs
|
||||||
|
|
||||||
|
# Vite : les VITE_* sont injectées au build (CapRover : build args ou CI avec --build-arg).
|
||||||
|
ARG VITE_MATOMO_URL=
|
||||||
|
ARG VITE_MATOMO_SITE_ID=
|
||||||
|
ENV VITE_MATOMO_URL=${VITE_MATOMO_URL}
|
||||||
|
ENV VITE_MATOMO_SITE_ID=${VITE_MATOMO_SITE_ID}
|
||||||
|
RUN npm run build:web
|
||||||
|
|
||||||
|
FROM node:22-alpine AS runtime
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production
|
||||||
|
COPY --from=build /app/apps/web/dist ./dist
|
||||||
|
RUN npm install -g serve@14.2.4 --omit=dev --no-audit --no-fund
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["serve", "-s", "dist", "-l", "3000"]
|
||||||
@@ -0,0 +1,156 @@
|
|||||||
|
# Ben-to
|
||||||
|
|
||||||
|
Constructeur de bento pixel-art, multi-plateforme (web + Android + iOS).
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- Web: SolidJS (Vite)
|
||||||
|
- Mobile: Capacitor
|
||||||
|
- Données: catalogue embarqué, progression locale (offline, sans compte cloud en V1)
|
||||||
|
- Qualité: Vitest + Playwright + Axe + Lighthouse
|
||||||
|
|
||||||
|
Partage des URLs recette (`/r/…`) et métadonnées Open Graph : voir [docs/seo-recipe-sharing.md](docs/seo-recipe-sharing.md).
|
||||||
|
|
||||||
|
Matomo (analytics + bandeau cookies) : voir [docs/matomo-analytics.md](docs/matomo-analytics.md) et `apps/web/.env.example`.
|
||||||
|
|
||||||
|
## Démarrage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run pipeline:recipes
|
||||||
|
npm run dev:web
|
||||||
|
```
|
||||||
|
|
||||||
|
Les **recettes** (fichiers `*.lang.bentext`), les **couvertures** (`ressources/public/`, placeholders dans `ressources/recipe-placeholder-covers/`), les **sprites ingrédients** (`ressources/public/ingredients.png`, `ingredient-sprites.bentext`, source Aseprite sous `ressources/source/`) sont **versionnés dans ce dépôt** — pas de synchronisation avec un serveur de contenus externe.
|
||||||
|
|
||||||
|
Après modification des sources, régénérer le catalogue :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run pipeline:recipes
|
||||||
|
```
|
||||||
|
|
||||||
|
Règles d’édition des fichiers bentext : `.cursor/rules/recipes-bentext.mdc`.
|
||||||
|
|
||||||
|
## Tester l'app web
|
||||||
|
|
||||||
|
À exécuter depuis la **racine** du dépôt.
|
||||||
|
|
||||||
|
**Même chaîne que la CI** (ESLint + TypeScript, Vitest avec **couverture** sur les packages métier, Playwright + Axe, pas de duplication unit/int séparée dans ce script) :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run pipeline:recipes # régénère le catalogue si besoin (dev / e2e)
|
||||||
|
npm run test:ci
|
||||||
|
```
|
||||||
|
|
||||||
|
Voir [CONTRIBUTING.md](CONTRIBUTING.md) (hook pre-commit, tickets, Gherkin `@int-*`).
|
||||||
|
|
||||||
|
Les **e2e** (`npm run test:e2e` ou via `test:ci`) s’appuient sur `playwright.config.ts` : le serveur Vite est démarré avec `npm run dev:web` si aucun n’écoute déjà sur le port (voir `reuseExistingServer`).
|
||||||
|
|
||||||
|
Pour **régénérer les GIF** du tour d’accueil (fichiers dans `apps/web/public/tour/`, hors `test:ci`) : `npm run tour:capture` — nécessite `ffmpeg` sur la machine (`playwright.tour-capture.config.ts`).
|
||||||
|
|
||||||
|
**Contrôles ciblés sur le paquet `apps/web`** (lint + types du front uniquement) :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run lint -w apps/web
|
||||||
|
npm run typecheck -w apps/web
|
||||||
|
```
|
||||||
|
|
||||||
|
**Build de production** du front :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run pipeline:recipes
|
||||||
|
npm run build:web
|
||||||
|
```
|
||||||
|
|
||||||
|
## Tester sur un téléphone Android (Capacitor)
|
||||||
|
|
||||||
|
Le shell natif est dans `**apps/mobile**` et embarque le build statique `**apps/web/dist**` (voir `apps/mobile/capacitor.config.ts`).
|
||||||
|
|
||||||
|
Un correctif **patch-package** (`patches/@capacitor-community+sqlite+8.1.0.patch`) remplace `proguard-android.txt` par `proguard-android-optimize.txt` dans le plugin SQLite (exigence R8 / AGP récents). Il est réappliqué à chaque `**npm install`** via le script `**postinstall`**.
|
||||||
|
|
||||||
|
**Important — répertoire courant** : `pipeline:recipes`, `build:web` et les scripts `mobile:`* sont définis dans le `**package.json` à la racine** du dépôt (`ben-to/`, là où se trouve ce README). Si vous lancez `npm run …` depuis `**apps/mobile`**, npm cherche ces scripts dans le workspace mobile et échoue (`Missing script`). Vérifiez avec `ls package.json` : vous devez voir le manifest racine, pas celui du sous-dossier.
|
||||||
|
|
||||||
|
### Prérequis
|
||||||
|
|
||||||
|
- [Android Studio](https://developer.android.com/studio) (SDK + outils plate-forme).
|
||||||
|
- Sur le téléphone : **Options pour les développeurs** activées, puis **Débogage USB** (câble USB) ou **Débogage sans fil** (Wi‑Fi) selon votre appareil.
|
||||||
|
|
||||||
|
### Première fois : ajouter la plateforme Android
|
||||||
|
|
||||||
|
Si le dossier `**apps/mobile/android/`** n’existe pas encore dans votre clone :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd apps/mobile
|
||||||
|
npx cap add android
|
||||||
|
cd ../..
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build du web, sync Capacitor, lancer sur l’appareil
|
||||||
|
|
||||||
|
**Toujours depuis la racine du dépôt** (puis Android Studio s’ouvre sur `apps/mobile/android`) :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run pipeline:recipes
|
||||||
|
npm run build:web
|
||||||
|
npm run mobile:sync
|
||||||
|
npm run mobile:open:android
|
||||||
|
```
|
||||||
|
|
||||||
|
(`mobile:sync` / `mobile:open:android` appellent le workspace `**@ben-to/mobile**` ; évite les erreurs du type `No workspaces found` si le flag `-w` ne cible pas le bon nom.)
|
||||||
|
|
||||||
|
Dans Android Studio : choisir votre téléphone comme cible, puis **Run** (▶).
|
||||||
|
|
||||||
|
En ligne de commande (appareil déjà autorisé / `adb devices` OK), **toujours depuis la racine** :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run mobile:run:android
|
||||||
|
```
|
||||||
|
|
||||||
|
### Modifier le front sans tout régénérer (optionnel)
|
||||||
|
|
||||||
|
Pour charger l’UI depuis votre PC sur le réseau local (évite un `build:web` à chaque changement), vous pouvez temporairement renseigner dans `apps/mobile/capacitor.config.ts` un bloc `server: { url: "http://VOTRE_IP_LAN:3000", cleartext: true }` (à retirer avant release), puis lancer le front avec l’écoute réseau :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run dev:web -- --host 0.0.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Adaptez le pare-feu / le même Wi‑Fi entre le PC et le téléphone.
|
||||||
|
|
||||||
|
## Qualité obligatoire
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run check:quality
|
||||||
|
npm run test:unit
|
||||||
|
npm run test:integration
|
||||||
|
npm run test:e2e
|
||||||
|
```
|
||||||
|
|
||||||
|
## CI / Sécurité
|
||||||
|
|
||||||
|
- `.github/workflows/ci.yml` — qualité, couverture, e2e + artefacts qualité, Lighthouse, **assembleDebug Android**, rapport PR
|
||||||
|
- `.github/workflows/security.yml` — CodeQL, `npm audit`, Gitleaks ([activation upload SARIF](docs/CODE_SCANNING.md))
|
||||||
|
- `.github/workflows/dependency-review.yml` — revue des dépendances sur les PR (selon options du dépôt)
|
||||||
|
- `.github/workflows/mobile-release.yml`
|
||||||
|
|
||||||
|
## Publication V1 (web + Android)
|
||||||
|
|
||||||
|
Checklist gel release : [docs/V1_LAUNCH_CHECKLIST.md](docs/V1_LAUNCH_CHECKLIST.md).
|
||||||
|
|
||||||
|
## Déploiement CapRover
|
||||||
|
|
||||||
|
- Le dépôt contient `Dockerfile` et `captain-definition` pour un déploiement via CapRover (hors GitHub Actions).
|
||||||
|
|
||||||
|
## Ticketing GitHub
|
||||||
|
|
||||||
|
Création rapide des issues MVP :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/github/create-issues.sh kazerlelutin/ben-to
|
||||||
|
```
|
||||||
|
|
||||||
|
Tickets post-MVP (builder SOLID, suppression des barrels `index`, SEO OG recettes) : gabarits sous [.github/ISSUE_TEMPLATE/](.github/ISSUE_TEMPLATE/) (`04`–`06`), corps dans [docs/tickets/](docs/tickets/), création en masse après `gh auth login` :
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/github/create-post-mvp-issues.sh
|
||||||
|
```
|
||||||
@@ -0,0 +1,91 @@
|
|||||||
|
# Using Android gitignore template: https://github.com/github/gitignore/blob/HEAD/Android.gitignore
|
||||||
|
|
||||||
|
# Built application files
|
||||||
|
*.apk
|
||||||
|
*.aar
|
||||||
|
*.ap_
|
||||||
|
*.aab
|
||||||
|
|
||||||
|
# Files for the ART/Dalvik VM
|
||||||
|
*.dex
|
||||||
|
|
||||||
|
# Java class files
|
||||||
|
*.class
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
bin/
|
||||||
|
gen/
|
||||||
|
out/
|
||||||
|
# Uncomment the following line in case you need and you don't have the release build type files in your app
|
||||||
|
# release/
|
||||||
|
|
||||||
|
# Gradle files
|
||||||
|
.gradle/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Local configuration file (sdk path, etc)
|
||||||
|
local.properties
|
||||||
|
|
||||||
|
# Proguard folder generated by Eclipse
|
||||||
|
proguard/
|
||||||
|
|
||||||
|
# Log Files
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Android Studio Navigation editor temp files
|
||||||
|
.navigation/
|
||||||
|
|
||||||
|
# Android Studio captures folder
|
||||||
|
captures/
|
||||||
|
|
||||||
|
# IntelliJ / Android Studio
|
||||||
|
*.iml
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Keystore files
|
||||||
|
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||||
|
#*.jks
|
||||||
|
#*.keystore
|
||||||
|
|
||||||
|
# External native build folder generated in Android Studio 2.2 and later
|
||||||
|
.externalNativeBuild
|
||||||
|
.cxx/
|
||||||
|
|
||||||
|
# Google Services (e.g. APIs or Firebase)
|
||||||
|
# google-services.json
|
||||||
|
|
||||||
|
# Freeline
|
||||||
|
freeline.py
|
||||||
|
freeline/
|
||||||
|
freeline_project_description.json
|
||||||
|
|
||||||
|
# fastlane
|
||||||
|
fastlane/report.xml
|
||||||
|
fastlane/Preview.html
|
||||||
|
fastlane/screenshots
|
||||||
|
fastlane/test_output
|
||||||
|
fastlane/readme.md
|
||||||
|
|
||||||
|
# Version control
|
||||||
|
vcs.xml
|
||||||
|
|
||||||
|
# lint
|
||||||
|
lint/intermediates/
|
||||||
|
lint/generated/
|
||||||
|
lint/outputs/
|
||||||
|
lint/tmp/
|
||||||
|
# lint/reports/
|
||||||
|
|
||||||
|
# Android Profiling
|
||||||
|
*.hprof
|
||||||
|
|
||||||
|
# Cordova plugins for Capacitor
|
||||||
|
capacitor-cordova-android-plugins
|
||||||
|
|
||||||
|
# Copied web assets
|
||||||
|
app/src/main/assets/public
|
||||||
|
|
||||||
|
# Generated Config files
|
||||||
|
app/src/main/assets/capacitor.config.json
|
||||||
|
app/src/main/assets/capacitor.plugins.json
|
||||||
|
app/src/main/res/xml/config.xml
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
/build/*
|
||||||
|
!/build/.npmkeep
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
/** Fichier optionnel `android/keystore.properties` + chemin `storeFile` — voir `keystore.properties.example`. */
|
||||||
|
def keystorePropertiesFile = rootProject.file("keystore.properties")
|
||||||
|
def keystoreProperties = new Properties()
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
|
||||||
|
}
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace "com.kazerlelutin.bento"
|
||||||
|
compileSdk rootProject.ext.compileSdkVersion
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.kazerlelutin.bento"
|
||||||
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
|
aaptOptions {
|
||||||
|
// Files and dirs to omit from the packaged assets dir, modified to accommodate modern web apps.
|
||||||
|
// Default: https://android.googlesource.com/platform/frameworks/base/+/282e181b58cf72b6ca770dc7ca5f91f135444502/tools/aapt/AaptAssets.cpp#61
|
||||||
|
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
keyAlias keystoreProperties["keyAlias"]
|
||||||
|
keyPassword keystoreProperties["keyPassword"]
|
||||||
|
storeFile rootProject.file(keystoreProperties["storeFile"])
|
||||||
|
storePassword keystoreProperties["storePassword"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
|
if (keystorePropertiesFile.exists()) {
|
||||||
|
signingConfig signingConfigs.release
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
flatDir{
|
||||||
|
dirs '../capacitor-cordova-android-plugins/src/main/libs', 'libs'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||||
|
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
||||||
|
implementation "androidx.core:core-splashscreen:$coreSplashScreenVersion"
|
||||||
|
implementation project(':capacitor-android')
|
||||||
|
testImplementation "junit:junit:$junitVersion"
|
||||||
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||||
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||||
|
implementation project(':capacitor-cordova-android-plugins')
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: 'capacitor.build.gradle'
|
||||||
|
|
||||||
|
try {
|
||||||
|
def servicesJSON = file('google-services.json')
|
||||||
|
if (servicesJSON.text) {
|
||||||
|
apply plugin: 'com.google.gms.google-services'
|
||||||
|
}
|
||||||
|
} catch(Exception e) {
|
||||||
|
logger.info("google-services.json not found, google-services plugin not applied. Push Notifications won't work")
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_21
|
||||||
|
targetCompatibility JavaVersion.VERSION_21
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "../capacitor-cordova-android-plugins/cordova.variables.gradle"
|
||||||
|
dependencies {
|
||||||
|
implementation project(':capacitor-share')
|
||||||
|
implementation project(':capacitor-community-sqlite')
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (hasProperty('postBuildExtras')) {
|
||||||
|
postBuildExtras()
|
||||||
|
}
|
||||||
@@ -0,0 +1,251 @@
|
|||||||
|
# This is a Gradle generated file for dependency locking.
|
||||||
|
# Manual edits can break the build and are not advised.
|
||||||
|
# This file is expected to be part of source control.
|
||||||
|
androidx.activity:activity:1.7.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.activity:activity:1.9.2=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation-experimental:1.4.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.annotation:annotation-experimental:1.4.1=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation-jvm:1.8.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.annotation:annotation:1.8.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.appcompat:appcompat-resources:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.appcompat:appcompat:1.7.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.arch.core:core-common:2.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.arch.core:core-runtime:2.1.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.arch.core:core-runtime:2.2.0=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.biometric:biometric:1.1.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.collection:collection-jvm:1.4.2=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.collection:collection:1.1.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.collection:collection:1.4.2=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures-ktx:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.concurrent:concurrent-futures:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.coordinatorlayout:coordinatorlayout:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.core:core-ktx:1.15.0=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.core:core-ktx:1.2.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.core:core-splashscreen:1.0.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.core:core:1.13.0=debugAndroidTestCompileClasspath
|
||||||
|
androidx.core:core:1.15.0=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.cursoradapter:cursoradapter:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.customview:customview:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.drawerlayout:drawerlayout:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.emoji2:emoji2-views-helper:1.3.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.emoji2:emoji2:1.3.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.fragment:fragment:1.5.4=debugAndroidTestCompileClasspath
|
||||||
|
androidx.fragment:fragment:1.8.4=debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.interpolator:interpolator:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-common:2.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-livedata-core:2.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-livedata:2.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-process:2.6.2=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-runtime:2.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.lifecycle:lifecycle-viewmodel:2.6.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.loader:loader:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.profileinstaller:profileinstaller:1.3.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.resourceinspection:resourceinspection-annotation:1.0.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.room:room-common:2.6.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.room:room-runtime:2.6.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.savedstate:savedstate:1.2.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.security:security-crypto:1.1.0-alpha06=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.sqlite:sqlite-framework:2.4.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.sqlite:sqlite:2.4.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.startup:startup-runtime:1.1.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.test.espresso:espresso-core:3.6.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test.espresso:espresso-idling-resource:3.6.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test.ext:junit:1.2.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test.services:storage:1.5.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:core:1.6.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:monitor:1.7.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.test:runner:1.6.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
androidx.tracing:tracing:1.2.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.vectordrawable:vectordrawable-animated:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.vectordrawable:vectordrawable:1.1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.versionedparcelable:versionedparcelable:1.1.1=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.viewpager:viewpager:1.0.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
androidx.webkit:webkit:1.12.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.android.tools.analytics-library:protos:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools.analytics-library:shared:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools.analytics-library:tracker:32.2.0=androidLintTool
|
||||||
|
com.android.tools.build:aapt2-proto:9.2.0-15009934=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools.build:builder-model:9.2.0=androidLintTool
|
||||||
|
com.android.tools.build:manifest-merger:32.2.0=androidLintTool
|
||||||
|
com.android.tools.ddms:ddmlib:32.2.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.emulator:proto:32.2.0=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
com.android.tools.external.com-intellij:intellij-core:32.2.0=androidLintTool
|
||||||
|
com.android.tools.external.com-intellij:kotlin-compiler:32.2.0=androidLintTool
|
||||||
|
com.android.tools.external.org-jetbrains:uast:32.2.0=androidLintTool
|
||||||
|
com.android.tools.layoutlib:layoutlib-api:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools.lint:lint-api:32.2.0=androidLintTool
|
||||||
|
com.android.tools.lint:lint-checks:32.2.0=androidLintTool
|
||||||
|
com.android.tools.lint:lint-gradle:32.2.0=androidLintTool
|
||||||
|
com.android.tools.lint:lint-model:32.2.0=androidLintTool
|
||||||
|
com.android.tools.lint:lint-typedef-remover:32.2.0=androidLintTool
|
||||||
|
com.android.tools.lint:lint:32.2.0=androidLintTool
|
||||||
|
com.android.tools.utp:android-device-provider-ddmlib-proto:32.2.0=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-device-provider-ddmlib:32.2.0=unified-test-platform-android-device-provider-ddmlib
|
||||||
|
com.android.tools.utp:android-test-plugin-host-additional-test-output-proto:32.2.0=unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-test-plugin-host-additional-test-output:32.2.0=unified-test-platform-android-test-plugin-host-additional-test-output
|
||||||
|
com.android.tools.utp:android-test-plugin-host-apk-installer-proto:32.2.0=unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-test-plugin-host-apk-installer:32.2.0=unified-test-platform-android-test-plugin-host-apk-installer
|
||||||
|
com.android.tools.utp:android-test-plugin-host-coverage-proto:32.2.0=unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-test-plugin-host-coverage:32.2.0=unified-test-platform-android-test-plugin-host-coverage
|
||||||
|
com.android.tools.utp:android-test-plugin-host-device-info-proto:32.2.0=unified-test-platform-android-test-plugin-host-device-info
|
||||||
|
com.android.tools.utp:android-test-plugin-host-device-info:32.2.0=unified-test-platform-android-test-plugin-host-device-info
|
||||||
|
com.android.tools.utp:android-test-plugin-host-emulator-control-proto:32.2.0=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-test-plugin-host-emulator-control:32.2.0=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
com.android.tools.utp:android-test-plugin-host-logcat-proto:32.2.0=unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-test-plugin-host-logcat:32.2.0=unified-test-platform-android-test-plugin-host-logcat
|
||||||
|
com.android.tools.utp:android-test-plugin-result-listener-gradle-proto:32.2.0=unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:android-test-plugin-result-listener-gradle:32.2.0=unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools.utp:gradle-work-action:32.2.0=unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools.utp:utp-common:32.2.0=unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-logcat
|
||||||
|
com.android.tools:annotations:32.2.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools:common:32.2.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.android.tools:dvlib:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools:play-sdk-proto:32.2.0=androidLintTool
|
||||||
|
com.android.tools:repository:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools:sdk-common:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.android.tools:sdklib:32.2.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.android:annotations:4.1.1.4=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
com.google.api.grpc:proto-google-common-protos:2.17.0=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core
|
||||||
|
com.google.api.grpc:proto-google-common-protos:2.48.0=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
com.google.auto.service:auto-service-annotations:1.1.1=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.auto.service:auto-service:1.1.1=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.auto:auto-common:1.2.1=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.code.findbugs:jsr305:3.0.2=androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
com.google.code.gson:gson:2.10.1=unified-test-platform-core,unified-test-platform-gradle-work-action
|
||||||
|
com.google.code.gson:gson:2.11.0=androidLintTool,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.code.gson:gson:2.8.9=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath,unified-test-platform-android-driver-instrumentation,unified-test-platform-launcher
|
||||||
|
com.google.crypto.tink:tink-android:1.8.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.google.crypto.tink:tink:1.18.0=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-gradle-work-action
|
||||||
|
com.google.dagger:dagger:2.48=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action
|
||||||
|
com.google.errorprone:error_prone_annotations:2.18.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
com.google.errorprone:error_prone_annotations:2.23.0=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
com.google.errorprone:error_prone_annotations:2.28.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.google.errorprone:error_prone_annotations:2.30.0=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
com.google.guava:failureaccess:1.0.1=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
com.google.guava:failureaccess:1.0.2=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.google.guava:guava:32.0.1-jre=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
com.google.guava:guava:33.3.1-jre=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.google.guava:listenablefuture:1.0=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
com.google.j2objc:j2objc-annotations:2.8=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
com.google.j2objc:j2objc-annotations:3.0.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.google.jimfs:jimfs:1.1=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.protobuf:protobuf-java-util:3.22.3=unified-test-platform-core
|
||||||
|
com.google.protobuf:protobuf-java-util:4.28.3=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
com.google.protobuf:protobuf-java:3.25.5=androidLintTool
|
||||||
|
com.google.protobuf:protobuf-java:4.28.3=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
com.google.protobuf:protobuf-kotlin:4.28.3=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
com.google.testing.platform:android-device-provider-local:0.0.9-alpha04=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.google.testing.platform:android-driver-instrumentation:0.0.9-alpha04=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
com.google.testing.platform:android-test-plugin:0.0.9-alpha04=unified-test-platform-android-test-plugin
|
||||||
|
com.google.testing.platform:core-proto:0.0.9-alpha04=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
com.google.testing.platform:core:0.0.9-alpha04=unified-test-platform-core
|
||||||
|
com.google.testing.platform:launcher:0.0.9-alpha04=unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
com.sun.istack:istack-commons-runtime:3.0.8=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
com.sun.xml.fastinfoset:FastInfoset:1.2.16=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
commons-codec:commons-codec:1.17.1=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
commons-io:commons-io:2.16.1=androidLintTool,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
commons-logging:commons-logging:1.2=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
io.grpc:grpc-api:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-api:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-context:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-context:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-core:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-core:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-netty:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-netty:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-protobuf-lite:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-protobuf-lite:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-protobuf:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-protobuf:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-services:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-stub:1.57.2=unified-test-platform-core
|
||||||
|
io.grpc:grpc-stub:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.grpc:grpc-util:1.69.1=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
io.netty:netty-buffer:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-codec-http2:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-codec-http:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-codec-socks:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-codec:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-common:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-handler-proxy:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-handler:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-resolver:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-transport-native-unix-common:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.netty:netty-transport:4.1.133.Final=unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-core
|
||||||
|
io.opencensus:opencensus-api:0.31.0=unified-test-platform-core
|
||||||
|
io.opencensus:opencensus-proto:0.2.0=unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
io.perfmark:perfmark-api:0.26.0=unified-test-platform-core
|
||||||
|
io.perfmark:perfmark-api:0.27.0=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
jakarta.activation:jakarta.activation-api:1.2.1=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
javax.annotation:javax.annotation-api:1.3.2=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
javax.inject:javax.inject:1=androidLintTool,debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action
|
||||||
|
junit:junit:4.13.2=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
|
net.java.dev.jna:jna-platform:5.6.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
net.java.dev.jna:jna:5.6.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
net.sf.kxml:kxml2:2.3.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
net.zetetic:sqlcipher-android:4.10.0=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.apache.commons:commons-compress:1.27.1=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.apache.commons:commons-lang3:3.16.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.apache.cordova:framework:10.1.1=debugAndroidTestLintChecksClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.apache.httpcomponents:httpclient:4.5.6=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.apache.httpcomponents:httpcore:4.4.16=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.apache.httpcomponents:httpmime:4.5.6=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.bouncycastle:bcpkix-jdk18on:1.79=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.bouncycastle:bcprov-jdk18on:1.79=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.bouncycastle:bcutil-jdk18on:1.79=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.checkerframework:checker-qual:3.33.0=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
org.checkerframework:checker-qual:3.43.0=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
org.codehaus.groovy:groovy:3.0.22=androidLintTool
|
||||||
|
org.codehaus.mojo:animal-sniffer-annotations:1.23=unified-test-platform-core
|
||||||
|
org.codehaus.mojo:animal-sniffer-annotations:1.24=unified-test-platform-android-test-plugin-host-emulator-control
|
||||||
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.glassfish.jaxb:txw2:2.3.2=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.hamcrest:hamcrest-core:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath
|
||||||
|
org.hamcrest:hamcrest-library:1.3=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath
|
||||||
|
org.jacoco:org.jacoco.agent:0.8.14=androidJacocoAnt
|
||||||
|
org.jacoco:org.jacoco.ant:0.8.14=androidJacocoAnt
|
||||||
|
org.jacoco:org.jacoco.core:0.8.14=androidJacocoAnt
|
||||||
|
org.jacoco:org.jacoco.report:0.8.14=androidJacocoAnt
|
||||||
|
org.jetbrains.kotlin:kotlin-reflect:1.8.21=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.21=unified-test-platform-android-test-plugin,unified-test-platform-core
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=unified-test-platform-android-driver-instrumentation,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-common:2.2.10=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-gradle-work-action
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-core,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.10=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib:1.8.21=unified-test-platform-android-test-plugin,unified-test-platform-core
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib:1.8.22=debugAndroidTestCompileClasspath,debugAndroidTestLintChecksClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib:1.9.0=unified-test-platform-android-driver-instrumentation,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=androidLintTool,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-gradle-work-action
|
||||||
|
org.jetbrains.kotlinx:atomicfu-jvm:0.22.0=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlinx:atomicfu:0.22.0=unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1=debugAndroidTestLintChecksClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.6.4=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.1=debugAndroidTestLintChecksClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.7.3=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.1=debugAndroidTestLintChecksClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.7.3=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.1=debugAndroidTestLintChecksClasspath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3=unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.jetbrains:annotations:13.0=debugAndroidTestCompileClasspath,debugAndroidTestRuntimeClasspath,debugCompileClasspath,debugLintChecksClasspath,debugRuntimeClasspath,debugUnitTestCompileClasspath,debugUnitTestLintChecksClasspath,debugUnitTestRuntimeClasspath,releaseCompileClasspath,releaseLintChecksClasspath,releaseRuntimeClasspath
|
||||||
|
org.jetbrains:annotations:23.0.0=androidLintTool,debugAndroidTestLintChecksClasspath,unified-test-platform-android-device-provider-ddmlib,unified-test-platform-android-driver-instrumentation,unified-test-platform-android-test-plugin,unified-test-platform-android-test-plugin-host-additional-test-output,unified-test-platform-android-test-plugin-host-apk-installer,unified-test-platform-android-test-plugin-host-coverage,unified-test-platform-android-test-plugin-host-device-info,unified-test-platform-android-test-plugin-host-emulator-control,unified-test-platform-android-test-plugin-host-logcat,unified-test-platform-android-test-plugin-result-listener-gradle,unified-test-platform-core,unified-test-platform-gradle-work-action,unified-test-platform-launcher
|
||||||
|
org.jvnet.staxex:stax-ex:1.8.1=androidLintTool,unified-test-platform-android-test-plugin-result-listener-gradle
|
||||||
|
org.ow2.asm:asm-analysis:9.9=androidLintTool
|
||||||
|
org.ow2.asm:asm-commons:9.9=androidJacocoAnt,androidLintTool
|
||||||
|
org.ow2.asm:asm-tree:9.9=androidJacocoAnt,androidLintTool
|
||||||
|
org.ow2.asm:asm:9.9=androidJacocoAnt,androidLintTool
|
||||||
|
empty=androidApis,androidJdkImage,androidTestUtil,coreLibraryDesugaring,debugAndroidTestAnnotationProcessorClasspath,debugAnnotationProcessorClasspath,debugReverseMetadataValues,debugUnitTestAnnotationProcessorClasspath,lintChecks,lintPublish,releaseAnnotationProcessorClasspath,releaseReverseMetadataValues
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# You can control the set of applied configuration files using the
|
||||||
|
# proguardFiles setting in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
||||||
|
|
||||||
|
# Uncomment this to preserve the line number information for
|
||||||
|
# debugging stack traces.
|
||||||
|
#-keepattributes SourceFile,LineNumberTable
|
||||||
|
|
||||||
|
# If you keep the line number information, uncomment this to
|
||||||
|
# hide the original source file name.
|
||||||
|
#-renamesourcefileattribute SourceFile
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.getcapacitor.myapp;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
import androidx.test.platform.app.InstrumentationRegistry;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instrumented test, which will execute on an Android device.
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class ExampleInstrumentedTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void useAppContext() throws Exception {
|
||||||
|
// Context of the app under test.
|
||||||
|
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
||||||
|
|
||||||
|
assertEquals("com.getcapacitor.app", appContext.getPackageName());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
|
android:supportsRtl="true"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
|
||||||
|
<activity
|
||||||
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode|navigation"
|
||||||
|
android:name=".MainActivity"
|
||||||
|
android:label="@string/title_activity_main"
|
||||||
|
android:theme="@style/AppTheme.NoActionBarLaunch"
|
||||||
|
android:launchMode="singleTask"
|
||||||
|
android:exported="true">
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
<provider
|
||||||
|
android:name="androidx.core.content.FileProvider"
|
||||||
|
android:authorities="${applicationId}.fileprovider"
|
||||||
|
android:exported="false"
|
||||||
|
android:grantUriPermissions="true">
|
||||||
|
<meta-data
|
||||||
|
android:name="android.support.FILE_PROVIDER_PATHS"
|
||||||
|
android:resource="@xml/file_paths"></meta-data>
|
||||||
|
</provider>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<!-- Permissions -->
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
</manifest>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package com.kazerlelutin.bento;
|
||||||
|
|
||||||
|
import com.getcapacitor.BridgeActivity;
|
||||||
|
|
||||||
|
public class MainActivity extends BridgeActivity {}
|
||||||
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 7.7 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 17 KiB |
@@ -0,0 +1,34 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:aapt="http://schemas.android.com/aapt"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportHeight="108"
|
||||||
|
android:viewportWidth="108">
|
||||||
|
<path
|
||||||
|
android:fillType="evenOdd"
|
||||||
|
android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1">
|
||||||
|
<aapt:attr name="android:fillColor">
|
||||||
|
<gradient
|
||||||
|
android:endX="78.5885"
|
||||||
|
android:endY="90.9159"
|
||||||
|
android:startX="48.7653"
|
||||||
|
android:startY="61.0927"
|
||||||
|
android:type="linear">
|
||||||
|
<item
|
||||||
|
android:color="#44000000"
|
||||||
|
android:offset="0.0" />
|
||||||
|
<item
|
||||||
|
android:color="#00000000"
|
||||||
|
android:offset="1.0" />
|
||||||
|
</gradient>
|
||||||
|
</aapt:attr>
|
||||||
|
</path>
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:fillType="nonZero"
|
||||||
|
android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z"
|
||||||
|
android:strokeColor="#00000000"
|
||||||
|
android:strokeWidth="1" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="108dp"
|
||||||
|
android:height="108dp"
|
||||||
|
android:viewportHeight="108"
|
||||||
|
android:viewportWidth="108">
|
||||||
|
<path
|
||||||
|
android:fillColor="#26A69A"
|
||||||
|
android:pathData="M0,0h108v108h-108z" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M9,0L9,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,0L19,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,0L29,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,0L39,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,0L49,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,0L59,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,0L69,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,0L79,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M89,0L89,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M99,0L99,108"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,9L108,9"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,19L108,19"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,29L108,29"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,39L108,39"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,49L108,49"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,59L108,59"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,69L108,69"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,79L108,79"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,89L108,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M0,99L108,99"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,29L89,29"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,39L89,39"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,49L89,49"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,59L89,59"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,69L89,69"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M19,79L89,79"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M29,19L29,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M39,19L39,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M49,19L49,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M59,19L59,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M69,19L69,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
<path
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:pathData="M79,19L79,89"
|
||||||
|
android:strokeColor="#33FFFFFF"
|
||||||
|
android:strokeWidth="0.8" />
|
||||||
|
</vector>
|
||||||
|
After Width: | Height: | Size: 3.9 KiB |
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".MainActivity">
|
||||||
|
|
||||||
|
<WebView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<background android:drawable="@color/ic_launcher_background"/>
|
||||||
|
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
||||||
|
</adaptive-icon>
|
||||||
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.2 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.7 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="ic_launcher_background">#FFFFFF</color>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version='1.0' encoding='utf-8'?>
|
||||||
|
<resources>
|
||||||
|
<string name="app_name">Ben-to</string>
|
||||||
|
<string name="title_activity_main">Ben-to</string>
|
||||||
|
<string name="package_name">com.kazerlelutin.bento</string>
|
||||||
|
<string name="custom_url_scheme">com.kazerlelutin.bento</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<!-- Base application theme. -->
|
||||||
|
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
|
||||||
|
<!-- Customize your theme here. -->
|
||||||
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="AppTheme.NoActionBar" parent="Theme.AppCompat.DayNight.NoActionBar">
|
||||||
|
<item name="windowActionBar">false</item>
|
||||||
|
<item name="windowNoTitle">true</item>
|
||||||
|
<item name="android:background">@null</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<style name="AppTheme.NoActionBarLaunch" parent="Theme.SplashScreen">
|
||||||
|
<item name="android:background">@drawable/splash</item>
|
||||||
|
</style>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<paths xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<external-path name="my_images" path="." />
|
||||||
|
<cache-path name="my_cache_images" path="." />
|
||||||
|
</paths>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package com.getcapacitor.myapp;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Example local unit test, which will execute on the development machine (host).
|
||||||
|
*
|
||||||
|
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
|
||||||
|
*/
|
||||||
|
public class ExampleUnitTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void addition_isCorrect() throws Exception {
|
||||||
|
assertEquals(4, 2 + 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||||
|
|
||||||
|
buildscript {
|
||||||
|
configurations.classpath {
|
||||||
|
resolutionStrategy.activateDependencyLocking()
|
||||||
|
}
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
classpath 'com.android.tools.build:gradle:9.2.0'
|
||||||
|
classpath 'com.google.gms:google-services:4.4.2'
|
||||||
|
|
||||||
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
// in the individual module build.gradle files
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "variables.gradle"
|
||||||
|
|
||||||
|
allprojects {
|
||||||
|
repositories {
|
||||||
|
google()
|
||||||
|
mavenCentral()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verrouillage des dépendances sur :app uniquement (module versionné).
|
||||||
|
// Le dossier capacitor-cordova-android-plugins est ignoré par git (généré par Capacitor) : pas de lockfiles versionnés là-bas.
|
||||||
|
subprojects { sub ->
|
||||||
|
if (sub.name == 'app') {
|
||||||
|
sub.dependencyLocking {
|
||||||
|
lockAllConfigurations()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
task clean(type: Delete) {
|
||||||
|
delete rootProject.buildDir
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
# This is a Gradle generated file for dependency locking.
|
||||||
|
# Manual edits can break the build and are not advised.
|
||||||
|
# This file is expected to be part of source control.
|
||||||
|
androidx.databinding:databinding-common:9.2.0=classpath
|
||||||
|
androidx.databinding:databinding-compiler-common:9.2.0=classpath
|
||||||
|
com.android.databinding:baseLibrary:9.2.0=classpath
|
||||||
|
com.android.tools.analytics-library:crash:32.2.0=classpath
|
||||||
|
com.android.tools.analytics-library:protos:32.2.0=classpath
|
||||||
|
com.android.tools.analytics-library:shared:32.2.0=classpath
|
||||||
|
com.android.tools.analytics-library:tracker:32.2.0=classpath
|
||||||
|
com.android.tools.build.jetifier:jetifier-core:1.0.0-beta10=classpath
|
||||||
|
com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta10=classpath
|
||||||
|
com.android.tools.build:aapt2-proto:9.2.0-15009934=classpath
|
||||||
|
com.android.tools.build:aaptcompiler:9.2.0=classpath
|
||||||
|
com.android.tools.build:apksig:9.2.0=classpath
|
||||||
|
com.android.tools.build:apkzlib:9.2.0=classpath
|
||||||
|
com.android.tools.build:builder-model:9.2.0=classpath
|
||||||
|
com.android.tools.build:builder-test-api:9.2.0=classpath
|
||||||
|
com.android.tools.build:builder:9.2.0=classpath
|
||||||
|
com.android.tools.build:bundletool:1.18.3=classpath
|
||||||
|
com.android.tools.build:gradle-api:9.2.0=classpath
|
||||||
|
com.android.tools.build:gradle-common-api:9.2.0=classpath
|
||||||
|
com.android.tools.build:gradle-settings-api:9.2.0=classpath
|
||||||
|
com.android.tools.build:gradle:9.2.0=classpath
|
||||||
|
com.android.tools.build:manifest-merger:32.2.0=classpath
|
||||||
|
com.android.tools.ddms:ddmlib:32.2.0=classpath
|
||||||
|
com.android.tools.layoutlib:layoutlib-api:32.2.0=classpath
|
||||||
|
com.android.tools.lint:lint-model:32.2.0=classpath
|
||||||
|
com.android.tools.lint:lint-typedef-remover:32.2.0=classpath
|
||||||
|
com.android.tools.utp:gradle-work-action-api:32.2.0=classpath
|
||||||
|
com.android.tools:annotations:32.2.0=classpath
|
||||||
|
com.android.tools:common:32.2.0=classpath
|
||||||
|
com.android.tools:dvlib:32.2.0=classpath
|
||||||
|
com.android.tools:repository:32.2.0=classpath
|
||||||
|
com.android.tools:sdk-common:32.2.0=classpath
|
||||||
|
com.android.tools:sdklib:32.2.0=classpath
|
||||||
|
com.android:signflinger:9.2.0=classpath
|
||||||
|
com.android:zipflinger:9.2.0=classpath
|
||||||
|
com.google.android.gms:strict-version-matcher-plugin:1.2.4=classpath
|
||||||
|
com.google.auto.value:auto-value-annotations:1.6.2=classpath
|
||||||
|
com.google.code.findbugs:jsr305:3.0.2=classpath
|
||||||
|
com.google.code.gson:gson:2.11.0=classpath
|
||||||
|
com.google.crypto.tink:tink:1.7.0=classpath
|
||||||
|
com.google.dagger:dagger:2.28.3=classpath
|
||||||
|
com.google.errorprone:error_prone_annotations:2.28.0=classpath
|
||||||
|
com.google.flatbuffers:flatbuffers-java:1.12.0=classpath
|
||||||
|
com.google.gms:google-services:4.4.2=classpath
|
||||||
|
com.google.guava:failureaccess:1.0.2=classpath
|
||||||
|
com.google.guava:guava:33.3.1-jre=classpath
|
||||||
|
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=classpath
|
||||||
|
com.google.j2objc:j2objc-annotations:3.0.0=classpath
|
||||||
|
com.google.jimfs:jimfs:1.1=classpath
|
||||||
|
com.google.protobuf:protobuf-java-util:3.25.5=classpath
|
||||||
|
com.google.protobuf:protobuf-java:3.25.5=classpath
|
||||||
|
com.googlecode.juniversalchardet:juniversalchardet:1.0.3=classpath
|
||||||
|
com.squareup:javapoet:1.13.0=classpath
|
||||||
|
com.squareup:javawriter:2.5.0=classpath
|
||||||
|
com.sun.istack:istack-commons-runtime:3.0.8=classpath
|
||||||
|
com.sun.xml.fastinfoset:FastInfoset:1.2.16=classpath
|
||||||
|
commons-codec:commons-codec:1.17.1=classpath
|
||||||
|
commons-io:commons-io:2.16.1=classpath
|
||||||
|
commons-logging:commons-logging:1.2=classpath
|
||||||
|
jakarta.activation:jakarta.activation-api:1.2.1=classpath
|
||||||
|
jakarta.xml.bind:jakarta.xml.bind-api:2.3.2=classpath
|
||||||
|
javax.inject:javax.inject:1=classpath
|
||||||
|
net.java.dev.jna:jna-platform:5.6.0=classpath
|
||||||
|
net.java.dev.jna:jna:5.6.0=classpath
|
||||||
|
net.sf.jopt-simple:jopt-simple:4.9=classpath
|
||||||
|
net.sf.kxml:kxml2:2.3.0=classpath
|
||||||
|
org.apache.commons:commons-compress:1.27.1=classpath
|
||||||
|
org.apache.commons:commons-lang3:3.16.0=classpath
|
||||||
|
org.apache.httpcomponents:httpclient:4.5.14=classpath
|
||||||
|
org.apache.httpcomponents:httpcore:4.4.16=classpath
|
||||||
|
org.apache.httpcomponents:httpmime:4.5.6=classpath
|
||||||
|
org.bitbucket.b_c:jose4j:0.9.5=classpath
|
||||||
|
org.bouncycastle:bcpkix-jdk18on:1.79=classpath
|
||||||
|
org.bouncycastle:bcprov-jdk18on:1.79=classpath
|
||||||
|
org.bouncycastle:bcutil-jdk18on:1.79=classpath
|
||||||
|
org.checkerframework:checker-qual:3.43.0=classpath
|
||||||
|
org.glassfish.jaxb:jaxb-runtime:2.3.2=classpath
|
||||||
|
org.glassfish.jaxb:txw2:2.3.2=classpath
|
||||||
|
org.jdom:jdom2:2.0.6=classpath
|
||||||
|
org.jetbrains.kotlin:abi-tools-api:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:fus-statistics-gradle-plugin:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-build-statistics:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-build-tools-api:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-compiler-runner:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-daemon-client:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugin-annotations:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugin-api:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugin-idea-proto:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugin-idea:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugin-model:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugin:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-gradle-plugins-bom:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-klib-commonizer-api:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-native-utils:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-reflect:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-tooling-core:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-util-io:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-util-klib-metadata:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlin:kotlin-util-klib:2.2.10=classpath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.9.0=classpath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.9.0=classpath
|
||||||
|
org.jetbrains.kotlinx:kotlinx-coroutines-core:1.9.0=classpath
|
||||||
|
org.jetbrains:annotations:23.0.0=classpath
|
||||||
|
org.jvnet.staxex:stax-ex:1.8.1=classpath
|
||||||
|
org.ow2.asm:asm-analysis:9.9=classpath
|
||||||
|
org.ow2.asm:asm-commons:9.9=classpath
|
||||||
|
org.ow2.asm:asm-tree:9.9=classpath
|
||||||
|
org.ow2.asm:asm-util:9.9=classpath
|
||||||
|
org.ow2.asm:asm:9.9=classpath
|
||||||
|
org.slf4j:slf4j-api:1.7.30=classpath
|
||||||
|
org.tensorflow:tensorflow-lite-metadata:0.2.0=classpath
|
||||||
|
empty=
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// DO NOT EDIT THIS FILE! IT IS GENERATED EACH TIME "capacitor update" IS RUN
|
||||||
|
include ':capacitor-android'
|
||||||
|
project(':capacitor-android').projectDir = new File('../../../node_modules/@capacitor/android/capacitor')
|
||||||
|
|
||||||
|
include ':capacitor-share'
|
||||||
|
project(':capacitor-share').projectDir = new File('../../../node_modules/@capacitor/share/android')
|
||||||
|
|
||||||
|
include ':capacitor-community-sqlite'
|
||||||
|
project(':capacitor-community-sqlite').projectDir = new File('../../../node_modules/@capacitor-community/sqlite/android')
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
# Project-wide Gradle settings.
|
||||||
|
|
||||||
|
# IDE (e.g. Android Studio) users:
|
||||||
|
# Gradle settings configured through the IDE *will override*
|
||||||
|
# any settings specified in this file.
|
||||||
|
|
||||||
|
# For more details on how to configure your build environment visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
|
|
||||||
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
|
org.gradle.jvmargs=-Xmx1536m
|
||||||
|
|
||||||
|
# When configured, Gradle will run in incubating parallel mode.
|
||||||
|
# This option should only be used with decoupled projects. More details, visit
|
||||||
|
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
|
||||||
|
# org.gradle.parallel=true
|
||||||
|
|
||||||
|
# AndroidX package structure to make it clearer which packages are bundled with the
|
||||||
|
# Android operating system, and which are packaged with your app's APK
|
||||||
|
# https://developer.android.com/topic/libraries/support-library/androidx-rn
|
||||||
|
android.useAndroidX=true
|
||||||
|
android.defaults.buildfeatures.resvalues=true
|
||||||
|
android.sdk.defaultTargetSdkToCompileSdkIfUnset=false
|
||||||
|
android.enableAppCompileTimeRClass=false
|
||||||
|
android.usesSdkInManifest.disallowed=false
|
||||||
|
android.uniquePackageNames=false
|
||||||
|
android.dependency.useConstraints=true
|
||||||
|
android.r8.strictFullModeForKeepRules=false
|
||||||
|
android.r8.optimizedResourceShrinking=false
|
||||||
|
android.builtInKotlin=false
|
||||||
|
android.newDsl=false
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
distributionBase=GRADLE_USER_HOME
|
||||||
|
distributionPath=wrapper/dists
|
||||||
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-all.zip
|
||||||
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
zipStorePath=wrapper/dists
|
||||||
@@ -0,0 +1,252 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
#
|
||||||
|
# Copyright © 2015-2021 the original authors.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
#
|
||||||
|
# Gradle start up script for POSIX generated by Gradle.
|
||||||
|
#
|
||||||
|
# Important for running:
|
||||||
|
#
|
||||||
|
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||||
|
# noncompliant, but you have some other compliant shell such as ksh or
|
||||||
|
# bash, then to run this script, type that shell name before the whole
|
||||||
|
# command line, like:
|
||||||
|
#
|
||||||
|
# ksh Gradle
|
||||||
|
#
|
||||||
|
# Busybox and similar reduced shells will NOT work, because this script
|
||||||
|
# requires all of these POSIX shell features:
|
||||||
|
# * functions;
|
||||||
|
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||||
|
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||||
|
# * compound commands having a testable exit status, especially «case»;
|
||||||
|
# * various built-in commands including «command», «set», and «ulimit».
|
||||||
|
#
|
||||||
|
# Important for patching:
|
||||||
|
#
|
||||||
|
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||||
|
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||||
|
#
|
||||||
|
# The "traditional" practice of packing multiple parameters into a
|
||||||
|
# space-separated string is a well documented source of bugs and security
|
||||||
|
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||||
|
# options in "$@", and eventually passing that to Java.
|
||||||
|
#
|
||||||
|
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||||
|
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||||
|
# see the in-line comments for details.
|
||||||
|
#
|
||||||
|
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||||
|
# Darwin, MinGW, and NonStop.
|
||||||
|
#
|
||||||
|
# (3) This script is generated from the Groovy template
|
||||||
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
|
# within the Gradle project.
|
||||||
|
#
|
||||||
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
|
#
|
||||||
|
##############################################################################
|
||||||
|
|
||||||
|
# Attempt to set APP_HOME
|
||||||
|
|
||||||
|
# Resolve links: $0 may be a link
|
||||||
|
app_path=$0
|
||||||
|
|
||||||
|
# Need this for daisy-chained symlinks.
|
||||||
|
while
|
||||||
|
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||||
|
[ -h "$app_path" ]
|
||||||
|
do
|
||||||
|
ls=$( ls -ld "$app_path" )
|
||||||
|
link=${ls#*' -> '}
|
||||||
|
case $link in #(
|
||||||
|
/*) app_path=$link ;; #(
|
||||||
|
*) app_path=$APP_HOME$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# This is normally unused
|
||||||
|
# shellcheck disable=SC2034
|
||||||
|
APP_BASE_NAME=${0##*/}
|
||||||
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
|
MAX_FD=maximum
|
||||||
|
|
||||||
|
warn () {
|
||||||
|
echo "$*"
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
die () {
|
||||||
|
echo
|
||||||
|
echo "$*"
|
||||||
|
echo
|
||||||
|
exit 1
|
||||||
|
} >&2
|
||||||
|
|
||||||
|
# OS specific support (must be 'true' or 'false').
|
||||||
|
cygwin=false
|
||||||
|
msys=false
|
||||||
|
darwin=false
|
||||||
|
nonstop=false
|
||||||
|
case "$( uname )" in #(
|
||||||
|
CYGWIN* ) cygwin=true ;; #(
|
||||||
|
Darwin* ) darwin=true ;; #(
|
||||||
|
MSYS* | MINGW* ) msys=true ;; #(
|
||||||
|
NONSTOP* ) nonstop=true ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
# Determine the Java command to use to start the JVM.
|
||||||
|
if [ -n "$JAVA_HOME" ] ; then
|
||||||
|
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
|
||||||
|
# IBM's JDK on AIX uses strange locations for the executables
|
||||||
|
JAVACMD=$JAVA_HOME/jre/sh/java
|
||||||
|
else
|
||||||
|
JAVACMD=$JAVA_HOME/bin/java
|
||||||
|
fi
|
||||||
|
if [ ! -x "$JAVACMD" ] ; then
|
||||||
|
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
JAVACMD=java
|
||||||
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
|
location of your Java installation."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Increase the maximum file descriptors if we can.
|
||||||
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
case $MAX_FD in #(
|
||||||
|
max*)
|
||||||
|
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
MAX_FD=$( ulimit -H -n ) ||
|
||||||
|
warn "Could not query maximum file descriptor limit"
|
||||||
|
esac
|
||||||
|
case $MAX_FD in #(
|
||||||
|
'' | soft) :;; #(
|
||||||
|
*)
|
||||||
|
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
|
||||||
|
# shellcheck disable=SC2039,SC3045
|
||||||
|
ulimit -n "$MAX_FD" ||
|
||||||
|
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||||
|
esac
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Collect all arguments for the java command, stacking in reverse order:
|
||||||
|
# * args from the command line
|
||||||
|
# * the main class name
|
||||||
|
# * -classpath
|
||||||
|
# * -D...appname settings
|
||||||
|
# * --module-path (only if needed)
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||||
|
|
||||||
|
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||||
|
if "$cygwin" || "$msys" ; then
|
||||||
|
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||||
|
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||||
|
|
||||||
|
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||||
|
|
||||||
|
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||||
|
for arg do
|
||||||
|
if
|
||||||
|
case $arg in #(
|
||||||
|
-*) false ;; # don't mess with options #(
|
||||||
|
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||||
|
[ -e "$t" ] ;; #(
|
||||||
|
*) false ;;
|
||||||
|
esac
|
||||||
|
then
|
||||||
|
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||||
|
fi
|
||||||
|
# Roll the args list around exactly as many times as the number of
|
||||||
|
# args, so each arg winds up back in the position where it started, but
|
||||||
|
# possibly modified.
|
||||||
|
#
|
||||||
|
# NB: a `for` loop captures its iteration list before it begins, so
|
||||||
|
# changing the positional parameters here affects neither the number of
|
||||||
|
# iterations, nor the values presented in `arg`.
|
||||||
|
shift # remove old arg
|
||||||
|
set -- "$@" "$arg" # push replacement arg
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
|
# Collect all arguments for the java command:
|
||||||
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
|
# and any embedded shellness will be escaped.
|
||||||
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
|
# treated as '${Hostname}' itself on the command line.
|
||||||
|
|
||||||
|
set -- \
|
||||||
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
|
-classpath "$CLASSPATH" \
|
||||||
|
org.gradle.wrapper.GradleWrapperMain \
|
||||||
|
"$@"
|
||||||
|
|
||||||
|
# Stop when "xargs" is not available.
|
||||||
|
if ! command -v xargs >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "xargs is not available"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Use "xargs" to parse quoted args.
|
||||||
|
#
|
||||||
|
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||||
|
#
|
||||||
|
# In Bash we could simply go:
|
||||||
|
#
|
||||||
|
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||||
|
# set -- "${ARGS[@]}" "$@"
|
||||||
|
#
|
||||||
|
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||||
|
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||||
|
# character that might be a shell metacharacter, then use eval to reverse
|
||||||
|
# that process (while maintaining the separation between arguments), and wrap
|
||||||
|
# the whole thing up as a single "set" statement.
|
||||||
|
#
|
||||||
|
# This will of course break if any of these variables contains a newline or
|
||||||
|
# an unmatched quote.
|
||||||
|
#
|
||||||
|
|
||||||
|
eval "set -- $(
|
||||||
|
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||||
|
xargs -n1 |
|
||||||
|
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||||
|
tr '\n' ' '
|
||||||
|
)" '"$@"'
|
||||||
|
|
||||||
|
exec "$JAVACMD" "$@"
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
@rem
|
||||||
|
@rem Copyright 2015 the original author or authors.
|
||||||
|
@rem
|
||||||
|
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
@rem you may not use this file except in compliance with the License.
|
||||||
|
@rem You may obtain a copy of the License at
|
||||||
|
@rem
|
||||||
|
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
@rem
|
||||||
|
@rem Unless required by applicable law or agreed to in writing, software
|
||||||
|
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@rem See the License for the specific language governing permissions and
|
||||||
|
@rem limitations under the License.
|
||||||
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
|
@if "%DEBUG%"=="" @echo off
|
||||||
|
@rem ##########################################################################
|
||||||
|
@rem
|
||||||
|
@rem Gradle startup script for Windows
|
||||||
|
@rem
|
||||||
|
@rem ##########################################################################
|
||||||
|
|
||||||
|
@rem Set local scope for the variables with windows NT shell
|
||||||
|
if "%OS%"=="Windows_NT" setlocal
|
||||||
|
|
||||||
|
set DIRNAME=%~dp0
|
||||||
|
if "%DIRNAME%"=="" set DIRNAME=.
|
||||||
|
@rem This is normally unused
|
||||||
|
set APP_BASE_NAME=%~n0
|
||||||
|
set APP_HOME=%DIRNAME%
|
||||||
|
|
||||||
|
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||||
|
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||||
|
|
||||||
|
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||||
|
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||||
|
|
||||||
|
@rem Find java.exe
|
||||||
|
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||||
|
|
||||||
|
set JAVA_EXE=java.exe
|
||||||
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:findJavaFromJavaHome
|
||||||
|
set JAVA_HOME=%JAVA_HOME:"=%
|
||||||
|
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
||||||
|
|
||||||
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
|
echo. 1>&2
|
||||||
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
|
echo. 1>&2
|
||||||
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
|
goto fail
|
||||||
|
|
||||||
|
:execute
|
||||||
|
@rem Setup the command line
|
||||||
|
|
||||||
|
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
||||||
|
|
||||||
|
|
||||||
|
@rem Execute Gradle
|
||||||
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
||||||
|
|
||||||
|
:end
|
||||||
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
if %ERRORLEVEL% equ 0 goto mainEnd
|
||||||
|
|
||||||
|
:fail
|
||||||
|
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
|
||||||
|
rem the _cmd.exe /c_ return code!
|
||||||
|
set EXIT_CODE=%ERRORLEVEL%
|
||||||
|
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||||
|
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||||
|
exit /b %EXIT_CODE%
|
||||||
|
|
||||||
|
:mainEnd
|
||||||
|
if "%OS%"=="Windows_NT" endlocal
|
||||||
|
|
||||||
|
:omega
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# Copier vers keystore.properties (non versionné) à côté de ce fichier.
|
||||||
|
# Génération du magasin : keytool -genkey -v -keystore release.keystore -alias BentoRelease -keyalg RSA -keysize 2048 -validity 10000
|
||||||
|
#
|
||||||
|
storeFile=release.keystore
|
||||||
|
storePassword=
|
||||||
|
keyAlias=BentoRelease
|
||||||
|
keyPassword=
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
include ':app'
|
||||||
|
include ':capacitor-cordova-android-plugins'
|
||||||
|
project(':capacitor-cordova-android-plugins').projectDir = new File('./capacitor-cordova-android-plugins/')
|
||||||
|
|
||||||
|
apply from: 'capacitor.settings.gradle'
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
ext {
|
||||||
|
minSdkVersion = 23
|
||||||
|
compileSdkVersion = 35
|
||||||
|
targetSdkVersion = 35
|
||||||
|
androidxActivityVersion = '1.9.2'
|
||||||
|
androidxAppCompatVersion = '1.7.0'
|
||||||
|
androidxCoordinatorLayoutVersion = '1.2.0'
|
||||||
|
androidxCoreVersion = '1.15.0'
|
||||||
|
androidxFragmentVersion = '1.8.4'
|
||||||
|
coreSplashScreenVersion = '1.0.1'
|
||||||
|
androidxWebkitVersion = '1.12.1'
|
||||||
|
junitVersion = '4.13.2'
|
||||||
|
androidxJunitVersion = '1.2.1'
|
||||||
|
androidxEspressoCoreVersion = '3.6.1'
|
||||||
|
cordovaAndroidVersion = '10.1.1'
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import type { CapacitorConfig } from "@capacitor/cli";
|
||||||
|
|
||||||
|
const config: CapacitorConfig = {
|
||||||
|
appId: "com.kazerlelutin.bento",
|
||||||
|
appName: "Bento",
|
||||||
|
webDir: "../web/dist",
|
||||||
|
server: {
|
||||||
|
androidScheme: "https"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"name": "@ben-to/mobile",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"sync": "npx cap sync",
|
||||||
|
"open:android": "npx cap open android",
|
||||||
|
"open:ios": "npx cap open ios",
|
||||||
|
"run:android": "npx cap run android"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@capacitor/android": "^8.4.1",
|
||||||
|
"@capacitor/core": "^8.4.1",
|
||||||
|
"@capacitor/ios": "^8.4.1",
|
||||||
|
"@capacitor/share": "^8.0.1",
|
||||||
|
"@capacitor-community/sqlite": "^8.1.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@capacitor/cli": "^8.4.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
# Optionnel — Matomo (mesure d’audience). Les deux variables sont requises pour activer
|
||||||
|
# le tracker et le bandeau de consentement cookies.
|
||||||
|
# VITE_MATOMO_URL=https://analytics.example.com/
|
||||||
|
# VITE_MATOMO_SITE_ID=1
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="fr">
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta name="description"
|
||||||
|
content="Composez vos bento idéaux grâce au système forme, goût et recette. Des idées de repas savoureux et faciles à transporter, illustrées en pixel-art." />
|
||||||
|
<meta name="theme-color" content="#f1e9de" />
|
||||||
|
<link rel="canonical" href="https://ben-to.fr/" />
|
||||||
|
<meta property="og:site_name" content="Ben-to" />
|
||||||
|
<meta property="og:url" content="https://ben-to.fr/" />
|
||||||
|
<meta property="og:title" content="Bento — Ben-to" />
|
||||||
|
<meta property="og:description"
|
||||||
|
content="Composez vos bento idéaux grâce au système forme, goût et recette. Des idées de repas savoureux et faciles à transporter, illustrées en pixel-art." />
|
||||||
|
<meta property="og:type" content="website" />
|
||||||
|
<meta property="og:locale" content="fr_FR" />
|
||||||
|
<meta property="og:locale:alternate" content="en_US" />
|
||||||
|
<meta property="og:locale:alternate" content="ko_KR" />
|
||||||
|
<meta property="og:locale:alternate" content="zh_CN" />
|
||||||
|
<meta property="og:image" content="https://ben-to.fr/branding/og.jpg" />
|
||||||
|
<meta property="og:image:alt" content="Logo onigiri pixel-art — Ben-to" />
|
||||||
|
<meta name="twitter:card" content="summary" />
|
||||||
|
<meta name="twitter:title" content="Bento — Ben-to" />
|
||||||
|
<meta name="twitter:description"
|
||||||
|
content="Composez vos bento idéaux grâce au système forme, goût et recette. Des idées de repas savoureux et faciles à transporter, illustrées en pixel-art." />
|
||||||
|
<meta name="twitter:image" content="https://ben-to.fr/branding/og.jpg" />
|
||||||
|
<meta name="twitter:image:alt" content="Logo onigiri pixel-art — Ben-to" />
|
||||||
|
<link rel="icon" type="image/png" href="/branding/onigiri-logo.png" />
|
||||||
|
<link rel="apple-touch-icon" href="/branding/onigiri-logo.png" />
|
||||||
|
<title>Bento</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="root"></div>
|
||||||
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"name": "@ben-to/web",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"predev": "node ../../scripts/build-recipes.mjs",
|
||||||
|
"dev": "vite",
|
||||||
|
"prebuild": "node ../../scripts/build-recipes.mjs",
|
||||||
|
"build": "vite build",
|
||||||
|
"preview": "vite preview",
|
||||||
|
"lint": "eslint src --ext .ts,.tsx",
|
||||||
|
"typecheck": "tsc -p tsconfig.json --noEmit"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@ben-to/builder": "0.1.0",
|
||||||
|
"@ben-to/i18n": "0.1.0",
|
||||||
|
"@ben-to/privacy": "0.1.0",
|
||||||
|
"@ben-to/recipes": "0.1.0",
|
||||||
|
"@capacitor/core": "^8.4.1",
|
||||||
|
"@capacitor/share": "^8.0.1",
|
||||||
|
"@solidjs/router": "^0.16.1",
|
||||||
|
"solid-js": "^1.9.14"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^6.0.3",
|
||||||
|
"vite": "^8.1.4",
|
||||||
|
"vite-plugin-solid": "^2.11.8"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2025 The Cause Project Authors (https://github.com/xconsau/Cause)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright (c) YoonDesign Inc. All Rights Reserved.
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
Copyright 2020 The Klee Project Authors (https://github.com/fontworks-fonts/Klee)
|
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||||
|
This license is copied below, and is also available with a FAQ at:
|
||||||
|
https://openfontlicense.org
|
||||||
|
|
||||||
|
|
||||||
|
-----------------------------------------------------------
|
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||||
|
-----------------------------------------------------------
|
||||||
|
|
||||||
|
PREAMBLE
|
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||||
|
development of collaborative font projects, to support the font creation
|
||||||
|
efforts of academic and linguistic communities, and to provide a free and
|
||||||
|
open framework in which fonts may be shared and improved in partnership
|
||||||
|
with others.
|
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and
|
||||||
|
redistributed freely as long as they are not sold by themselves. The
|
||||||
|
fonts, including any derivative works, can be bundled, embedded,
|
||||||
|
redistributed and/or sold with any software provided that any reserved
|
||||||
|
names are not used by derivative works. The fonts and derivatives,
|
||||||
|
however, cannot be released under any other type of license. The
|
||||||
|
requirement for fonts to remain under this license does not apply
|
||||||
|
to any document created using the fonts or their derivatives.
|
||||||
|
|
||||||
|
DEFINITIONS
|
||||||
|
"Font Software" refers to the set of files released by the Copyright
|
||||||
|
Holder(s) under this license and clearly marked as such. This may
|
||||||
|
include source files, build scripts and documentation.
|
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the
|
||||||
|
copyright statement(s).
|
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as
|
||||||
|
distributed by the Copyright Holder(s).
|
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||||
|
or substituting -- in part or in whole -- any of the components of the
|
||||||
|
Original Version, by changing formats or by porting the Font Software to a
|
||||||
|
new environment.
|
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical
|
||||||
|
writer or other person who contributed to the Font Software.
|
||||||
|
|
||||||
|
PERMISSION & CONDITIONS
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||||
|
redistribute, and sell modified and unmodified copies of the Font
|
||||||
|
Software, subject to the following conditions:
|
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components,
|
||||||
|
in Original or Modified Versions, may be sold by itself.
|
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled,
|
||||||
|
redistributed and/or sold with any software, provided that each copy
|
||||||
|
contains the above copyright notice and this license. These can be
|
||||||
|
included either as stand-alone text files, human-readable headers or
|
||||||
|
in the appropriate machine-readable metadata fields within text or
|
||||||
|
binary files as long as those fields can be easily viewed by the user.
|
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font
|
||||||
|
Name(s) unless explicit written permission is granted by the corresponding
|
||||||
|
Copyright Holder. This restriction only applies to the primary font name as
|
||||||
|
presented to the users.
|
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||||
|
Software shall not be used to promote, endorse or advertise any
|
||||||
|
Modified Version, except to acknowledge the contribution(s) of the
|
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||||
|
permission.
|
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole,
|
||||||
|
must be distributed entirely under this license, and must not be
|
||||||
|
distributed under any other license. The requirement for fonts to
|
||||||
|
remain under this license does not apply to any document created
|
||||||
|
using the Font Software.
|
||||||
|
|
||||||
|
TERMINATION
|
||||||
|
This license becomes null and void if any of the above conditions are
|
||||||
|
not met.
|
||||||
|
|
||||||
|
DISCLAIMER
|
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
,assiette,fouet,baguettes,carnet,,,,,,,,,,,,,,,,,,,
|
||||||
|
,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
eau|vinaigre de riz|Vinaigre blanc|mirin,huile|jus de citron,jus d'orange,jus de citron vert,lait|crême fraîche liquide entière|Crème fraîche épaisse,chocolat fondu|sauce soja|aromate pistache,purée de sésame noir,moutarde forte,Chapelure panko|Chapelure,,,,,,,,,,,,,,,
|
||||||
|
,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
onigiri,empenadas,gimbap,radis mariné,kimchi,ramen,tofu,udon,dan bing|Omelette roulée,mandu,muffin,madelaine|madeleine,naan,bao,mandu shiitake,mandu aubergine,onigiri kimchi,blinis,cheese naan fromage,empanada-intensesalty,empanadas-butternut,empanadas-citron,madeleine-chocolat-blanc,guacamole
|
||||||
|
gateau de savoie,tranche cake,banana cake,carrot cake,cake au citron,cake à l'orange,flan,cheesecake-speculoos,speculoos,financier,financier lin,muffin au sésame noir,muffin aux pépites de chocolat,muffin chocolat blanc,muffin pistache et chocolat blanc,muffin pomme cannelle,muffin menthe et pépites de chocolat,gua bao,,,,,,
|
||||||
|
citron,orange,pomme rouge|Pomme,pomme verte,poire,,,,,,,,,,,,,,,,,,,
|
||||||
|
,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
betterave,carotte| carottes râpées,feuille de nori,cornichon|concombre,poivron rouge|poivron,poivron orange,poivron vert,poivron jaune,gingembre,navet,danmuji|radis jaune,aubergine|aubergines,champignon|champignons|shiitake,ail|aïl|ail frais|,radis|radis râpé,tomate|tomates,melon|melons,,,,,,,
|
||||||
|
haricots noirs,flageolets,haricots rouges,mais,epinard,courge,oignon,piment rouge,ciboulette,ciboule,piment vert,banane|bananes,Avocat|avocats|Avocados,Butternut|butternuts,Feuilles de coriandre|coriandre,Échalote|echalote,menthe|mint,,,,,,,
|
||||||
|
oeuf|oeufs|œufs|œuf,jaune d'oeuf|jaune d'œufs|jaune d'œuf,blanc d'oeuf|blanc d'œufs|blanc d'œuf,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
sel|bicarbonate|fleur de sel,poivre,poudre verte,poudre beige|poudre d'amande|poudre d'amandes|canelle en poudre|cannelle|cassonade|sucre brun|Levure boulangère sèche,gingembre en poudre,poudre blanche|sucre en poudre|sucre|fécule|fécule de maïs|levure chimique,poudre rouge|piment de cayenne,poudre orange,,,,,,,,,,,,,,,,
|
||||||
|
vanille,noisette|noisettes,noix,Muscade|muscade,Clous de girofle |clous de girofle|girofle,,,,,,,,,,,,,,,,,,,
|
||||||
|
pepite de chocolat au lait,pepites de chocolat noir,pepite de chocolat blanc|pepite chocolat blanc,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
tablette chocolat|chocolat,tablette chocolat blanc|chocolat blanc,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
emmental,beurre|beurre doux,mozzarella,comté|gruyère,cheddar,fromage frais|yaourt grec,fromage râpé,,,,,,,,,,,,,,,,,
|
||||||
|
,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
farine,sucre de canne,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
riz,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
graines de sésame|graines de lin,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
arachide|---,,,,,,,,,,,,,,,,,,,,,,,
|
||||||
|
|
After Width: | Height: | Size: 378 B |
|
After Width: | Height: | Size: 20 KiB |
@@ -0,0 +1,4 @@
|
|||||||
|
User-agent: *
|
||||||
|
Allow: /
|
||||||
|
|
||||||
|
Sitemap: https://ben-to.fr/sitemap.xml
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||||
|
<url>
|
||||||
|
<loc>https://ben-to.fr/</loc>
|
||||||
|
<changefreq>weekly</changefreq>
|
||||||
|
<priority>1.0</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://ben-to.fr/a-propos</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.6</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://ben-to.fr/cgu</loc>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.5</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://ben-to.fr/mentions-legales</loc>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.5</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://ben-to.fr/confidentialite</loc>
|
||||||
|
<changefreq>yearly</changefreq>
|
||||||
|
<priority>0.5</priority>
|
||||||
|
</url>
|
||||||
|
</urlset>
|
||||||
|
After Width: | Height: | Size: 298 KiB |
|
After Width: | Height: | Size: 573 KiB |
@@ -0,0 +1,13 @@
|
|||||||
|
import { readAnalyticsConsent } from "./cookie-consent-storage";
|
||||||
|
|
||||||
|
type MatomoWindow = Window &
|
||||||
|
typeof globalThis & {
|
||||||
|
_paq?: unknown[][];
|
||||||
|
};
|
||||||
|
|
||||||
|
export const trackEvent = (category: string, action: string, name?: string): void => {
|
||||||
|
if (readAnalyticsConsent() !== "analytics-accepted") return;
|
||||||
|
const matomoWindow = window as MatomoWindow;
|
||||||
|
matomoWindow._paq = matomoWindow._paq ?? [];
|
||||||
|
matomoWindow._paq.push(["trackEvent", category, action, name ?? ""]);
|
||||||
|
};
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("./cookie-consent-storage", () => ({
|
||||||
|
readAnalyticsConsent: vi.fn()
|
||||||
|
}));
|
||||||
|
|
||||||
|
import { readAnalyticsConsent } from "./cookie-consent-storage";
|
||||||
|
import { trackEvent } from "./analytics";
|
||||||
|
|
||||||
|
const readConsent = vi.mocked(readAnalyticsConsent);
|
||||||
|
|
||||||
|
describe("trackEvent (Matomo)", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
readConsent.mockReset();
|
||||||
|
readConsent.mockReturnValue("analytics-rejected");
|
||||||
|
vi.stubGlobal("window", { _paq: [] as unknown[][] });
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("n’envoie rien sans consentement analytics", () => {
|
||||||
|
trackEvent("recipe", "share", "x");
|
||||||
|
expect(window._paq?.length ?? 0).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("pousse un trackEvent Matomo lorsque le consentement est accepté", () => {
|
||||||
|
readConsent.mockReturnValue("analytics-accepted");
|
||||||
|
vi.stubGlobal("window", { _paq: [] as unknown[][] });
|
||||||
|
trackEvent("recipe", "share", "y");
|
||||||
|
expect(window._paq).toContainEqual(["trackEvent", "recipe", "share", "y"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import {
|
||||||
|
COOKIE_CONSENT_STORAGE_KEY,
|
||||||
|
normalizeConsentRaw,
|
||||||
|
type ConsentParseResult,
|
||||||
|
type StoredAnalyticsConsent
|
||||||
|
} from "@ben-to/privacy/cookie-consent";
|
||||||
|
|
||||||
|
export const readAnalyticsConsent = (): ConsentParseResult => {
|
||||||
|
try {
|
||||||
|
return normalizeConsentRaw(localStorage.getItem(COOKIE_CONSENT_STORAGE_KEY));
|
||||||
|
} catch {
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeAnalyticsConsent = (value: StoredAnalyticsConsent): void => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(COOKIE_CONSENT_STORAGE_KEY, value);
|
||||||
|
} catch {
|
||||||
|
/* stockage indisponible (mode privé strict, etc.) */
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import { readAnalyticsConsent } from "./cookie-consent-storage";
|
||||||
|
|
||||||
|
export type MatomoRuntimeConfig = Readonly<{
|
||||||
|
baseUrl: string;
|
||||||
|
siteId: string;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type MatomoWindow = Window &
|
||||||
|
typeof globalThis & {
|
||||||
|
_paq?: unknown[][];
|
||||||
|
};
|
||||||
|
|
||||||
|
let injectPromise: Promise<void> | null = null;
|
||||||
|
|
||||||
|
export const getMatomoRuntimeConfig = (): MatomoRuntimeConfig | null => {
|
||||||
|
const rawUrl = import.meta.env.VITE_MATOMO_URL;
|
||||||
|
const rawSite = import.meta.env.VITE_MATOMO_SITE_ID;
|
||||||
|
const url = typeof rawUrl === "string" ? rawUrl.trim() : "";
|
||||||
|
const siteId = typeof rawSite === "string" ? rawSite.trim() : "";
|
||||||
|
if (!url || !siteId) return null;
|
||||||
|
const baseUrl = url.endsWith("/") ? url : `${url}/`;
|
||||||
|
return { baseUrl, siteId };
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isMatomoConfigured = (): boolean => getMatomoRuntimeConfig() !== null;
|
||||||
|
|
||||||
|
export const injectMatomoTracker = (cfg: MatomoRuntimeConfig): Promise<void> => {
|
||||||
|
if (injectPromise) return injectPromise;
|
||||||
|
injectPromise = new Promise<void>((resolve, reject) => {
|
||||||
|
const w = window as MatomoWindow;
|
||||||
|
w._paq = w._paq ?? [];
|
||||||
|
w._paq.push(["setTrackerUrl", `${cfg.baseUrl}matomo.php`]);
|
||||||
|
w._paq.push(["setSiteId", cfg.siteId]);
|
||||||
|
const g = document.createElement("script");
|
||||||
|
g.async = true;
|
||||||
|
g.src = `${cfg.baseUrl}matomo.js`;
|
||||||
|
g.onload = () => {
|
||||||
|
const mw = window as MatomoWindow;
|
||||||
|
mw._paq?.push(["enableLinkTracking"]);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
g.onerror = () => reject(new Error("Failed to load matomo.js"));
|
||||||
|
const s = document.getElementsByTagName("script")[0];
|
||||||
|
if (s?.parentNode) {
|
||||||
|
s.parentNode.insertBefore(g, s);
|
||||||
|
} else {
|
||||||
|
document.head.appendChild(g);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return injectPromise;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const trackMatomoPageView = (): void => {
|
||||||
|
if (readAnalyticsConsent() !== "analytics-accepted") return;
|
||||||
|
const w = window as MatomoWindow;
|
||||||
|
if (!w._paq) return;
|
||||||
|
w._paq.push(["setCustomUrl", window.location.href]);
|
||||||
|
w._paq.push(["setDocumentTitle", document.title]);
|
||||||
|
w._paq.push(["trackPageView"]);
|
||||||
|
};
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import type { BentoSelection } from "@ben-to/builder/domain";
|
||||||
|
|
||||||
|
const key = "ben-to.selection";
|
||||||
|
|
||||||
|
export const saveSelection = (selection: BentoSelection): void => {
|
||||||
|
localStorage.setItem(key, JSON.stringify(selection));
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadSelection = (): BentoSelection | null => {
|
||||||
|
const raw = localStorage.getItem(key);
|
||||||
|
return raw ? (JSON.parse(raw) as BentoSelection) : null;
|
||||||
|
};
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
const STORAGE_KEY = "ben-to.recipe-checklist";
|
||||||
|
|
||||||
|
export type RecipeChecklistStored = Readonly<{
|
||||||
|
ingredientIds: readonly string[];
|
||||||
|
stepIds: readonly string[];
|
||||||
|
}>;
|
||||||
|
|
||||||
|
type RecipeChecklistMap = Record<string, RecipeChecklistStored>;
|
||||||
|
|
||||||
|
const emptyEntry = (): RecipeChecklistStored =>
|
||||||
|
Object.freeze({ ingredientIds: Object.freeze([]), stepIds: Object.freeze([]) });
|
||||||
|
|
||||||
|
const loadMap = (): RecipeChecklistMap => {
|
||||||
|
if (typeof localStorage === "undefined") return {};
|
||||||
|
try {
|
||||||
|
const raw = localStorage.getItem(STORAGE_KEY);
|
||||||
|
if (!raw) return {};
|
||||||
|
const parsed = JSON.parse(raw) as unknown;
|
||||||
|
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
||||||
|
return parsed as RecipeChecklistMap;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveMap = (map: RecipeChecklistMap): void => {
|
||||||
|
if (typeof localStorage === "undefined") return;
|
||||||
|
try {
|
||||||
|
localStorage.setItem(STORAGE_KEY, JSON.stringify(map));
|
||||||
|
} catch {
|
||||||
|
/* quota / private mode */
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const loadRecipeChecklist = (recipeKey: string): RecipeChecklistStored => {
|
||||||
|
const map = loadMap();
|
||||||
|
const entry = map[recipeKey];
|
||||||
|
if (!entry || !Array.isArray(entry.ingredientIds) || !Array.isArray(entry.stepIds)) {
|
||||||
|
return emptyEntry();
|
||||||
|
}
|
||||||
|
return Object.freeze({
|
||||||
|
ingredientIds: Object.freeze([...entry.ingredientIds]),
|
||||||
|
stepIds: Object.freeze([...entry.stepIds])
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export const saveRecipeChecklist = (recipeKey: string, data: RecipeChecklistStored): void => {
|
||||||
|
const map = loadMap();
|
||||||
|
map[recipeKey] = Object.freeze({
|
||||||
|
ingredientIds: Object.freeze([...data.ingredientIds]),
|
||||||
|
stepIds: Object.freeze([...data.stepIds])
|
||||||
|
});
|
||||||
|
saveMap(map);
|
||||||
|
};
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
readWelcomeTourDismissed,
|
||||||
|
WELCOME_TOUR_SCHEMA_VERSION,
|
||||||
|
WELCOME_TOUR_STORAGE_KEY,
|
||||||
|
writeWelcomeTourDismissed
|
||||||
|
} from "./welcome-tour-storage";
|
||||||
|
|
||||||
|
const mockStorage = () => {
|
||||||
|
const map = new Map<string, string>();
|
||||||
|
vi.stubGlobal("localStorage", {
|
||||||
|
getItem: (k: string) => (map.has(k) ? map.get(k)! : null),
|
||||||
|
setItem: (k: string, v: string) => void map.set(k, v),
|
||||||
|
removeItem: (k: string) => void map.delete(k),
|
||||||
|
clear: () => void map.clear(),
|
||||||
|
key: (i: number) => [...map.keys()][i] ?? null,
|
||||||
|
get length() {
|
||||||
|
return map.size;
|
||||||
|
}
|
||||||
|
} as Storage);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("welcome tour storage (Gherkin @int-welcome-tour-dismiss)", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @int-welcome-tour-dismiss */
|
||||||
|
it("enregistre la version courante lorsque le tour est fermé", () => {
|
||||||
|
mockStorage();
|
||||||
|
expect(readWelcomeTourDismissed()).toBe(false);
|
||||||
|
writeWelcomeTourDismissed();
|
||||||
|
expect(localStorage.getItem(WELCOME_TOUR_STORAGE_KEY)).toBe(WELCOME_TOUR_SCHEMA_VERSION);
|
||||||
|
expect(readWelcomeTourDismissed()).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/** Clé localStorage : fermeture du tour d'accueil pour une version de contenu donnée. */
|
||||||
|
export const WELCOME_TOUR_STORAGE_KEY = "ben-to.welcome-tour-dismissed";
|
||||||
|
|
||||||
|
/** Incrémenter pour réafficher le tour après refonte majeure du contenu. */
|
||||||
|
export const WELCOME_TOUR_SCHEMA_VERSION = "v1";
|
||||||
|
|
||||||
|
export const readWelcomeTourDismissed = (): boolean => {
|
||||||
|
try {
|
||||||
|
return localStorage.getItem(WELCOME_TOUR_STORAGE_KEY) === WELCOME_TOUR_SCHEMA_VERSION;
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const writeWelcomeTourDismissed = (): void => {
|
||||||
|
try {
|
||||||
|
localStorage.setItem(WELCOME_TOUR_STORAGE_KEY, WELCOME_TOUR_SCHEMA_VERSION);
|
||||||
|
} catch {
|
||||||
|
/* stockage indisponible */
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||||
|
import {
|
||||||
|
readWelcomeTourDismissed,
|
||||||
|
WELCOME_TOUR_SCHEMA_VERSION,
|
||||||
|
WELCOME_TOUR_STORAGE_KEY,
|
||||||
|
writeWelcomeTourDismissed
|
||||||
|
} from "./welcome-tour-storage";
|
||||||
|
|
||||||
|
const mockStorage = () => {
|
||||||
|
const map = new Map<string, string>();
|
||||||
|
vi.stubGlobal("localStorage", {
|
||||||
|
getItem: (k: string) => (map.has(k) ? map.get(k)! : null),
|
||||||
|
setItem: (k: string, v: string) => void map.set(k, v),
|
||||||
|
removeItem: (k: string) => void map.delete(k),
|
||||||
|
clear: () => void map.clear(),
|
||||||
|
key: (i: number) => [...map.keys()][i] ?? null,
|
||||||
|
get length() {
|
||||||
|
return map.size;
|
||||||
|
}
|
||||||
|
} as Storage);
|
||||||
|
};
|
||||||
|
|
||||||
|
describe("welcome-tour-storage", () => {
|
||||||
|
afterEach(() => {
|
||||||
|
vi.unstubAllGlobals();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("readWelcomeTourDismissed est faux sans valeur", () => {
|
||||||
|
mockStorage();
|
||||||
|
expect(readWelcomeTourDismissed()).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("write puis read indique dismiss pour la version courante", () => {
|
||||||
|
mockStorage();
|
||||||
|
writeWelcomeTourDismissed();
|
||||||
|
expect(localStorage.getItem(WELCOME_TOUR_STORAGE_KEY)).toBe(WELCOME_TOUR_SCHEMA_VERSION);
|
||||||
|
expect(readWelcomeTourDismissed()).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("une ancienne valeur ne compte pas comme dismiss", () => {
|
||||||
|
mockStorage();
|
||||||
|
localStorage.setItem(WELCOME_TOUR_STORAGE_KEY, "v0");
|
||||||
|
expect(readWelcomeTourDismissed()).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
import { render } from "solid-js/web";
|
||||||
|
import { App } from "./ui/App";
|
||||||
|
import "./ui/app.css";
|
||||||
|
|
||||||
|
render(() => <App />, document.getElementById("root")!);
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { Route, Router } from "@solidjs/router";
|
||||||
|
import { BuilderFlow } from "./BuilderFlow";
|
||||||
|
import { RootLayout } from "./RootLayout";
|
||||||
|
import { StaticInfoPage } from "./pages/StaticInfoPage";
|
||||||
|
|
||||||
|
export function App() {
|
||||||
|
return (
|
||||||
|
<Router root={RootLayout}>
|
||||||
|
<Route path="/" component={BuilderFlow} />
|
||||||
|
<Route path="/r/:baseId/:variantId" component={BuilderFlow} />
|
||||||
|
<Route path="/a-propos" component={() => <StaticInfoPage kind="about" />} />
|
||||||
|
<Route path="/cgu" component={() => <StaticInfoPage kind="terms" />} />
|
||||||
|
<Route path="/mentions-legales" component={() => <StaticInfoPage kind="legal" />} />
|
||||||
|
<Route path="/confidentialite" component={() => <StaticInfoPage kind="privacy" />} />
|
||||||
|
<Route path="*" component={() => <StaticInfoPage kind="notFound" />} />
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
import type { RouteSectionProps } from "@solidjs/router";
|
||||||
|
import type { BentoSelection } from "@ben-to/builder/domain";
|
||||||
|
import { createInitialSelection } from "@ben-to/builder/domain";
|
||||||
|
import { fetchRecipesIndex } from "@ben-to/recipes/catalog";
|
||||||
|
import { getDictionary } from "@ben-to/i18n/dictionary";
|
||||||
|
import { createEffect, createMemo, createResource, createSignal, Show } from "solid-js";
|
||||||
|
import { clearBuilderResetBus, readBuilderResetNonce } from "./builder-reset-bus";
|
||||||
|
import { useAppLocale } from "./app-locale-context";
|
||||||
|
import { BuilderBaseStep } from "./builder-flow/BuilderBaseStep";
|
||||||
|
import { BuilderCtaDock } from "./builder-flow/BuilderCtaDock";
|
||||||
|
import { BuilderStepsNav } from "./builder-flow/BuilderStepsNav";
|
||||||
|
import { BuilderVariantStep } from "./builder-flow/BuilderVariantStep";
|
||||||
|
import { RecipeSheetSection } from "./builder-flow/RecipeSheetSection";
|
||||||
|
import { useBuilderCatalog } from "./builder-flow/use-builder-catalog";
|
||||||
|
import { useBuilderSteps } from "./builder-flow/use-builder-steps";
|
||||||
|
import { useRecipeSheet } from "./builder-flow/use-recipe-sheet";
|
||||||
|
|
||||||
|
export function BuilderFlow(_props: RouteSectionProps) {
|
||||||
|
const { locale } = useAppLocale();
|
||||||
|
const [selection, setSelection] = createSignal<BentoSelection>(createInitialSelection());
|
||||||
|
const [recipesIndex] = createResource(async () => fetchRecipesIndex());
|
||||||
|
const t = createMemo(() => getDictionary(locale()));
|
||||||
|
|
||||||
|
const steps = useBuilderSteps({
|
||||||
|
selection,
|
||||||
|
setSelection,
|
||||||
|
recipesIndex
|
||||||
|
});
|
||||||
|
|
||||||
|
const catalog = useBuilderCatalog({
|
||||||
|
recipesIndex,
|
||||||
|
selection,
|
||||||
|
flavorFilter: steps.flavorFilter,
|
||||||
|
locale
|
||||||
|
});
|
||||||
|
|
||||||
|
const recipe = useRecipeSheet({
|
||||||
|
selection,
|
||||||
|
currentStep: steps.currentStep,
|
||||||
|
mergedRecipe: catalog.mergedRecipe,
|
||||||
|
recipeDisplayTitle: catalog.recipeDisplayTitle,
|
||||||
|
locale,
|
||||||
|
t
|
||||||
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
const n = readBuilderResetNonce();
|
||||||
|
if (n === 0) return;
|
||||||
|
steps.goHomeWizard();
|
||||||
|
recipe.resetServingsForGoHome();
|
||||||
|
clearBuilderResetBus();
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<main
|
||||||
|
classList={{
|
||||||
|
"app-shell": true,
|
||||||
|
"app-shell--with-dock": steps.canContinue(),
|
||||||
|
"app-shell--internal-scroll": true,
|
||||||
|
"app-shell--recipe-scroll": steps.currentStep() === "recipe"
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<BuilderStepsNav
|
||||||
|
t={t}
|
||||||
|
progressStepIndex={steps.progressStepIndex}
|
||||||
|
progressPercent={steps.progressPercent}
|
||||||
|
canNavigateToStep={steps.canNavigateToStep}
|
||||||
|
goToBuilderStep={steps.goToBuilderStep}
|
||||||
|
currentStep={steps.currentStep}
|
||||||
|
recipeProgressCompact={recipe.recipeProgressCompact}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Show when={steps.currentStep() === "base"}>
|
||||||
|
<div class="builder-scroll">
|
||||||
|
<BuilderBaseStep
|
||||||
|
t={t}
|
||||||
|
locale={locale}
|
||||||
|
recipesIndex={recipesIndex}
|
||||||
|
filteredBases={catalog.filteredBases}
|
||||||
|
flavorFilter={steps.flavorFilter}
|
||||||
|
setFlavorFilter={steps.setFlavorFilter}
|
||||||
|
selection={selection}
|
||||||
|
setSelection={setSelection}
|
||||||
|
advanceAfterBasePickDouble={steps.advanceAfterBasePickDouble}
|
||||||
|
onPickCardTouchEndForDouble={steps.onPickCardTouchEndForDouble}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={steps.currentStep() === "variant"}>
|
||||||
|
<div class="builder-scroll">
|
||||||
|
<BuilderVariantStep
|
||||||
|
t={t}
|
||||||
|
locale={locale}
|
||||||
|
currentBase={catalog.currentBase}
|
||||||
|
availableVariants={catalog.availableVariants}
|
||||||
|
selection={selection}
|
||||||
|
setSelection={setSelection}
|
||||||
|
advanceAfterVariantPickDouble={steps.advanceAfterVariantPickDouble}
|
||||||
|
onPickCardTouchEndForDouble={steps.onPickCardTouchEndForDouble}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<RecipeSheetSection
|
||||||
|
currentStep={steps.currentStep}
|
||||||
|
locale={locale}
|
||||||
|
t={t}
|
||||||
|
recipeCoverImageUrl={catalog.recipeCoverImageUrl}
|
||||||
|
recipeDisplayTitle={catalog.recipeDisplayTitle}
|
||||||
|
mergedRecipe={catalog.mergedRecipe}
|
||||||
|
recipe={recipe}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<BuilderCtaDock
|
||||||
|
canContinue={steps.canContinue}
|
||||||
|
currentStep={steps.currentStep}
|
||||||
|
currentBase={catalog.currentBase}
|
||||||
|
currentVariant={catalog.currentVariant}
|
||||||
|
locale={locale}
|
||||||
|
t={t}
|
||||||
|
nextStep={steps.nextStep}
|
||||||
|
/>
|
||||||
|
</main>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
import { A } from "@solidjs/router";
|
||||||
|
import type { Accessor } from "solid-js";
|
||||||
|
import type { Dictionary } from "@ben-to/i18n/dictionary";
|
||||||
|
|
||||||
|
export function CookieConsentBanner(props: {
|
||||||
|
readonly t: Accessor<Dictionary>;
|
||||||
|
readonly onAccept: () => void;
|
||||||
|
readonly onReject: () => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<div class="cookie-consent" role="region" aria-labelledby="cookie-consent-heading">
|
||||||
|
<div class="cookie-consent__inner">
|
||||||
|
<h2 id="cookie-consent-heading" class="cookie-consent__title">
|
||||||
|
{props.t().cookieConsentTitle}
|
||||||
|
</h2>
|
||||||
|
<p class="cookie-consent__text">{props.t().cookieConsentDescription}</p>
|
||||||
|
<p class="cookie-consent__privacy">
|
||||||
|
<A href="/confidentialite" class="cookie-consent__link">
|
||||||
|
{props.t().navPrivacy}
|
||||||
|
</A>
|
||||||
|
</p>
|
||||||
|
<div class="cookie-consent__actions">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="cookie-consent__btn cookie-consent__btn--primary"
|
||||||
|
onClick={() => props.onAccept()}
|
||||||
|
>
|
||||||
|
{props.t().cookieConsentAccept}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="cookie-consent__btn cookie-consent__btn--ghost"
|
||||||
|
onClick={() => props.onReject()}
|
||||||
|
>
|
||||||
|
{props.t().cookieConsentReject}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,222 @@
|
|||||||
|
import { A, useLocation } from "@solidjs/router";
|
||||||
|
import type { RouteSectionProps } from "@solidjs/router";
|
||||||
|
import { createEffect, createSignal, For, onCleanup, onMount, Show } from "solid-js";
|
||||||
|
import { getDictionary, type LocaleCode } from "@ben-to/i18n/dictionary";
|
||||||
|
import { readAnalyticsConsent, writeAnalyticsConsent } from "../infra/cookie-consent-storage";
|
||||||
|
import { readWelcomeTourDismissed, writeWelcomeTourDismissed } from "../infra/welcome-tour-storage";
|
||||||
|
import { getMatomoRuntimeConfig, injectMatomoTracker, trackMatomoPageView } from "../infra/matomo";
|
||||||
|
import { bumpBuilderResetBus } from "./builder-reset-bus";
|
||||||
|
import { AppLocaleProvider, useAppLocale } from "./app-locale-context";
|
||||||
|
import { CookieConsentBanner } from "./CookieConsentBanner";
|
||||||
|
import { WelcomeTourModal } from "./WelcomeTourModal";
|
||||||
|
import { publicAssetHref } from "./builder-flow/public-asset";
|
||||||
|
|
||||||
|
const localeOptions: LocaleCode[] = ["fr", "en", "ko", "zh"];
|
||||||
|
|
||||||
|
const localeNativeNames: Record<LocaleCode, string> = {
|
||||||
|
fr: "Français",
|
||||||
|
en: "English",
|
||||||
|
ko: "한국어",
|
||||||
|
zh: "中文"
|
||||||
|
};
|
||||||
|
|
||||||
|
const localeFlags: Record<LocaleCode, string> = {
|
||||||
|
fr: "🇫🇷",
|
||||||
|
en: "🇬🇧",
|
||||||
|
ko: "🇰🇷",
|
||||||
|
zh: "🇨🇳"
|
||||||
|
};
|
||||||
|
|
||||||
|
function RootLayoutInner(props: RouteSectionProps) {
|
||||||
|
const { locale, setLocale } = useAppLocale();
|
||||||
|
const location = useLocation();
|
||||||
|
const [menuOpen, setMenuOpen] = createSignal(false);
|
||||||
|
const t = () => getDictionary(locale());
|
||||||
|
const matomoCfg = getMatomoRuntimeConfig();
|
||||||
|
const [matomoReady, setMatomoReady] = createSignal(false);
|
||||||
|
const [consentBannerOpen, setConsentBannerOpen] = createSignal(readAnalyticsConsent() === "unknown");
|
||||||
|
const [welcomeTourOpen, setWelcomeTourOpen] = createSignal(false);
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
location.pathname;
|
||||||
|
setMenuOpen(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
location.pathname;
|
||||||
|
location.search;
|
||||||
|
if (!matomoReady()) return;
|
||||||
|
trackMatomoPageView();
|
||||||
|
});
|
||||||
|
|
||||||
|
const acceptAnalyticsCookies = () => {
|
||||||
|
writeAnalyticsConsent("analytics-accepted");
|
||||||
|
setConsentBannerOpen(false);
|
||||||
|
if (matomoCfg) {
|
||||||
|
void injectMatomoTracker(matomoCfg).then(() => setMatomoReady(true));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const rejectAnalyticsCookies = () => {
|
||||||
|
writeAnalyticsConsent("analytics-rejected");
|
||||||
|
setConsentBannerOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const dismissWelcomeTour = () => {
|
||||||
|
writeWelcomeTourDismissed();
|
||||||
|
setWelcomeTourOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
location.pathname;
|
||||||
|
consentBannerOpen();
|
||||||
|
if (location.pathname !== "/" || consentBannerOpen()) {
|
||||||
|
setWelcomeTourOpen(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (readWelcomeTourDismissed()) {
|
||||||
|
setWelcomeTourOpen(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setWelcomeTourOpen(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
const consent = readAnalyticsConsent();
|
||||||
|
if (consent === "unknown") setConsentBannerOpen(true);
|
||||||
|
if (consent === "analytics-accepted" && matomoCfg) {
|
||||||
|
void injectMatomoTracker(matomoCfg).then(() => setMatomoReady(true));
|
||||||
|
}
|
||||||
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
if (welcomeTourOpen()) {
|
||||||
|
dismissWelcomeTour();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setMenuOpen(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.addEventListener("keydown", onKeyDown);
|
||||||
|
onCleanup(() => window.removeEventListener("keydown", onKeyDown));
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<header class="topbar">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="topbar__burger"
|
||||||
|
aria-expanded={menuOpen()}
|
||||||
|
aria-controls="site-nav-drawer"
|
||||||
|
aria-label={t().menu}
|
||||||
|
onClick={() => setMenuOpen((open) => !open)}
|
||||||
|
>
|
||||||
|
<span class="topbar__burger-line" aria-hidden="true" />
|
||||||
|
<span class="topbar__burger-line" aria-hidden="true" />
|
||||||
|
<span class="topbar__burger-line" aria-hidden="true" />
|
||||||
|
</button>
|
||||||
|
<h1 class="topbar__title">
|
||||||
|
<A
|
||||||
|
href="/"
|
||||||
|
class="brand"
|
||||||
|
aria-label={t().home}
|
||||||
|
end
|
||||||
|
onClick={(event) => {
|
||||||
|
if (location.pathname === "/") {
|
||||||
|
event.preventDefault();
|
||||||
|
bumpBuilderResetBus();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<img class="brand__logo" src={publicAssetHref("/branding/onigiri-logo.png")} width="40" height="40" alt="" />
|
||||||
|
<span class="brand__wordmark" aria-hidden="true">
|
||||||
|
<span class="brand__ben">Ben</span>
|
||||||
|
<span class="brand__to">to</span>
|
||||||
|
</span>
|
||||||
|
</A>
|
||||||
|
</h1>
|
||||||
|
<div class="topbar__locale" role="radiogroup" aria-label={t().language}>
|
||||||
|
<For each={localeOptions}>
|
||||||
|
{(code) => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="topbar__locale-btn"
|
||||||
|
classList={{ "topbar__locale-btn--active": locale() === code }}
|
||||||
|
role="radio"
|
||||||
|
aria-checked={locale() === code}
|
||||||
|
title={localeNativeNames[code]}
|
||||||
|
onClick={() => setLocale(code)}
|
||||||
|
>
|
||||||
|
<span class="visually-hidden">{localeNativeNames[code]}</span>
|
||||||
|
<span class="topbar__locale-flag" aria-hidden="true">
|
||||||
|
{localeFlags[code]}
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{props.children}
|
||||||
|
|
||||||
|
<Show when={menuOpen()}>
|
||||||
|
<div
|
||||||
|
class="nav-drawer__backdrop"
|
||||||
|
role="presentation"
|
||||||
|
onClick={() => setMenuOpen(false)}
|
||||||
|
/>
|
||||||
|
<nav
|
||||||
|
id="site-nav-drawer"
|
||||||
|
class="nav-drawer"
|
||||||
|
aria-label={t().menu}
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
>
|
||||||
|
<div class="nav-drawer__header">
|
||||||
|
<span class="nav-drawer__title">{t().menu}</span>
|
||||||
|
<button type="button" class="nav-drawer__close" onClick={() => setMenuOpen(false)}>
|
||||||
|
{t().menuClose}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<ul class="nav-drawer__list">
|
||||||
|
<li>
|
||||||
|
<A href="/a-propos" class="nav-drawer__link" onClick={() => setMenuOpen(false)}>
|
||||||
|
{t().navAbout}
|
||||||
|
</A>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<A href="/cgu" class="nav-drawer__link" onClick={() => setMenuOpen(false)}>
|
||||||
|
{t().navTerms}
|
||||||
|
</A>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<A href="/mentions-legales" class="nav-drawer__link" onClick={() => setMenuOpen(false)}>
|
||||||
|
{t().navLegal}
|
||||||
|
</A>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<A href="/confidentialite" class="nav-drawer__link" onClick={() => setMenuOpen(false)}>
|
||||||
|
{t().navPrivacy}
|
||||||
|
</A>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<Show when={consentBannerOpen()}>
|
||||||
|
<CookieConsentBanner t={t} onAccept={acceptAnalyticsCookies} onReject={rejectAnalyticsCookies} />
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<WelcomeTourModal t={t} open={welcomeTourOpen} onDismiss={dismissWelcomeTour} />
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Enveloppe : locale partagée + barre + menu latéral. */
|
||||||
|
export function RootLayout(props: RouteSectionProps) {
|
||||||
|
return (
|
||||||
|
<AppLocaleProvider>
|
||||||
|
<RootLayoutInner {...props} />
|
||||||
|
</AppLocaleProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import type { Accessor } from "solid-js";
|
||||||
|
import { For, Show, createEffect } from "solid-js";
|
||||||
|
import type { Dictionary } from "@ben-to/i18n/dictionary";
|
||||||
|
import { publicAssetHref } from "./builder-flow/public-asset";
|
||||||
|
|
||||||
|
export function WelcomeTourModal(props: {
|
||||||
|
readonly t: Accessor<Dictionary>;
|
||||||
|
readonly open: Accessor<boolean>;
|
||||||
|
readonly onDismiss: () => void;
|
||||||
|
}) {
|
||||||
|
let primaryButton: HTMLButtonElement | undefined;
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!props.open()) return;
|
||||||
|
queueMicrotask(() => primaryButton?.focus());
|
||||||
|
});
|
||||||
|
|
||||||
|
const bullets = () =>
|
||||||
|
[
|
||||||
|
props.t().welcomeTourBulletSteps,
|
||||||
|
props.t().welcomeTourBulletFilters,
|
||||||
|
props.t().welcomeTourBulletServings,
|
||||||
|
props.t().welcomeTourBulletShare
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Show when={props.open()}>
|
||||||
|
<div
|
||||||
|
class="welcome-tour__backdrop"
|
||||||
|
role="presentation"
|
||||||
|
aria-hidden="true"
|
||||||
|
onClick={() => props.onDismiss()}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
id="welcome-tour-dialog"
|
||||||
|
class="welcome-tour"
|
||||||
|
role="dialog"
|
||||||
|
aria-modal="true"
|
||||||
|
aria-labelledby="welcome-tour-heading"
|
||||||
|
aria-describedby="welcome-tour-intro"
|
||||||
|
>
|
||||||
|
<div class="welcome-tour__inner">
|
||||||
|
<h2 id="welcome-tour-heading" class="welcome-tour__title">
|
||||||
|
{props.t().welcomeTourTitle}
|
||||||
|
</h2>
|
||||||
|
<p id="welcome-tour-intro" class="welcome-tour__intro">
|
||||||
|
{props.t().welcomeTourIntro}
|
||||||
|
</p>
|
||||||
|
<ul class="welcome-tour__bullets">
|
||||||
|
<For each={bullets()}>{(text) => <li>{text}</li>}</For>
|
||||||
|
</ul>
|
||||||
|
<div class="welcome-tour__gifs">
|
||||||
|
<figure class="welcome-tour__figure">
|
||||||
|
<img
|
||||||
|
class="welcome-tour__gif"
|
||||||
|
src={publicAssetHref("/tour/flow-builder.gif")}
|
||||||
|
alt={props.t().welcomeTourGifFlowAlt}
|
||||||
|
width={360}
|
||||||
|
height={202}
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
<figure class="welcome-tour__figure">
|
||||||
|
<img
|
||||||
|
class="welcome-tour__gif"
|
||||||
|
src={publicAssetHref("/tour/recipe-sheet.gif")}
|
||||||
|
alt={props.t().welcomeTourGifRecipeAlt}
|
||||||
|
width={360}
|
||||||
|
height={202}
|
||||||
|
loading="lazy"
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
</div>
|
||||||
|
<div class="welcome-tour__actions">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="welcome-tour__btn welcome-tour__btn--primary"
|
||||||
|
ref={(el) => (primaryButton = el)}
|
||||||
|
onClick={() => props.onDismiss()}
|
||||||
|
>
|
||||||
|
{props.t().welcomeTourCtaStart}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="welcome-tour__btn welcome-tour__btn--ghost" onClick={() => props.onDismiss()}>
|
||||||
|
{props.t().welcomeTourCtaClose}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { createContext, createSignal, useContext, type ParentProps } from "solid-js";
|
||||||
|
import type { LocaleCode } from "@ben-to/i18n/dictionary";
|
||||||
|
|
||||||
|
export type AppLocaleValue = Readonly<{
|
||||||
|
locale: () => LocaleCode;
|
||||||
|
setLocale: (code: LocaleCode) => void;
|
||||||
|
}>;
|
||||||
|
|
||||||
|
const AppLocaleContext = createContext<AppLocaleValue>();
|
||||||
|
|
||||||
|
export function AppLocaleProvider(props: ParentProps) {
|
||||||
|
const [locale, setLocale] = createSignal<LocaleCode>("fr");
|
||||||
|
const value: AppLocaleValue = {
|
||||||
|
locale,
|
||||||
|
setLocale
|
||||||
|
};
|
||||||
|
return <AppLocaleContext.Provider value={value}>{props.children}</AppLocaleContext.Provider>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useAppLocale(): AppLocaleValue {
|
||||||
|
const ctx = useContext(AppLocaleContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error("useAppLocale doit être utilisé sous AppLocaleProvider");
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import type { Accessor, Resource, Setter } from "solid-js";
|
||||||
|
import { For, Show } from "solid-js";
|
||||||
|
import type { BaseOption, BentoSelection } from "@ben-to/builder/domain";
|
||||||
|
import type { RecipesIndex } from "@ben-to/recipes/catalog";
|
||||||
|
import type { LocaleCode } from "@ben-to/i18n/dictionary";
|
||||||
|
import type { DictionaryView } from "./dictionary-view";
|
||||||
|
import type { FlavorFilter } from "./builder-flow-types";
|
||||||
|
import { SpriteTile } from "./SpriteTile";
|
||||||
|
import { publicAssetHref } from "./public-asset";
|
||||||
|
|
||||||
|
export function BuilderBaseStep(props: {
|
||||||
|
readonly t: Accessor<DictionaryView>;
|
||||||
|
readonly locale: Accessor<LocaleCode>;
|
||||||
|
readonly recipesIndex: Resource<RecipesIndex | undefined>;
|
||||||
|
readonly filteredBases: Accessor<BaseOption[]>;
|
||||||
|
readonly flavorFilter: Accessor<FlavorFilter>;
|
||||||
|
readonly setFlavorFilter: Setter<FlavorFilter>;
|
||||||
|
readonly selection: Accessor<BentoSelection>;
|
||||||
|
readonly setSelection: Setter<BentoSelection>;
|
||||||
|
readonly advanceAfterBasePickDouble: () => void;
|
||||||
|
readonly onPickCardTouchEndForDouble: (
|
||||||
|
cardKey: string,
|
||||||
|
advance: () => void
|
||||||
|
) => (e: TouchEvent) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section aria-label={props.t().selectBase}>
|
||||||
|
<div class="filters">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={props.flavorFilter() === "all" ? "chip selected" : "chip"}
|
||||||
|
onClick={() => props.setFlavorFilter("all")}
|
||||||
|
>
|
||||||
|
{props.t().filterAll}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={props.flavorFilter() === "savory" ? "chip selected" : "chip"}
|
||||||
|
onClick={() => props.setFlavorFilter("savory")}
|
||||||
|
>
|
||||||
|
{props.t().filterSavory}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={props.flavorFilter() === "sweet" ? "chip selected" : "chip"}
|
||||||
|
onClick={() => props.setFlavorFilter("sweet")}
|
||||||
|
>
|
||||||
|
{props.t().filterSweet}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<Show when={props.recipesIndex.loading}>
|
||||||
|
<p>{props.t().loading}</p>
|
||||||
|
</Show>
|
||||||
|
<Show when={props.recipesIndex.error}>
|
||||||
|
<p role="alert">{props.t().loadError}</p>
|
||||||
|
</Show>
|
||||||
|
<div class="cards">
|
||||||
|
<For each={props.filteredBases()}>
|
||||||
|
{(base) => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={`card card--pick ${props.selection().baseId === base.id ? "selected" : ""}`}
|
||||||
|
onClick={() => props.setSelection((prev) => ({ ...prev, baseId: base.id, variantId: null }))}
|
||||||
|
onDblClick={() => props.advanceAfterBasePickDouble()}
|
||||||
|
onTouchEnd={props.onPickCardTouchEndForDouble(`base:${base.id}`, props.advanceAfterBasePickDouble)}
|
||||||
|
>
|
||||||
|
<Show when={base.coverImageUrl}>
|
||||||
|
<img class="card__pick-icon" src={publicAssetHref(base.coverImageUrl)} alt="" />
|
||||||
|
</Show>
|
||||||
|
<Show when={!base.coverImageUrl && base.coverSprite}>
|
||||||
|
<SpriteTile
|
||||||
|
sprite={base.coverSprite!}
|
||||||
|
size={32}
|
||||||
|
class="card__sprite card__pick-sprite"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<span class="card__pick-name">{base.name[props.locale()]}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
import type { Accessor } from "solid-js";
|
||||||
|
import { createEffect, onCleanup, Show } from "solid-js";
|
||||||
|
import type { BaseOption, StepKind, VariantOption } from "@ben-to/builder/domain";
|
||||||
|
import type { LocaleCode } from "@ben-to/i18n/dictionary";
|
||||||
|
import type { DictionaryView } from "./dictionary-view";
|
||||||
|
import { SpriteTile } from "./SpriteTile";
|
||||||
|
import { publicAssetHref } from "./public-asset";
|
||||||
|
|
||||||
|
export function BuilderCtaDock(props: {
|
||||||
|
readonly canContinue: Accessor<boolean>;
|
||||||
|
readonly currentStep: Accessor<StepKind>;
|
||||||
|
readonly currentBase: Accessor<BaseOption | undefined>;
|
||||||
|
readonly currentVariant: Accessor<VariantOption | undefined>;
|
||||||
|
readonly locale: Accessor<LocaleCode>;
|
||||||
|
readonly t: Accessor<DictionaryView>;
|
||||||
|
readonly nextStep: () => void;
|
||||||
|
}) {
|
||||||
|
let dockEl: HTMLDivElement | undefined;
|
||||||
|
let dockObserver: ResizeObserver | undefined;
|
||||||
|
|
||||||
|
const updateDockHeight = () => {
|
||||||
|
document.documentElement.style.setProperty(
|
||||||
|
"--cta-dock-height",
|
||||||
|
props.canContinue() && dockEl ? `${Math.ceil(dockEl.getBoundingClientRect().height)}px` : "0px"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const observeDock = () => {
|
||||||
|
dockObserver?.disconnect();
|
||||||
|
if (!props.canContinue() || !dockEl) return;
|
||||||
|
dockObserver = new ResizeObserver(updateDockHeight);
|
||||||
|
dockObserver.observe(dockEl);
|
||||||
|
updateDockHeight();
|
||||||
|
};
|
||||||
|
|
||||||
|
createEffect(() => {
|
||||||
|
if (!props.canContinue()) {
|
||||||
|
dockObserver?.disconnect();
|
||||||
|
dockObserver = undefined;
|
||||||
|
document.documentElement.style.setProperty("--cta-dock-height", "0px");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
observeDock();
|
||||||
|
});
|
||||||
|
|
||||||
|
onCleanup(() => {
|
||||||
|
dockObserver?.disconnect();
|
||||||
|
document.documentElement.style.removeProperty("--cta-dock-height");
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Show when={props.canContinue()}>
|
||||||
|
<div
|
||||||
|
class="cta-dock"
|
||||||
|
role="presentation"
|
||||||
|
ref={(el) => {
|
||||||
|
dockEl = el;
|
||||||
|
observeDock();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div class="cta-dock__inner">
|
||||||
|
<Show when={props.currentStep() === "base" && props.currentBase()} keyed>
|
||||||
|
{(base: BaseOption) => {
|
||||||
|
const hasMedia = Boolean(base.coverImageUrl || base.coverSprite);
|
||||||
|
return (
|
||||||
|
<div class="cta-context" classList={{ "cta-context--with-media": hasMedia }}>
|
||||||
|
{base.coverImageUrl ? (
|
||||||
|
<div class="cta-context__media">
|
||||||
|
<img
|
||||||
|
class="cta-context__icon"
|
||||||
|
src={publicAssetHref(base.coverImageUrl)}
|
||||||
|
alt=""
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : base.coverSprite ? (
|
||||||
|
<div class="cta-context__media">
|
||||||
|
<SpriteTile sprite={base.coverSprite} size={32} class="cta-context__sprite" />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<p class="cta-context__title">{base.name[props.locale()]}</p>
|
||||||
|
<p class="cta-context__subtitle">{base.history[props.locale()]}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Show>
|
||||||
|
<Show when={props.currentStep() === "variant" && props.currentVariant()} keyed>
|
||||||
|
{(variant: VariantOption) => {
|
||||||
|
const hasMedia = Boolean(variant.coverImageUrl || variant.coverSprite);
|
||||||
|
return (
|
||||||
|
<div class="cta-context" classList={{ "cta-context--with-media": hasMedia }}>
|
||||||
|
{variant.coverImageUrl ? (
|
||||||
|
<div class="cta-context__media">
|
||||||
|
<img
|
||||||
|
class="cta-context__icon"
|
||||||
|
src={publicAssetHref(variant.coverImageUrl)}
|
||||||
|
alt=""
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
) : variant.coverSprite ? (
|
||||||
|
<div class="cta-context__media">
|
||||||
|
<SpriteTile sprite={variant.coverSprite} size={32} class="cta-context__sprite" />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
|
<p class="cta-context__title">{variant.name[props.locale()]}</p>
|
||||||
|
<p class="cta-context__subtitle">{variant.story[props.locale()]}</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Show>
|
||||||
|
<button type="button" class="cta" onClick={props.nextStep}>
|
||||||
|
{props.t().continue}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import type { Accessor } from "solid-js";
|
||||||
|
import type { StepKind } from "@ben-to/builder/domain";
|
||||||
|
import type { DictionaryView } from "./dictionary-view";
|
||||||
|
|
||||||
|
export function BuilderStepsNav(props: {
|
||||||
|
readonly t: Accessor<DictionaryView>;
|
||||||
|
readonly progressStepIndex: Accessor<number>;
|
||||||
|
readonly progressPercent: Accessor<number>;
|
||||||
|
readonly canNavigateToStep: (step: StepKind) => boolean;
|
||||||
|
readonly goToBuilderStep: (step: StepKind) => void;
|
||||||
|
readonly currentStep: Accessor<StepKind>;
|
||||||
|
readonly recipeProgressCompact: Accessor<boolean>;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<nav
|
||||||
|
class="builder-steps"
|
||||||
|
classList={{
|
||||||
|
"builder-steps--compact": props.currentStep() === "recipe" && props.recipeProgressCompact()
|
||||||
|
}}
|
||||||
|
aria-label={props.t().progress}
|
||||||
|
>
|
||||||
|
<ol class="builder-steps__list">
|
||||||
|
<li
|
||||||
|
class="builder-steps__step"
|
||||||
|
classList={{
|
||||||
|
"builder-steps__step--done": props.progressStepIndex() > 0,
|
||||||
|
"builder-steps__step--current": props.progressStepIndex() === 0
|
||||||
|
}}
|
||||||
|
aria-current={props.progressStepIndex() === 0 ? "step" : undefined}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="builder-steps__badge"
|
||||||
|
aria-label={props.t().builderNavToBase}
|
||||||
|
onClick={() => props.goToBuilderStep("base")}
|
||||||
|
>
|
||||||
|
1
|
||||||
|
</button>
|
||||||
|
<span class="builder-steps__label">{props.t().builderStepBase}</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="builder-steps__step"
|
||||||
|
classList={{
|
||||||
|
"builder-steps__step--done": props.progressStepIndex() > 1,
|
||||||
|
"builder-steps__step--current": props.progressStepIndex() === 1
|
||||||
|
}}
|
||||||
|
aria-current={props.progressStepIndex() === 1 ? "step" : undefined}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="builder-steps__badge"
|
||||||
|
disabled={!props.canNavigateToStep("variant")}
|
||||||
|
aria-label={
|
||||||
|
props.canNavigateToStep("variant")
|
||||||
|
? props.t().builderNavToVariant
|
||||||
|
: props.t().builderNavVariantDisabled
|
||||||
|
}
|
||||||
|
onClick={() => props.goToBuilderStep("variant")}
|
||||||
|
>
|
||||||
|
2
|
||||||
|
</button>
|
||||||
|
<span class="builder-steps__label">{props.t().builderStepVariant}</span>
|
||||||
|
</li>
|
||||||
|
<li
|
||||||
|
class="builder-steps__step"
|
||||||
|
classList={{
|
||||||
|
"builder-steps__step--done": props.progressStepIndex() > 2,
|
||||||
|
"builder-steps__step--current": props.progressStepIndex() === 2
|
||||||
|
}}
|
||||||
|
aria-current={props.progressStepIndex() === 2 ? "step" : undefined}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="builder-steps__badge"
|
||||||
|
disabled={!props.canNavigateToStep("recipe")}
|
||||||
|
aria-label={
|
||||||
|
props.canNavigateToStep("recipe")
|
||||||
|
? props.t().builderNavToRecipe
|
||||||
|
: props.t().builderNavRecipeDisabled
|
||||||
|
}
|
||||||
|
onClick={() => props.goToBuilderStep("recipe")}
|
||||||
|
>
|
||||||
|
3
|
||||||
|
</button>
|
||||||
|
<span class="builder-steps__label">{props.t().builderStepRecipe}</span>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
<div class="builder-steps__track" aria-hidden="true">
|
||||||
|
<div class="builder-steps__fill" style={{ width: `${props.progressPercent()}%` }} />
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,89 @@
|
|||||||
|
import { For, Show } from "solid-js";
|
||||||
|
import type { Accessor, Setter } from "solid-js";
|
||||||
|
import type { BaseOption, BentoSelection, VariantOption } from "@ben-to/builder/domain";
|
||||||
|
import { primaryBaseIdForVariant } from "@ben-to/builder/domain";
|
||||||
|
import type { LocaleCode } from "@ben-to/i18n/dictionary";
|
||||||
|
import type { DictionaryView } from "./dictionary-view";
|
||||||
|
import { SpriteTile } from "./SpriteTile";
|
||||||
|
import { publicAssetHref } from "./public-asset";
|
||||||
|
|
||||||
|
export function BuilderVariantStep(props: {
|
||||||
|
readonly t: Accessor<DictionaryView>;
|
||||||
|
readonly locale: Accessor<LocaleCode>;
|
||||||
|
readonly currentBase: Accessor<BaseOption | undefined>;
|
||||||
|
readonly availableVariants: Accessor<VariantOption[]>;
|
||||||
|
readonly selection: () => BentoSelection;
|
||||||
|
readonly setSelection: Setter<BentoSelection>;
|
||||||
|
readonly advanceAfterVariantPickDouble: () => void;
|
||||||
|
readonly onPickCardTouchEndForDouble: (
|
||||||
|
cardKey: string,
|
||||||
|
advance: () => void
|
||||||
|
) => (e: TouchEvent) => void;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<section aria-label={props.t().selectVariant}>
|
||||||
|
<Show when={props.currentBase()}>
|
||||||
|
{(base) => (
|
||||||
|
<p class="builder-variant-base-reminder" role="status">
|
||||||
|
<span class="builder-variant-base-reminder__media" aria-hidden="true">
|
||||||
|
<Show when={base().coverImageUrl}>
|
||||||
|
<img
|
||||||
|
class="builder-variant-base-reminder__icon"
|
||||||
|
src={publicAssetHref(base().coverImageUrl)}
|
||||||
|
width="28"
|
||||||
|
height="28"
|
||||||
|
alt=""
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<Show when={!base().coverImageUrl && base().coverSprite}>
|
||||||
|
<SpriteTile
|
||||||
|
sprite={base().coverSprite!}
|
||||||
|
size={28}
|
||||||
|
class="builder-variant-base-reminder__sprite"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
</span>
|
||||||
|
<span class="builder-variant-base-reminder__text">
|
||||||
|
{props.t().builderVariantBaseReminderTemplate.replace("{base}", base().name[props.locale()])}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</Show>
|
||||||
|
<div class="cards">
|
||||||
|
<For each={props.availableVariants()}>
|
||||||
|
{(variant) => (
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class={`card card--pick ${props.selection().variantId === variant.id ? "selected" : ""}`}
|
||||||
|
onClick={() =>
|
||||||
|
props.setSelection((prev) => ({
|
||||||
|
...prev,
|
||||||
|
variantId: variant.id,
|
||||||
|
baseId: primaryBaseIdForVariant(variant, prev.baseId)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
onDblClick={() => props.advanceAfterVariantPickDouble()}
|
||||||
|
onTouchEnd={props.onPickCardTouchEndForDouble(
|
||||||
|
`variant:${variant.id}`,
|
||||||
|
props.advanceAfterVariantPickDouble
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Show when={variant.coverImageUrl}>
|
||||||
|
<img class="card__pick-icon" src={publicAssetHref(variant.coverImageUrl)} alt="" />
|
||||||
|
</Show>
|
||||||
|
<Show when={!variant.coverImageUrl && variant.coverSprite}>
|
||||||
|
<SpriteTile
|
||||||
|
sprite={variant.coverSprite!}
|
||||||
|
size={32}
|
||||||
|
class="card__sprite card__pick-sprite"
|
||||||
|
/>
|
||||||
|
</Show>
|
||||||
|
<span class="card__pick-name">{variant.name[props.locale()]}</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
import type { Accessor } from "solid-js";
|
||||||
|
import { For, Show } from "solid-js";
|
||||||
|
import type { StepKind } from "@ben-to/builder/domain";
|
||||||
|
import { computeRecipeSteps } from "@ben-to/builder/domain";
|
||||||
|
import type { LocaleCode } from "@ben-to/i18n/dictionary";
|
||||||
|
import type { DictionaryView } from "./dictionary-view";
|
||||||
|
import { fillRecipeTemplate } from "./recipe-template";
|
||||||
|
import { SpriteTile } from "./SpriteTile";
|
||||||
|
import { publicAssetHref } from "./public-asset";
|
||||||
|
import type { RecipeSheetHandle } from "./use-recipe-sheet";
|
||||||
|
|
||||||
|
type MergedRecipeView = ReturnType<typeof computeRecipeSteps>;
|
||||||
|
|
||||||
|
export function RecipeSheetSection(props: {
|
||||||
|
readonly currentStep: Accessor<StepKind>;
|
||||||
|
readonly locale: Accessor<LocaleCode>;
|
||||||
|
readonly t: Accessor<DictionaryView>;
|
||||||
|
readonly recipeCoverImageUrl: Accessor<string | null>;
|
||||||
|
readonly recipeDisplayTitle: Accessor<string>;
|
||||||
|
readonly mergedRecipe: Accessor<MergedRecipeView>;
|
||||||
|
readonly recipe: RecipeSheetHandle;
|
||||||
|
}) {
|
||||||
|
const r = props.recipe;
|
||||||
|
return (
|
||||||
|
<Show when={props.currentStep() === "recipe"}>
|
||||||
|
<div
|
||||||
|
class="recipe-scroll"
|
||||||
|
ref={(el) => {
|
||||||
|
r.bindRecipeScrollHost(el);
|
||||||
|
}}
|
||||||
|
onScroll={r.onRecipeScroll}
|
||||||
|
>
|
||||||
|
<section class="recipe-sheet" aria-labelledby="recipe-sheet-title">
|
||||||
|
<Show when={props.recipeCoverImageUrl()}>
|
||||||
|
<div class="recipe-sheet__hero">
|
||||||
|
<div class="recipe-sheet__hero-media">
|
||||||
|
<img
|
||||||
|
class="recipe-sheet__photo"
|
||||||
|
src={publicAssetHref(props.recipeCoverImageUrl())}
|
||||||
|
alt={props.recipeDisplayTitle() || props.t().recipe}
|
||||||
|
width="1200"
|
||||||
|
height="675"
|
||||||
|
decoding="async"
|
||||||
|
fetchpriority="high"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<h2 class="recipe-sheet__title" id="recipe-sheet-title">
|
||||||
|
{props.recipeDisplayTitle() || props.t().recipe}
|
||||||
|
</h2>
|
||||||
|
|
||||||
|
<div class="recipe-sheet__actions">
|
||||||
|
<button type="button" class="recipe-sheet__action" onClick={() => void r.shareRecipe()}>
|
||||||
|
{props.t().shareRecipe}
|
||||||
|
</button>
|
||||||
|
<button type="button" class="recipe-sheet__action" onClick={r.printRecipe}>
|
||||||
|
{props.t().printRecipe}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Show when={r.shareFeedback()}>
|
||||||
|
<p class="recipe-sheet__share-feedback" role="status" aria-live="polite">
|
||||||
|
{r.shareFeedback()}
|
||||||
|
</p>
|
||||||
|
</Show>
|
||||||
|
|
||||||
|
<div class="servings-stepper" role="group" aria-label={props.t().servings}>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="servings-stepper__btn"
|
||||||
|
aria-label={props.t().decreaseServings}
|
||||||
|
disabled={r.servings() <= 1}
|
||||||
|
onClick={() => r.bumpServings(-1)}
|
||||||
|
>
|
||||||
|
−
|
||||||
|
</button>
|
||||||
|
<label class="servings-stepper__field">
|
||||||
|
<span class="visually-hidden">{props.t().servings}</span>
|
||||||
|
<input
|
||||||
|
class="servings-stepper__input"
|
||||||
|
type="text"
|
||||||
|
inputMode="numeric"
|
||||||
|
autocomplete="off"
|
||||||
|
maxLength={2}
|
||||||
|
value={r.servingsFieldValue()}
|
||||||
|
onFocus={r.onServingsFocus}
|
||||||
|
onInput={r.onServingsInput}
|
||||||
|
onBlur={r.onServingsBlur}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="servings-stepper__btn"
|
||||||
|
aria-label={props.t().increaseServings}
|
||||||
|
disabled={r.servings() >= 99}
|
||||||
|
onClick={() => r.bumpServings(1)}
|
||||||
|
>
|
||||||
|
+
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="recipe-sheet__print-servings" aria-hidden="true">
|
||||||
|
{props.t().servings}: {r.servings()}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3 class="recipe-sheet__subtitle">{props.t().ingredients}</h3>
|
||||||
|
<ul class="recipe-sheet__ingredient-list">
|
||||||
|
<For each={r.displayedIngredients()}>
|
||||||
|
{(ingredient) => (
|
||||||
|
<li class="recipe-sheet__ingredient-item">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="recipe-sheet__ingredient-row"
|
||||||
|
classList={{
|
||||||
|
"recipe-sheet__ingredient-row--done": r.checkedIngredientIds().has(ingredient.id)
|
||||||
|
}}
|
||||||
|
aria-pressed={r.checkedIngredientIds().has(ingredient.id)}
|
||||||
|
title={[
|
||||||
|
fillRecipeTemplate(props.t().recipeIngredientCheckboxLabel, {
|
||||||
|
name: ingredient.name[props.locale()]
|
||||||
|
}),
|
||||||
|
String(ingredient.info[props.locale()] ?? "").trim()
|
||||||
|
]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join(" — ")}
|
||||||
|
onClick={() => r.toggleIngredientChecklist(ingredient.id)}
|
||||||
|
>
|
||||||
|
<span class="recipe-sheet__ingredient-media" aria-hidden="true">
|
||||||
|
{ingredient.coverSprite ? (
|
||||||
|
<SpriteTile
|
||||||
|
sprite={ingredient.coverSprite}
|
||||||
|
size={32}
|
||||||
|
class="recipe-sheet__ingredient-sprite"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<img
|
||||||
|
class="recipe-sheet__ingredient-fallback"
|
||||||
|
src={publicAssetHref("/ingredient-unknown.png")}
|
||||||
|
width="32"
|
||||||
|
height="32"
|
||||||
|
alt=""
|
||||||
|
decoding="async"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<span class="recipe-sheet__ingredient-text">
|
||||||
|
<strong>
|
||||||
|
{ingredient.quantity}
|
||||||
|
{ingredient.unit ? ` ${ingredient.unit}` : ""}
|
||||||
|
</strong>{" "}
|
||||||
|
{ingredient.name[props.locale()]}
|
||||||
|
</span>
|
||||||
|
<span class="recipe-sheet__ingredient-row-check" aria-hidden="true">
|
||||||
|
<span class="recipe-sheet__ingredient-mark__glyph">✓</span>
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</ul>
|
||||||
|
<h3 class="recipe-sheet__subtitle">{props.t().steps}</h3>
|
||||||
|
<ol class="recipe-sheet__steps-list">
|
||||||
|
<For each={props.mergedRecipe().steps}>
|
||||||
|
{(step, index) => (
|
||||||
|
<li class="recipe-sheet__step-item">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="recipe-sheet__step-btn"
|
||||||
|
classList={{
|
||||||
|
"recipe-sheet__step-btn--done": r.doneStepIds().has(step.id)
|
||||||
|
}}
|
||||||
|
aria-pressed={r.doneStepIds().has(step.id)}
|
||||||
|
title={fillRecipeTemplate(props.t().recipeStepToggleLabel, {
|
||||||
|
n: index() + 1
|
||||||
|
})}
|
||||||
|
onClick={() => r.toggleStepChecklist(step.id)}
|
||||||
|
>
|
||||||
|
{step.text[props.locale()]}
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
|
</For>
|
||||||
|
</ol>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</Show>
|
||||||
|
);
|
||||||
|
}
|
||||||