diff --git a/.github/workflows/actionsflow.yml b/.github/workflows/actionsflow.yml new file mode 100644 index 00000000..f3e71791 --- /dev/null +++ b/.github/workflows/actionsflow.yml @@ -0,0 +1,28 @@ +name: Deploy MkDocs to GitHub Pages + +on: + push: + branches: + - pages + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.x + - uses: actions/cache@v3 # Atualizado para v3 + with: + key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }} + path: .aux + + - run: pip install mkdocs-bootswatch + - run: pip install mkdocs-material mkdocs-with-pdf + - run: mkdocs build + - run: mkdocs gh-deploy --force diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/.idea/T2G3-Sistema-Instalacao-Eletrica.iml b/.idea/T2G3-Sistema-Instalacao-Eletrica.iml deleted file mode 100644 index 90496925..00000000 --- a/.idea/T2G3-Sistema-Instalacao-Eletrica.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 6e866721..00000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 5a84757f..00000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1ddf..00000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4b8a2e9f..00000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "cmake.sourceDirectory": "/home/danilo/Desktop/T2G3-Sistema-Instalacao-Eletrica/frontend/sige_ie/linux" -} diff --git a/README.md b/README.md deleted file mode 100644 index ebdcb4be..00000000 --- a/README.md +++ /dev/null @@ -1,284 +0,0 @@ -

- -![Versões do Django](./doc/img/sige_ie_logo.jpeg) - -SIGE IE -

- -## Fase -Release 1 ✔️ Ir para milestone da release 1 - -Release 2 ✔️ Ir para milestone da release 2 - -Release 3 (atual) Ir para milestone da release 3 -## Visão geral do produto - -### Sobre -Aplicativo web mobile desenvolvido para a Universidade de Brasília com objetivo de gerenciar as instalações elétricas e dar suporte ao retrofitting das instalações. - -### Posição -O SIGE IE é um sistema da Universidade de Brasília para o gerenciamento de instalações elétricas com o objetivo de facilitar o cadastro das informações de instalação elétrica para ajudar na reforma da parte elétrica dos prédios e salas. Ele permite a automatização da geração de relatórios das instalações elétricas de cada lugar e a centralização dessas informações para uso dos responsáveis pelas instalações. As pessoas devem usar o SIGE IE porque ele simplifica e agiliza o processo de gerenciamento, principalmente do retrofitting de instalações elétricas, garantindo maior eficiência e segurança. - -### Objetivos -Simplificar o cadastro e gerenciamento de informações de instalações elétricas e automatizar a geração de relatórios. -### Tecnologias -#### Back-end - -
- -| Nome | Versão | Uso | Configuração | -|---|---|---|---| -| Python | 3.11.8| Linguagem | [Site oficial do Python](https://www.python.org/downloads/) Ou veja na seção "Como subir o back-end" | -| Django | 4.2 (LTS) | Framework web | Automática | -| Django REST framework | 3.14 | API REST | Automática | -| Docker | 25.0.4 | Conteiner e imagem | [Site oficial do Docker](https://docs.docker.com/desktop/install/ubuntu/) | -| Redis | 7.2 | Banco de dados cache para sessão | Automática via Docker | -| MySQL | 8.1 | Banco de dados | Automática via Docker | -| Cabeçalhos do Python3 e do MySQL | - | Cabeçalhos de desenvolvimento e bibliotecas | [Site do Pypi com as configurações](https://pypi.org/project/mysqlclient/) Ou veja na seção "Como subir o back-end" - -
- -##### Observação -Atualmente o Django REST Framework suporta as seguintes versões do Python e do Django: - -
- -| Python | 3.6 | 3.7 | 3.8 | 3.9 | 3.10 | 3.11 | -|--------|-----|-----|-----|-----|------|------| -| Django | 3.0 | 3.1 | 3.2 | 4.0 | 4.1 | 4.2 (LTS) | - -
- -Como a versão LTS mais recente do Django (2024) é a 4.2, escolhemos configurar o projeto usando Python 3.11. - -#### Front-end mobile - -
- -| Nome | Versão | Uso | Configuração | -|---|---|---|---| -| Flutter | 3.19.3 | Framework frontend | [Site oficial do Flutter](https://docs.flutter.dev/get-started/install/linux) | -| Android Studio | Iguana | IDE para desenvolvimento Android com Android SDK | [Site oficial do Android Studio](https://developer.android.com/studio/index.html) | - -
- -### Contribuidores -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AlefMemTavPedro LucasContribuidor
EngDannDaniloContribuidor
kauan2872KauanContribuidor
OscarDeBritoOscarContribuidor
ramires31RamiresContribuidor
-
- -## Visão geral do projeto - -### Organização -
- -| Papel | Atribuições | Responsável | Participantes | -| --- | --- | --- | --- | -| Cliente | Validar as entregas | Loana | Loana, Alex | -| Desenvolvedor back-end | Codificar o backend, configurar a infraestrutura | Pedro | Pedro, Kauan, Oscar | -| Desenvolvedor frontend | Codificar o frontend, realizar integração com backend | Danilo | Danilo, Ramires, Pedro | -| UX design | Projetar a interface do usuário, criar protótipos e realizar entrevistas com os clientes | Danilo | Danilo | -| Analista de requisitos | Levantar requisitos, gerenciar a documentação, validar com cliente | Oscar | Oscar, Ramires, Pedro | - -
- -## Configuração do ambiente -### Como subir o projeto -Estas etapas são válidas para Linux OS e WSL. -#### Como subir o back-end: - -##### Pela primeira vez - -Primeiramente, interrompa qualquer processo que use o porto 8080, 3306 e 6379. Então atualize o seu sistema: - ``` - sudo apt-get update - ``` - - ``` - sudo apt-get upgrade - ``` - -Em seguida, caso já não tenha instalado: - -- Instale o Python, Pip e os cabeçalhos do Python e MySQL: - - Python: - ``` - sudo apt-get install python3.11 - ``` - - Pip: - ``` - sudo apt-get install python3-pip - ``` - - Cabeçalhos: - ``` - sudo apt-get install python3.11-dev default-libmysqlclient-dev build-essential pkg-config - ``` - -- Instale o virtualenv para criar um ambiente virtual do projeto: - - Virtualenv: - ``` - sudo pip3 install virtualenv - ``` - -Vá para dentro da pasta raiz `api`: - -1. Cria o ambiente virtual e ative-o: - - Criar ambiente virtual: - ``` - virtualenv -p python3.11 venv - ``` - - Ativar ambiente: - ``` - source venv/bin/activate - ``` - -2. Com o ambiente virtual ativado, instale as dependências: - - ``` - pip install -r requirements.txt - ``` - -3. Inicie o Docker, depois vá para o diretório `api` e crie a imagem do banco de dados e da api pela primeira vez: - - ``` - docker-compose up --build - ``` - -4. Em outro terminal, retorne para o diretório raiz `api` e aplique as migrações: - - ``` - python manage.py makemigrations - ``` - - ``` - python manage.py migrate - ``` - -Pronto, o servidor já está rodando com o banco de dados configurado. - -##### Pela segunda vez - -Garanta que não haja nenhum processo que use o porto 8080, 3306 e 6379. Por fim, com todas as dependências configuradas, basta: - -- Inicar o Docker e o container `sigeie`; -- Baixar as atualizações (caso haja): - - ``` - git pull - ``` - -- Atualizar as dependências, fazer as migrações e iniciar o servidor: - -``` - source venv/bin/activate && python manage.py makemigrations && python manage.py migrate -``` - -Isso é tudo, pessoal. - -#### Como subir o front-end: - -Antes de começar, verifique se o Flutter SDK está atualizado e compatível com o projeto. Siga as instruções específicas para sua plataforma (Windows, macOS, Linux) disponíveis na [documentação oficial do Flutter](https://flutter.dev/docs/get-started/install). - -Caso ainda não tenha feito, instale os seguintes requisitos em sua máquina: - -- **Flutter SDK**: - Siga as instruções de instalação para a sua plataforma. - -- **Android Studio ou Visual Studio Code**: - - - Android Studio: - ``` - sudo snap install android-studio --classic - ``` - - - Visual Studio Code: - ``` - sudo snap install code --classic - ``` - Para o VS Code, instale as extensões do Flutter e Dart disponíveis na aba de extensões do editor. - -- **Emulador Android ou um dispositivo físico**: - Configure um emulador usando o AVD Manager do Android Studio ou [configure seu dispositivo Android para depuração USB](https://developer.android.com/studio/debug/dev-options). - -Com o ambiente preparado, siga os passos abaixo: - -1. **Clone o Repositório do Front-end**: - ``` - git clone https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica.git - ``` - -2. **Abra o Projeto no Editor**: - Abra a pasta clonada no Android Studio ou no Visual Studio Code. - -3. **Baixe as Dependências**: - Abra um terminal na pasta frontend/sige_ie e execute o comando: - ``` - flutter pub get - ``` - -4. **Execute o Projeto**: - - **No Android Studio:** Escolha um dispositivo ou emulador na barra de ferramentas e clique em 'Run'. - - **No Visual Studio Code:** Selecione um dispositivo ou emulador na barra de status e pressione `F5` ou utilize o comando `flutter run` na paleta de comandos. - -Pronto, o Front end já está rodando e você pode utilizá-lo. - -## Contribuição -### Como contribuir -1. Faça um fork do repositório do projeto. -2. Clone o fork na sua máquina: - - ``` - git clone https://github.com/{seu-usuario}/T2G3-Sistema-Instalacao-Eletrica.git - ``` - -4. Comente na issue que deseja contribuir ou crie uma issue nova. -5. Entre no repositório clonado na sua máquina: - - ``` - cd T2G3-Sistema-Instalacao-Eletrica - ``` - -7. Após enviar suas contribuições para o fork do seu repositório, faça um pull request. -8. Aguarde a revisão. - -## Documentação -- [Requisitos de software](https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica/issues/1) -- [Cronograma](https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica/issues/3) -- [Backlog do produto](https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica/issues/9) -- [Releases](https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica/milestones) -- [Arquitetura](https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica/issues/2) -- [Atas de reunião](https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica/issues/4) diff --git a/api/.dockerignore b/api/.dockerignore deleted file mode 100644 index 354168f2..00000000 --- a/api/.dockerignore +++ /dev/null @@ -1 +0,0 @@ -data/mysql/db diff --git a/api/.gitignore b/api/.gitignore deleted file mode 100644 index a2b4fdf4..00000000 --- a/api/.gitignore +++ /dev/null @@ -1,144 +0,0 @@ -# Django # -*.log -*.pot -*.pyc -*/__pycache__/ -db.sqlite3 -media/ -*/data/ - -# Photos # -equipment_photos/ - -# Backup files # -*.bak - -# If you are using PyCharm # -# User-specific stuff -.idea/**/workspace.xml -.idea/**/tasks.xml -.idea/**/usage.statistics.xml -.idea/**/dictionaries -.idea/**/shelf - -# AWS User-specific -.idea/**/aws.xml - -# Generated files -.idea/**/contentModel.xml - -# Sensitive or high-churn files -.idea/**/dataSources/ -.idea/**/dataSources.ids -.idea/**/dataSources.local.xml -.idea/**/sqlDataSources.xml -.idea/**/dynamic.xml -.idea/**/uiDesigner.xml -.idea/**/dbnavigator.xml - -# Gradle -.idea/**/gradle.xml -.idea/**/libraries - -# File-based project format -*.iws - -# IntelliJ -out/ - -# JIRA plugin -atlassian-ide-plugin.xml - -# Python # -*.py[cod] -*$py.class - -# Distribution / packaging -.Python build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -*.whl -*.egg-info/ -.installed.cfg -*.egg -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.coverage -.coverage.* -.cache -.pytest_cache/ -nosetests.xml -coverage.xml -*.cover -.hypothesis/ - -# Jupyter Notebook -.ipynb_checkpoints - -# pyenv -.python-version - -# celery -celerybeat-schedule.* - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ - -# Sublime Text # -*.tmlanguage.cache -*.tmPreferences.cache -*.stTheme.cache -*.sublime-workspace -*.sublime-project - -# sftp configuration file -sftp-config.json - -# Package control specific files Package -Control.last-run -Control.ca-list -Control.ca-bundle -Control.system-ca-bundle -GitHub.sublime-settings - -# Visual Studio Code # -.vscode/* -!.vscode/settings.json -!.vscode/tasks.json -!.vscode/launch.json -!.vscode/extensions.json -.history -data/ - diff --git a/api/.idea/.gitignore b/api/.idea/.gitignore deleted file mode 100644 index 13566b81..00000000 --- a/api/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/api/.idea/api.iml b/api/.idea/api.iml deleted file mode 100644 index b00c88e2..00000000 --- a/api/.idea/api.iml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/api/.idea/dataSources.xml b/api/.idea/dataSources.xml deleted file mode 100644 index bb66d67c..00000000 --- a/api/.idea/dataSources.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - mysql.8 - true - com.mysql.cj.jdbc.Driver - jdbc:mysql://localhost:3306/sigeie_db - $ProjectFileDir$ - - - \ No newline at end of file diff --git a/api/.idea/inspectionProfiles/profiles_settings.xml b/api/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da..00000000 --- a/api/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/api/.idea/misc.xml b/api/.idea/misc.xml deleted file mode 100644 index 6ae386b6..00000000 --- a/api/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/api/.idea/modules.xml b/api/.idea/modules.xml deleted file mode 100644 index d50cf45f..00000000 --- a/api/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/api/.idea/vcs.xml b/api/.idea/vcs.xml deleted file mode 100644 index 6c0b8635..00000000 --- a/api/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/api/.vscode/settings.json b/api/.vscode/settings.json deleted file mode 100644 index b92839d5..00000000 --- a/api/.vscode/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "workbench.colorCustomizations": { - "activityBar.activeBackground": "#65c89b", - "activityBar.background": "#65c89b", - "activityBar.foreground": "#15202b", - "activityBar.inactiveForeground": "#15202b99", - "activityBarBadge.background": "#945bc4", - "activityBarBadge.foreground": "#e7e7e7", - "commandCenter.border": "#15202b99", - "sash.hoverBorder": "#65c89b", - "statusBar.background": "#42b883", - "statusBar.foreground": "#15202b", - "statusBarItem.hoverBackground": "#359268", - "statusBarItem.remoteBackground": "#42b883", - "statusBarItem.remoteForeground": "#15202b", - "titleBar.activeBackground": "#42b883", - "titleBar.activeForeground": "#15202b", - "titleBar.inactiveBackground": "#42b88399", - "titleBar.inactiveForeground": "#15202b99" - }, - "peacock.color": "#42b883" -} \ No newline at end of file diff --git a/api/Dockerfile b/api/Dockerfile deleted file mode 100644 index 3d6b28de..00000000 --- a/api/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM python:3.11 - -WORKDIR /app - -COPY requirements.txt /app/ - -RUN pip install --no-cache-dir -r requirements.txt - -COPY . /app/ - -EXPOSE 8000 diff --git a/api/docker-compose.yml b/api/docker-compose.yml deleted file mode 100644 index e38f4b8a..00000000 --- a/api/docker-compose.yml +++ /dev/null @@ -1,31 +0,0 @@ -version: "3.9" -services: - db: - image: mysql:8.1.0 - restart: always - environment: - MYSQL_DATABASE: 'sigeie_db' - MYSQL_ROOT_PASSWORD: 'root' - container_name: sigeie_mysql_db - ports: - - "3306:3306" - volumes: - - ./data/mysql/db:/var/lib/mysql - redis: - image: redis:7.2 - restart: always - container_name: sigeie_redis_db - ports: - - "6379:6379" - web: - build: . - restart: always - container_name: sigeie_web - command: ["python", "manage.py", "runserver", "0.0.0.0:8000"] - volumes: - - .:/app - ports: - - "8000:8000" - depends_on: - - db - - redis \ No newline at end of file diff --git a/api/equipments/__init__.py b/api/equipments/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/equipments/admin.py b/api/equipments/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/api/equipments/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/api/equipments/apps.py b/api/equipments/apps.py deleted file mode 100644 index 0b795db5..00000000 --- a/api/equipments/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class EquipmentsConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'equipments' diff --git a/api/equipments/migrations/0001_initial.py b/api/equipments/migrations/0001_initial.py deleted file mode 100644 index 70dd3fa6..00000000 --- a/api/equipments/migrations/0001_initial.py +++ /dev/null @@ -1,46 +0,0 @@ -# Generated by Django 4.2 on 2024-04-18 17:23 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('places', '0019_delete_atmosfericdischargesystem'), - ('systems', '0006_remove_equipment_equipmentphoto_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='EquipmentType', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('type', models.CharField(max_length=50)), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='systems.system')), - ], - ), - migrations.CreateModel( - name='Equipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('photo', models.ImageField(null=True, upload_to='equipment_photos/')), - ('description', models.CharField(max_length=50)), - ('equipmentType', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmenttype')), - ], - ), - migrations.CreateModel( - name='AtmosphericDischargeSystem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='places.place')), - ('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='places.room')), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='systems.system')), - ], - options={ - 'db_table': 'atmospheric_discharge_systems', - }, - ), - ] diff --git a/api/equipments/migrations/0002_equipment_placeowner_and_more.py b/api/equipments/migrations/0002_equipment_placeowner_and_more.py deleted file mode 100644 index 34ec64e4..00000000 --- a/api/equipments/migrations/0002_equipment_placeowner_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-04-18 18:24 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0004_alter_placeowner_user'), - ('equipments', '0001_initial'), - ] - - operations = [ - migrations.AddField( - model_name='equipment', - name='placeOwner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.placeowner'), - ), - migrations.DeleteModel( - name='AtmosphericDischargeSystem', - ), - ] diff --git a/api/equipments/migrations/0003_atmosphericdischargeequipment.py b/api/equipments/migrations/0003_atmosphericdischargeequipment.py deleted file mode 100644 index 434456c4..00000000 --- a/api/equipments/migrations/0003_atmosphericdischargeequipment.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 18:15 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0021_room_place_room_systems'), - ('equipments', '0002_equipment_placeowner_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='AtmosphericDischargeEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('equipment', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipment')), - ('room', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.room')), - ], - ), - ] diff --git a/api/equipments/migrations/0004_rename_equipment_equipmentdetail.py b/api/equipments/migrations/0004_rename_equipment_equipmentdetail.py deleted file mode 100644 index b7cb03fe..00000000 --- a/api/equipments/migrations/0004_rename_equipment_equipmentdetail.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 18:54 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0004_alter_placeowner_user'), - ('equipments', '0003_atmosphericdischargeequipment'), - ] - - operations = [ - migrations.RenameModel( - old_name='Equipment', - new_name='EquipmentDetail', - ), - ] diff --git a/api/equipments/migrations/0005_remove_atmosphericdischargeequipment_room.py b/api/equipments/migrations/0005_remove_atmosphericdischargeequipment_room.py deleted file mode 100644 index f1047511..00000000 --- a/api/equipments/migrations/0005_remove_atmosphericdischargeequipment_room.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 19:22 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0004_rename_equipment_equipmentdetail'), - ] - - operations = [ - migrations.RemoveField( - model_name='atmosphericdischargeequipment', - name='room', - ), - ] diff --git a/api/equipments/migrations/0006_atmosphericdischargeequipment_area.py b/api/equipments/migrations/0006_atmosphericdischargeequipment_area.py deleted file mode 100644 index bf889635..00000000 --- a/api/equipments/migrations/0006_atmosphericdischargeequipment_area.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 19:22 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0022_area_delete_room'), - ('equipments', '0005_remove_atmosphericdischargeequipment_room'), - ] - - operations = [ - migrations.AddField( - model_name='atmosphericdischargeequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - ] diff --git a/api/equipments/migrations/0007_alter_atmosphericdischargeequipment_table_and_more.py b/api/equipments/migrations/0007_alter_atmosphericdischargeequipment_table_and_more.py deleted file mode 100644 index 8ab0948b..00000000 --- a/api/equipments/migrations/0007_alter_atmosphericdischargeequipment_table_and_more.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 19:24 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0006_atmosphericdischargeequipment_area'), - ] - - operations = [ - migrations.AlterModelTable( - name='atmosphericdischargeequipment', - table='atmospheric_discharge_equipments', - ), - migrations.AlterModelTable( - name='equipmentdetail', - table='equipment_details', - ), - migrations.AlterModelTable( - name='equipmenttype', - table='equipment_types', - ), - ] diff --git a/api/equipments/migrations/0008_alter_atmosphericdischargeequipment_table_and_more.py b/api/equipments/migrations/0008_alter_atmosphericdischargeequipment_table_and_more.py deleted file mode 100644 index d45e74ad..00000000 --- a/api/equipments/migrations/0008_alter_atmosphericdischargeequipment_table_and_more.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 19:25 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0007_alter_atmosphericdischargeequipment_table_and_more'), - ] - - operations = [ - migrations.AlterModelTable( - name='atmosphericdischargeequipment', - table='equipments_atmospheric_discharge_equipments', - ), - migrations.AlterModelTable( - name='equipmentdetail', - table='equipments_equipment_details', - ), - migrations.AlterModelTable( - name='equipmenttype', - table='equipments_equipment_types', - ), - ] diff --git a/api/equipments/migrations/0009_rename_equipment_atmosphericdischargeequipment_equipment_detail.py b/api/equipments/migrations/0009_rename_equipment_atmosphericdischargeequipment_equipment_detail.py deleted file mode 100644 index e522ad03..00000000 --- a/api/equipments/migrations/0009_rename_equipment_atmosphericdischargeequipment_equipment_detail.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 20:23 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0008_alter_atmosphericdischargeequipment_table_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='atmosphericdischargeequipment', - old_name='equipment', - new_name='equipment_detail', - ), - ] diff --git a/api/equipments/migrations/0010_rename_type_equipmenttype_name.py b/api/equipments/migrations/0010_rename_type_equipmenttype_name.py deleted file mode 100644 index 7d8e4a0f..00000000 --- a/api/equipments/migrations/0010_rename_type_equipmenttype_name.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-04-25 12:50 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0009_rename_equipment_atmosphericdischargeequipment_equipment_detail'), - ] - - operations = [ - migrations.RenameField( - model_name='equipmenttype', - old_name='type', - new_name='name', - ), - ] diff --git a/api/equipments/migrations/0011_rename_placeowner_equipmentdetail_place_owner.py b/api/equipments/migrations/0011_rename_placeowner_equipmentdetail_place_owner.py deleted file mode 100644 index 9ac02fb3..00000000 --- a/api/equipments/migrations/0011_rename_placeowner_equipmentdetail_place_owner.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-04-25 13:29 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0010_rename_type_equipmenttype_name'), - ] - - operations = [ - migrations.RenameField( - model_name='equipmentdetail', - old_name='placeOwner', - new_name='place_owner', - ), - ] diff --git a/api/equipments/migrations/0012_sructeredcablingequipment_iluminationequipment_and_more.py b/api/equipments/migrations/0012_sructeredcablingequipment_iluminationequipment_and_more.py deleted file mode 100644 index 807a3d82..00000000 --- a/api/equipments/migrations/0012_sructeredcablingequipment_iluminationequipment_and_more.py +++ /dev/null @@ -1,71 +0,0 @@ -# Generated by Django 4.2 on 2024-04-25 13:51 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0023_alter_area_place'), - ('equipments', '0011_rename_placeowner_equipmentdetail_place_owner'), - ] - - operations = [ - migrations.CreateModel( - name='SructeredCablingEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - migrations.CreateModel( - name='IluminationEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - migrations.CreateModel( - name='FireAlarmEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - migrations.CreateModel( - name='ElectricalLoadEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - migrations.CreateModel( - name='ElectricalLineEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - migrations.CreateModel( - name='ElectricalCircuitEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - migrations.CreateModel( - name='DistributionBoardEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - ] diff --git a/api/equipments/migrations/0013_atmosphericdischargeequipment_system_and_more.py b/api/equipments/migrations/0013_atmosphericdischargeequipment_system_and_more.py deleted file mode 100644 index d5222883..00000000 --- a/api/equipments/migrations/0013_atmosphericdischargeequipment_system_and_more.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 13:25 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0012_sructeredcablingequipment_iluminationequipment_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='atmosphericdischargeequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='electricalcircuitequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='electricallineequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='electricalloadequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='firealarmequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='iluminationequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AddField( - model_name='sructeredcablingequipment', - name='system', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - ] diff --git a/api/equipments/migrations/0014_alter_atmosphericdischargeequipment_system_and_more.py b/api/equipments/migrations/0014_alter_atmosphericdischargeequipment_system_and_more.py deleted file mode 100644 index 88952f33..00000000 --- a/api/equipments/migrations/0014_alter_atmosphericdischargeequipment_system_and_more.py +++ /dev/null @@ -1,55 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 13:28 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0013_atmosphericdischargeequipment_system_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosphericdischargeequipment', - name='system', - field=models.OneToOneField(default=7, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='distributionboardequipment', - name='system', - field=models.OneToOneField(default=5, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='electricalcircuitequipment', - name='system', - field=models.OneToOneField(default=4, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='electricallineequipment', - name='system', - field=models.OneToOneField(default=3, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='electricalloadequipment', - name='system', - field=models.OneToOneField(default=2, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='system', - field=models.OneToOneField(default=8, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='iluminationequipment', - name='system', - field=models.OneToOneField(default=1, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='sructeredcablingequipment', - name='system', - field=models.OneToOneField(default=6, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - ] diff --git a/api/equipments/migrations/0015_rename_sructeredcablingequipment_structuredcablingequipment_and_more.py b/api/equipments/migrations/0015_rename_sructeredcablingequipment_structuredcablingequipment_and_more.py deleted file mode 100644 index 01b2e558..00000000 --- a/api/equipments/migrations/0015_rename_sructeredcablingequipment_structuredcablingequipment_and_more.py +++ /dev/null @@ -1,47 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 15:38 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('places', '0026_alter_area_place'), - ('equipments', '0014_alter_atmosphericdischargeequipment_system_and_more'), - ] - - operations = [ - migrations.RenameModel( - old_name='SructeredCablingEquipment', - new_name='StructuredCablingEquipment', - ), - migrations.AlterModelTable( - name='distributionboardequipment', - table='equipments_distribution_board_equipments', - ), - migrations.AlterModelTable( - name='electricalcircuitequipment', - table='equipments_electrical_circuit_equipments', - ), - migrations.AlterModelTable( - name='electricallineequipment', - table='equipments_electrical_line_equipments', - ), - migrations.AlterModelTable( - name='electricalloadequipment', - table='equipments_electrical_load_equipments', - ), - migrations.AlterModelTable( - name='firealarmequipment', - table='equipments_fire_alarm_equipments', - ), - migrations.AlterModelTable( - name='iluminationequipment', - table='equipments_ilumination_equipments', - ), - migrations.AlterModelTable( - name='structuredcablingequipment', - table='equipments_structured_cabling_equipments', - ), - ] diff --git a/api/equipments/migrations/0016_alter_atmosphericdischargeequipment_system.py b/api/equipments/migrations/0016_alter_atmosphericdischargeequipment_system.py deleted file mode 100644 index e8356204..00000000 --- a/api/equipments/migrations/0016_alter_atmosphericdischargeequipment_system.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 16:34 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0015_rename_sructeredcablingequipment_structuredcablingequipment_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosphericdischargeequipment', - name='system', - field=models.ForeignKey(default=7, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - ] diff --git a/api/equipments/migrations/0017_alter_distributionboardequipment_system_and_more.py b/api/equipments/migrations/0017_alter_distributionboardequipment_system_and_more.py deleted file mode 100644 index 4684b905..00000000 --- a/api/equipments/migrations/0017_alter_distributionboardequipment_system_and_more.py +++ /dev/null @@ -1,50 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 16:53 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0016_alter_atmosphericdischargeequipment_system'), - ] - - operations = [ - migrations.AlterField( - model_name='distributionboardequipment', - name='system', - field=models.ForeignKey(default=5, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='electricalcircuitequipment', - name='system', - field=models.ForeignKey(default=4, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='electricallineequipment', - name='system', - field=models.ForeignKey(default=3, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='electricalloadequipment', - name='system', - field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='system', - field=models.ForeignKey(default=8, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='iluminationequipment', - name='system', - field=models.ForeignKey(default=1, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterField( - model_name='structuredcablingequipment', - name='system', - field=models.ForeignKey(default=6, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - ] diff --git a/api/equipments/migrations/0018_personalequipmenttype.py b/api/equipments/migrations/0018_personalequipmenttype.py deleted file mode 100644 index 28eece20..00000000 --- a/api/equipments/migrations/0018_personalequipmenttype.py +++ /dev/null @@ -1,28 +0,0 @@ -# Generated by Django 4.2 on 2024-05-13 16:21 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0004_alter_placeowner_user'), - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0017_alter_distributionboardequipment_system_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='PersonalEquipmentType', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('place_owner', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.placeowner')), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='systems.system')), - ], - options={ - 'db_table': 'equipments_personal_equipment_types', - }, - ), - ] diff --git a/api/equipments/migrations/0019_remove_equipmentdetail_description_and_more.py b/api/equipments/migrations/0019_remove_equipmentdetail_description_and_more.py deleted file mode 100644 index 29fded19..00000000 --- a/api/equipments/migrations/0019_remove_equipmentdetail_description_and_more.py +++ /dev/null @@ -1,45 +0,0 @@ -# Generated by Django 4.2 on 2024-05-23 14:16 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('places', '0028_place_photo'), - ('equipments', '0018_personalequipmenttype'), - ] - - operations = [ - migrations.RemoveField( - model_name='equipmentdetail', - name='description', - ), - migrations.RemoveField( - model_name='equipmentdetail', - name='photo', - ), - migrations.CreateModel( - name='RefrigerationEquipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('area', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area')), - ('equipment_detail', models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ('system', models.ForeignKey(default=2, on_delete=django.db.models.deletion.CASCADE, to='systems.system')), - ], - options={ - 'db_table': 'refrigeration_equipments', - }, - ), - migrations.CreateModel( - name='EquipmentPhoto', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('photo', models.ImageField(null=True, upload_to='equipment_photos/')), - ('description', models.CharField(max_length=50)), - ('equipment_detail', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail')), - ], - ), - ] diff --git a/api/equipments/migrations/0020_remove_equipmentphoto_equipment_detail_and_more.py b/api/equipments/migrations/0020_remove_equipmentphoto_equipment_detail_and_more.py deleted file mode 100644 index 22ee62c0..00000000 --- a/api/equipments/migrations/0020_remove_equipmentphoto_equipment_detail_and_more.py +++ /dev/null @@ -1,33 +0,0 @@ -# Generated by Django 4.2 on 2024-06-05 17:36 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0019_remove_equipmentdetail_description_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='equipmentphoto', - name='equipment_detail', - ), - migrations.AddField( - model_name='equipmentphoto', - name='equipmentType', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmenttype'), - ), - migrations.AddField( - model_name='equipmentphoto', - name='personalEquipmentType', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.personalequipmenttype'), - ), - migrations.AlterField( - model_name='equipmentphoto', - name='description', - field=models.CharField(max_length=50, null=True), - ), - ] diff --git a/api/equipments/migrations/0021_remove_equipmentphoto_equipmenttype_and_more.py b/api/equipments/migrations/0021_remove_equipmentphoto_equipmenttype_and_more.py deleted file mode 100644 index 673f7782..00000000 --- a/api/equipments/migrations/0021_remove_equipmentphoto_equipmenttype_and_more.py +++ /dev/null @@ -1,32 +0,0 @@ -# Generated by Django 4.2 on 2024-06-05 18:28 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0020_remove_equipmentphoto_equipment_detail_and_more'), - ] - - operations = [ - migrations.RemoveField( - model_name='equipmentphoto', - name='equipmentType', - ), - migrations.RemoveField( - model_name='equipmentphoto', - name='personalEquipmentType', - ), - migrations.AddField( - model_name='equipmentdetail', - name='personalEquipmentType', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.personalequipmenttype'), - ), - migrations.AlterField( - model_name='equipmentdetail', - name='equipmentType', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmenttype'), - ), - ] diff --git a/api/equipments/migrations/0022_equipmentphoto_equipment_detail.py b/api/equipments/migrations/0022_equipmentphoto_equipment_detail.py deleted file mode 100644 index 34d12076..00000000 --- a/api/equipments/migrations/0022_equipmentphoto_equipment_detail.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-06-12 20:29 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0021_remove_equipmentphoto_equipmenttype_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='equipmentphoto', - name='equipment_detail', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='equipments.equipmentdetail'), - ), - ] diff --git a/api/equipments/migrations/0023_rename_equipmentdetail_equipment_and_more.py b/api/equipments/migrations/0023_rename_equipmentdetail_equipment_and_more.py deleted file mode 100644 index 1bca0743..00000000 --- a/api/equipments/migrations/0023_rename_equipmentdetail_equipment_and_more.py +++ /dev/null @@ -1,95 +0,0 @@ -# Generated by Django 4.2 on 2024-06-14 13:54 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0006_alter_placeowner_user'), - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0022_equipmentphoto_equipment_detail'), - ] - - operations = [ - migrations.RenameModel( - old_name='EquipmentDetail', - new_name='Equipment', - ), - migrations.RenameModel( - old_name='EquipmentType', - new_name='GenericEquipmentCategory', - ), - migrations.RenameModel( - old_name='PersonalEquipmentType', - new_name='PersonalEquipmentCategory', - ), - migrations.RenameField( - model_name='atmosphericdischargeequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='distributionboardequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='electricalcircuitequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='electricallineequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='electricalloadequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='equipment', - old_name='equipmentType', - new_name='genericEquipmentCategory', - ), - migrations.RenameField( - model_name='equipment', - old_name='personalEquipmentType', - new_name='personalEquipmentCategory', - ), - migrations.RenameField( - model_name='equipmentphoto', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='firealarmequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='iluminationequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='refrigerationequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.RenameField( - model_name='structuredcablingequipment', - old_name='equipment_detail', - new_name='equipment', - ), - migrations.AlterModelTable( - name='genericequipmentcategory', - table='equipments_generic_equipment_categories', - ), - migrations.AlterModelTable( - name='personalequipmentcategory', - table='equipments_personal_equipment_categories', - ), - ] diff --git a/api/equipments/migrations/0024_rename_genericequipmentcategory_equipment_generic_equipment_category_and_more.py b/api/equipments/migrations/0024_rename_genericequipmentcategory_equipment_generic_equipment_category_and_more.py deleted file mode 100644 index 1c60d476..00000000 --- a/api/equipments/migrations/0024_rename_genericequipmentcategory_equipment_generic_equipment_category_and_more.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-06-14 15:38 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0023_rename_equipmentdetail_equipment_and_more'), - ] - - operations = [ - migrations.RenameField( - model_name='equipment', - old_name='genericEquipmentCategory', - new_name='generic_equipment_category', - ), - migrations.RenameField( - model_name='equipment', - old_name='personalEquipmentCategory', - new_name='personal_equipment_category', - ), - ] diff --git a/api/equipments/migrations/0025_alter_atmosphericdischargeequipment_area_and_more.py b/api/equipments/migrations/0025_alter_atmosphericdischargeequipment_area_and_more.py deleted file mode 100644 index 8b111a11..00000000 --- a/api/equipments/migrations/0025_alter_atmosphericdischargeequipment_area_and_more.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 4.2 on 2024-06-17 14:34 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0031_remove_place_access_code'), - ('equipments', '0024_rename_genericequipmentcategory_equipment_generic_equipment_category_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosphericdischargeequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='AtmosphericDischargeEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='distributionboardequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='DistributionBoardEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricalcircuitequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ElectricalCircuitEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricallineequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ElectricalLineEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricalloadequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ElectricalLoadEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='firealarmequipment', to='places.area'), - ), - migrations.AlterField( - model_name='iluminationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='IluminationEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='refrigerationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='RefrigerationEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='structuredcablingequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='StructuredCablingEquipment', to='places.area'), - ), - ] diff --git a/api/equipments/migrations/0026_alter_atmosphericdischargeequipment_area_and_more.py b/api/equipments/migrations/0026_alter_atmosphericdischargeequipment_area_and_more.py deleted file mode 100644 index 5d6bcc24..00000000 --- a/api/equipments/migrations/0026_alter_atmosphericdischargeequipment_area_and_more.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 4.2 on 2024-06-17 16:34 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0031_remove_place_access_code'), - ('equipments', '0025_alter_atmosphericdischargeequipment_area_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosphericdischargeequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='distributionboardequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='electricalcircuitequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='electricallineequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='electricalloadequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='iluminationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='refrigerationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - migrations.AlterField( - model_name='structuredcablingequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.area'), - ), - ] diff --git a/api/equipments/migrations/0027_alter_atmosphericdischargeequipment_area_and_more.py b/api/equipments/migrations/0027_alter_atmosphericdischargeequipment_area_and_more.py deleted file mode 100644 index ebbb285b..00000000 --- a/api/equipments/migrations/0027_alter_atmosphericdischargeequipment_area_and_more.py +++ /dev/null @@ -1,60 +0,0 @@ -# Generated by Django 4.2 on 2024-06-17 16:59 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0031_remove_place_access_code'), - ('equipments', '0026_alter_atmosphericdischargeequipment_area_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosphericdischargeequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='AtmosphericDischargeEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='distributionboardequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='DistributionBoardEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricalcircuitequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ElectricalCircuitEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricallineequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ElectricalLineEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricalloadequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ElectricalLoadEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='firealarmequipment', to='places.area'), - ), - migrations.AlterField( - model_name='iluminationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='IluminationEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='refrigerationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='RefrigerationEquipment', to='places.area'), - ), - migrations.AlterField( - model_name='structuredcablingequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='StructuredCablingEquipment', to='places.area'), - ), - ] diff --git a/api/equipments/migrations/0028_alter_atmosphericdischargeequipment_area_and_more.py b/api/equipments/migrations/0028_alter_atmosphericdischargeequipment_area_and_more.py deleted file mode 100644 index 324c01eb..00000000 --- a/api/equipments/migrations/0028_alter_atmosphericdischargeequipment_area_and_more.py +++ /dev/null @@ -1,61 +0,0 @@ -# Generated by Django 4.2 on 2024-06-18 20:55 -# Generated by Django 4.2 on 2024-06-19 17:19 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0031_remove_place_access_code'), - ('equipments', '0027_alter_atmosphericdischargeequipment_area_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosphericdischargeequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='distributionboardequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='distribution_board_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricalcircuitequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='electrical_circuit_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricallineequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='electrical_line_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='electricalloadequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='electrical_load_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fire_alarm_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='iluminationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='ilumination_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='refrigerationequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='refrigeration_equipment', to='places.area'), - ), - migrations.AlterField( - model_name='structuredcablingequipment', - name='area', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='structured_cabling_equipment', to='places.area'), - ), - ] diff --git a/api/equipments/migrations/0029_alter_equipment_place_owner_and_more.py b/api/equipments/migrations/0029_alter_equipment_place_owner_and_more.py deleted file mode 100644 index 2c28d3f2..00000000 --- a/api/equipments/migrations/0029_alter_equipment_place_owner_and_more.py +++ /dev/null @@ -1,35 +0,0 @@ -# Generated by Django 4.2 on 2024-06-21 12:47 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0006_alter_placeowner_user'), - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0028_alter_atmosphericdischargeequipment_area_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='equipment', - name='place_owner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='equipment', to='users.placeowner'), - ), - migrations.AlterField( - model_name='firealarmequipment', - name='equipment', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='fire_alarm', to='equipments.equipment'), - ), - migrations.AlterField( - model_name='refrigerationequipment', - name='system', - field=models.ForeignKey(default=9, on_delete=django.db.models.deletion.CASCADE, to='systems.system'), - ), - migrations.AlterModelTable( - name='refrigerationequipment', - table='equipments_refrigeration_equipments', - ), - ] diff --git a/api/equipments/migrations/0030_alter_equipment_place_owner.py b/api/equipments/migrations/0030_alter_equipment_place_owner.py deleted file mode 100644 index 6eedb78d..00000000 --- a/api/equipments/migrations/0030_alter_equipment_place_owner.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-06-21 18:13 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0006_alter_placeowner_user'), - ('equipments', '0029_alter_equipment_place_owner_and_more'), - ] - - operations = [ - migrations.AlterField( - model_name='equipment', - name='place_owner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.placeowner'), - ), - ] diff --git a/api/equipments/migrations/0031_alter_atmosphericdischargeequipment_table_and_more.py b/api/equipments/migrations/0031_alter_atmosphericdischargeequipment_table_and_more.py deleted file mode 100644 index 7448428c..00000000 --- a/api/equipments/migrations/0031_alter_atmosphericdischargeequipment_table_and_more.py +++ /dev/null @@ -1,65 +0,0 @@ -# Generated by Django 4.2 on 2024-06-30 14:55 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0030_alter_equipment_place_owner'), - ] - - operations = [ - migrations.AlterModelTable( - name='atmosphericdischargeequipment', - table='atmospheric_discharges', - ), - migrations.AlterModelTable( - name='distributionboardequipment', - table='distribution_boards', - ), - migrations.AlterModelTable( - name='electricalcircuitequipment', - table='electrical_circuits', - ), - migrations.AlterModelTable( - name='electricallineequipment', - table='electrical_lines', - ), - migrations.AlterModelTable( - name='electricalloadequipment', - table='electrical_loads', - ), - migrations.AlterModelTable( - name='equipment', - table='equipments', - ), - migrations.AlterModelTable( - name='equipmentphoto', - table='equipment_photos', - ), - migrations.AlterModelTable( - name='firealarmequipment', - table='fire_alarms', - ), - migrations.AlterModelTable( - name='genericequipmentcategory', - table='generic_equipment_categories', - ), - migrations.AlterModelTable( - name='iluminationequipment', - table='illuminations', - ), - migrations.AlterModelTable( - name='personalequipmentcategory', - table='personal_equipment_categories', - ), - migrations.AlterModelTable( - name='refrigerationequipment', - table='refrigeration_equipments', - ), - migrations.AlterModelTable( - name='structuredcablingequipment', - table='structured_cabling', - ), - ] diff --git a/api/equipments/migrations/0032_alter_atmosphericdischargeequipment_table_and_more.py b/api/equipments/migrations/0032_alter_atmosphericdischargeequipment_table_and_more.py deleted file mode 100644 index 05913c04..00000000 --- a/api/equipments/migrations/0032_alter_atmosphericdischargeequipment_table_and_more.py +++ /dev/null @@ -1,53 +0,0 @@ -# Generated by Django 4.2 on 2024-06-30 14:58 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0031_alter_atmosphericdischargeequipment_table_and_more'), - ] - - operations = [ - migrations.AlterModelTable( - name='atmosphericdischargeequipment', - table='equipments_atmospheric_discharges', - ), - migrations.AlterModelTable( - name='distributionboardequipment', - table='equipments_distribution_boards', - ), - migrations.AlterModelTable( - name='electricalcircuitequipment', - table='equipments_electrical_circuits', - ), - migrations.AlterModelTable( - name='electricallineequipment', - table='equipments_electrical_lines', - ), - migrations.AlterModelTable( - name='electricalloadequipment', - table='equipments_electrical_loads', - ), - migrations.AlterModelTable( - name='equipmentphoto', - table='equipments_photos', - ), - migrations.AlterModelTable( - name='firealarmequipment', - table='equipments_fire_alarms', - ), - migrations.AlterModelTable( - name='iluminationequipment', - table='equipments_illuminations', - ), - migrations.AlterModelTable( - name='refrigerationequipment', - table='equipments_refrigeration', - ), - migrations.AlterModelTable( - name='structuredcablingequipment', - table='equipments_structured_cabling', - ), - ] diff --git a/api/equipments/migrations/0033_distributionboardequipment_dps_and_more.py b/api/equipments/migrations/0033_distributionboardequipment_dps_and_more.py deleted file mode 100644 index cdd2e893..00000000 --- a/api/equipments/migrations/0033_distributionboardequipment_dps_and_more.py +++ /dev/null @@ -1,103 +0,0 @@ -# Generated by Django 4.2 on 2024-07-09 18:42 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0032_alter_atmosphericdischargeequipment_table_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='distributionboardequipment', - name='dps', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='dr', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='grounding', - field=models.BooleanField(default=False), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='method_installation', - field=models.CharField(max_length=50, null=True), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='power', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='type_material', - field=models.CharField(max_length=30, null=True), - ), - migrations.AddField( - model_name='electricalcircuitequipment', - name='isolament', - field=models.CharField(default=None, max_length=30), - ), - migrations.AddField( - model_name='electricalcircuitequipment', - name='size', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='electricalloadequipment', - name='brand', - field=models.CharField(default=None, max_length=30), - ), - migrations.AddField( - model_name='electricalloadequipment', - name='model', - field=models.CharField(default=None, max_length=50), - ), - migrations.AddField( - model_name='electricalloadequipment', - name='power', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='electricalloadequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='iluminationequipment', - name='format', - field=models.CharField(default=None, max_length=30), - ), - migrations.AddField( - model_name='iluminationequipment', - name='power', - field=models.IntegerField(default=1), - ), - migrations.AddField( - model_name='iluminationequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='iluminationequipment', - name='tecnology', - field=models.CharField(default=None, max_length=30), - ), - migrations.AddField( - model_name='refrigerationequipment', - name='power', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='refrigerationequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - ] diff --git a/api/equipments/migrations/0034_atmosphericdischargeequipment_quantity_and_more.py b/api/equipments/migrations/0034_atmosphericdischargeequipment_quantity_and_more.py deleted file mode 100644 index 6affde09..00000000 --- a/api/equipments/migrations/0034_atmosphericdischargeequipment_quantity_and_more.py +++ /dev/null @@ -1,43 +0,0 @@ -# Generated by Django 4.2 on 2024-07-17 17:25 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('equipments', '0033_distributionboardequipment_dps_and_more'), - ] - - operations = [ - migrations.AddField( - model_name='atmosphericdischargeequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='distributionboardequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='electricalcircuitequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='electricallineequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='firealarmequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - migrations.AddField( - model_name='structuredcablingequipment', - name='quantity', - field=models.IntegerField(default=0), - ), - ] diff --git a/api/equipments/migrations/__init__.py b/api/equipments/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/equipments/mixins.py b/api/equipments/mixins.py deleted file mode 100644 index 51d406a4..00000000 --- a/api/equipments/mixins.py +++ /dev/null @@ -1,24 +0,0 @@ -from rest_framework import serializers - - -class ValidateAreaMixin: - - def validate_area(self, value): - """ - Garante que a area pertence ao place owner ou ao editor. - """ - user = self.context['request'].user - if value.place.place_owner != user.place_owner and not value.place.editors.filter(user=user).exists(): - raise serializers.ValidationError("You are not the owner or editor of this place") - return value - - -class EquipmentCategoryMixin: - - def get_equipment_category(self, obj): - equipment = obj.equipment - if equipment.generic_equipment_category is not None: - return equipment.generic_equipment_category.name - elif equipment.personal_equipment_category is not None: - return equipment.personal_equipment_category.name - return None diff --git a/api/equipments/models.py b/api/equipments/models.py deleted file mode 100644 index b74bdcf0..00000000 --- a/api/equipments/models.py +++ /dev/null @@ -1,163 +0,0 @@ -from django.db import models -from places.models import Place, Area -from systems.models import System -from users.models import PlaceOwner - - -class PersonalEquipmentCategory(models.Model): - name = models.CharField(max_length=50) - system = models.ForeignKey(System, on_delete=models.CASCADE) - place_owner = models.ForeignKey(PlaceOwner, on_delete=models.CASCADE, null=True) - - def __str__(self): - return self.name - - class Meta: - db_table = 'personal_equipment_categories' - - -class GenericEquipmentCategory(models.Model): - name = models.CharField(max_length=50) - system = models.ForeignKey(System, on_delete=models.CASCADE) - - def __str__(self): - return self.name - - class Meta: - db_table = 'generic_equipment_categories' - - -class Equipment(models.Model): - generic_equipment_category = models.ForeignKey(GenericEquipmentCategory, on_delete=models.CASCADE, null=True) - personal_equipment_category = models.ForeignKey(PersonalEquipmentCategory, on_delete=models.CASCADE, null=True) - place_owner = models.ForeignKey(PlaceOwner, on_delete=models.CASCADE, null=True) - - def __str__(self): - if self.generic_equipment_category is not None: - return str(self.generic_equipment_category.name) - elif self.personal_equipment_category is not None: - return str(self.personal_equipment_category.name) - return 'No category' - - class Meta: - db_table = 'equipments' - - -class EquipmentPhoto(models.Model): - photo = models.ImageField(null=True, upload_to='equipment_photos/') - description = models.CharField(max_length=50, null=True) - equipment = models.ForeignKey(Equipment, on_delete=models.CASCADE, null=True) - - def __str__(self): - return self.description - - class Meta: - db_table = 'equipments_photos' - - -class IluminationEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="ilumination_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=1) - power = models.IntegerField(default=1) - tecnology = models.CharField(max_length=30, default=None) - format = models.CharField(max_length=30, default=None) - quantity = models.IntegerField(default=0) - - - class Meta: - db_table = 'equipments_illuminations' - - -class ElectricalLoadEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="electrical_load_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=2) - brand = models.CharField(max_length=30, default=None) - model = models.CharField(max_length=50, default=None) - power = models.IntegerField(default=0) - quantity = models.IntegerField(default=0) - - - class Meta: - db_table = 'equipments_electrical_loads' - - -class ElectricalLineEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="electrical_line_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=3) - quantity = models.IntegerField(default=0) - - class Meta: - db_table = 'equipments_electrical_lines' - - -class ElectricalCircuitEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name='electrical_circuit_equipment') - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=4) - size = models.IntegerField(default=0) - isolament = models.CharField(max_length=30, default=None) - quantity = models.IntegerField(default=0) - - class Meta: - db_table = 'equipments_electrical_circuits' - - -class DistributionBoardEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="distribution_board_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=5) - power = models.IntegerField(default=0) - dr = models.BooleanField(default=False) - dps = models.BooleanField(default=False) - grounding = models.BooleanField(default=False) - type_material = models.CharField(max_length=30, null=True) - method_installation = models.CharField(max_length=50, null=True) - quantity = models.IntegerField(default=0) - - - class Meta: - db_table = 'equipments_distribution_boards' - - -class StructuredCablingEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="structured_cabling_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=6) - quantity = models.IntegerField(default=0) - - class Meta: - db_table = 'equipments_structured_cabling' - - -class AtmosphericDischargeEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="atmospheric_discharge_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=7) - quantity = models.IntegerField(default=0) - - class Meta: - db_table = 'equipments_atmospheric_discharges' - - -class FireAlarmEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="fire_alarm_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True, related_name="fire_alarm") - system = models.ForeignKey(System, on_delete=models.CASCADE, default=8) - quantity = models.IntegerField(default=0) - - class Meta: - db_table = 'equipments_fire_alarms' - - -class RefrigerationEquipment(models.Model): - area = models.ForeignKey(Area, on_delete=models.CASCADE, null=True, related_name="refrigeration_equipment") - equipment = models.OneToOneField(Equipment, on_delete=models.CASCADE, null=True) - system = models.ForeignKey(System, on_delete=models.CASCADE, default=9) - power = models.IntegerField(default=0) - quantity = models.IntegerField(default=0) - - class Meta: - db_table = 'equipments_refrigeration' diff --git a/api/equipments/permissions.py b/api/equipments/permissions.py deleted file mode 100644 index 21377d5a..00000000 --- a/api/equipments/permissions.py +++ /dev/null @@ -1,47 +0,0 @@ -from rest_framework.permissions import BasePermission - -from users.models import PlaceOwner - - -def get_place_owner_or_create(user): - try: - return user.place_owner - except PlaceOwner.DoesNotExist: - return PlaceOwner.objects.create(user=user) - - -class IsOwner(BasePermission): - def has_object_permission(self, request, view, obj): - get_place_owner_or_create(request.user) - return obj.place_owner == request.user.place_owner - - -class IsPlaceOwner(BasePermission): - def has_object_permission(self, request, view, obj): - if obj.place_owner == request.user.place_owner: - return True - return False - - -class IsEquipmentOwner(BasePermission): - def has_object_permission(self, request, view, obj): - if obj.equipment and obj.equipment.place_owner: - return obj.equipment.place_owner == request.user.place_owner - return False - - -class IsEquipmentEditor(BasePermission): - def has_object_permission(self, request, view, obj): - return obj.place_owner.places.editors.filter(user=request.user).exists() - - -class IsEquipmentEditorPhoto(BasePermission): - def has_object_permission(self, request, view, obj): - return obj.equipment.place_owner.places.editors.filter(user=request.user).exists() - - -class IsSpecificEquipmentEditor(BasePermission): - def has_object_permission(self, request, view, obj): - if obj.area and obj.area.place: - return obj.area.place.editors.filter(user=request.user).exists() - return False diff --git a/api/equipments/serializers.py b/api/equipments/serializers.py deleted file mode 100644 index 0ded426a..00000000 --- a/api/equipments/serializers.py +++ /dev/null @@ -1,259 +0,0 @@ -import base64 -from django.core.files.base import ContentFile -from rest_framework import serializers -from .models import * - -from .mixins import ValidateAreaMixin, EquipmentCategoryMixin - - -class PersonalEquipmentCategorySerializer(serializers.ModelSerializer): - class Meta: - model = PersonalEquipmentCategory - fields = '__all__' - - -class GenericEquipmentCategorySerializer(serializers.ModelSerializer): - class Meta: - model = GenericEquipmentCategory - fields = '__all__' - - -class EquipmentPhotoSerializer(serializers.ModelSerializer): - photo = serializers.CharField(write_only=True) - photo_base64 = serializers.SerializerMethodField() - - class Meta: - model = EquipmentPhoto - fields = ['id', 'photo', 'photo_base64', 'description', 'equipment'] - - def create(self, validated_data): - photo_data = validated_data.pop('photo') - try: - format, imgstr = photo_data.split(';base64,') - ext = format.split('/')[-1] - photo = ContentFile(base64.b64decode(imgstr), name='temp.' + ext) - except ValueError: - raise serializers.ValidationError("Invalid image data") - - equipment_photo = EquipmentPhoto.objects.create(photo=photo, **validated_data) - return equipment_photo - - def update(self, instance, validated_data): - photo_data = validated_data.pop('photo', None) - if photo_data: - try: - format, imgstr = photo_data.split(';base64,') - ext = format.split('/')[-1] - photo = ContentFile(base64.b64decode(imgstr), name='temp.' + ext) - instance.photo = photo - except ValueError: - raise serializers.ValidationError("Invalid image data") - - instance.description = validated_data.get('description', instance.description) - instance.equipment = validated_data.get('equipment', instance.equipment) - instance.save() - return instance - - def get_photo_base64(self, obj): - if obj.photo: - with obj.photo.open('rb') as image_file: - return 'data:image/jpeg;base64,' + base64.b64encode(image_file.read()).decode('utf-8') - return None - - -class FireAlarmEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = FireAlarmEquipment - fields = '__all__' - - -class AtmosphericDischargeEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = AtmosphericDischargeEquipment - fields = '__all__' - - -class StructuredCablingEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = StructuredCablingEquipment - fields = '__all__' - - -class DistributionBoardEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = DistributionBoardEquipment - fields = '__all__' - - -class ElectricalCircuitEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = ElectricalCircuitEquipment - fields = '__all__' - - -class ElectricalLineEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = ElectricalLineEquipment - fields = '__all__' - - -class ElectricalLoadEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = ElectricalLoadEquipment - fields = '__all__' - - -class IluminationEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = IluminationEquipment - fields = '__all__' - - -class RefrigerationEquipmentSerializer(ValidateAreaMixin, serializers.ModelSerializer): - class Meta: - model = RefrigerationEquipment - fields = '__all__' - - -class FireAlarmEquipmentResponseSerializer(ValidateAreaMixin, EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = FireAlarmEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'quantity'] - - -class AtmosphericDischargeEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = AtmosphericDischargeEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'quantity'] - - -class StructuredCablingEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = StructuredCablingEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'quantity'] - - -class DistributionBoardEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = DistributionBoardEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'power', 'dr', 'dps', 'grounding', 'type_material', 'method_installation', 'quantity'] - - -class ElectricalCircuitEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = ElectricalCircuitEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'size', 'isolament', 'quantity'] - - -class ElectricalLineEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = ElectricalLineEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'quantity'] - - -class ElectricalLoadEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = ElectricalLoadEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'quantity'] - - -class IluminationEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = IluminationEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'quantity'] - - -class RefrigerationEquipmentResponseSerializer(EquipmentCategoryMixin, serializers.ModelSerializer): - equipment_category = serializers.SerializerMethodField() - - class Meta: - model = RefrigerationEquipment - fields = ['id', 'area', 'equipment_category', 'system', 'power', 'quantity'] - - -class EquipmentSerializer(serializers.ModelSerializer): - fire_alarm_equipment = FireAlarmEquipmentSerializer(required=False) - atmospheric_discharge_equipment = AtmosphericDischargeEquipmentSerializer(required=False) - structured_cabling_equipment = StructuredCablingEquipmentSerializer(required=False) - distribution_board_equipment = DistributionBoardEquipmentSerializer(required=False) - electrical_circuit_equipment = ElectricalCircuitEquipmentSerializer(required=False) - electrical_line_equipment = ElectricalLineEquipmentSerializer(required=False) - electrical_load_equipment = ElectricalLoadEquipmentSerializer(required=False) - ilumination_equipment = IluminationEquipmentSerializer(required=False) - refrigeration_equipment = RefrigerationEquipmentSerializer(required=False) - - class Meta: - model = Equipment - fields = '__all__' - extra_kwargs = {'place_owner': {'read_only': True}} - - def create(self, validated_data): - request = self.context.get('request') - validated_data['place_owner'] = request.user.place_owner - - fire_alarm_data = validated_data.pop('fire_alarm_equipment', None) - atmospheric_discharge_data = validated_data.pop('atmospheric_discharge_equipment', None) - structured_cabling_data = validated_data.pop('structured_cabling_equipment', None) - distribution_board_data = validated_data.pop('distribution_board_equipment', None) - electrical_circuit_data = validated_data.pop('electrical_circuit_equipment', None) - electrical_line_data = validated_data.pop('electrical_line_equipment', None) - electrical_load_data = validated_data.pop('electrical_load_equipment', None) - ilumination_equipment_data = validated_data.pop('ilumination_equipment', None) - refrigeration_equipment_data = validated_data.pop('refrigeration_equipment', None) - - equipment = Equipment.objects.create(**validated_data) - - if fire_alarm_data: - if 'equipment' in fire_alarm_data: - fire_alarm_data.pop('equipment') - FireAlarmEquipment.objects.create(equipment=equipment, **fire_alarm_data) - elif atmospheric_discharge_data: - if 'equipment' in atmospheric_discharge_data: - atmospheric_discharge_data.pop('equipment') - AtmosphericDischargeEquipment.objects.create(equipment=equipment, **atmospheric_discharge_data) - elif structured_cabling_data: - if 'equipment' in structured_cabling_data: - structured_cabling_data.pop('equipment') - StructuredCablingEquipment.objects.create(equipment=equipment, **structured_cabling_data) - elif distribution_board_data: - if 'equipment' in distribution_board_data: - distribution_board_data.pop('equipment') - DistributionBoardEquipment.objects.create(equipment=equipment, **distribution_board_data) - elif electrical_circuit_data: - if 'equipment' in electrical_circuit_data: - electrical_circuit_data.pop('equipment') - ElectricalCircuitEquipment.objects.create(equipment=equipment, **electrical_circuit_data) - elif electrical_line_data: - if 'equipment' in electrical_line_data: - electrical_line_data.pop('equipment') - ElectricalLineEquipment.objects.create(equipment=equipment, **electrical_line_data) - elif electrical_load_data: - if 'equipment' in electrical_load_data: - electrical_load_data.pop('equipment') - ElectricalLoadEquipment.objects.create(equipment=equipment, **electrical_load_data) - elif ilumination_equipment_data: - if 'equipment' in ilumination_equipment_data: - ilumination_equipment_data.pop('equipment') - IluminationEquipment.objects.create(equipment=equipment, **ilumination_equipment_data) - elif refrigeration_equipment_data: - if 'equipment' in refrigeration_equipment_data: - refrigeration_equipment_data.pop('equipment') - RefrigerationEquipment.objects.create(equipment=equipment, **refrigeration_equipment_data) - - return equipment diff --git a/api/equipments/tests.py b/api/equipments/tests.py deleted file mode 100644 index 7ce503c2..00000000 --- a/api/equipments/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/api/equipments/urls.py b/api/equipments/urls.py deleted file mode 100644 index 16510fc1..00000000 --- a/api/equipments/urls.py +++ /dev/null @@ -1,42 +0,0 @@ -from .views import * -from django.urls import path - -urlpatterns = [ - path('personal-equipment-types/', PersonalEquipmentCategoryCreate.as_view(), name='personal_equipment_category_create'), - path('personal-equipment-types/by-system//', PersonalEquipmentCategoryList.as_view(), name='personal_equipment_category_by_system'), - path('personal-equipment-types//', PersonalEquipmentCategoryDetail.as_view()), - path('equipment-types/by-system//', GenericEquipmentCategoryList.as_view(), name='personal_equipment_types_by_system'), - path('equipment-types//', GenericEquipmentCategoryDetail.as_view()), - path('equipments/', EquipmentListCreateView.as_view(), name='equipments'), - path('equipments//', EquipmentDetail.as_view()), - path('equipment-photos/', EquipmentPhotoList.as_view()), - path('equipment-photos/by-equipment//', EquipmentPhotoByEquipmentList.as_view(), name='equipment-photo-list'), - path('equipment-photos//', EquipmentPhotoDetail.as_view()), - path('refrigerations/', RefrigerationEquipmentList.as_view()), - path('refrigeration/by-area//', RefrigerationEquipmentByAreaList.as_view()), - path('refrigerations//', RefrigerationEquipmentDetail.as_view()), - path('fire-alarms/', FireAlarmEquipmentList.as_view()), - path('fire-alarms/by-area//', FireAlarmEquipmentByAreaList.as_view()), - path('fire-alarms//', FireAlarmEquipmentDetail.as_view()), - path('atmospheric-discharges/', AtmosphericDischargeEquipmentList.as_view()), - path('atmospheric-discharges/by-area//', AtmosphericDischargeEquipmentByAreaList.as_view()), - path('atmospheric-discharges//', AtmosphericDischargeEquipmentDetail.as_view()), - path('structured-cabling/', StructuredCablingEquipmentList.as_view()), - path('structured-cabling/by-area//', StructuredCablingEquipmentByAreaList.as_view()), - path('structured-cabling//', StructuredCablingEquipmentDetail.as_view()), - path('distribution-boards/', DistributionBoardEquipmentList.as_view()), - path('distribution-boards/by-area//', DistributionBoardEquipmentByAreaList.as_view()), - path('distribution-boards//', DistributionBoardEquipmentDetail.as_view()), - path('electrical-circuits/', ElectricalCircuitEquipmentList.as_view()), - path('electrical-circuits/by-area//', ElectricalCircuitEquipmentByAreaList.as_view()), - path('electrical-circuits//', ElectricalCircuitEquipmentDetail.as_view()), - path('electrical-lines/', ElectricalLineEquipmentList.as_view()), - path('electrical-lines/by-area//', ElectricalLineEquipmentByAreaList.as_view()), - path('electrical-lines//', ElectricalLineEquipmentDetail.as_view()), - path('electrical-loads/', ElectricalLoadEquipmentList.as_view()), - path('electrical-loads/by-area//', ElectricalLoadEquipmentByAreaList.as_view()), - path('electrical-loads//', ElectricalLoadEquipmentDetail.as_view()), - path('iluminations/', IluminationEquipmentList.as_view()), - path('iluminations/by-area//', IluminationEquipmentByAreaList.as_view()), - path('iluminations//', IluminationEquipmentDetail.as_view()) -] diff --git a/api/equipments/views.py b/api/equipments/views.py deleted file mode 100644 index 57858caf..00000000 --- a/api/equipments/views.py +++ /dev/null @@ -1,541 +0,0 @@ -from rest_framework import generics -from rest_framework import status -from rest_framework.permissions import IsAuthenticated -from rest_framework.response import Response - -from .permissions import * -from .serializers import * - - -def get_place_owner_or_create(user): - try: - return user.place_owner - except PlaceOwner.DoesNotExist: - return PlaceOwner.objects.create(user=user) - - -class PersonalEquipmentCategoryCreate(generics.CreateAPIView): - queryset = PersonalEquipmentCategory.objects.all() - serializer_class = PersonalEquipmentCategorySerializer - permission_classes = [IsAuthenticated, IsOwner] - - def create(self, request, *args, **kwargs): - user = request.user - place_owner = get_place_owner_or_create(user) - serializer = self.get_serializer(data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save(place_owner=place_owner) - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) - - -class PersonalEquipmentCategoryList(generics.ListAPIView): - queryset = PersonalEquipmentCategory.objects.all() - serializer_class = PersonalEquipmentCategorySerializer - permission_classes = [IsAuthenticated, IsOwner] - - def get_queryset(self): - system_id = self.kwargs['system_id'] - return PersonalEquipmentCategory.objects.filter(system_id=system_id) - - -class PersonalEquipmentCategoryDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = PersonalEquipmentCategory.objects.all() - serializer_class = PersonalEquipmentCategorySerializer - permission_classes = [IsAuthenticated] - - -class GenericEquipmentCategoryList(generics.ListAPIView): - queryset = GenericEquipmentCategory.objects.all() - serializer_class = GenericEquipmentCategorySerializer - permission_classes = [IsAuthenticated] - - def get_queryset(self): - system_id = self.kwargs['system_id'] - return GenericEquipmentCategory.objects.filter(system_id=system_id) - - -class GenericEquipmentCategoryDetail(generics.RetrieveAPIView): - queryset = GenericEquipmentCategory.objects.all() - serializer_class = GenericEquipmentCategorySerializer - permission_classes = [IsAuthenticated] - - -class EquipmentListCreateView(generics.ListCreateAPIView): - queryset = Equipment.objects.all() - serializer_class = EquipmentSerializer - permission_classes = [IsAuthenticated, IsOwner or IsEquipmentEditor] - - -class EquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = Equipment.objects.all() - serializer_class = EquipmentSerializer - permission_classes = [IsAuthenticated, IsOwner or IsEquipmentEditor] - - -class EquipmentPhotoList(generics.ListCreateAPIView): - queryset = EquipmentPhoto.objects.all() - serializer_class = EquipmentPhotoSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner or IsEquipmentEditorPhoto] - - def get_queryset(self): - user = self.request.user - queryset = super().get_queryset() - return queryset.filter(equipment__place_owner__user=user) - - -class EquipmentPhotoDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = EquipmentPhoto.objects.all() - serializer_class = EquipmentPhotoSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner or IsEquipmentEditorPhoto] - - -class EquipmentPhotoByEquipmentList(generics.ListAPIView): - serializer_class = EquipmentPhotoSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner] - - def get_queryset(self): - equipment_id = self.kwargs['equipment_id'] - user = self.request.user - return EquipmentPhoto.objects.filter(equipment_id=equipment_id, equipment__place_owner__user=user) - - -class RefrigerationEquipmentList(generics.ListCreateAPIView): - queryset = RefrigerationEquipment.objects.all() - serializer_class = RefrigerationEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner, IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return RefrigerationEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 9 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class RefrigerationEquipmentByAreaList(generics.ListAPIView): - serializer_class = RefrigerationEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = RefrigerationEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class RefrigerationEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = RefrigerationEquipment.objects.all() - serializer_class = RefrigerationEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class FireAlarmEquipmentList(generics.ListCreateAPIView): - queryset = FireAlarmEquipment.objects.all() - serializer_class = FireAlarmEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return FireAlarmEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 8 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class FireAlarmEquipmentByAreaList(generics.ListAPIView): - serializer_class = FireAlarmEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = FireAlarmEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class FireAlarmEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = FireAlarmEquipment.objects.all() - serializer_class = FireAlarmEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class AtmosphericDischargeEquipmentList(generics.ListCreateAPIView): - queryset = AtmosphericDischargeEquipment.objects.all() - serializer_class = AtmosphericDischargeEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return AtmosphericDischargeEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 7 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class AtmosphericDischargeEquipmentByAreaList(generics.ListAPIView): - serializer_class = AtmosphericDischargeEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner, IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = AtmosphericDischargeEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class AtmosphericDischargeEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = AtmosphericDischargeEquipment.objects.all() - serializer_class = AtmosphericDischargeEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class StructuredCablingEquipmentList(generics.ListCreateAPIView): - queryset = StructuredCablingEquipment.objects.all() - serializer_class = StructuredCablingEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return StructuredCablingEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 6 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class StructuredCablingEquipmentByAreaList(generics.ListAPIView): - serializer_class = StructuredCablingEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = StructuredCablingEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class StructuredCablingEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = StructuredCablingEquipment.objects.all() - serializer_class = StructuredCablingEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class DistributionBoardEquipmentList(generics.ListCreateAPIView): - queryset = DistributionBoardEquipment.objects.all() - serializer_class = DistributionBoardEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return DistributionBoardEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 5 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class DistributionBoardEquipmentByAreaList(generics.ListAPIView): - serializer_class = DistributionBoardEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = DistributionBoardEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class DistributionBoardEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = DistributionBoardEquipment.objects.all() - serializer_class = DistributionBoardEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class ElectricalCircuitEquipmentList(generics.ListCreateAPIView): - queryset = ElectricalCircuitEquipment.objects.all() - serializer_class = ElectricalCircuitEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return ElectricalCircuitEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 4 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class ElectricalCircuitEquipmentByAreaList(generics.ListAPIView): - serializer_class = ElectricalCircuitEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = ElectricalCircuitEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class ElectricalCircuitEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = ElectricalCircuitEquipment.objects.all() - serializer_class = ElectricalCircuitEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class ElectricalLineEquipmentList(generics.ListCreateAPIView): - queryset = ElectricalLineEquipment.objects.all() - serializer_class = ElectricalLineEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return ElectricalLineEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 3 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class ElectricalLineEquipmentByAreaList(generics.ListAPIView): - serializer_class = ElectricalLineEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = ElectricalLineEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class ElectricalLineEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = ElectricalLineEquipment.objects.all() - serializer_class = ElectricalLineEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class ElectricalLoadEquipmentList(generics.ListCreateAPIView): - queryset = ElectricalLoadEquipment.objects.all() - serializer_class = ElectricalLoadEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return ElectricalLoadEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 2 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class ElectricalLoadEquipmentByAreaList(generics.ListAPIView): - serializer_class = ElectricalLoadEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = ElectricalLoadEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class ElectricalLoadEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = ElectricalLoadEquipment.objects.all() - serializer_class = ElectricalLoadEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - -class IluminationEquipmentList(generics.ListCreateAPIView): - queryset = IluminationEquipment.objects.all() - serializer_class = IluminationEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - user = self.request.user - place_owner = get_place_owner_or_create(user) - return IluminationEquipment.objects.filter(area__place__place_owner=place_owner) - - def create(self, request, *args, **kwargs): - data = request.data.copy() - data["system"] = 1 - serializer = self.get_serializer(data=data) - serializer.is_valid(raise_exception=True) - serializer.save() - headers = self.get_success_headers(serializer.data) - return Response(serializer.data, status=status.HTTP_200_OK, headers=headers) - - -class IluminationEquipmentByAreaList(generics.ListAPIView): - serializer_class = IluminationEquipmentResponseSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] - - def get_queryset(self): - area_id = self.kwargs['area_id'] - queryset = IluminationEquipment.objects.filter(area_id=area_id) - - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True - - -class IluminationEquipmentDetail(generics.RetrieveUpdateDestroyAPIView): - queryset = IluminationEquipment.objects.all() - serializer_class = IluminationEquipmentSerializer - permission_classes = [IsAuthenticated, IsEquipmentOwner | IsSpecificEquipmentEditor] diff --git a/api/manage.py b/api/manage.py deleted file mode 100755 index 7398656e..00000000 --- a/api/manage.py +++ /dev/null @@ -1,22 +0,0 @@ -#!/usr/bin/env python -"""Django's command-line utility for administrative tasks.""" -import os -import sys - - -def main(): - """Run administrative tasks.""" - os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sigeie.settings') - try: - from django.core.management import execute_from_command_line - except ImportError as exc: - raise ImportError( - "Couldn't import Django. Are you sure it's installed and " - "available on your PYTHONPATH environment variable? Did you " - "forget to activate a virtual environment?" - ) from exc - execute_from_command_line(sys.argv) - - -if __name__ == '__main__': - main() diff --git a/api/places/__init__.py b/api/places/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/places/admin.py b/api/places/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/api/places/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/api/places/apps.py b/api/places/apps.py deleted file mode 100644 index b3d0c3d3..00000000 --- a/api/places/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class PlacesConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'places' diff --git a/api/places/migrations/0001_initial.py b/api/places/migrations/0001_initial.py deleted file mode 100644 index cf2a9fd5..00000000 --- a/api/places/migrations/0001_initial.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2024-03-27 13:42 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='PlacesModel', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='places')), - ], - ), - ] diff --git a/api/places/migrations/0002_places_delete_placesmodel.py b/api/places/migrations/0002_places_delete_placesmodel.py deleted file mode 100644 index b4c72ac7..00000000 --- a/api/places/migrations/0002_places_delete_placesmodel.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2 on 2024-03-27 14:20 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('places', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='Places', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='donos')), - ], - ), - migrations.DeleteModel( - name='PlacesModel', - ), - ] diff --git a/api/places/migrations/0003_place_delete_places.py b/api/places/migrations/0003_place_delete_places.py deleted file mode 100644 index 431a699d..00000000 --- a/api/places/migrations/0003_place_delete_places.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2 on 2024-03-27 14:37 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('places', '0002_places_delete_placesmodel'), - ] - - operations = [ - migrations.CreateModel( - name='Place', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='creator')), - ], - ), - migrations.DeleteModel( - name='Places', - ), - ] diff --git a/api/places/migrations/0004_room.py b/api/places/migrations/0004_room.py deleted file mode 100644 index 82acbc56..00000000 --- a/api/places/migrations/0004_room.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-03-27 18:38 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0003_place_delete_places'), - ] - - operations = [ - migrations.CreateModel( - name='Room', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('floor', models.IntegerField(default=0)), - ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='places.place')), - ], - ), - ] diff --git a/api/places/migrations/0005_alter_room_floor_alter_room_place.py b/api/places/migrations/0005_alter_room_floor_alter_room_place.py deleted file mode 100644 index 8d060b6a..00000000 --- a/api/places/migrations/0005_alter_room_floor_alter_room_place.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2024-03-27 22:26 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0004_room'), - ] - - operations = [ - migrations.AlterField( - model_name='room', - name='floor', - field=models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)]), - ), - migrations.AlterField( - model_name='room', - name='place', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='places.place'), - ), - ] diff --git a/api/places/migrations/0006_room_systems.py b/api/places/migrations/0006_room_systems.py deleted file mode 100644 index d915eccc..00000000 --- a/api/places/migrations/0006_room_systems.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-04-01 14:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0001_initial'), - ('places', '0005_alter_room_floor_alter_room_place'), - ] - - operations = [ - migrations.AddField( - model_name='room', - name='systems', - field=models.ManyToManyField(to='systems.system'), - ), - ] diff --git a/api/places/migrations/0007_remove_place_user_place_place_owner.py b/api/places/migrations/0007_remove_place_user_place_place_owner.py deleted file mode 100644 index a87f5d96..00000000 --- a/api/places/migrations/0007_remove_place_user_place_place_owner.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2 on 2024-04-10 18:53 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ('places', '0006_room_systems'), - ] - - operations = [ - migrations.RemoveField( - model_name='place', - name='user', - ), - migrations.AddField( - model_name='place', - name='place_owner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='users.placeowner'), - ), - ] diff --git a/api/places/migrations/0008_alter_place_place_owner.py b/api/places/migrations/0008_alter_place_place_owner.py deleted file mode 100644 index de40950f..00000000 --- a/api/places/migrations/0008_alter_place_place_owner.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-04-10 18:57 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ('places', '0007_remove_place_user_place_place_owner'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.DO_NOTHING, to='users.placeowner'), - ), - ] diff --git a/api/places/migrations/0009_alter_room_place.py b/api/places/migrations/0009_alter_room_place.py deleted file mode 100644 index 6558ffb1..00000000 --- a/api/places/migrations/0009_alter_room_place.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-04-10 18:59 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0008_alter_place_place_owner'), - ] - - operations = [ - migrations.AlterField( - model_name='room', - name='place', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='places.place'), - ), - ] diff --git a/api/places/migrations/0010_alter_place_place_owner_alter_room_place.py b/api/places/migrations/0010_alter_place_place_owner_alter_room_place.py deleted file mode 100644 index 761e92be..00000000 --- a/api/places/migrations/0010_alter_place_place_owner_alter_room_place.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2024-04-10 19:19 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0001_initial'), - ('places', '0009_alter_room_place'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.placeowner'), - ), - migrations.AlterField( - model_name='room', - name='place', - field=models.OneToOneField(on_delete=django.db.models.deletion.DO_NOTHING, related_name='rooms', to='places.place'), - ), - ] diff --git a/api/places/migrations/0011_alter_place_place_owner.py b/api/places/migrations/0011_alter_place_place_owner.py deleted file mode 100644 index 13bfae87..00000000 --- a/api/places/migrations/0011_alter_place_place_owner.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-04-11 19:38 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_alter_placeowner_user'), - ('places', '0010_alter_place_place_owner_alter_room_place'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.placeowner'), - ), - ] diff --git a/api/places/migrations/0012_alter_place_place_owner.py b/api/places/migrations/0012_alter_place_place_owner.py deleted file mode 100644 index ad6d9136..00000000 --- a/api/places/migrations/0012_alter_place_place_owner.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-04-11 19:43 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_alter_placeowner_user'), - ('places', '0011_alter_place_place_owner'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.placeowner', unique=True), - ), - ] diff --git a/api/places/migrations/0013_alter_place_place_owner.py b/api/places/migrations/0013_alter_place_place_owner.py deleted file mode 100644 index 357ff692..00000000 --- a/api/places/migrations/0013_alter_place_place_owner.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-04-11 19:46 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_alter_placeowner_user'), - ('places', '0012_alter_place_place_owner'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='users.placeowner'), - ), - ] diff --git a/api/places/migrations/0014_alter_room_place.py b/api/places/migrations/0014_alter_room_place.py deleted file mode 100644 index 3a37a425..00000000 --- a/api/places/migrations/0014_alter_room_place.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-04-12 14:13 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0013_alter_place_place_owner'), - ] - - operations = [ - migrations.AlterField( - model_name='room', - name='place', - field=models.ForeignKey(on_delete=django.db.models.deletion.DO_NOTHING, related_name='rooms', to='places.place'), - ), - ] diff --git a/api/places/migrations/0015_alter_room_place.py b/api/places/migrations/0015_alter_room_place.py deleted file mode 100644 index 91bbb25c..00000000 --- a/api/places/migrations/0015_alter_room_place.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-04-12 15:40 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0014_alter_room_place'), - ] - - operations = [ - migrations.AlterField( - model_name='room', - name='place', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='places.place'), - ), - ] diff --git a/api/places/migrations/0016_alter_place_place_owner.py b/api/places/migrations/0016_alter_place_place_owner.py deleted file mode 100644 index 69d70a4a..00000000 --- a/api/places/migrations/0016_alter_place_place_owner.py +++ /dev/null @@ -1,20 +0,0 @@ -# Generated by Django 4.2 on 2024-04-12 17:20 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0002_alter_placeowner_user'), - ('places', '0015_alter_room_place'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='users.placeowner'), - ), - ] diff --git a/api/places/migrations/0017_atmosfericdischargesystem.py b/api/places/migrations/0017_atmosfericdischargesystem.py deleted file mode 100644 index ec3b46c8..00000000 --- a/api/places/migrations/0017_atmosfericdischargesystem.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2 on 2024-04-17 17:48 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0001_initial'), - ('places', '0016_alter_place_place_owner'), - ] - - operations = [ - migrations.CreateModel( - name='AtmosfericDischargeSystem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharg_systems', to='places.place')), - ('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharg_systems', to='places.room')), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharg_systems', to='systems.system')), - ], - ), - ] diff --git a/api/places/migrations/0018_alter_atmosfericdischargesystem_place_and_more.py b/api/places/migrations/0018_alter_atmosfericdischargesystem_place_and_more.py deleted file mode 100644 index f1ed9298..00000000 --- a/api/places/migrations/0018_alter_atmosfericdischargesystem_place_and_more.py +++ /dev/null @@ -1,34 +0,0 @@ -# Generated by Django 4.2 on 2024-04-17 17:51 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0001_initial'), - ('places', '0017_atmosfericdischargesystem'), - ] - - operations = [ - migrations.AlterField( - model_name='atmosfericdischargesystem', - name='place', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharge_systems', to='places.place'), - ), - migrations.AlterField( - model_name='atmosfericdischargesystem', - name='room', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharge_systems', to='places.room'), - ), - migrations.AlterField( - model_name='atmosfericdischargesystem', - name='system', - field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharge_systems', to='systems.system'), - ), - migrations.AlterModelTable( - name='atmosfericdischargesystem', - table='atmosferic_discharge_system', - ), - ] diff --git a/api/places/migrations/0019_delete_atmosfericdischargesystem.py b/api/places/migrations/0019_delete_atmosfericdischargesystem.py deleted file mode 100644 index 9b467921..00000000 --- a/api/places/migrations/0019_delete_atmosfericdischargesystem.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2 on 2024-04-17 17:56 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0018_alter_atmosfericdischargesystem_place_and_more'), - ] - - operations = [ - migrations.DeleteModel( - name='AtmosfericDischargeSystem', - ), - ] diff --git a/api/places/migrations/0020_remove_room_place_remove_room_systems.py b/api/places/migrations/0020_remove_room_place_remove_room_systems.py deleted file mode 100644 index 7a2532fc..00000000 --- a/api/places/migrations/0020_remove_room_place_remove_room_systems.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-04-18 19:54 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0019_delete_atmosfericdischargesystem'), - ] - - operations = [ - migrations.RemoveField( - model_name='room', - name='place', - ), - migrations.RemoveField( - model_name='room', - name='systems', - ), - ] diff --git a/api/places/migrations/0021_room_place_room_systems.py b/api/places/migrations/0021_room_place_room_systems.py deleted file mode 100644 index 4659a37a..00000000 --- a/api/places/migrations/0021_room_place_room_systems.py +++ /dev/null @@ -1,25 +0,0 @@ -# Generated by Django 4.2 on 2024-04-19 16:08 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('places', '0020_remove_room_place_remove_room_systems'), - ] - - operations = [ - migrations.AddField( - model_name='room', - name='place', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='rooms', to='places.place'), - ), - migrations.AddField( - model_name='room', - name='systems', - field=models.ManyToManyField(to='systems.system'), - ), - ] diff --git a/api/places/migrations/0022_area_delete_room.py b/api/places/migrations/0022_area_delete_room.py deleted file mode 100644 index f55fe63a..00000000 --- a/api/places/migrations/0022_area_delete_room.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 19:22 - -import django.core.validators -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0008_delete_atmosphericdischargesystem'), - ('equipments', '0005_remove_atmosphericdischargeequipment_room'), - ('places', '0021_room_place_room_systems'), - ] - - operations = [ - migrations.CreateModel( - name='Area', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ('floor', models.IntegerField(default=0, validators=[django.core.validators.MinValueValidator(0)])), - ('place', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='areas', to='places.place')), - ('systems', models.ManyToManyField(to='systems.system')), - ], - ), - migrations.DeleteModel( - name='Room', - ), - ] diff --git a/api/places/migrations/0023_alter_area_place.py b/api/places/migrations/0023_alter_area_place.py deleted file mode 100644 index 3f3e1056..00000000 --- a/api/places/migrations/0023_alter_area_place.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-04-24 20:50 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0022_area_delete_room'), - ] - - operations = [ - migrations.AlterField( - model_name='area', - name='place', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='places.place'), - ), - ] diff --git a/api/places/migrations/0024_place_lat_place_lon.py b/api/places/migrations/0024_place_lat_place_lon.py deleted file mode 100644 index 409a2182..00000000 --- a/api/places/migrations/0024_place_lat_place_lon.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-04-25 15:13 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0023_alter_area_place'), - ] - - operations = [ - migrations.AddField( - model_name='place', - name='lat', - field=models.FloatField(null=True), - ), - migrations.AddField( - model_name='place', - name='lon', - field=models.FloatField(null=True), - ), - ] diff --git a/api/places/migrations/0025_remove_area_systems.py b/api/places/migrations/0025_remove_area_systems.py deleted file mode 100644 index 574f6279..00000000 --- a/api/places/migrations/0025_remove_area_systems.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 13:17 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0024_place_lat_place_lon'), - ] - - operations = [ - migrations.RemoveField( - model_name='area', - name='systems', - ), - ] diff --git a/api/places/migrations/0026_alter_area_place.py b/api/places/migrations/0026_alter_area_place.py deleted file mode 100644 index 4b7a7943..00000000 --- a/api/places/migrations/0026_alter_area_place.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-05-03 13:55 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0025_remove_area_systems'), - ] - - operations = [ - migrations.AlterField( - model_name='area', - name='place', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='areas', to='places.place'), - ), - ] diff --git a/api/places/migrations/0027_alter_area_floor.py b/api/places/migrations/0027_alter_area_floor.py deleted file mode 100644 index 678177b2..00000000 --- a/api/places/migrations/0027_alter_area_floor.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-05-07 13:01 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0026_alter_area_place'), - ] - - operations = [ - migrations.AlterField( - model_name='area', - name='floor', - field=models.IntegerField(default=0), - ), - ] diff --git a/api/places/migrations/0028_place_photo.py b/api/places/migrations/0028_place_photo.py deleted file mode 100644 index 52a0e5ac..00000000 --- a/api/places/migrations/0028_place_photo.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-05-23 14:16 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0027_alter_area_floor'), - ] - - operations = [ - migrations.AddField( - model_name='place', - name='photo', - field=models.ImageField(null=True, upload_to='place_photos/'), - ), - ] diff --git a/api/places/migrations/0029_place_editors.py b/api/places/migrations/0029_place_editors.py deleted file mode 100644 index 803f27ee..00000000 --- a/api/places/migrations/0029_place_editors.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-06-12 13:26 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0005_placeeditor'), - ('places', '0028_place_photo'), - ] - - operations = [ - migrations.AddField( - model_name='place', - name='editors', - field=models.ManyToManyField(related_name='places', to='users.placeeditor'), - ), - ] diff --git a/api/places/migrations/0030_place_access_code.py b/api/places/migrations/0030_place_access_code.py deleted file mode 100644 index ed49739a..00000000 --- a/api/places/migrations/0030_place_access_code.py +++ /dev/null @@ -1,18 +0,0 @@ -# Generated by Django 4.2 on 2024-06-12 14:15 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0029_place_editors'), - ] - - operations = [ - migrations.AddField( - model_name='place', - name='access_code', - field=models.CharField(blank=True, max_length=36, null=True, unique=True), - ), - ] diff --git a/api/places/migrations/0031_remove_place_access_code.py b/api/places/migrations/0031_remove_place_access_code.py deleted file mode 100644 index 0325efb7..00000000 --- a/api/places/migrations/0031_remove_place_access_code.py +++ /dev/null @@ -1,17 +0,0 @@ -# Generated by Django 4.2 on 2024-06-12 14:32 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0030_place_access_code'), - ] - - operations = [ - migrations.RemoveField( - model_name='place', - name='access_code', - ), - ] diff --git a/api/places/migrations/0032_alter_place_place_owner.py b/api/places/migrations/0032_alter_place_place_owner.py deleted file mode 100644 index a2109717..00000000 --- a/api/places/migrations/0032_alter_place_place_owner.py +++ /dev/null @@ -1,21 +0,0 @@ - -# Generated by Django 4.2 on 2024-07-09 18:42 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('users', '0006_alter_placeowner_user'), - ('places', '0031_remove_place_access_code'), - ] - - operations = [ - migrations.AlterField( - model_name='place', - name='place_owner', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='places', to='users.placeowner'), - ), - ] diff --git a/api/places/migrations/__init__.py b/api/places/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/places/models.py b/api/places/models.py deleted file mode 100644 index 57b3d024..00000000 --- a/api/places/models.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.db import models - -from users.models import PlaceOwner, PlaceEditor - - -class Place(models.Model): - name = models.CharField(max_length=50) - place_owner = models.ForeignKey(PlaceOwner, on_delete=models.CASCADE, null=True, related_name="places") - lon = models.FloatField(null=True) - lat = models.FloatField(null=True) - photo = models.ImageField(null=True, upload_to='place_photos/') - editors = models.ManyToManyField(PlaceEditor, related_name='places') - - def __str__(self): - return self.name - - -class Area(models.Model): - name = models.CharField(max_length=50) - floor = models.IntegerField(default=0) - place = models.ForeignKey(Place, on_delete=models.CASCADE, null=True, related_name='areas') - - def __str__(self): - return self.name diff --git a/api/places/permissions.py b/api/places/permissions.py deleted file mode 100644 index 13818834..00000000 --- a/api/places/permissions.py +++ /dev/null @@ -1,12 +0,0 @@ -from rest_framework import permissions -from .models import Area - - -class IsPlaceOwner(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - return obj.place_owner.user == request.user - - -class IsPlaceEditor(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - return obj.editors.filter(user=request.user).exists() diff --git a/api/places/serializers.py b/api/places/serializers.py deleted file mode 100644 index 07b7fc18..00000000 --- a/api/places/serializers.py +++ /dev/null @@ -1,23 +0,0 @@ -from rest_framework import serializers - -from .models import Place, Area - - -class PlaceSerializer(serializers.ModelSerializer): - class Meta: - model = Place - fields = ['id', 'name', 'place_owner', 'lon', 'lat'] - extra_kwargs = { - 'name': {'required': True} - } - - -class AreaSerializer(serializers.ModelSerializer): - class Meta: - model = Area - fields = ['id', 'name', 'floor', 'place'] - extra_kwargs = { - 'name': {'required': True}, - 'floor': {'required': True}, - 'place': {'required': True} - } diff --git a/api/places/tests.py b/api/places/tests.py deleted file mode 100644 index 7ce503c2..00000000 --- a/api/places/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/api/places/urls.py b/api/places/urls.py deleted file mode 100644 index fd79ac9a..00000000 --- a/api/places/urls.py +++ /dev/null @@ -1,14 +0,0 @@ -from django.urls import path, include -from .views import * -from rest_framework.routers import SimpleRouter -from .views import GeneratePDFView - -router = SimpleRouter() -router.register(r'places',PlaceViewSet) -router.register(r'areas', AreaViewSet) -router.register(r'grant_access', GrantAccessViewSet, basename='grant_access') -router.register(r'refuse_access', RefuseAccessViewSet, basename = 'refuse_access') - -urlpatterns = [ - path('places//report/', GeneratePDFView.as_view(), name='place-report'), -] \ No newline at end of file diff --git a/api/places/views.py b/api/places/views.py deleted file mode 100644 index 621e87d4..00000000 --- a/api/places/views.py +++ /dev/null @@ -1,324 +0,0 @@ -from rest_framework.views import APIView -from django.db.models import Q -from django.contrib.auth.models import User -from users.models import PlaceOwner, PlaceEditor -from rest_framework.generics import get_object_or_404 -from rest_framework.permissions import IsAuthenticated -from places.permissions import * -from rest_framework import viewsets, status -from rest_framework.decorators import action -from rest_framework.response import Response -from rest_framework.exceptions import NotFound -from django.http import HttpResponse -from reportlab.lib.pagesizes import A4 -from reportlab.pdfgen import canvas -from .models import Place, Area -from .serializers import PlaceSerializer, AreaSerializer - - -def get_place_owner_or_create(user): - try: - return user.place_owner - except PlaceOwner.DoesNotExist: - return PlaceOwner.objects.create(user=user) - - -class PlaceViewSet(viewsets.ModelViewSet): - queryset = Place.objects.all() - serializer_class = PlaceSerializer - permission_classes = [IsAuthenticated, IsPlaceOwner | IsPlaceEditor] - - def create(self, request, *args, **kwargs): - user = request.user - place_owner = get_place_owner_or_create(user) - - place_data = request.data.copy() - place_data['place_owner'] = place_owner.id - place_serializer = self.get_serializer(data=place_data) - place_serializer.is_valid(raise_exception=True) - self.perform_create(place_serializer) - - headers = self.get_success_headers(place_serializer.data) - return Response(place_serializer.data, status=status.HTTP_201_CREATED, headers=headers) - - def list(self, request, *args, **kwargs): - user = request.user - place_owner = get_place_owner_or_create(user) - - places = Place.objects.filter( - Q(place_owner=place_owner) | - Q(editors__user=user) - ).distinct() - - place_serializer = PlaceSerializer(places, many=True) - return Response(place_serializer.data) - - def retrieve(self, request, pk=None): - place = get_object_or_404(Place, pk=pk) - user = request.user - place_owner = get_place_owner_or_create(user) - if place.place_owner.id == place_owner.id or place.editors.filter(user=user).exists(): - serializer = PlaceSerializer(place) - return Response(serializer.data) - else: - return Response({"message": "You are not the owner or an editor of this place"}, - status=status.HTTP_403_FORBIDDEN) - - def update(self, request, pk=None): - place = get_object_or_404(Place, pk=pk) - user = request.user - place_owner = get_place_owner_or_create(user) - if place.place_owner.id == place_owner.id or place.editors.filter(user=user).exists(): - serializer = PlaceSerializer(place, data=request.data) - serializer.is_valid(raise_exception=True) - serializer.save() - return Response(serializer.data) - else: - return Response({"message": "You are not the owner or an editor of this place"}, - status=status.HTTP_403_FORBIDDEN) - - def destroy(self, request, pk=None): - user = request.user - place_owner = get_place_owner_or_create(user) - - place = get_object_or_404(Place, pk=pk) - if place.place_owner.id == place_owner.id: - place.delete() - return Response({"message": "Place deleted successfully"}, status=status.HTTP_204_NO_CONTENT) - else: - return Response({"message": "You are not the owner of this place"}, status=status.HTTP_403_FORBIDDEN) - - @action(detail=True, methods=['get'], permission_classes=[IsAuthenticated, IsPlaceOwner | IsPlaceEditor]) - def areas(self, request, pk=None): - place = self.get_object() - serializer = AreaSerializer(place.areas.all(), many=True) - return Response(serializer.data) - - @action(detail=True, methods=['get'], url_path='areas/(?P\d+)', - permission_classes=[IsAuthenticated]) - def area(self, request, pk=None, area_pk=None): - place = self.get_object() - area = get_object_or_404(place.areas.all(), pk=area_pk) - if(request.user.place_owner == area.place.place_owner or area.place.editors.filter(user=request.user).exists()): - serializer = AreaSerializer(area) - return Response(serializer.data) - return Response({"Error" : "You're not the owner or editor of this Area"}) - - -class AreaViewSet(viewsets.ModelViewSet): - queryset = Area.objects.all() - serializer_class = AreaSerializer - permission_classes = [IsAuthenticated] - - def create(self, request, *args, **kwargs): - user = request.user - place_owner = get_place_owner_or_create(user) - place_id = request.data.get('place') - place = get_object_or_404(Place, id=place_id) - - if place.place_owner.id == place_owner.id or place.editors.filter(user=user).exists(): - area_serializer = AreaSerializer(data=request.data) - area_serializer.is_valid(raise_exception=True) - area_serializer.save() - return Response(area_serializer.data, status=status.HTTP_201_CREATED) - else: - return Response({"message": "You are not the owner or an editor of this place"}, - status=status.HTTP_403_FORBIDDEN) - - def list(self, request, *args, **kwargs): - user = request.user - place_owner = get_place_owner_or_create(user) - place_id = request.query_params.get('place') - - if not place_id: - raise NotFound("Place ID must be provided.") - - place = get_object_or_404(Place, id=place_id) - - if place.place_owner.id == place_owner.id or place.editors.filter(user=user).exists(): - areas = Area.objects.filter(place=place) - area_serializer = AreaSerializer(areas, many=True) - return Response(area_serializer.data) - else: - return Response({"message": "You are not the owner or an editor of this place"}, - status=status.HTTP_403_FORBIDDEN) - - def retrieve(self, request, pk=None): - user = request.user - place_owner = get_place_owner_or_create(user) - - area = get_object_or_404(Area, pk=pk) - - if area.place.place_owner.id == place_owner.id or area.place.editors.filter(user=user).exists(): - serializer = AreaSerializer(area) - return Response(serializer.data) - else: - return Response({"message": "You are not the owner or an editor of this area"}, - status=status.HTTP_403_FORBIDDEN) - - def destroy(self, request, pk=None): - user = request.user - place_owner = get_place_owner_or_create(user) - area = get_object_or_404(Area, pk=pk) - - if area.place.place_owner.id == place_owner.id: - area.delete() - return Response({"message": "Area deleted successfully"}, status=status.HTTP_204_NO_CONTENT) - else: - return Response({"message": "You are not the owner of this area"}, status=status.HTTP_403_FORBIDDEN) - - -class RefuseAccessViewSet(viewsets.ViewSet): - permission_classes = [IsAuthenticated, IsPlaceOwner] - - @action(detail=True, methods=['post']) - def refuse_access(self, request, pk=None): - place = get_object_or_404(Place, pk=pk) - place_owner = place.place_owner - - if request.user != place_owner.user: - return Response({"message": "You are not the owner of this place"}, status=status.HTTP_403_FORBIDDEN) - - username = request.data.get('username') - - if not username: - return Response({'error': 'Username is required'}, status=status.HTTP_400_BAD_REQUEST) - - user = get_object_or_404(User, username=username) - - place_editor = PlaceEditor.objects.filter(user=user).first() - - if not place_editor: - return Response({'error': 'This user is not an editor of the place'}, status=status.HTTP_400_BAD_REQUEST) - - place.editors.remove(place_editor) - - return Response({'message': 'Access revoked successfully'}, status=status.HTTP_200_OK) - -class GrantAccessViewSet(viewsets.ViewSet): - permission_classes = [IsAuthenticated, IsPlaceOwner] - - @action(detail=True, methods=['post']) - def grant_access(self, request, pk=None): - place = get_object_or_404(Place, pk=pk) - place_owner = place.place_owner - - if request.user != place_owner.user: - return Response({"message": "You are not the owner of this place"}, status=status.HTTP_403_FORBIDDEN) - - username = request.data.get('username') - - if not username: - return Response({'error': 'Username is required'}, status=status.HTTP_400_BAD_REQUEST) - - user = get_object_or_404(User, username=username) - - place_editor, created = PlaceEditor.objects.get_or_create(user=user) - - place.editors.add(place_editor) - - return Response({'message': 'Access granted successfully'}, status=status.HTTP_200_OK) - - -class Altura: - def __init__(self): - self.alt = 840 - - def get_alt(self, p, margin=30): - self.alt -= 40 - if self.alt < margin: - p.showPage() - self.alt = 800 - return self.alt - return self.alt - - -def genericOrPersonal(system): - if system.equipment.generic_equipment_category is not None: - return system.equipment.generic_equipment_category - else: - return system.equipment.personal_equipment_category - - -class GeneratePDFView(APIView): - permission_classes = [IsAuthenticated, IsPlaceOwner | IsPlaceEditor] - - def get(self, request, pk=None): - place = get_object_or_404(Place, pk=pk) - - self.check_object_permissions(request, place) - - response = HttpResponse(content_type='application/pdf') - response['Content-Disposition'] = f'attachment; filename="place_{place.id}_report.pdf"' - - p = canvas.Canvas(response, pagesize=A4) - alt = Altura() - - p.setFont('Helvetica-Bold', 16) - - p.drawString(205, alt.get_alt(p), f"Relatório do Local: {place.name}") - - p.setFont('Helvetica-Bold', 14) - p.drawString(100, alt.get_alt(p), "Áreas:") - - for area in place.areas.all(): - p.setFont('Helvetica-Bold', 14) - p.drawString(120, alt.get_alt(p), f"Relatório da Área: {area.name}") - - for system in area.fire_alarm_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.atmospheric_discharge_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.structured_cabling_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.distribution_board_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.electrical_circuit_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.electrical_line_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.electrical_load_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.ilumination_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - for system in area.refrigeration_equipment.all(): - if (system == None): - break - p.setFont('Helvetica', 12) - p.drawString(140, alt.get_alt(p), f"Sistema: {system.system} - Tipo: {genericOrPersonal(system)}") - - p.showPage() - p.save() - return response diff --git a/api/requirements.txt b/api/requirements.txt deleted file mode 100644 index 44f1d13f..00000000 --- a/api/requirements.txt +++ /dev/null @@ -1,15 +0,0 @@ -asgiref==3.7.2 -async-timeout==4.0.3 -chardet==5.2.0 -Django==4.2 -django-cors-headers==4.3.1 -django-redis==5.4.0 -django-redis-session-store==0.1.1 -django-redis-sessions==0.6.2 -djangorestframework==3.14.0 -mysqlclient==2.2.4 -pillow==10.3.0 -pytz==2024.1 -redis==5.0.3 -reportlab==4.2.0 -sqlparse==0.4.4 diff --git a/api/sigeie/__init__.py b/api/sigeie/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/sigeie/asgi.py b/api/sigeie/asgi.py deleted file mode 100644 index d0b8cb22..00000000 --- a/api/sigeie/asgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -ASGI config for sigeie project. - -It exposes the ASGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/howto/deployment/asgi/ -""" - -import os - -from django.core.asgi import get_asgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sigeie.settings') - -application = get_asgi_application() diff --git a/api/sigeie/base_views.py b/api/sigeie/base_views.py deleted file mode 100644 index f3981182..00000000 --- a/api/sigeie/base_views.py +++ /dev/null @@ -1,27 +0,0 @@ -from rest_framework import generics - - -class PermissionFilteredListView(generics.ListAPIView): - """ - Classe base para ListAPIView que filtra o queryset baseado nas permissões do usuário. - """ - - def get_queryset(self): - queryset = super().get_queryset() - - user = self.request.user - permitted_objects = [] - for obj in queryset: - if self.check_object_permissions(self.request, obj): - permitted_objects.append(obj.id) - - return queryset.filter(id__in=permitted_objects) - - def check_object_permissions(self, request, obj): - """ - Verifica as permissões de objeto para cada item no queryset. - """ - for permission in self.get_permissions(): - if not permission.has_object_permission(request, self, obj): - return False - return True diff --git a/api/sigeie/middleware.py b/api/sigeie/middleware.py deleted file mode 100644 index 51f9ccec..00000000 --- a/api/sigeie/middleware.py +++ /dev/null @@ -1,8 +0,0 @@ - -class DisableCSRFMiddleware(object): - def __init__(self, get_response): - self.get_response = get_response - def __call__(self, request): - setattr(request, '_dont_enforce_csrf_checks', True) - response = self.get_response(request) - return response \ No newline at end of file diff --git a/api/sigeie/settings.py b/api/sigeie/settings.py deleted file mode 100644 index fa63a638..00000000 --- a/api/sigeie/settings.py +++ /dev/null @@ -1,139 +0,0 @@ -from pathlib import Path - -BASE_DIR = Path(__file__).resolve().parent.parent - -SECRET_KEY = 'django-insecure-vy00e(4im2%orzf_b+dv6k$6)%c$8zfjgb6vb^hd^ugxfqpk1)' - -DEBUG = True - -ALLOWED_HOSTS = ['127.0.0.1', '10.0.2.2'] - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rest_framework', - 'corsheaders', - 'users', - 'places', - 'systems', - 'equipments' -] - -MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - "corsheaders.middleware.CorsMiddleware", - 'django.middleware.common.CommonMiddleware', - 'sigeie.middleware.DisableCSRFMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'sigeie.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [BASE_DIR / 'users.templates'], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'sigeie.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/4.2/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'HOST': 'db', - 'PORT': '3306', - 'USER': 'root', - 'PASSWORD': 'root', - 'NAME': 'sigeie_db', - 'OPTIONS': { - 'init_command': "SET sql_mode ='STRICT_TRANS_TABLES'" - } - } -} - -CACHES = { - 'default': { - 'BACKEND': 'django_redis.cache.RedisCache', - 'LOCATION': 'redis://localhost:6379', - 'OPTIONS': { - 'CLIENT_CLASS': 'django_redis.client.DefaultClient', - } - } -} - -SESSION_ENGINE = 'django.contrib.sessions.backends.cache' - -SESSION_CACHE_ALIAS = 'default' - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_TZ = True - -STATIC_URL = 'static/' -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' - -REST_FRAMEWORK = { - 'DEFAULT_AUTHENTICATION_CLASSES': [ - 'rest_framework.authentication.SessionAuthentication', - ], - 'DEFAULT_PERMISSION_CLASSES': { - 'rest_framework.permissions.IsAuthenticated', - } -} - -CORS_ALLOW_CREDENTIALS = True -CORS_ALLOW_ALL_ORIGINS = True -CORS_ALLOW_HEADERS = ( - "accept", - "authorization", - "content-type", - "user-agent", - "x-csrftoken", - "x-requested-with", -) - -EMAIL_HOST = 'sandbox.smtp.mailtrap.io' -EMAIL_HOST_USER = '1ae45caf98a722' -EMAIL_HOST_PASSWORD = 'c6aa9de24a4720' -EMAIL_PORT = '465' - diff --git a/api/sigeie/urls.py b/api/sigeie/urls.py deleted file mode 100644 index 877cd7b7..00000000 --- a/api/sigeie/urls.py +++ /dev/null @@ -1,29 +0,0 @@ -""" -URL configuration for sigeie project. - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/4.2/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: path('', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.urls import include, path - 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) -""" -from django.contrib import admin -from django.urls import path, include -from places.urls import router - -urlpatterns = [ - path('admin/', admin.site.urls), - path('api/', include('users.urls')), - path('api/', include(router.urls)), - path('api/', include('systems.urls')), - path('auth/', include('rest_framework.urls')), - path('api/', include('equipments.urls')), - path('api/', include('places.urls')) -] diff --git a/api/sigeie/wsgi.py b/api/sigeie/wsgi.py deleted file mode 100644 index c5d484d4..00000000 --- a/api/sigeie/wsgi.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -WSGI config for sigeie project. - -It exposes the WSGI callable as a module-level variable named ``application``. - -For more information on this file, see -https://docs.djangoproject.com/en/4.2/howto/deployment/wsgi/ -""" - -import os - -from django.core.wsgi import get_wsgi_application - -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sigeie.settings') - -application = get_wsgi_application() diff --git a/api/systems/__init__.py b/api/systems/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/systems/admin.py b/api/systems/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/api/systems/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/api/systems/apps.py b/api/systems/apps.py deleted file mode 100644 index 22403977..00000000 --- a/api/systems/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class SystemsConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'systems' diff --git a/api/systems/migrations/0001_initial.py b/api/systems/migrations/0001_initial.py deleted file mode 100644 index 9f4befc5..00000000 --- a/api/systems/migrations/0001_initial.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-04-01 14:49 - -from django.db import migrations, models - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ] - - operations = [ - migrations.CreateModel( - name='System', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('name', models.CharField(max_length=50)), - ], - ), - ] diff --git a/api/systems/migrations/0002_atmosfericdischargesystem.py b/api/systems/migrations/0002_atmosfericdischargesystem.py deleted file mode 100644 index 4f81e285..00000000 --- a/api/systems/migrations/0002_atmosfericdischargesystem.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2 on 2024-04-17 17:56 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0019_delete_atmosfericdischargesystem'), - ('systems', '0001_initial'), - ] - - operations = [ - migrations.CreateModel( - name='AtmosfericDischargeSystem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharge_systems', to='places.place')), - ('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharge_systems', to='places.room')), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmosferic_discharge_systems', to='systems.system')), - ], - options={ - 'db_table': 'atmosferic_discharge_system', - }, - ), - ] diff --git a/api/systems/migrations/0003_atmosphericdischargesystem_and_more.py b/api/systems/migrations/0003_atmosphericdischargesystem_and_more.py deleted file mode 100644 index b7cad046..00000000 --- a/api/systems/migrations/0003_atmosphericdischargesystem_and_more.py +++ /dev/null @@ -1,30 +0,0 @@ -# Generated by Django 4.2 on 2024-04-17 18:00 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0019_delete_atmosfericdischargesystem'), - ('systems', '0002_atmosfericdischargesystem'), - ] - - operations = [ - migrations.CreateModel( - name='AtmosphericDischargeSystem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='places.place')), - ('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='places.room')), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='systems.system')), - ], - options={ - 'db_table': 'atmospheric_discharge_systems', - }, - ), - migrations.DeleteModel( - name='AtmosfericDischargeSystem', - ), - ] diff --git a/api/systems/migrations/0004_equipmentphoto_equipmenttype_equipment.py b/api/systems/migrations/0004_equipmentphoto_equipmenttype_equipment.py deleted file mode 100644 index 6e60b0fa..00000000 --- a/api/systems/migrations/0004_equipmentphoto_equipmenttype_equipment.py +++ /dev/null @@ -1,38 +0,0 @@ -# Generated by Django 4.2 on 2024-04-17 18:28 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0003_atmosphericdischargesystem_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='EquipmentPhoto', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('photo', models.ImageField(null=True, upload_to='equipment_photos/')), - ('description', models.CharField(max_length=50)), - ], - ), - migrations.CreateModel( - name='EquipmentType', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('type', models.CharField(max_length=50)), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='systems.system')), - ], - ), - migrations.CreateModel( - name='Equipment', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('equipmentPhoto', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='systems.equipmentphoto')), - ('equipmentType', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='systems.equipmenttype')), - ], - ), - ] diff --git a/api/systems/migrations/0005_alter_equipment_equipmentphoto.py b/api/systems/migrations/0005_alter_equipment_equipmentphoto.py deleted file mode 100644 index b0d4bac5..00000000 --- a/api/systems/migrations/0005_alter_equipment_equipmentphoto.py +++ /dev/null @@ -1,19 +0,0 @@ -# Generated by Django 4.2 on 2024-04-18 12:50 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0004_equipmentphoto_equipmenttype_equipment'), - ] - - operations = [ - migrations.AlterField( - model_name='equipment', - name='equipmentPhoto', - field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='systems.equipmentphoto'), - ), - ] diff --git a/api/systems/migrations/0006_remove_equipment_equipmentphoto_and_more.py b/api/systems/migrations/0006_remove_equipment_equipmentphoto_and_more.py deleted file mode 100644 index 7ab2c6fb..00000000 --- a/api/systems/migrations/0006_remove_equipment_equipmentphoto_and_more.py +++ /dev/null @@ -1,37 +0,0 @@ -# Generated by Django 4.2 on 2024-04-18 17:23 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0005_alter_equipment_equipmentphoto'), - ] - - operations = [ - migrations.RemoveField( - model_name='equipment', - name='equipmentPhoto', - ), - migrations.RemoveField( - model_name='equipment', - name='equipmentType', - ), - migrations.RemoveField( - model_name='equipmenttype', - name='system', - ), - migrations.DeleteModel( - name='AtmosphericDischargeSystem', - ), - migrations.DeleteModel( - name='Equipment', - ), - migrations.DeleteModel( - name='EquipmentPhoto', - ), - migrations.DeleteModel( - name='EquipmentType', - ), - ] diff --git a/api/systems/migrations/0007_atmosphericdischargesystem.py b/api/systems/migrations/0007_atmosphericdischargesystem.py deleted file mode 100644 index fa37505a..00000000 --- a/api/systems/migrations/0007_atmosphericdischargesystem.py +++ /dev/null @@ -1,27 +0,0 @@ -# Generated by Django 4.2 on 2024-04-18 18:24 - -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - ('places', '0019_delete_atmosfericdischargesystem'), - ('systems', '0006_remove_equipment_equipmentphoto_and_more'), - ] - - operations = [ - migrations.CreateModel( - name='AtmosphericDischargeSystem', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='places.place')), - ('room', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='places.room')), - ('system', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='atmospheric_discharge_systems', to='systems.system')), - ], - options={ - 'db_table': 'atmospheric_discharge_systems', - }, - ), - ] diff --git a/api/systems/migrations/0008_delete_atmosphericdischargesystem.py b/api/systems/migrations/0008_delete_atmosphericdischargesystem.py deleted file mode 100644 index d3aed114..00000000 --- a/api/systems/migrations/0008_delete_atmosphericdischargesystem.py +++ /dev/null @@ -1,16 +0,0 @@ -# Generated by Django 4.2 on 2024-04-19 16:08 - -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('systems', '0007_atmosphericdischargesystem'), - ] - - operations = [ - migrations.DeleteModel( - name='AtmosphericDischargeSystem', - ), - ] diff --git a/api/systems/migrations/__init__.py b/api/systems/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/systems/models.py b/api/systems/models.py deleted file mode 100644 index d35f60da..00000000 --- a/api/systems/models.py +++ /dev/null @@ -1,8 +0,0 @@ -from places.models import models - - -class System(models.Model): - name = models.CharField(max_length=50) - - def __str__(self): - return self.name diff --git a/api/systems/serializers.py b/api/systems/serializers.py deleted file mode 100644 index f99c5b40..00000000 --- a/api/systems/serializers.py +++ /dev/null @@ -1,8 +0,0 @@ -from rest_framework import serializers -from .models import System - - -class SystemSerializer(serializers.ModelSerializer): - class Meta: - model = System - fields = ['id', 'name'] diff --git a/api/systems/tests.py b/api/systems/tests.py deleted file mode 100644 index 7ce503c2..00000000 --- a/api/systems/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/api/systems/urls.py b/api/systems/urls.py deleted file mode 100644 index d186b7e5..00000000 --- a/api/systems/urls.py +++ /dev/null @@ -1,9 +0,0 @@ -from django.urls import path, include -from .views import SystemViewDetail, SystemViewList - -urlpatterns = [ - path('systems/', SystemViewList.as_view()), - path('systems//', SystemViewDetail.as_view()) - -] - diff --git a/api/systems/views.py b/api/systems/views.py deleted file mode 100644 index b676c274..00000000 --- a/api/systems/views.py +++ /dev/null @@ -1,15 +0,0 @@ -from rest_framework import generics -from .models import System -from .serializers import SystemSerializer - - -class SystemViewList(generics.ListAPIView): - queryset = System.objects.all() - serializer_class = SystemSerializer - permission_classes = [] - - -class SystemViewDetail(generics.RetrieveAPIView): - queryset = System.objects.all() - serializer_class = SystemSerializer - permission_classes = [] diff --git a/api/users/__init__.py b/api/users/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/users/admin.py b/api/users/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/api/users/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/api/users/apps.py b/api/users/apps.py deleted file mode 100644 index 72b14010..00000000 --- a/api/users/apps.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.apps import AppConfig - - -class UsersConfig(AppConfig): - default_auto_field = 'django.db.models.BigAutoField' - name = 'users' diff --git a/api/users/migrations/0001_initial.py b/api/users/migrations/0001_initial.py deleted file mode 100644 index 650ab025..00000000 --- a/api/users/migrations/0001_initial.py +++ /dev/null @@ -1,24 +0,0 @@ -# Generated by Django 4.2 on 2024-04-10 18:53 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ] - - operations = [ - migrations.CreateModel( - name='PlaceOwner', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL, verbose_name='user')), - ], - ), - ] diff --git a/api/users/migrations/0002_alter_placeowner_user.py b/api/users/migrations/0002_alter_placeowner_user.py deleted file mode 100644 index 0131ed9d..00000000 --- a/api/users/migrations/0002_alter_placeowner_user.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-04-11 19:34 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('users', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='placeowner', - name='user', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='user'), - ), - ] diff --git a/api/users/migrations/0003_alter_placeowner_user.py b/api/users/migrations/0003_alter_placeowner_user.py deleted file mode 100644 index 6a60a746..00000000 --- a/api/users/migrations/0003_alter_placeowner_user.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-04-12 17:23 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('users', '0002_alter_placeowner_user'), - ] - - operations = [ - migrations.AlterField( - model_name='placeowner', - name='user', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='placeowner', to=settings.AUTH_USER_MODEL), - ), - ] diff --git a/api/users/migrations/0004_alter_placeowner_user.py b/api/users/migrations/0004_alter_placeowner_user.py deleted file mode 100644 index 4c48c10c..00000000 --- a/api/users/migrations/0004_alter_placeowner_user.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-04-16 18:14 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('users', '0003_alter_placeowner_user'), - ] - - operations = [ - migrations.AlterField( - model_name='placeowner', - name='user', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='placeowner', to=settings.AUTH_USER_MODEL, verbose_name='user'), - ), - ] diff --git a/api/users/migrations/0005_placeeditor.py b/api/users/migrations/0005_placeeditor.py deleted file mode 100644 index 5adb732c..00000000 --- a/api/users/migrations/0005_placeeditor.py +++ /dev/null @@ -1,23 +0,0 @@ -# Generated by Django 4.2 on 2024-06-12 13:26 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('users', '0004_alter_placeowner_user'), - ] - - operations = [ - migrations.CreateModel( - name='PlaceEditor', - fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='place_editor', to=settings.AUTH_USER_MODEL, verbose_name='user')), - ], - ), - ] diff --git a/api/users/migrations/0006_alter_placeowner_user.py b/api/users/migrations/0006_alter_placeowner_user.py deleted file mode 100644 index 437f24cc..00000000 --- a/api/users/migrations/0006_alter_placeowner_user.py +++ /dev/null @@ -1,21 +0,0 @@ -# Generated by Django 4.2 on 2024-06-14 13:54 - -from django.conf import settings -from django.db import migrations, models -import django.db.models.deletion - - -class Migration(migrations.Migration): - - dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), - ('users', '0005_placeeditor'), - ] - - operations = [ - migrations.AlterField( - model_name='placeowner', - name='user', - field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='place_owner', to=settings.AUTH_USER_MODEL, verbose_name='user'), - ), - ] diff --git a/api/users/migrations/__init__.py b/api/users/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/api/users/models.py b/api/users/models.py deleted file mode 100644 index 0c582299..00000000 --- a/api/users/models.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - - -class PlaceOwner(models.Model): - user = models.OneToOneField(User, verbose_name="user", on_delete=models.CASCADE, related_name='place_owner') - - def __str__(self): - return self.user.first_name - - -class PlaceEditor(models.Model): - user = models.OneToOneField(User, verbose_name="user", on_delete=models.CASCADE, related_name='place_editor') - - def __str__(self): - return self.user.first_name diff --git a/api/users/permissions.py b/api/users/permissions.py deleted file mode 100644 index 9335de03..00000000 --- a/api/users/permissions.py +++ /dev/null @@ -1,13 +0,0 @@ -from rest_framework import permissions - - -class IsOwner(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - return request.user == obj - - -class IsOwnerOrReadOnly(permissions.BasePermission): - def has_object_permission(self, request, view, obj): - if request.method in permissions.SAFE_METHODS: - return True - return obj.owner == request.user diff --git a/api/users/serializers.py b/api/users/serializers.py deleted file mode 100644 index c2875908..00000000 --- a/api/users/serializers.py +++ /dev/null @@ -1,71 +0,0 @@ -# serializers.py -from rest_framework import serializers, response -from django.contrib.auth.models import User -from .models import PlaceOwner, PlaceEditor -import re - - -def validate_username(value): - if not re.match("^[a-zA-Z0-9]+$", value): - raise serializers.ValidationError("The username must contain only letters and numbers.") - return value - - -class UserSerializer(serializers.ModelSerializer): - username = serializers.CharField(min_length=6, max_length=23, required=True) - password = serializers.CharField(min_length=6, max_length=200, write_only=True) - first_name = serializers.CharField(required=True) - email = serializers.EmailField(required=True) - - class Meta: - model = User - fields = ['id', 'password', 'username', 'first_name', 'email', 'is_active', 'date_joined', 'groups'] - extra_kwargs = { - 'password': {'write_only': True}, - 'first_name': {'required': True}, - 'email': {'required': True}, - 'is_active': {'read_only': True}, - 'date_joined': {'read_only': True}, - 'groups': {'read_only': True} - } - - def create(self, validated_data): - user = User.objects.create_user( - username=validated_data['username'], - password=validated_data['password'], - first_name=validated_data['first_name'], - email=validated_data.get('email') - ) - return user - - -class UserLoginSerializer(serializers.Serializer): - username = serializers.CharField(min_length=6, max_length=23, required=True) - password = serializers.CharField(min_length=6, max_length=200, required=True) - - -class UsernameSerializer(serializers.Serializer): - username = serializers.CharField(min_length=6, max_length=23, required=True) - - -class UserUpdateSerializer(serializers.Serializer): - first_name = serializers.CharField(required=True) - email = serializers.EmailField(required=True) - - def update(self, instance, validated_data): - instance.first_name = validated_data.get('first_name', instance.first_name) - instance.email = validated_data.get('email', instance.email) - instance.save() - return instance - - -class PlaceOwnerSerializer(serializers.ModelSerializer): - class Meta: - model = PlaceOwner - fields = ['id'] - - -class PlaceEditorSerializer(serializers.ModelSerializer): - class Meta: - model = PlaceEditor - fields = ['id'] diff --git a/api/users/templates/password_reset_email.html b/api/users/templates/password_reset_email.html deleted file mode 100644 index ed81c32a..00000000 --- a/api/users/templates/password_reset_email.html +++ /dev/null @@ -1,12 +0,0 @@ -{% autoescape off %} -Olá {{ user.username }}, - -Você solicitou a redefinição de senha para sua conta. Insira o código abaixo para redefinir sua senha: - -{{ token }} - -Se você não solicitou a redefinição de senha, ignore este e-mail. - -Atenciosamente, -Equipe do seu site -{% endautoescape %} diff --git a/api/users/tests.py b/api/users/tests.py deleted file mode 100644 index 7ce503c2..00000000 --- a/api/users/tests.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/api/users/urls.py b/api/users/urls.py deleted file mode 100644 index d636ccc2..00000000 --- a/api/users/urls.py +++ /dev/null @@ -1,17 +0,0 @@ -# urls.py -from django.urls import path -from .views import GetCSRFToken, GetSessionCookie, CheckAuthenticatedView, UserCreateView, AuthenticatedUserView, UserDetailView, LoginView, LogoutView, Email, PasswordResetConfirmView -from django.urls import include - -urlpatterns = [ - path('csrfcookie/', GetCSRFToken.as_view(), name='csrf-cookie'), - path('sessioncookie/', GetSessionCookie.as_view(), name='session-cookie'), - path('checkauth/', CheckAuthenticatedView.as_view(), name='check-auth'), - path('users/', UserCreateView.as_view(), name='create-user'), - path('userauth/', AuthenticatedUserView.as_view(), name='authenticated-user'), - path('users//', UserDetailView.as_view(), name='user_detail'), - path('login/', LoginView.as_view(), name='login'), - path('logout/', LogoutView.as_view(), name='logout'), - path('recover/', Email.as_view()), - path('reset/', PasswordResetConfirmView.as_view()) -] diff --git a/api/users/views.py b/api/users/views.py deleted file mode 100644 index 456115c8..00000000 --- a/api/users/views.py +++ /dev/null @@ -1,138 +0,0 @@ -# views.py -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth import get_user_model -from django.contrib.auth.models import User -from django.contrib.auth.tokens import default_token_generator -from django.core.mail import EmailMessage -from django.http import HttpResponse, JsonResponse -from django.template.loader import render_to_string -from django.utils.decorators import method_decorator -from django.views.decorators.csrf import ensure_csrf_cookie -from rest_framework import generics -from rest_framework import status -from rest_framework.permissions import AllowAny, IsAuthenticated -from rest_framework.response import Response -from rest_framework.views import APIView - -from .permissions import IsOwner -from .serializers import UserSerializer, UserLoginSerializer, UserUpdateSerializer - - -@method_decorator(ensure_csrf_cookie, name='dispatch') -class GetCSRFToken(APIView): - permission_classes = [AllowAny] - - def get(self, request): - return Response({'success': 'CSRF Cookie Set'}) - - -class GetSessionCookie(APIView): - permission_classes = [IsAuthenticated] - - def get(self, request): - sessionid = request.COOKIES.get('sessionid') - response = HttpResponse() - response.set_cookie('sessionid', sessionid) - return response - - -class CheckAuthenticatedView(APIView): - permission_classes = [AllowAny] - - def get(self, request): - if request.user.is_authenticated: - return Response({'isAuthenticated': True}) - else: - return Response({'isAuthenticated': False}) - - -class UserCreateView(generics.CreateAPIView): - queryset = User.objects.all() - serializer_class = UserSerializer - permission_classes = [AllowAny] - - -class UserDetailView(generics.RetrieveUpdateDestroyAPIView): - queryset = User.objects.all() - serializer_class = UserUpdateSerializer - permission_classes = [IsOwner, IsAuthenticated] - - -class AuthenticatedUserView(generics.RetrieveAPIView): - queryset = User.objects.all() - serializer_class = UserSerializer - permission_classes = [IsAuthenticated] - - def get_object(self): - return self.request.user - - -class LoginView(APIView): - permission_classes = [AllowAny] - - def post(self, request, format=None): - serializer = UserLoginSerializer(data=request.data) - if serializer.is_valid(): - username = serializer.validated_data["username"] - password = serializer.validated_data["password"] - user = authenticate(username=username, password=password) - if user is not None: - login(request, user) - return Response({'message': 'Login successful'}, status=status.HTTP_200_OK) - else: - return Response({'message': 'Invalid credentials'}, status=status.HTTP_401_UNAUTHORIZED) - return JsonResponse(serializer.errors) - - -class LogoutView(APIView): - permission_classes = [IsAuthenticated] - - def post(self, request, format=None): - logout(request) - return Response({'message': 'Logout successful'}, status=status.HTTP_200_OK) - - -class Email(APIView): - permission_classes = [] - - def post(self, request, *args, **kwargs): - email = request.data.get('email') - user = User.objects.filter(email=email).first() - if user is not None: - token = default_token_generator.make_token(user) - mail_subject = 'Redefinição de senha' - message = render_to_string('password_reset_email.html', { - 'user': user, - 'token': token, - }) - email = EmailMessage(mail_subject, message, to=[email]) - email.send() - return Response({'message': 'Email de redefinição de senha enviado'}, status=status.HTTP_200_OK) - else: - return Response({'message': 'Usuário não encontrado'}, status=status.HTTP_404_NOT_FOUND) - - -class PasswordResetConfirmView(APIView): - permission_classes = [] - - def post(self, request): - try: - email = request.data.get("email") - token = request.data.get("token") - - user = get_user_model().objects.get(email=email) - except (TypeError, ValueError, OverflowError, get_user_model().DoesNotExist): - user = None - - if user is not None and default_token_generator.check_token(user, token): - new_password = request.data.get('new_password') - confirm_password = request.data.get('confirm_password') - if new_password == confirm_password: - user.set_password(new_password) - user.save() - return Response({'message': 'Senha redefinida com sucesso'}, status=status.HTTP_200_OK) - else: - return Response({'message': 'As senhas não correspondem'}, status=status.HTTP_400_BAD_REQUEST) - else: - return Response({'message': 'O link de redefinição de senha é inválido'}, - status=status.HTTP_400_BAD_REQUEST) diff --git a/doc/img/release-roadmap.4cf783b31fbe.png b/doc/img/release-roadmap.4cf783b31fbe.png deleted file mode 100644 index d18faa44..00000000 Binary files a/doc/img/release-roadmap.4cf783b31fbe.png and /dev/null differ diff --git a/doc/img/sige-ie-img.png b/doc/img/sige-ie-img.png deleted file mode 100644 index e16bb804..00000000 Binary files a/doc/img/sige-ie-img.png and /dev/null differ diff --git a/doc/img/sige_ie_logo.jpeg b/doc/img/sige_ie_logo.jpeg deleted file mode 100644 index b5c183d6..00000000 Binary files a/doc/img/sige_ie_logo.jpeg and /dev/null differ diff --git a/docs/assets/1.png b/docs/assets/1.png new file mode 100644 index 00000000..d6d1d464 Binary files /dev/null and b/docs/assets/1.png differ diff --git a/frontend/sige_ie/assets/1000x1000Horizontal.png b/docs/assets/1000x1000Horizontal.png similarity index 100% rename from frontend/sige_ie/assets/1000x1000Horizontal.png rename to docs/assets/1000x1000Horizontal.png diff --git a/docs/assets/Electrician-black.gif b/docs/assets/Electrician-black.gif new file mode 100644 index 00000000..194fdc9b Binary files /dev/null and b/docs/assets/Electrician-black.gif differ diff --git a/docs/assets/Electrician.gif b/docs/assets/Electrician.gif new file mode 100644 index 00000000..8bc513c4 Binary files /dev/null and b/docs/assets/Electrician.gif differ diff --git a/docs/assets/Electrician2-black.gif b/docs/assets/Electrician2-black.gif new file mode 100644 index 00000000..a6ef8fce Binary files /dev/null and b/docs/assets/Electrician2-black.gif differ diff --git a/docs/assets/Electrician2.gif b/docs/assets/Electrician2.gif new file mode 100644 index 00000000..9c510c12 Binary files /dev/null and b/docs/assets/Electrician2.gif differ diff --git a/docs/assets/Login Page Wireframe Mobile UI Prototype-2_page-0019.jpg b/docs/assets/Login Page Wireframe Mobile UI Prototype-2_page-0019.jpg new file mode 100644 index 00000000..5b806049 Binary files /dev/null and b/docs/assets/Login Page Wireframe Mobile UI Prototype-2_page-0019.jpg differ diff --git a/docs/assets/R1.png b/docs/assets/R1.png new file mode 100644 index 00000000..05513eb9 Binary files /dev/null and b/docs/assets/R1.png differ diff --git a/docs/assets/R2.png b/docs/assets/R2.png new file mode 100644 index 00000000..6ba88dc3 Binary files /dev/null and b/docs/assets/R2.png differ diff --git a/docs/assets/R3.png b/docs/assets/R3.png new file mode 100644 index 00000000..b33c593d Binary files /dev/null and b/docs/assets/R3.png differ diff --git a/docs/assets/R4.png b/docs/assets/R4.png new file mode 100644 index 00000000..ceee2344 Binary files /dev/null and b/docs/assets/R4.png differ diff --git a/frontend/sige_ie/assets/UNB.png b/docs/assets/UNB.png similarity index 100% rename from frontend/sige_ie/assets/UNB.png rename to docs/assets/UNB.png diff --git a/docs/assets/adicionar.equipamentos.jpg b/docs/assets/adicionar.equipamentos.jpg new file mode 100644 index 00000000..198ef2a8 Binary files /dev/null and b/docs/assets/adicionar.equipamentos.jpg differ diff --git a/doc/img/arquitetura-api-rest-sigeie.png b/docs/assets/arquitetura.png similarity index 100% rename from doc/img/arquitetura-api-rest-sigeie.png rename to docs/assets/arquitetura.png diff --git a/docs/assets/day-and-night.png b/docs/assets/day-and-night.png new file mode 100644 index 00000000..0edb5d13 Binary files /dev/null and b/docs/assets/day-and-night.png differ diff --git a/docs/assets/default_765x625.png b/docs/assets/default_765x625.png new file mode 100644 index 00000000..424e36dd Binary files /dev/null and b/docs/assets/default_765x625.png differ diff --git a/frontend/sige_ie/assets/1000x1000.png b/docs/assets/default_transparent_1000x1000.png similarity index 100% rename from frontend/sige_ie/assets/1000x1000.png rename to docs/assets/default_transparent_1000x1000.png diff --git a/docs/assets/default_transparent_765x625.png b/docs/assets/default_transparent_765x625.png new file mode 100644 index 00000000..4c8229f6 Binary files /dev/null and b/docs/assets/default_transparent_765x625.png differ diff --git a/docs/assets/favicon.ico b/docs/assets/favicon.ico new file mode 100644 index 00000000..cf72f904 Binary files /dev/null and b/docs/assets/favicon.ico differ diff --git a/docs/assets/favicon_transparent_32x32.png b/docs/assets/favicon_transparent_32x32.png new file mode 100644 index 00000000..5c441352 Binary files /dev/null and b/docs/assets/favicon_transparent_32x32.png differ diff --git a/docs/assets/github-sign.png b/docs/assets/github-sign.png new file mode 100644 index 00000000..7b222645 Binary files /dev/null and b/docs/assets/github-sign.png differ diff --git a/docs/assets/google-play.png b/docs/assets/google-play.png new file mode 100644 index 00000000..3487f7f8 Binary files /dev/null and b/docs/assets/google-play.png differ diff --git a/docs/assets/imagem.mapa.jpg b/docs/assets/imagem.mapa.jpg new file mode 100644 index 00000000..4e89060a Binary files /dev/null and b/docs/assets/imagem.mapa.jpg differ diff --git a/frontend/sige_ie/assets/lighting.png b/docs/assets/lighting.png similarity index 100% rename from frontend/sige_ie/assets/lighting.png rename to docs/assets/lighting.png diff --git a/docs/assets/linkedin.png b/docs/assets/linkedin.png new file mode 100644 index 00000000..b6231a35 Binary files /dev/null and b/docs/assets/linkedin.png differ diff --git a/docs/assets/locais.jpg b/docs/assets/locais.jpg new file mode 100644 index 00000000..4d2e088d Binary files /dev/null and b/docs/assets/locais.jpg differ diff --git a/docs/assets/logo.png b/docs/assets/logo.png new file mode 100644 index 00000000..300aee64 Binary files /dev/null and b/docs/assets/logo.png differ diff --git "a/docs/assets/menu.instala\303\247oes.jpg" "b/docs/assets/menu.instala\303\247oes.jpg" new file mode 100644 index 00000000..f8e223b9 Binary files /dev/null and "b/docs/assets/menu.instala\303\247oes.jpg" differ diff --git a/docs/assets/moon.png b/docs/assets/moon.png new file mode 100644 index 00000000..39405601 Binary files /dev/null and b/docs/assets/moon.png differ diff --git a/docs/assets/pp.pdf b/docs/assets/pp.pdf new file mode 100644 index 00000000..8e84a862 Binary files /dev/null and b/docs/assets/pp.pdf differ diff --git a/docs/assets/release2.1.png b/docs/assets/release2.1.png new file mode 100644 index 00000000..ca9e15c0 Binary files /dev/null and b/docs/assets/release2.1.png differ diff --git a/docs/assets/release2.png b/docs/assets/release2.png new file mode 100644 index 00000000..4c987d0d Binary files /dev/null and b/docs/assets/release2.png differ diff --git a/docs/assets/sun.png b/docs/assets/sun.png new file mode 100644 index 00000000..187b7db6 Binary files /dev/null and b/docs/assets/sun.png differ diff --git a/docs/atas/ata1.md b/docs/atas/ata1.md new file mode 100644 index 00000000..7ffdb6b6 --- /dev/null +++ b/docs/atas/ata1.md @@ -0,0 +1,69 @@ +### Ata de Reunião - Criação de Aplicativo Mobile para Retrofitting de Instalações Elétricas em Edificações + +-- +### Detalhes da Reunião + + Data:27 de Fevereiro de 2024 + Horário:14 horas + Local: LDTEA 206 + +--- + +### Participantes + +- **Oscar de Brito** +- **Danilo Melo** +- **Kauan José** +- **Pedro Lucas** +- **Ramires Rocha** + +--- + +### Pauta + +1. Discussão sobre a criação de um aplicativo mobile baseado no TCC de Estudo de Metodologia de Levantamento de Dados para Retrofitting de Instalações Elétricas em Edificações. +2. Definição dos objetivos e funcionalidades do aplicativo. +3. Distribuição de tarefas entre os membros da equipe. + +--- + +### Decisões e Discussões + +#### 1. Objetivos e Funcionalidades do Aplicativo + +- **Objetivo Principal:** Facilitar o levantamento de dados para o retrofit de instalações elétricas em edificações. +- **Funcionalidades Básicas:** + - Cadastro de edificações + - Registro de características elétricas atuais + - Geração de relatórios + - Interface intuitiva e fácil de usar + +#### 2. Distribuição de Tarefas + +- **Design da Interface do Usuário:** + - **Danilo Melo** + - **Ramires Rocha** +- **Desenvolvimento do Banco de Dados:** + - **Kauan José** + - **Pedro Lucas** +- **Desenvolvimento do Backend e História do Usuário:** + - **Oscar de Brito** + +#### 3. Definição de Objetivos + +- **Ferramentas de Desenvolvimento:** Estabelecimento das ferramentas necessárias. +- **Prazos:** Conclusão do projeto dentro do prazo estabelecido. + +--- + +### Próxima Reunião + +**Data:** 20 de Março de 2024 +**Horário:** 15:00 +**Local:** LTDEA 206 + +--- + +### Observações + +Na presente reunião, foram elucidados todos os requisitos funcionais e não funcionais do projeto, bem como todas as demandas necessárias para a criação do projeto. A divisão da equipe e o levantamento dos requisitos necessários foram estabelecidos para que cada um elabore sua parte do projeto. diff --git a/docs/atas/ata2.md b/docs/atas/ata2.md new file mode 100644 index 00000000..2748f8c5 --- /dev/null +++ b/docs/atas/ata2.md @@ -0,0 +1,77 @@ +### Ata de Reunião - Apresentação do Protótipo com Tela de Login, Registro e Layout da Página do Aplicativo Mobile, Apresentação do Nome, Sistema e Subsistemas + +--- + +### Detalhes da Reunião + + Data:20 de Março de 2024 + Horário:14 horas + Local:LDTEA Sala 206 + +--- + +### Participantes + +- **Danilo de Melo** +- **Kauan Jóse** +- **Oscar de Brito** +- **Ramires Rocha** +- **Pedro Lucas** + +--- + +### Pauta + +- Apresentação do protótipo inicial do aplicativo, incluindo: + - Tela de login + - Registro + - Layout da página principal +- Discussão sobre a usabilidade e design do protótipo +- Feedback dos membros da equipe +- Definição de próximos passos e ajustes necessários + +--- + +### Descrição + +### 1. Apresentação do Protótipo + +- O protótipo inicial do aplicativo foi apresentado aos membros da equipe. +- Foram demonstradas as telas de login e registro, bem como o layout preliminar da página principal. +- Apresentação do nome do aplicativo definido como **Sigeie**. +- Foram apresentados todos os sistemas e subsistemas definidos a partir do material de apoio disponibilizado para a geração do aplicativo, incluindo: + - Instalações de Baixa Tensão + - Cabeamento Estruturado + - Sistema de Proteção contra Descargas Elétricas + - Sistema de Detecção de Alarme de Incêndio + +### 2. Discussão sobre Usabilidade e Design + +- Os membros da equipe discutiram a usabilidade e o design do protótipo. +- Foram levantados pontos positivos e áreas que necessitam de melhoria em termos de interface e experiência do usuário. +- Discussão sobre a usabilidade de todos os sistemas e subsistemas apresentados. + +### 3. Feedback do Cliente + +- O cliente apresentou seu feedback da apresentação com pontos positivos e negativos e pontos de melhoria. +- O cliente concordou com o layout, design e interface. +- O cliente solicitou melhorias nos sistemas e subsistemas, recomendando acréscimos e retiradas de objetos nos sistemas e subsistemas. + +### 4. Definição de Próximos Passos + +- Foi acordado que serão feitos ajustes com base no feedback recebido. +- Cada membro da equipe foi designado para realizar as alterações específicas em suas respectivas áreas de responsabilidade. + +--- + +### Próxima Reunião + + Data:20 de Junho de 2024 + Horário: 15 horas + Local: LDTEA Sala 206 + +--- + +### Observações + +- Na presente reunião, houve a aprovação por parte do cliente da logo criada, assim como de toda a interface e aprovação da divisão dos sistemas e subsistemas do protótipo apresentado. diff --git a/docs/atas/ata3.md b/docs/atas/ata3.md new file mode 100644 index 00000000..05b7cda0 --- /dev/null +++ b/docs/atas/ata3.md @@ -0,0 +1,87 @@ +# Ata de Reunião - Apresentação do Protótipo com Sistema e Subsistemas + +--- + +### Detalhes da Reunião + + Data: 20 de Junho de 2024 + Horário: 15 horas + Local: LDTEA Sala 206 + +--- + +### Participantes + +- **Danilo de Melo** +- **Kauan Jóse** +- **Oscar de Brito** +- **Ramires Rocha** +- **Pedro Lucas** + +--- + +### Pauta + +- Apresentação do protótipo inicial do aplicativo, incluindo os sistemas de: + - **Iluminação** + - **Refrigeração** + - **Cargas Elétricas** + - **Linhas Elétricas** + - **Quadro de Distribuição** + - **Cabeamento Estruturado** + - **Circuitos Elétricos** + - **Sistema de Proteção contra Descargas Atmosféricas** + - **Sistema de Detecção de Alarme de Incêndio** +- Discussão sobre a usabilidade e design do protótipo. +- Feedback dos membros da equipe. +- Definição de próximos passos e ajustes necessários. + +--- + +### Descrição + +### 1. Apresentação do Protótipo + +- O protótipo inicial do aplicativo foi apresentado aos membros da equipe. +- Foram demonstrados os sistemas criados, incluindo: + - **Sistema de Iluminação** + - **Sistema de Refrigeração** + - **Cargas Elétricas** + - **Linhas Elétricas** + - **Quadro de Distribuição** + - **Cabeamento Estruturado** + - **Circuitos Elétricos** + - **Sistema de Proteção contra Descargas Atmosféricas** + - **Sistema de Detecção de Alarme de Incêndio** +- Apresentação do nome do aplicativo definido como **Sigeie**. +- Apresentação dos sistemas e subsistemas definidos a partir do material de apoio disponibilizado para a geração do aplicativo. + +### 2. Discussão sobre Usabilidade e Design + +- Os membros da equipe discutiram a usabilidade e o design do protótipo. +- Foram levantados pontos positivos e áreas que necessitam de melhoria em termos de interface e experiência do usuário. +- Discussão detalhada sobre a usabilidade de todos os sistemas e subsistemas apresentados. + +### 3. Feedback do Cliente + +- O cliente apresentou seu feedback da apresentação com pontos positivos e negativos, e sugestões de melhoria. +- O cliente solicitou melhorias nos sistemas e subsistemas, recomendando acréscimos e retiradas de objetos nos sistemas e subsistemas. + +### 4. Definição de Próximos Passos + +- Foi acordado que serão feitos ajustes com base no feedback recebido. +- Cada membro da equipe foi designado para realizar as alterações específicas em suas respectivas áreas de responsabilidade. + +--- + +## Próxima Reunião + + Data: 05 de Agosto de 2024 + Horário: 10 horas + Local: LDTEA Sala 313 + +--- + +### Observações + +- Na presente reunião, houve a aprovação por parte do cliente das informações contidas em cada campo de cada sistema e subsistema. Ficou acordado também que possíveis alterações serão relatadas para mudanças futuras. diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..2070e36e --- /dev/null +++ b/docs/index.html @@ -0,0 +1,630 @@ + + + + + + + SIGE IE + + + + + + + + +
+
+

+ Sistema de Auxilio para Operação e Manutenção de Instalação + Elétrica. +

+
+

+ Uma ferramenta inovadora, projetada para otimizar a + coleta de dados e o suporte em operações e manutenções + de sistemas elétricos. Este aplicativo móvel foi + desenvolvido para acelerar a obtenção de informações + essenciais, aumentando a eficiência das operações e + garantindo uma gestão mais eficaz das instalações + elétricas. +

+
+
+ +
+
+ + + + + + + + + + + +
+ +
+
+

+ Descrição do Produto +

+
+
+

+ Gerenciamento de Instalações +

+

+ Melhore a eficiência e a gestão das instalações + elétricas com uma interface intuitiva que facilita a + coleta de dados e o suporte às operações e + manutenções. Supervise e acompanhe manutenções + preventivas e corretivas, garantindo que todas as + atividades sejam realizadas no tempo certo e da + melhor forma. +

+
+
+ Imagem de eletricista +
+
+
+
+ Imagem de eletricista +
+
+

+ Funcionalidades Diversas +

+

+ Aproveite uma ampla gama de funcionalidades que + garantem uma gestão eficiente e segura das + instalações elétricas. Cadastre, edite e exclua + locais e equipamentos, monitore em tempo real, gere + relatórios, integre com mapas e desfrute de uma + interface intuitiva. +

+
+
+
+
+ +
+
+

+ Funcionalidades +

+
+
+
+
+
+

+ Cadastro de Equipamento +

+
+

+ Cadastre os equipamentos presentes em cada + local, organizando e estruturando as + instalações. Edite e exclua equipamentos + conforme necessário para manter as informações + sempre atualizadas. +

+
+ Gerenciamento de Instalações +
+
+
+
+

+ Cadastro de Locais +

+
+

+ Mantenha um registro detalhado de todos os + locais e salas dentro da instalação, facilitando + a gestão e manutenção. Edite e exclua locais + conforme necessário. Gere relatórios completos + de cada local de forma instantânea. +

+
+ Cadastro de Locais +
+
+
+
+
+
+

+ Menu de Instalações +

+
+

+ Acesse rapidamente todos os sistemas presentes + em um local e adicione novos de forma prática e + simples. +

+
+ Menu de Instalações +
+
+
+
+

+ Integração com Mapas +

+
+

+ Acompanhe localizações e salas registradas em + tempo real. Crie e atualize locais + instantaneamente, garantindo que todas as + mudanças sejam refletidas no sistema sem + atrasos. +

+
+ Map Integration +
+
+
+
+
+
+ +
+
+

+ Equipe de Desenvolvimento +

+
+
+
+ +
+
+ +
+
+
+

Baixe o nosso aplicativo:

+ + Disponível no Google Play + +
+

+ © 2024 SIGE IE. Todos os direitos reservados. +

+
+
+ + + + + + diff --git a/docs/info/Roadmap.md b/docs/info/Roadmap.md new file mode 100644 index 00000000..68445de3 --- /dev/null +++ b/docs/info/Roadmap.md @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/info/arquitetura.md b/docs/info/arquitetura.md new file mode 100644 index 00000000..0954eee6 --- /dev/null +++ b/docs/info/arquitetura.md @@ -0,0 +1,35 @@ +Arquitetura de uma aplicação com uma API REST, onde os clientes interagem com servidores que, por sua vez, interagem com um banco de dados MySQL e um armazenamento de sessão no Redis. + +### Clientes +- **Função:** São os usuários finais ou sistemas que fazem requisições para a API. +- **Interação:** Fazem requisições HTTP para os servidores e recebem respostas em formato JSON. + +### Servidores +- **Função:** Provedores da API REST que processam as requisições dos clientes. +- **Interação com Banco de Dados:** Realizam operações CRUD (Criar, Ler, Atualizar, Deletar) no banco de dados MySQL. +- **Interação com Redis:** Utilizam o Redis para gerenciamento de sessão dos usuários. + +### Banco de Dados MySQL +- **Função:** Armazenamento persistente dos dados da aplicação. +- **Operações CRUD:** Recebe comandos dos servidores para realizar operações CRUD. + +### Sessão no Redis +- **Função:** Armazenamento de dados de sessão para usuários autenticados. +- **Interação:** Os servidores lêem e escrevem dados de sessão para gerenciar o estado da sessão dos clientes. + +### Fluxo Geral +1. O cliente faz uma requisição HTTP para o servidor. +2. O servidor processa a requisição, que pode envolver: + - A leitura ou escrita de informações no banco de dados MySQL. + - A verificação ou atualização de dados de sessão no Redis. +3. Após processar a requisição, o servidor envia uma resposta em formato JSON de volta ao cliente. + +### Observações +- **Escalabilidade:** A presença de múltiplos servidores sugere que a arquitetura foi projetada para escalar horizontalmente. +- **Performance:** O uso do Redis para sessões indica uma preocupação com a velocidade de acesso aos dados de sessão, que são geralmente mais voláteis e acessados com frequência. +- **Segurança:** A gestão de sessões no Redis sugere que o sistema implementa mecanismos de autenticação e possivelmente de autorização. +- **Disponibilidade:** A arquitetura sugere que há redundância nos servidores para garantir a disponibilidade do serviço. + +A arquitetura é representativa de muitas aplicações web modernas que buscam desempenho, escalabilidade e confiabilidade. + \ No newline at end of file diff --git a/docs/info/backend.md b/docs/info/backend.md new file mode 100644 index 00000000..1978a24d --- /dev/null +++ b/docs/info/backend.md @@ -0,0 +1,114 @@ +### Como subir o projeto +Estas etapas são válidas para Linux OS e WSL. +#### Como subir o back-end: + +Primeiramente, interrompa qualquer processo que use o porto 8080, 3306 e 6379. Então atualize o seu sistema: + ``` + sudo apt-get update + ``` + + ``` + sudo apt-get upgrade + ``` + +2. **Instalação de Dependências:** + +- Instale o Python, Pip e os cabeçalhos do Python e MySQL: + + Python: + ``` + sudo apt-get install python3.11 + ``` + + Pip: + ``` + sudo apt-get install python3-pip + ``` + + Cabeçalhos: + ``` + sudo apt-get install python3.11-dev default-libmysqlclient-dev build-essential pkg-config + ``` + + mysqlclient: + + ``` + pip install mysqlclient + ``` + +- Instale o virtualenv para criar um ambiente virtual do projeto: + + Virtualenv: + ``` + sudo pip3 install virtualenv + ``` + +Vá para dentro da pasta raiz `api`: + +1. Cria o ambiente virtual e ative-o: + + Criar ambiente virtual: + ``` + virtualenv -p python3.11 venv + ``` + + Ativar ambiente: + ``` + source venv/bin/activate + ``` + +3. Com o ambiente virtual ativado, instale as dependências: + + ``` + pip install -r requirements.txt + ``` + +4. Com o docker iniciado, crie a imagem do banco de dados pela primeira vez: + + ``` + docker-compose build + ``` + +6. Suba a imagem: + + ``` + docker-compose up + ``` + +8. Ainda no diretório raiz `api`, aplique as migrações: + + ``` + python manage.py makemigrations + ``` + + ``` + python3 manage.py migrate + ``` + +10. Inicie o servidor: + + ``` + python3 manage.py runserver + ``` + +Pronto! O servidor está configurado e em execução com o banco de dados configurado. + +#### Pela segunda vez + +Garanta que não haja nenhum processo que use o porto `8080`, `3306` e `6379`. Por fim, com todas as dependências configuradas, basta: + +- Iniciar o Docker e o container `sigeie`; +- Baixar as atualizações (caso haja): + +```sh +git pull +``` + +- Atualizar as dependências, fazer as migrações e iniciar o servidor: + +```sh +source venv/bin/activate && pip install -r requirements.txt && python manage.py makemigrations && python manage.py migrate && python manage.py runserver +``` + +Isso é tudo, pessoal. +``` \ No newline at end of file diff --git a/docs/info/contribuir.md b/docs/info/contribuir.md new file mode 100644 index 00000000..a3c649c0 --- /dev/null +++ b/docs/info/contribuir.md @@ -0,0 +1,18 @@ +### Como contribuir +1. Faça um fork do repositório do projeto. +2. Clone o fork na sua máquina: + + ``` + git clone https://github.com/{seu-usuario}/T2G3-Sistema-Instalacao-Eletrica.git + ``` + +4. Comente na issue que deseja contribuir ou crie uma issue nova. +5. Entre no repositório clonado na sua máquina: + + ``` + cd T2G3-Sistema-Instalacao-Eletrica + ``` + +7. Após enviar suas contribuições para o fork do seu repositório, faça um pull request. +8. Aguarde a revisão. + diff --git a/docs/info/cronograma.md b/docs/info/cronograma.md new file mode 100644 index 00000000..e5181a66 --- /dev/null +++ b/docs/info/cronograma.md @@ -0,0 +1,14 @@ +Cronograma do projeto: + +| Semana | Status | Entrega | Início | Fim | +| --- | --- | --- | --- | --- | +1 | Feito | Separação da equipe e estudo do projeto | 19/02/24 | 26/02/24 +2 | Feito | Reunião com o cliente, levantamento de requisitos, criação do repositório no GitHub e documentação | 26/02/24 | 04/03/24 +3 | Feito | Preparação do ambiente de desenvolvimento do backend e frontend, levantamento de requisitos e escrita de histórias de usuário da release 1, prototipação em baixa fidelidade | 04/03/24 | 11/03/24 +4 | Feito | Prototipação em baixa fidelidade, levantamento de requisitos e escrita das histórias de usuário, agendamento com o cliente para apresentar os resultados | 11/03/24 | 18/03/24 +5 | Feito | Reunião com o cliente para apresentar os resultados e validar, modelagem do diagrama entidade-relacionamento e codificação da release 1 | 18/03/24 | 25/03/24 +6 | Feito | Codificação da release 1 e atualização do diagrama entidade-relacionamento | 25/03/24 | 01/04/24 +7 | Feito | Codificação da release 1 e entrega da release 1 e entrega da tela de login e tela de cadastro | 01/04/24 | 08/04/24 +8 | Feito | Codificação da release 2 e atualização do diagrama entidade-relacionamento e produção das telas de gerenciar local,gerenciar SPDA e gerenciar salas| 08/04/24| 08/05/24 +9 | Feito | Entrega da realese 2 e atualização do diagrama entidade-relacionamento e planejamento para entrega das próximas releases| 08/05/24 | 01/07/24 +10| Feito | Codificação da realese 3, reunião com cliente com a apresentação do desenvolvimento do prototipo e aprovação jun to ao cliente| 01/07/2024 | 05/07/2024 \ No newline at end of file diff --git a/docs/info/frontend.md b/docs/info/frontend.md new file mode 100644 index 00000000..10346abb --- /dev/null +++ b/docs/info/frontend.md @@ -0,0 +1,52 @@ +### Guia de Configuração do Front-end + +### Como subir o front-end: + +Antes de começar, verifique se o Flutter SDK está atualizado e compatível com o projeto. Siga as instruções específicas para sua plataforma (Windows, macOS, Linux) disponíveis na documentação oficial do Flutter. + +Caso ainda não tenha feito, instale os seguintes requisitos em sua máquina: + +#### Flutter SDK: +Siga as instruções de instalação para a sua plataforma. + +#### Android Studio ou Visual Studio Code: + +##### Android Studio: + +```sh +sudo snap install android-studio --classic +``` + +##### Visual Studio Code: + +```sh +sudo snap install code --classic +``` + +Para o VS Code, instale as extensões do Flutter e Dart disponíveis na aba de extensões do editor. + +#### Emulador Android ou um dispositivo físico: +Configure um emulador usando o AVD Manager do Android Studio ou configure seu dispositivo Android para depuração USB. + +Com o ambiente preparado, siga os passos abaixo: + +#### Clone o Repositório do Front-end: + +```sh +git clone https://github.com/ResidenciaTICBrisa/T2G3-Sistema-Instalacao-Eletrica.git +``` + +#### Abra o Projeto no Editor: +Abra a pasta clonada no Android Studio ou no Visual Studio Code. + +#### Baixe as Dependências: +Abra um terminal na pasta `frontend/sige_ie` e execute o comando: + +```sh +flutter pub get +``` + +#### Execute o Projeto: + +- No Android Studio: Escolha um dispositivo ou emulador na barra de ferramentas e clique em 'Run'. +- No Visual Studio Code: Selecione um dispositivo ou emulador na barra de status e pressione `F5` ou utilize o comando `flutter run` na paleta de comandos. diff --git a/docs/info/home.md b/docs/info/home.md new file mode 100644 index 00000000..a81c3947 --- /dev/null +++ b/docs/info/home.md @@ -0,0 +1,69 @@ +

SIGE IE

+ + + +
+

Sobre este projeto

+ +Aplicativo web mobile desenvolvido para a Universidade de Brasília com objetivo de gerenciar as instalações elétricas e dar suporte ao retrofitting das instalações. + +

Posição

+O SIGE IE é um sistema da Universidade de Brasília para o gerenciamento de instalações elétricas com o objetivo de facilitar o cadastro das informações de instalação elétrica para ajudar na reforma da parte elétrica dos prédios e salas. Ele permite a automatização da geração de relatórios das instalações elétricas de cada lugar e a centralização dessas informações para uso dos responsáveis pelas instalações. As pessoas devem usar o SIGE IE porque ele simplifica e agiliza o processo de gerenciamento, principalmente do retrofitting de instalações elétricas, garantindo maior eficiência e segurança. + + +

Objetivo

+Simplificar o cadastro e gerenciamento de informações de instalações elétricas e automatizar a geração de relatórios. + + +

Tecnologias

+ +##### Back-end + +| Nome | Versão | Uso | Configuração | +|-------------------|--------|-------------------|-------------------------------------------------------------------------| +| Python | 3.11.8 | Linguagem | [Site oficial do Python](https://www.python.org/downloads/) | +| Django | 4.2 (LTS) | Framework web | Automática | +| Django REST framework | 3.14 | API REST | Automática | +| Docker | 25.0.4 | Conteiner e imagem | [Site oficial do Docker](https://docs.docker.com/desktop/install/ubuntu/) | +| Redis | 7.2 | Banco de dados cache para sessão | Automática via Docker | +| MySQL | 8.1 | Banco de dados | Automática via Docker | +| mysqlclient | 2.2.4 | Cliente para se conectar com MySQL | [Site do Pypi com as configurações](https://pypi.org/project/mysqlclient/) | + +###### Observação + +Atualmente o Django REST Framework suporta as seguintes versões do Python e do Django: + +| Python | 3.6 | 3.7 | 3.8 | 3.9 | 3.10 | 3.11 | +|--------|-----|-----|-----|-----|------|------| +| Django | 3.0 | 3.1 | 3.2 | 4.0 | 4.1 | 4.2 (LTS) | + +Como a versão LTS mais recente do Django (2024) é a 4.2, escolhemos configurar o projeto usando Python 3.11. + +##### Front-end mobile + +| Nome | Versão | Uso | Configuração | +|---------------|--------|--------------------|--------------------------------------------------------------| +| Flutter | 3.19.3 | Framework frontend | [Site oficial do Flutter](https://docs.flutter.dev/get-started/install/linux) | +| Android Studio| Iguana | IDE para desenvolvimento Android com Android SDK | [Site oficial do Android Studio](https://developer.android.com/studio/index.html) | + +## Equipe + + + + +

Danilo Melo

+

Kauan José

+

Oscar de Brito

+

Pedro Lucas

+

Ramires Rocha

+ + +### Organização + +| Papel | Atribuições | Responsável | Participantes | +| --- | --- | --- | --- | +| Cliente | Validar as entregas | Loana | Loana e Alex | +| Desenvolvedor back-end | Codificar o backend, configurar a infraestrutura | Pedro | Pedro, Kauan e Oscar | +| Desenvolvedor frontend | Codificar o frontend, realizar integração com backend | Danilo | Danilo, Ramires, Pedro e Oscar | +| UX design | Projetar a interface do usuário, criar protótipos e realizar entrevistas com os clientes | Danilo | Danilo | +| Analista de requisitos | Levantar requisitos, gerenciar a documentação, validar com cliente | Oscar | Oscar, Ramires e Pedro | \ No newline at end of file diff --git a/docs/info/modelagemBD.md b/docs/info/modelagemBD.md new file mode 100644 index 00000000..ae518362 --- /dev/null +++ b/docs/info/modelagemBD.md @@ -0,0 +1,8 @@ +### Banco de dados + +A estrutura do banco de dados é projetada para uma aplicação de gerenciamento de instalações, onde os usuários podem manter registros de locais, salas, sistemas e equipamentos. O esquema reflete uma hierarquia de dados bem definida e normalizada, facilitando a manutenção, a consulta e a expansão do banco de dados. + +A complexidade dos relacionamentos indica uma solução robusta capaz de lidar com uma grande variedade de informações operacionais, mantendo a integridade e a eficiência dos dados. Cada entidade é projetada para armazenar informações específicas, permitindo consultas detalhadas e relatórios sobre o estado e uso dos equipamentos e sistemas. + + + diff --git a/docs/info/prototipo.md b/docs/info/prototipo.md new file mode 100644 index 00000000..45d382ed --- /dev/null +++ b/docs/info/prototipo.md @@ -0,0 +1,27 @@ +# Protótipo de Aplicativo Móvel: Gerenciamento de Instalações + +Este documento apresenta um protótipo detalhado de um aplicativo móvel projetado para o gerenciamento e configuração de instalações. Com um foco específico no controle de espaços físicos e infraestrutura, o aplicativo oferece uma gama abrangente de funcionalidades que visam simplificar e efetivar a administração de locais. + +## Funcionalidades Principais + +- **Autenticação de Usuário:** Interface de login segura para acessar funcionalidades personalizadas. +- **Registro e Gerenciamento de Locais:** Capacidade de adicionar, editar e gerenciar detalhes de locais, como salas, incluindo atributos específicos como andar e nome. +- **Configuração de Sistemas:** Opções para ajustar sistemas dentro de um local, abrangendo desde baixa tensão até alarmes de incêndio, indicando uma abordagem minuciosa ao gerenciamento de infraestrutura. +- **Inventário de Equipamentos:** Funcionalidades para incluir e administrar equipamentos por categoria, quantidade e localização, refletindo um componente de inventário essencial. +- **Relatórios e Análises:** Ferramentas para a geração de relatórios, proporcionando insights e revisões das configurações e instalações. + +## Design e Usabilidade + +O aplicativo exibe um design minimalista, priorizando a clareza e a facilidade de navegação. Utiliza uma paleta de cores sóbrias e uma barra de navegação inferior constante para promover uma experiência de usuário intuitiva e eficiente. + +## Visualização do Protótipo + +Para uma visão detalhada do protótipo e suas funcionalidades, veja o documento incorporado abaixo: + + +Se seu navegador não suporta iframes. Você pode acessar o PDF diretamente aqui. + +Este protótipo evidencia uma solução abrangente para o gerenciamento de instalações, destacando-se por sua interface limpa, navegação intuitiva, e um conjunto robusto de funcionalidades práticas. Ideal para profissionais e organizações que buscam otimizar o controle e administração de espaços físicos e infraestrutura. + + diff --git a/docs/info/requisitosEpicos.md b/docs/info/requisitosEpicos.md new file mode 100644 index 00000000..79dacdcd --- /dev/null +++ b/docs/info/requisitosEpicos.md @@ -0,0 +1,12 @@ +# Épicos +| N. | Eṕicos | +| --- | --- | +| 1 | Prover contas | +| 2 | Prover locais | +| 3 | Prover retrofitting de instalações de baixa tensão | +| 4 | Prover retrofitting de cabeamento estruturado | +| 5 | Prover retrofitting de sistema de proteção conta descargas atmosféricas (SPDA) | +| 6 | Prover retrofitting de sistema de detecção de alarme de incêndio | +| 7 | Prover retrofiting de sistema de refrigeração | +| 8 | Gerar relatorio | + diff --git a/docs/info/requisitosFeatures.md b/docs/info/requisitosFeatures.md new file mode 100644 index 00000000..a6093ff0 --- /dev/null +++ b/docs/info/requisitosFeatures.md @@ -0,0 +1,16 @@ +# Features +| N. | Épico | Features | +| --- | --- | --- | +| 1 | 1 | Gerenciar conta de usuário | +| 2 | 2 | Gerenciar locais | +| 3 | 2 | Gerenciar salas | +| 4 | 3 | Gerenciar sistema de iluminação | +| 5 | 3 | Gerenciar cargas elétricas | +| 6 | 3 | Gerenciar linhas elétricas | +| 7 | 3| Gerenciar circuitos elétricos | +| 8 | 3 | Gerenciar quadros de distribuição | +| 9 | 4 | Gerenciar cabeamento estruturado | +| 10 | 5 | Gerenciar sistema de proteção conta descargas atmosféricas (SPDA) | +| 11 | 6 | Gerenciar sistema de detecção de alarme de incêndio (SDAI) | +| 12 | 7 | Gerenciar sistema de Refrigeração| +| 13 | 8 | Gerar relatório | \ No newline at end of file diff --git a/docs/releases/Release1.md b/docs/releases/Release1.md new file mode 100644 index 00000000..a126d36b --- /dev/null +++ b/docs/releases/Release1.md @@ -0,0 +1,15 @@ +Data de Inicio: 19 de fevereiro de 2024; +Data de Termino: 08 de Abril de 2024; + + +O release, que ocorreu de 19 de fevereiro a 08 de abril de 2024, foi marcado pela conclusão bem-sucedida das User Stories planejadas, conforme mostrado na imagem fornecida. A equipe demonstrou compromisso com a excelência e a qualidade, mantendo uma comunicação eficaz e adaptando-se às mudanças. + + + + +Entregas:Na imagem a seguir são mostradas as US entregues; + + + + \ No newline at end of file diff --git a/docs/releases/release2.md b/docs/releases/release2.md new file mode 100644 index 00000000..0eb84aae --- /dev/null +++ b/docs/releases/release2.md @@ -0,0 +1,19 @@ +Data de Inicio: 09 de Abril de 2024; +Data de Termino: 08 de Maio de 2024; + + +Entregas: Na imagem a seguir são mostradas as US que serão entregues; + + + + + + + + + + + + diff --git a/docs/releases/release3.md b/docs/releases/release3.md new file mode 100644 index 00000000..4c0d68da --- /dev/null +++ b/docs/releases/release3.md @@ -0,0 +1,17 @@ +Data de Inicio : 21 de Maio de 2024; +Data de Entrega: 05 de Julho de 2024; + + +Entregas: Nas imagem a seguir são mostradas as US que serão entregues; + + + + + + + + + + + \ No newline at end of file diff --git a/docs/releases/release4.md b/docs/releases/release4.md new file mode 100644 index 00000000..6e430a43 --- /dev/null +++ b/docs/releases/release4.md @@ -0,0 +1,19 @@ +Data de Inicio : 02 de Julho de 2024; +Data de Termino: 05 de Agosto de 2024; + + + +Entregas:Na imagem a seguir são mostradas as US que serão entregues; + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/script.js b/docs/script.js new file mode 100644 index 00000000..290945b8 --- /dev/null +++ b/docs/script.js @@ -0,0 +1,60 @@ +function toggleMenu() { + const navToggle = document.getElementById("nav-toggle"); + const navContent = document.getElementById("nav-content"); + navToggle.classList.toggle("open"); + navContent.classList.toggle("open"); +} + +document.getElementById("modeToggle").addEventListener("click", function () { + document.body.classList.toggle("dark-mode"); + + if (document.body.classList.contains("dark-mode")) { + document.getElementById("image1").src = "assets/Electrician-black.gif"; + document.getElementById("image2").src = "assets/Electrician2-black.gif"; + document.getElementById("img-sun-moon").src = "assets/moon.png"; + document.querySelector(".gradient-bg").classList.add("dark-mode"); + } else { + document.getElementById("image1").src = "assets/Electrician.gif"; + document.getElementById("image2").src = "assets/Electrician2.gif"; + document.getElementById("img-sun-moon").src = "assets/sun.png"; + document.querySelector(".gradient-bg").classList.remove("dark-mode"); + } +}); + +$(document).ready(function () { + $(".team-carousel").slick({ + infinite: true, + slidesToShow: 3, + slidesToScroll: 1, + arrows: true, + autoplay: true, + autoplaySpeed: 2000, + responsive: [ + { + breakpoint: 1024, + settings: { + slidesToShow: 2, + slidesToScroll: 1, + infinite: true, + dots: true, + }, + }, + { + breakpoint: 600, + settings: { + slidesToShow: 1, + slidesToScroll: 1, + }, + }, + ], + }); +}); + +document.querySelectorAll('a[href^="#"]').forEach((anchor) => { + anchor.addEventListener("click", function (e) { + e.preventDefault(); + document.querySelector(this.getAttribute("href")).scrollIntoView({ + behavior: "smooth", + }); + }); +}); diff --git a/docs/style.css b/docs/style.css new file mode 100644 index 00000000..3bfc65ce --- /dev/null +++ b/docs/style.css @@ -0,0 +1,351 @@ +#nav-toggle { + display: none; +} + +@media (max-width: 1280px) { + #nav-content { + display: none; + } + #nav-content .sun-moon { + width: 60px; + height: auto; + display: block; + margin: auto; + transform: translateX(-8px); + } + #nav-toggle { + display: block; + } + + #nav-toggle.open + #nav-content { + display: flex; + flex-direction: column; + margin: auto; + width: 100%; + background-color: #003366fb; + position: absolute; + top: 60px; + left: 0; + padding: 1em 0; + } + .dark-mode #nav-toggle.open + #nav-content { + background-color: #1f1f1ffb; + } + + #nav-content a { + padding: 1em; + text-align: center; + width: 100%; + } + + #nav-content a:hover { + transform: scale(1.1); + } +} + +#nav-toggle.open .bar1 { + transform: rotate(-45deg) translate(-4px, 6px); +} + +#nav-toggle.open .bar2 { + opacity: 0; +} + +#nav-toggle.open .bar3 { + transform: rotate(45deg) translate(-4px, -6px); +} + +.bar1, +.bar2, +.bar3 { + width: 25px; + height: 3px; + background-color: white; + margin: 4px 30px; + transition: 0.4s; +} + +.gradient-bg { + background: linear-gradient(to bottom, #003366, #ffcc00); +} + +.dark-mode .gradient-bg { + background: linear-gradient(to bottom, #333333, #777777); +} + +.image-container { + display: flex; + justify-content: center; + align-items: center; +} + +.image-container img { + width: 100%; + height: auto; + max-width: 300px; + border-radius: 8px; + margin: 0 auto; +} + +.slick-slide { + display: flex; + flex-direction: column; + align-items: center; +} + +#navAction { + padding: 10px; + border-radius: 10px; + text-decoration: none; +} + +#modeToggle img { + width: 35%; + height: 35%; +} + +#modeToggle img:hover { + transform: scale(1.2); +} + +.slick-prev, +.slick-next { + color: #333; + font-size: 24px; + line-height: 1; + opacity: 0.75; + transition: opacity 0.3s ease; +} + +.slick-prev:hover, +.slick-next:hover { + opacity: 1; +} + +.slick-prev:before, +.slick-next:before { + font-family: "slick"; + font-size: 24px; +} + +.slick-prev:before { + content: "←"; +} + +.slick-next:before { + content: "→"; +} + +#logo { + display: flex; + align-items: center; + height: 100%; + padding-right: 20px; +} + +#logo img { + width: 160px; + height: auto; + margin-left: 10px; +} + +.navbar-item { + display: flex; + align-items: center; + height: 100%; + padding: 0 15px 0 15px; +} + +#navAction { + padding: 10px; + border-radius: 10px; + text-decoration: none; +} +.navbar-item a { + padding: 0 15px; + color: white; + text-decoration: none; + font-weight: bold; +} + +.dark-mode nav { + background-color: #1f1f1f; +} + +#header { + background-color: #003366; +} + +.dark-mode #header { + background-color: #1f1f1f; +} + +.dark-mode .bg-white { + background-color: #1f1f1f; + color: #ffffff; +} + +#nav-content { + background-color: transparent; +} + +.dark-mode #navAction { + background-color: #ffcc00; + color: #1f1f1f; +} + +nav a { + color: #ffffff; + transition: 0.3s; +} + +nav a:hover { + color: #ffcc00; +} + +.dark-mode nav a { + color: #ffffff; +} + +.dark-mode nav a:hover { + color: #ffcc00; +} + +#navAction { + background-color: #ffcc00; + color: #003366; +} + +#navAction:hover { + background-color: #ffa500; +} + +.dark-mode #navAction { + color: #1f1f1f; +} + +.dark-mode #navAction:hover { + background-color: #ffa500; +} + +body.dark-mode { + background-color: #121212; + color: #ffffff; +} + +body.dark-mode .bg-white { + background-color: #333333; + color: #ffffff; +} + +body.dark-mode .text-gray-800 { + color: #ffffff; +} + +body.dark-mode .text-gray-600 { + color: #bbbbbb; +} + +body.dark-mode .team-carousel .text-gray-800 { + color: #ffffff; +} + +body.dark-mode .team-carousel .text-gray-600 { + color: #bbbbbb; +} + +.waves { + position: relative; + width: 100%; + height: 15vh; + margin-bottom: -7px; + min-height: 100px; + max-height: 150px; +} + +.parallax > use { + animation: move-forever 25s cubic-bezier(0.55, 0.5, 0.45, 0.5) infinite; +} + +.parallax > use:nth-child(1) { + animation-delay: -2s; + animation-duration: 7s; +} + +.parallax > use:nth-child(2) { + animation-delay: -3s; + animation-duration: 10s; +} + +.parallax > use:nth-child(3) { + animation-delay: -4s; + animation-duration: 13s; +} + +.parallax > use:nth-child(4) { + animation-delay: -5s; + animation-duration: 20s; +} + +@keyframes move-forever { + 0% { + transform: translate3d(-90px, 0, 0); + } + 100% { + transform: translate3d(85px, 0, 0); + } +} + +.dark-mode .waves path { + fill: #333333; +} + +footer { + background-color: #003366; + color: #ffffff; + padding: 20px 0; + text-align: center; +} + +.dark-mode footer { + background-color: #1f1f1f; +} + +footer a { + color: #ffcc00; + text-decoration: none; +} + +footer a:hover { + text-decoration: underline; +} + +footer p { + margin: 0; + font-size: 14px; +} + +.download-app { + text-align: center; + margin-top: 10px; + margin-bottom: 15px; +} + +.download-app img { + width: 60px; + height: auto; + margin: auto; + transition: transform 0.3s; +} + +.download-app img:hover { + transform: scale(1.1); +} + +.download-app p { + margin: 0; +} +.download-app h2 { + font-size: 25px; + font-family: Cambria, Cochin, Georgia, Times, "Times New Roman", serif; +} diff --git a/frontend/.idea/.gitignore b/frontend/.idea/.gitignore deleted file mode 100644 index 26d33521..00000000 --- a/frontend/.idea/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml diff --git a/frontend/.idea/frontend.iml b/frontend/.idea/frontend.iml deleted file mode 100644 index 92e2a39e..00000000 --- a/frontend/.idea/frontend.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/frontend/.idea/misc.xml b/frontend/.idea/misc.xml deleted file mode 100644 index 639900d1..00000000 --- a/frontend/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/frontend/.idea/modules.xml b/frontend/.idea/modules.xml deleted file mode 100644 index f3d93d75..00000000 --- a/frontend/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/frontend/.idea/vcs.xml b/frontend/.idea/vcs.xml deleted file mode 100644 index 6c0b8635..00000000 --- a/frontend/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/frontend/sige_ie/.gitignore b/frontend/sige_ie/.gitignore deleted file mode 100644 index 29a3a501..00000000 --- a/frontend/sige_ie/.gitignore +++ /dev/null @@ -1,43 +0,0 @@ -# Miscellaneous -*.class -*.log -*.pyc -*.swp -.DS_Store -.atom/ -.buildlog/ -.history -.svn/ -migrate_working_dir/ - -# IntelliJ related -*.iml -*.ipr -*.iws -.idea/ - -# The .vscode folder contains launch configuration and tasks you configure in -# VS Code which you may wish to be included in version control, so this line -# is commented out by default. -#.vscode/ - -# Flutter/Dart/Pub related -**/doc/api/ -**/ios/Flutter/.last_build_id -.dart_tool/ -.flutter-plugins -.flutter-plugins-dependencies -.pub-cache/ -.pub/ -/build/ - -# Symbolication related -app.*.symbols - -# Obfuscation related -app.*.map.json - -# Android Studio will place build artifacts here -/android/app/debug -/android/app/profile -/android/app/release diff --git a/frontend/sige_ie/.metadata b/frontend/sige_ie/.metadata deleted file mode 100644 index aa90aa80..00000000 --- a/frontend/sige_ie/.metadata +++ /dev/null @@ -1,45 +0,0 @@ -# This file tracks properties of this Flutter project. -# Used by Flutter tool to assess capabilities and perform upgrades etc. -# -# This file should be version controlled and should not be manually edited. - -version: - revision: "ba393198430278b6595976de84fe170f553cc728" - channel: "stable" - -project_type: app - -# Tracks metadata for the flutter migrate command -migration: - platforms: - - platform: root - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: android - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: ios - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: linux - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: macos - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: web - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - platform: windows - create_revision: ba393198430278b6595976de84fe170f553cc728 - base_revision: ba393198430278b6595976de84fe170f553cc728 - - # User provided section - - # List of Local paths (relative to this file) that should be - # ignored by the migrate tool. - # - # Files that are not part of the templates will be ignored by default. - unmanaged_files: - - 'lib/main.dart' - - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/frontend/sige_ie/.vscode/settings.json b/frontend/sige_ie/.vscode/settings.json deleted file mode 100644 index 79eab2c1..00000000 --- a/frontend/sige_ie/.vscode/settings.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "workbench.colorCustomizations": { - "activityBar.activeBackground": "#3399ff", - "activityBar.background": "#3399ff", - "activityBar.foreground": "#15202b", - "activityBar.inactiveForeground": "#15202b99", - "activityBarBadge.background": "#bf0060", - "activityBarBadge.foreground": "#e7e7e7", - "commandCenter.border": "#e7e7e799", - "sash.hoverBorder": "#3399ff", - "statusBar.background": "#007fff", - "statusBar.foreground": "#e7e7e7", - "statusBarItem.hoverBackground": "#3399ff", - "statusBarItem.remoteBackground": "#007fff", - "statusBarItem.remoteForeground": "#e7e7e7", - "titleBar.activeBackground": "#007fff", - "titleBar.activeForeground": "#e7e7e7", - "titleBar.inactiveBackground": "#007fff99", - "titleBar.inactiveForeground": "#e7e7e799" - }, - "peacock.color": "#007fff" -} \ No newline at end of file diff --git a/frontend/sige_ie/README.md b/frontend/sige_ie/README.md deleted file mode 100644 index 1e0bc35c..00000000 --- a/frontend/sige_ie/README.md +++ /dev/null @@ -1,16 +0,0 @@ -# sige_ie - -A new Flutter project. - -## Getting Started - -This project is a starting point for a Flutter application. - -A few resources to get you started if this is your first Flutter project: - -- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) -- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) - -For help getting started with Flutter development, view the -[online documentation](https://docs.flutter.dev/), which offers tutorials, -samples, guidance on mobile development, and a full API reference. diff --git a/frontend/sige_ie/analysis_options.yaml b/frontend/sige_ie/analysis_options.yaml deleted file mode 100644 index 0d290213..00000000 --- a/frontend/sige_ie/analysis_options.yaml +++ /dev/null @@ -1,28 +0,0 @@ -# This file configures the analyzer, which statically analyzes Dart code to -# check for errors, warnings, and lints. -# -# The issues identified by the analyzer are surfaced in the UI of Dart-enabled -# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be -# invoked from the command line by running `flutter analyze`. - -# The following line activates a set of recommended lints for Flutter apps, -# packages, and plugins designed to encourage good coding practices. -include: package:flutter_lints/flutter.yaml - -linter: - # The lint rules applied to this project can be customized in the - # section below to disable rules from the `package:flutter_lints/flutter.yaml` - # included above or to enable additional rules. A list of all available lints - # and their documentation is published at https://dart.dev/lints. - # - # Instead of disabling a lint rule for the entire project in the - # section below, it can also be suppressed for a single line of code - # or a specific dart file by using the `// ignore: name_of_lint` and - # `// ignore_for_file: name_of_lint` syntax on the line or in the file - # producing the lint. - rules: - # avoid_print: false # Uncomment to disable the `avoid_print` rule - # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule - -# Additional information about this file can be found at -# https://dart.dev/guides/language/analysis-options diff --git a/frontend/sige_ie/android/.gitignore b/frontend/sige_ie/android/.gitignore deleted file mode 100644 index 6f568019..00000000 --- a/frontend/sige_ie/android/.gitignore +++ /dev/null @@ -1,13 +0,0 @@ -gradle-wrapper.jar -/.gradle -/captures/ -/gradlew -/gradlew.bat -/local.properties -GeneratedPluginRegistrant.java - -# Remember to never publicly share your keystore. -# See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app -key.properties -**/*.keystore -**/*.jks diff --git a/frontend/sige_ie/android/app/build.gradle b/frontend/sige_ie/android/app/build.gradle deleted file mode 100644 index 8233a549..00000000 --- a/frontend/sige_ie/android/app/build.gradle +++ /dev/null @@ -1,72 +0,0 @@ -plugins { - id "com.android.application" - id "kotlin-android" - id "dev.flutter.flutter-gradle-plugin" -} - -def localProperties = new Properties() -def localPropertiesFile = rootProject.file('local.properties') -if (localPropertiesFile.exists()) { - localPropertiesFile.withReader('UTF-8') { reader -> - localProperties.load(reader) - } -} - -def flutterVersionCode = localProperties.getProperty('flutter.versionCode') -if (flutterVersionCode == null) { - flutterVersionCode = '1' -} - -def flutterVersionName = localProperties.getProperty('flutter.versionName') -if (flutterVersionName == null) { - flutterVersionName = '1.0' -} - -android { - namespace "com.example.sige_ie" - compileSdk flutter.compileSdkVersion - ndkVersion flutter.ndkVersion - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - kotlinOptions { - jvmTarget = '1.8' - } - - sourceSets { - main.java.srcDirs += 'src/main/kotlin' - } - - defaultConfig { - applicationId "com.example.sige_ie" - // Defina os valores a seguir de acordo com as necessidades do seu aplicativo. - minSdkVersion 21 // Definido como 21 conforme sua especificação - targetSdkVersion 31 // Atualizado para apontar para a versão 31, que é a mais recente no momento - versionCode flutterVersionCode.toInteger() - versionName flutterVersionName - multiDexEnabled true // Ativado para suportar múltiplos DEX -} - - - buildTypes { - release { - // TODO: Add your own signing config for the release build. - // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug - } - } -} - -flutter { - source '../..' -} - -dependencies { - implementation 'androidx.multidex:multidex:2.0.1' - implementation 'com.google.android.gms:play-services-maps:18.0.2' - implementation 'com.google.android.gms:play-services-location:21.0.1' - implementation 'com.google.maps.android:android-maps-utils:2.3.0' -} diff --git a/frontend/sige_ie/android/app/src/debug/AndroidManifest.xml b/frontend/sige_ie/android/app/src/debug/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/frontend/sige_ie/android/app/src/debug/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/frontend/sige_ie/android/app/src/main/AndroidManifest.xml b/frontend/sige_ie/android/app/src/main/AndroidManifest.xml deleted file mode 100644 index 24e1cadb..00000000 --- a/frontend/sige_ie/android/app/src/main/AndroidManifest.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/android/app/src/main/kotlin/com/example/sige_ie/MainActivity.kt b/frontend/sige_ie/android/app/src/main/kotlin/com/example/sige_ie/MainActivity.kt deleted file mode 100644 index 9076008d..00000000 --- a/frontend/sige_ie/android/app/src/main/kotlin/com/example/sige_ie/MainActivity.kt +++ /dev/null @@ -1,5 +0,0 @@ -package com.example.sige_ie - -import io.flutter.embedding.android.FlutterActivity - -class MainActivity: FlutterActivity() diff --git a/frontend/sige_ie/android/app/src/main/res/drawable-v21/launch_background.xml b/frontend/sige_ie/android/app/src/main/res/drawable-v21/launch_background.xml deleted file mode 100644 index f74085f3..00000000 --- a/frontend/sige_ie/android/app/src/main/res/drawable-v21/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/frontend/sige_ie/android/app/src/main/res/drawable/launch_background.xml b/frontend/sige_ie/android/app/src/main/res/drawable/launch_background.xml deleted file mode 100644 index 304732f8..00000000 --- a/frontend/sige_ie/android/app/src/main/res/drawable/launch_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - diff --git a/frontend/sige_ie/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/frontend/sige_ie/android/app/src/main/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index db77bb4b..00000000 Binary files a/frontend/sige_ie/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/frontend/sige_ie/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/frontend/sige_ie/android/app/src/main/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index 17987b79..00000000 Binary files a/frontend/sige_ie/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/frontend/sige_ie/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/frontend/sige_ie/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 09d43914..00000000 Binary files a/frontend/sige_ie/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/frontend/sige_ie/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/frontend/sige_ie/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index d5f1c8d3..00000000 Binary files a/frontend/sige_ie/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/frontend/sige_ie/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/frontend/sige_ie/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 4d6372ee..00000000 Binary files a/frontend/sige_ie/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/frontend/sige_ie/android/app/src/main/res/values-night/styles.xml b/frontend/sige_ie/android/app/src/main/res/values-night/styles.xml deleted file mode 100644 index 06952be7..00000000 --- a/frontend/sige_ie/android/app/src/main/res/values-night/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/frontend/sige_ie/android/app/src/main/res/values/styles.xml b/frontend/sige_ie/android/app/src/main/res/values/styles.xml deleted file mode 100644 index cb1ef880..00000000 --- a/frontend/sige_ie/android/app/src/main/res/values/styles.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - diff --git a/frontend/sige_ie/android/app/src/profile/AndroidManifest.xml b/frontend/sige_ie/android/app/src/profile/AndroidManifest.xml deleted file mode 100644 index 399f6981..00000000 --- a/frontend/sige_ie/android/app/src/profile/AndroidManifest.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - diff --git a/frontend/sige_ie/android/build.gradle b/frontend/sige_ie/android/build.gradle deleted file mode 100644 index bc157bd1..00000000 --- a/frontend/sige_ie/android/build.gradle +++ /dev/null @@ -1,18 +0,0 @@ -allprojects { - repositories { - google() - mavenCentral() - } -} - -rootProject.buildDir = '../build' -subprojects { - project.buildDir = "${rootProject.buildDir}/${project.name}" -} -subprojects { - project.evaluationDependsOn(':app') -} - -tasks.register("clean", Delete) { - delete rootProject.buildDir -} diff --git a/frontend/sige_ie/android/gradle.properties b/frontend/sige_ie/android/gradle.properties deleted file mode 100644 index 598d13fe..00000000 --- a/frontend/sige_ie/android/gradle.properties +++ /dev/null @@ -1,3 +0,0 @@ -org.gradle.jvmargs=-Xmx4G -android.useAndroidX=true -android.enableJetifier=true diff --git a/frontend/sige_ie/android/gradle/wrapper/gradle-wrapper.properties b/frontend/sige_ie/android/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index e1ca574e..00000000 --- a/frontend/sige_ie/android/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,5 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-all.zip diff --git a/frontend/sige_ie/android/settings.gradle b/frontend/sige_ie/android/settings.gradle deleted file mode 100644 index 985a6e2e..00000000 --- a/frontend/sige_ie/android/settings.gradle +++ /dev/null @@ -1,26 +0,0 @@ -pluginManagement { - def flutterSdkPath = { - def properties = new Properties() - file("local.properties").withInputStream { properties.load(it) } - def flutterSdkPath = properties.getProperty("flutter.sdk") - assert flutterSdkPath != null, "flutter.sdk not set in local.properties" - return flutterSdkPath - } - settings.ext.flutterSdkPath = flutterSdkPath() - - includeBuild("${settings.ext.flutterSdkPath}/packages/flutter_tools/gradle") - - repositories { - google() - mavenCentral() - gradlePluginPortal() - } -} - -plugins { - id "dev.flutter.flutter-plugin-loader" version "1.0.0" - id "com.android.application" version "7.3.0" apply false - id "org.jetbrains.kotlin.android" version "1.9.22" apply false -} - -include ":app" diff --git a/frontend/sige_ie/assets/Loading.mp4 b/frontend/sige_ie/assets/Loading.mp4 deleted file mode 100644 index e7cd9901..00000000 Binary files a/frontend/sige_ie/assets/Loading.mp4 and /dev/null differ diff --git a/frontend/sige_ie/ios/.gitignore b/frontend/sige_ie/ios/.gitignore deleted file mode 100644 index 7a7f9873..00000000 --- a/frontend/sige_ie/ios/.gitignore +++ /dev/null @@ -1,34 +0,0 @@ -**/dgph -*.mode1v3 -*.mode2v3 -*.moved-aside -*.pbxuser -*.perspectivev3 -**/*sync/ -.sconsign.dblite -.tags* -**/.vagrant/ -**/DerivedData/ -Icon? -**/Pods/ -**/.symlinks/ -profile -xcuserdata -**/.generated/ -Flutter/App.framework -Flutter/Flutter.framework -Flutter/Flutter.podspec -Flutter/Generated.xcconfig -Flutter/ephemeral/ -Flutter/app.flx -Flutter/app.zip -Flutter/flutter_assets/ -Flutter/flutter_export_environment.sh -ServiceDefinitions.json -Runner/GeneratedPluginRegistrant.* - -# Exceptions to above rules. -!default.mode1v3 -!default.mode2v3 -!default.pbxuser -!default.perspectivev3 diff --git a/frontend/sige_ie/ios/Flutter/AppFrameworkInfo.plist b/frontend/sige_ie/ios/Flutter/AppFrameworkInfo.plist deleted file mode 100644 index 7c569640..00000000 --- a/frontend/sige_ie/ios/Flutter/AppFrameworkInfo.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - App - CFBundleIdentifier - io.flutter.flutter.app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - App - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1.0 - MinimumOSVersion - 12.0 - - diff --git a/frontend/sige_ie/ios/Flutter/Debug.xcconfig b/frontend/sige_ie/ios/Flutter/Debug.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/frontend/sige_ie/ios/Flutter/Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/frontend/sige_ie/ios/Flutter/Release.xcconfig b/frontend/sige_ie/ios/Flutter/Release.xcconfig deleted file mode 100644 index 592ceee8..00000000 --- a/frontend/sige_ie/ios/Flutter/Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "Generated.xcconfig" diff --git a/frontend/sige_ie/ios/Runner.xcodeproj/project.pbxproj b/frontend/sige_ie/ios/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index c6591a32..00000000 --- a/frontend/sige_ie/ios/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,616 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXBuildFile section */ - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 97C146E61CF9000F007C117D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 97C146ED1CF9000F007C117D; - remoteInfo = Runner; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 9705A1C41CF9048500538489 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; - 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; - 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; - 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; - 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; - 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 97C146EB1CF9000F007C117D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C8082294A63A400263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C807B294A618700263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 9740EEB11CF90186004384FC /* Flutter */ = { - isa = PBXGroup; - children = ( - 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 9740EEB31CF90195004384FC /* Generated.xcconfig */, - ); - name = Flutter; - sourceTree = ""; - }; - 97C146E51CF9000F007C117D = { - isa = PBXGroup; - children = ( - 9740EEB11CF90186004384FC /* Flutter */, - 97C146F01CF9000F007C117D /* Runner */, - 97C146EF1CF9000F007C117D /* Products */, - 331C8082294A63A400263BE5 /* RunnerTests */, - ); - sourceTree = ""; - }; - 97C146EF1CF9000F007C117D /* Products */ = { - isa = PBXGroup; - children = ( - 97C146EE1CF9000F007C117D /* Runner.app */, - 331C8081294A63A400263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 97C146F01CF9000F007C117D /* Runner */ = { - isa = PBXGroup; - children = ( - 97C146FA1CF9000F007C117D /* Main.storyboard */, - 97C146FD1CF9000F007C117D /* Assets.xcassets */, - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, - 97C147021CF9000F007C117D /* Info.plist */, - 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, - 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, - 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, - 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, - ); - path = Runner; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C8080294A63A400263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 331C807D294A63A400263BE5 /* Sources */, - 331C807F294A63A400263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C8086294A63A400263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 97C146ED1CF9000F007C117D /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 9740EEB61CF901F6004384FC /* Run Script */, - 97C146EA1CF9000F007C117D /* Sources */, - 97C146EB1CF9000F007C117D /* Frameworks */, - 97C146EC1CF9000F007C117D /* Resources */, - 9705A1C41CF9048500538489 /* Embed Frameworks */, - 3B06AD1E1E4923F5004D2608 /* Thin Binary */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = Runner; - productName = Runner; - productReference = 97C146EE1CF9000F007C117D /* Runner.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 97C146E61CF9000F007C117D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C8080294A63A400263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 97C146ED1CF9000F007C117D; - }; - 97C146ED1CF9000F007C117D = { - CreatedOnToolsVersion = 7.3.1; - LastSwiftMigration = 1100; - }; - }; - }; - buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 97C146E51CF9000F007C117D; - productRefGroup = 97C146EF1CF9000F007C117D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 97C146ED1CF9000F007C117D /* Runner */, - 331C8080294A63A400263BE5 /* RunnerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C807F294A63A400263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EC1CF9000F007C117D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, - 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, - 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", - ); - name = "Thin Binary"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; - }; - 9740EEB61CF901F6004384FC /* Run Script */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - name = "Run Script"; - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C807D294A63A400263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 97C146EA1CF9000F007C117D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, - 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 97C146ED1CF9000F007C117D /* Runner */; - targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 97C146FA1CF9000F007C117D /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C146FB1CF9000F007C117D /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; - 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { - isa = PBXVariantGroup; - children = ( - 97C147001CF9000F007C117D /* Base */, - ); - name = LaunchScreen.storyboard; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 249021D3217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Profile; - }; - 249021D4217E4FDB00AE95B9 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Profile; - }; - 331C8088294A63A400263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Debug; - }; - 331C8089294A63A400263BE5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Release; - }; - 331C808A294A63A400263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; - }; - name = Profile; - }; - 97C147031CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 97C147041CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu99; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = iphoneos; - SUPPORTED_PLATFORMS = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - TARGETED_DEVICE_FAMILY = "1,2"; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - 97C147061CF9000F007C117D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Debug; - }; - 97C147071CF9000F007C117D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; - ENABLE_BITCODE = NO; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; - SWIFT_VERSION = 5.0; - VERSIONING_SYSTEM = "apple-generic"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C8088294A63A400263BE5 /* Debug */, - 331C8089294A63A400263BE5 /* Release */, - 331C808A294A63A400263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147031CF9000F007C117D /* Debug */, - 97C147041CF9000F007C117D /* Release */, - 249021D3217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 97C147061CF9000F007C117D /* Debug */, - 97C147071CF9000F007C117D /* Release */, - 249021D4217E4FDB00AE95B9 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 97C146E61CF9000F007C117D /* Project object */; -} diff --git a/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/frontend/sige_ie/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/frontend/sige_ie/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/sige_ie/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index 8e3ca5df..00000000 --- a/frontend/sige_ie/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/ios/Runner.xcworkspace/contents.xcworkspacedata b/frontend/sige_ie/ios/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/frontend/sige_ie/ios/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/frontend/sige_ie/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/sige_ie/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/frontend/sige_ie/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/frontend/sige_ie/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/frontend/sige_ie/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings deleted file mode 100644 index f9b0d7c5..00000000 --- a/frontend/sige_ie/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - PreviewsEnabled - - - diff --git a/frontend/sige_ie/ios/Runner/AppDelegate.swift b/frontend/sige_ie/ios/Runner/AppDelegate.swift deleted file mode 100644 index 70693e4a..00000000 --- a/frontend/sige_ie/ios/Runner/AppDelegate.swift +++ /dev/null @@ -1,13 +0,0 @@ -import UIKit -import Flutter - -@UIApplicationMain -@objc class AppDelegate: FlutterAppDelegate { - override func application( - _ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? - ) -> Bool { - GeneratedPluginRegistrant.register(with: self) - return super.application(application, didFinishLaunchingWithOptions: launchOptions) - } -} diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index d36b1fab..00000000 --- a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada47..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png deleted file mode 100644 index 7353c41e..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png deleted file mode 100644 index 797d452e..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index 6ed2d933..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png deleted file mode 100644 index 4cd7b009..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index fe730945..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png deleted file mode 100644 index 321773cd..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png deleted file mode 100644 index 797d452e..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index 502f463a..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index 0ec30343..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index 0ec30343..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index e9f5fea2..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index 84ac32ae..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png deleted file mode 100644 index 8953cba0..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png deleted file mode 100644 index 0467bf12..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json deleted file mode 100644 index 0bedcf2f..00000000 --- a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "LaunchImage.png", - "scale" : "1x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@2x.png", - "scale" : "2x" - }, - { - "idiom" : "universal", - "filename" : "LaunchImage@3x.png", - "scale" : "3x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png deleted file mode 100644 index 9da19eac..00000000 Binary files a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png and /dev/null differ diff --git a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md deleted file mode 100644 index 89c2725b..00000000 --- a/frontend/sige_ie/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Launch Screen Assets - -You can customize the launch screen with your own desired assets by replacing the image files in this directory. - -You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/frontend/sige_ie/ios/Runner/Base.lproj/LaunchScreen.storyboard b/frontend/sige_ie/ios/Runner/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index f2e259c7..00000000 --- a/frontend/sige_ie/ios/Runner/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/ios/Runner/Base.lproj/Main.storyboard b/frontend/sige_ie/ios/Runner/Base.lproj/Main.storyboard deleted file mode 100644 index f3c28516..00000000 --- a/frontend/sige_ie/ios/Runner/Base.lproj/Main.storyboard +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/ios/Runner/Info.plist b/frontend/sige_ie/ios/Runner/Info.plist deleted file mode 100644 index 829c7ead..00000000 --- a/frontend/sige_ie/ios/Runner/Info.plist +++ /dev/null @@ -1,53 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Sige Ie - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - sige_ie - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS - - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - CADisableMinimumFrameDurationOnPhone - - UIApplicationSupportsIndirectInputEvents - - NSLocationWhenInUseUsageDescription - Este aplicativo precisa de acesso à sua localização para funcionar corretamente. - NSLocationAlwaysUsageDescription - Este aplicativo precisa de acesso constante à sua localização para oferecer os melhores serviços. - - diff --git a/frontend/sige_ie/ios/Runner/Runner-Bridging-Header.h b/frontend/sige_ie/ios/Runner/Runner-Bridging-Header.h deleted file mode 100644 index 308a2a56..00000000 --- a/frontend/sige_ie/ios/Runner/Runner-Bridging-Header.h +++ /dev/null @@ -1 +0,0 @@ -#import "GeneratedPluginRegistrant.h" diff --git a/frontend/sige_ie/ios/RunnerTests/RunnerTests.swift b/frontend/sige_ie/ios/RunnerTests/RunnerTests.swift deleted file mode 100644 index 86a7c3b1..00000000 --- a/frontend/sige_ie/ios/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import Flutter -import UIKit -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/frontend/sige_ie/lib/Teams/teams.dart b/frontend/sige_ie/lib/Teams/teams.dart deleted file mode 100644 index 8ccf8cdd..00000000 --- a/frontend/sige_ie/lib/Teams/teams.dart +++ /dev/null @@ -1,225 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; - -class TeamsPage extends StatefulWidget { - const TeamsPage({super.key}); - - @override - _TeamsPageState createState() => _TeamsPageState(); -} - -class _TeamsPageState extends State { - final List teams = [ - Team('Equipe 1', ['Membro 1', 'Membro 2', 'Membro 3']), - Team('Equipe 2', ['Membro 4', 'Membro 5']), - Team('Equipe 3', ['Membro 6', 'Membro 7', 'Membro 8']), - ]; - - void _addTeam(String teamName) { - setState(() { - teams.add(Team(teamName, [])); - }); - } - - void _removeTeam(int index) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: const Text('Você realmente deseja excluir esta equipe?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - setState(() { - teams.removeAt(index); - }); - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipe excluída com sucesso!'), - backgroundColor: Colors.green, - ), - ); - }, - ), - ], - ); - }, - ); - } - - void _switchTeam(String teamName) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Troca de Equipe'), - content: - Text('Você realmente deseja trocar para a equipe "$teamName"?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Trocar'), - onPressed: () { - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - content: Text( - 'Troca concluída. Você agora está na equipe "$teamName".'), - backgroundColor: Colors.green, - ), - ); - }, - ), - ], - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - automaticallyImplyLeading: false, - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 20), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Column( - children: [ - Text( - 'Equipes', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: teams.length, - itemBuilder: (context, index) { - final team = teams[index]; - return Card( - child: ListTile( - leading: const Icon(Icons.group, - color: AppColors.sigeIeBlue), - title: Text(team.name), - subtitle: Text('Membros: ${team.members.length}'), - trailing: IconButton( - icon: - const Icon(Icons.delete, color: AppColors.warn), - onPressed: () { - _removeTeam(index); - }, - ), - onTap: () { - _switchTeam(team.name); - }, - ), - ); - }, - ), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () { - showDialog( - context: context, - builder: (context) { - final TextEditingController _controller = TextEditingController(); - return AlertDialog( - title: const Text('Adicionar nova equipe'), - content: TextField( - controller: _controller, - decoration: const InputDecoration( - hintText: 'Digite o código da equipe', - ), - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(); - }, - child: const Text('Cancelar'), - ), - TextButton( - onPressed: () { - if (_controller.text.isNotEmpty) { - _addTeam(_controller.text); - Navigator.of(context).pop(); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipe adicionada com sucesso!'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Nome da equipe não pode ser vazio!'), - backgroundColor: Colors.red, - ), - ); - } - }, - child: const Text('Adicionar'), - ), - ], - ); - }, - ); - }, - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} - -class Team { - final String name; - final List members; - - Team(this.name, this.members); -} diff --git a/frontend/sige_ie/lib/areas/data/area_request_model.dart b/frontend/sige_ie/lib/areas/data/area_request_model.dart deleted file mode 100644 index 2cd56094..00000000 --- a/frontend/sige_ie/lib/areas/data/area_request_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class AreaRequestModel { - String name; - int? floor; - int? place; - - AreaRequestModel({required this.name, this.floor, this.place}); - - Map toJson() { - return { - 'name': name, - 'floor': floor, - 'place': place, - }; - } - - factory AreaRequestModel.fromJson(Map json) { - return AreaRequestModel( - name: json['name'], - floor: json['floor'], - place: json['place'], - ); - } -} diff --git a/frontend/sige_ie/lib/areas/data/area_response_model.dart b/frontend/sige_ie/lib/areas/data/area_response_model.dart deleted file mode 100644 index 28adcb04..00000000 --- a/frontend/sige_ie/lib/areas/data/area_response_model.dart +++ /dev/null @@ -1,31 +0,0 @@ -class AreaResponseModel { - int id; - String name; - int? floor; - int place; - - AreaResponseModel({ - required this.id, - required this.name, - this.floor, - required this.place, - }); - - factory AreaResponseModel.fromJson(Map json) { - return AreaResponseModel( - id: json['id'], - name: json['name'], - floor: json['floor'], - place: json['place'], - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'floor': floor, - 'place': place, - }; - } -} diff --git a/frontend/sige_ie/lib/areas/data/area_service.dart b/frontend/sige_ie/lib/areas/data/area_service.dart deleted file mode 100644 index 157117dc..00000000 --- a/frontend/sige_ie/lib/areas/data/area_service.dart +++ /dev/null @@ -1,101 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart'; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/areas/data/area_response_model.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; -import 'package:sige_ie/areas/data/area_request_model.dart'; - -class AreaService { - final Logger _logger = Logger('AreaService'); - Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - final String baseUrl = 'http://10.0.2.2:8000/api/areas/'; - - // POST -// POST - Future createArea( - AreaRequestModel areaRequestModel) async { - var url = Uri.parse(baseUrl); - print('URL: $url'); // Log da URL - print( - 'Request Body: ${jsonEncode(areaRequestModel.toJson())}'); // Log do corpo da requisição - - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(areaRequestModel.toJson()), - ); - - print( - 'Response Status Code: ${response.statusCode}'); // Log do status da resposta - print('Response Body: ${response.body}'); // Log do corpo da resposta - - if (response.statusCode == 201) { - var data = jsonDecode(response.body); - print('Response Data: $data'); // Log dos dados da resposta - return AreaResponseModel.fromJson(data); - } else { - print( - 'Failed to create area. Status Code: ${response.statusCode}'); // Log do erro com status code - throw Exception('Failed to create area'); - } - } - - // Fetch all areas for a specific place - Future> fetchAreasByPlaceId(int placeId) async { - var url = Uri.parse('http://10.0.2.2:8000/api/places/$placeId/areas/'); - var response = await client.get(url); - - if (response.statusCode == 200) { - List dataList = jsonDecode(response.body); - return dataList.map((data) => AreaResponseModel.fromJson(data)).toList(); - } else { - throw Exception('Failed to load areas for place $placeId'); - } - } - - // GET - Future fetchArea(int areaId) async { - var url = Uri.parse('$baseUrl$areaId/'); - var response = await client.get(url); - - if (response.statusCode == 200) { - var data = jsonDecode(response.body); - return AreaResponseModel.fromJson(data); - } else { - throw Exception('Failed to load area with ID $areaId'); - } - } - - // PUT - Future updateArea(int areaId, AreaRequestModel areaRequestModel) async { - var url = Uri.parse('$baseUrl$areaId/'); - - _logger.info('Sending PUT request to $url'); - _logger.info('Request body: ${jsonEncode(areaRequestModel.toJson())}'); - - var response = await client.put( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(areaRequestModel.toJson()), - ); - - _logger.info('Response status: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - return response.statusCode == 200; - } - - // DELETE - Future deleteArea(int areaId) async { - var url = Uri.parse('$baseUrl$areaId/'); - - var response = await client.delete(url); - - return response.statusCode == 204; - } -} diff --git a/frontend/sige_ie/lib/areas/feature/register/new_area.dart b/frontend/sige_ie/lib/areas/feature/register/new_area.dart deleted file mode 100644 index 9a2d4eee..00000000 --- a/frontend/sige_ie/lib/areas/feature/register/new_area.dart +++ /dev/null @@ -1,304 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/areas/data/area_response_model.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/areas/data/area_request_model.dart'; -import 'package:sige_ie/areas/data/area_service.dart'; - -class AreaLocation extends StatefulWidget { - final String localName; - final int localId; - - const AreaLocation( - {super.key, required this.localName, required this.localId}); - @override - _AreaLocationState createState() => _AreaLocationState(); -} - -class _AreaLocationState extends State { - int? selectedFloor; - final TextEditingController areaController = TextEditingController(); - final TextEditingController floorController = TextEditingController(); - - @override - void initState() { - super.initState(); - floorController.text = selectedFloor?.toString() ?? ''; - } - - @override - void dispose() { - areaController.dispose(); - floorController.dispose(); - super.dispose(); - } - - void logState() { - print('selectedFloor: $selectedFloor'); - print('areaController.text: ${areaController.text}'); - print('floorController.text: ${floorController.text}'); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - automaticallyImplyLeading: false, - ), - body: SingleChildScrollView( - child: Column( - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text('${widget.localName} - Área', - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - const SizedBox(height: 60), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - const Text('Andar', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black)), - IconButton( - icon: const Icon(Icons.info_outline), - onPressed: () { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: - const Text('Informação sobre os Andares'), - content: const Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text('0 = Térreo', - style: TextStyle(fontSize: 16)), - Text('1 = 1° Andar', - style: TextStyle(fontSize: 16)), - Text('2 = 2° Andar', - style: TextStyle(fontSize: 16)), - ], - ), - actions: [ - TextButton( - child: const Text('OK'), - onPressed: () => - Navigator.of(context).pop(), - ), - ], - ); - }, - ); - }, - ), - ], - ), - const SizedBox(height: 10), - Container( - padding: const EdgeInsets.symmetric(horizontal: 10), - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextFormField( - controller: floorController, - keyboardType: TextInputType.number, - decoration: const InputDecoration( - border: InputBorder.none, - ), - onChanged: (value) { - setState(() { - selectedFloor = int.tryParse(value); - }); - logState(); // Log the state after changing the value - }, - ), - ), - const SizedBox(height: 40), - const Text('Área', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black)), - const SizedBox(height: 10), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10)), - child: TextField( - controller: areaController, - decoration: const InputDecoration( - hintText: 'Digite o nome da Sala', - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 10), - ), - onChanged: (value) { - logState(); // Log the state after changing the value - }, - ), - ), - const SizedBox(height: 60), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: AppColors.lightText, - backgroundColor: AppColors.warn, - minimumSize: const Size(150, 50), - textStyle: const TextStyle( - fontWeight: FontWeight.bold, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onPressed: () { - Navigator.of(context) - .popUntil((route) => route.isFirst); - Navigator.pushReplacementNamed( - context, - '/homeScreen', - arguments: {'initialPage': 1}, - ); - }, - child: const Text('ENCERRAR'), - ), - ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: AppColors.lightText, - backgroundColor: AppColors.sigeIeBlue, - minimumSize: const Size(150, 50), - textStyle: const TextStyle( - fontWeight: FontWeight.bold, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onPressed: () async { - logState(); // Log the state before making the API call - if (selectedFloor != null && - areaController.text.isNotEmpty) { - AreaService areaService = AreaService(); - try { - AreaResponseModel newArea = - await areaService.createArea(AreaRequestModel( - name: areaController.text, - floor: selectedFloor, - place: widget.localId, - )); - print( - 'Sala Registrada: ${newArea.name} no ${newArea.floor}° andar'); - Navigator.pushNamed(context, '/systemLocation', - arguments: { - 'areaName': newArea.name, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': newArea.id, - }); - } catch (e) { - print('Erro ao criar sala: $e'); // Log the error - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Erro'), - content: Text("Falha ao criar sala: $e"), - actions: [ - TextButton( - child: const Text("OK"), - onPressed: () => - Navigator.of(context).pop(), - ), - ], - ); - }, - ); - } - } else { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Erro'), - content: const Text( - "Por favor, selecione um andar e digite o nome da sala"), - actions: [ - TextButton( - child: const Text("OK"), - onPressed: () => - Navigator.of(context).pop(), - ), - ], - ); - }, - ); - } - }, - child: const Text('CONTINUAR'), - ), - ], - ), - ], - ), - ), - ], - ), - ), - ); - } -} - -Widget _buildDropdown({ - required List items, - required String? value, - required void Function(String?) onChanged, -}) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 10), - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: DropdownButtonHideUnderline( - child: DropdownButtonFormField( - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(vertical: 4), - ), - value: value, - isExpanded: true, - items: items.map((String item) { - return DropdownMenuItem( - value: item, - child: Text(item), - ); - }).toList(), - onChanged: onChanged, - style: const TextStyle(color: Colors.black), - dropdownColor: Colors.grey[200], - ), - ), - ); -} - diff --git a/frontend/sige_ie/lib/config/app_styles.dart b/frontend/sige_ie/lib/config/app_styles.dart deleted file mode 100644 index beda3627..00000000 --- a/frontend/sige_ie/lib/config/app_styles.dart +++ /dev/null @@ -1,32 +0,0 @@ -import 'package:flutter/material.dart'; - -class AppColors { - static const Color sigeIeYellow = Color(0xFFF1F60E); - static const Color sigeIeBlue = Color(0xff123c75); - static const Color dartText = Color.fromRGBO(22, 22, 22, 1); - static const Color lightText = Color.fromARGB(255, 238, 233, 233); - static const Color warn = Color.fromARGB(255, 231, 27, 27); - static const Color accent = Color.fromARGB(255, 231, 85, 27); -} - -class AppButtonStyles { - static ButtonStyle warnButton = ElevatedButton.styleFrom( - backgroundColor: const Color.fromARGB(255, 231, 27, 27), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ); - static ButtonStyle accentButton = ElevatedButton.styleFrom( - backgroundColor: const Color.fromARGB(255, 231, 160, 27), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ); - static ButtonStyle standardButton = ElevatedButton.styleFrom( - backgroundColor: AppColors.sigeIeYellow, - foregroundColor: AppColors.sigeIeBlue, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ); -} diff --git a/frontend/sige_ie/lib/core/data/auth_interceptor.dart b/frontend/sige_ie/lib/core/data/auth_interceptor.dart deleted file mode 100644 index 2a752367..00000000 --- a/frontend/sige_ie/lib/core/data/auth_interceptor.dart +++ /dev/null @@ -1,29 +0,0 @@ -import 'package:cookie_jar/cookie_jar.dart'; -import 'package:http_interceptor/http_interceptor.dart'; - -class AuthInterceptor implements InterceptorContract { - CookieJar cookieJar; - - AuthInterceptor(this.cookieJar); - - @override - Future interceptRequest({required RequestData data}) async { - var cookies = await cookieJar - .loadForRequest(Uri.parse('http://10.0.2.2:8000/api/login/')); - Cookie? sessionCookie; - for (var cookie in cookies) { - if (cookie.name == 'sessionid') { - sessionCookie = cookie; - break; - } - } - data.headers - .addAll({'Cookie': '${sessionCookie!.name}=${sessionCookie.value}'}); - return data; - } - - @override - Future interceptResponse({required ResponseData data}) async { - return data; - } -} diff --git a/frontend/sige_ie/lib/core/data/auth_service.dart b/frontend/sige_ie/lib/core/data/auth_service.dart deleted file mode 100644 index b645f393..00000000 --- a/frontend/sige_ie/lib/core/data/auth_service.dart +++ /dev/null @@ -1,129 +0,0 @@ -import 'dart:convert'; -import 'package:cookie_jar/cookie_jar.dart'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class AuthService { - static Future fetchCsrfToken() async { - const String url = 'http://10.0.2.2:8000/api/csrfcookie/'; - final response = await http.get(Uri.parse(url)); - - if (response.statusCode == 200) { - String cookie = response.headers['set-cookie']!; - String csrfToken = cookie.split(';')[0].substring('csrftoken='.length); - - final csrfCookie = Cookie('csrftoken', csrfToken); - cookieJar.saveFromResponse( - Uri.parse('http://10.0.2.2:8000/api/csrftoken/'), [csrfCookie]); - - return csrfToken; - } else { - throw Exception('Falha ao obter o token CSRF: ${response.statusCode}'); - } - } - - static Future fetchSessionCookie() async { - const url = 'http://10.0.2.2:8000/api/sessioncookie/'; - final response = await http.get(Uri.parse(url)); - - if (response.statusCode == 200) { - final cookies = response.headers['set-cookie']?.split(','); - - String? sessionid; - if (cookies != null) { - for (var cookie in cookies) { - if (cookie.contains('sessionid')) { - sessionid = cookie.split(';')[0].split('=')[1]; - break; - } - } - } - return sessionid!; - } else { - throw Exception('Failed to fetch session cookie: ${response.statusCode}'); - } - } - - Future checkAuthenticated() async { - var client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - final response = - await client.get(Uri.parse('http://10.0.2.2:8000/api/checkauth/')); - - if (response.statusCode == 200) { - var data = jsonDecode(response.body); - return data['isAuthenticated']; - } else { - throw Exception('Failed to check authentication'); - } - } - - Future login(String username, String password) async { - //var csrfToken = await fetchCsrfToken(); - //print(csrfToken); - - var url = Uri.parse('http://10.0.2.2:8000/api/login/'); - - try { - var response = await http.post(url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode({ - 'username': username, - 'password': password, - })); - final cookies = response.headers['set-cookie']?.split(','); - - String? sessionid; - if (cookies != null) { - for (var cookie in cookies) { - if (cookie.contains('sessionid')) { - sessionid = cookie.split(';')[0].split('=')[1]; - break; - } - } - } - - final cookie = Cookie('sessionid', sessionid!); - cookieJar.saveFromResponse( - Uri.parse('http://10.0.2.2:8000/api/login/'), [cookie]); - - if (response.statusCode == 200) { - //print("Login bem-sucedido: $data"); - return true; - } else { - //print("Falha no login: ${response.body}"); - return false; - } - } catch (e) { - //print("Erro ao tentar fazer login: $e"); - return false; - } - } - - Future logout() async { - //final cookies = await cookieJar.loadForRequest(Uri.parse('http://10.0.2.2:8000/api/csrftoken/')); - - var url = Uri.parse('http://10.0.2.2:8000/api/logout/'); - - try { - var client = - InterceptedClient.build(interceptors: [AuthInterceptor(cookieJar)]); - var response = - await client.post(url, headers: {'Content-Type': 'application/json'}); - cookieJar.deleteAll(); - if (response.statusCode == 200) { - //print("Logout bem-sucedido"); - } else { - //print("Falha no logout: ${response.body}"); - //bool isAuth = await checkAuthenticated(); - //print(isAuth); - } - } catch (e) { - //print("Erro ao tentar fazer logout: $e"); - } - } -} diff --git a/frontend/sige_ie/lib/core/feature/login/login.dart b/frontend/sige_ie/lib/core/feature/login/login.dart deleted file mode 100644 index eb260119..00000000 --- a/frontend/sige_ie/lib/core/feature/login/login.dart +++ /dev/null @@ -1,268 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/core/data/auth_service.dart'; - -class LoginScreen extends StatefulWidget { - const LoginScreen({super.key}); - @override - State createState() => _LoginScreenState(); -} - -class _LoginScreenState extends State { - AuthService authService = AuthService(); - bool rememberMe = false; - final _loginScreen = GlobalKey(); - final TextEditingController usernameController = TextEditingController(); - final TextEditingController passwordController = TextEditingController(); - bool isLoading = false; - - @override - void dispose() { - usernameController.dispose(); - passwordController.dispose(); - super.dispose(); - } - - Future _login() async { - if (!_loginScreen.currentState!.validate()) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Por favor, preencha todos os campos')), - ); - return; - } - - setState(() { - isLoading = true; - }); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Processando dados')), - ); - - bool success = await authService.login( - usernameController.text, - passwordController.text, - ); - - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - - setState(() { - isLoading = false; - }); - - if (success) { - if (!mounted) return; - Navigator.of(context).pushReplacementNamed('/homeScreen'); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Login falhou, verifique suas credenciais')), - ); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xff123c75), - appBar: AppBar( - automaticallyImplyLeading: false, - iconTheme: const IconThemeData(color: Colors.white), - backgroundColor: const Color(0xff123c75), - ), - body: Center( - child: Column( - children: [ - Expanded( - flex: 2, - child: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/1000x1000.png'), - fit: BoxFit.cover, - ), - ), - ), - ), - Expanded( - flex: 6, - child: Container( - padding: const EdgeInsets.fromLTRB(25.0, 50.0, 25.0, 20.0), - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.only(topLeft: Radius.circular(50.0)), - ), - child: SingleChildScrollView( - child: Form( - key: _loginScreen, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Text( - 'Login', - style: TextStyle( - fontSize: 30.0, - fontWeight: FontWeight.w900, - color: Colors.black, - ), - ), - const SizedBox(height: 35), - TextFormField( - controller: usernameController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por favor, insira um username válido'; - } - return null; - }, - decoration: InputDecoration( - label: const Text('Username'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Insira o seu username', - hintStyle: const TextStyle( - color: Colors.black, - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 39, 38, 38), - ), - borderRadius: BorderRadius.circular(10), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 0, 0, 0), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - ), - const SizedBox(height: 20), - TextFormField( - controller: passwordController, - obscureText: true, - obscuringCharacter: '*', - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por favor, insira uma senha válida'; - } - return null; - }, - decoration: InputDecoration( - label: const Text('Senha'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Insira a senha', - hintStyle: const TextStyle( - color: Color.fromARGB(255, 0, 0, 0), - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(31, 255, 3, 3), - ), - borderRadius: BorderRadius.circular(10), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 0, 0, 0), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Checkbox( - value: rememberMe, - onChanged: (bool? value) { - setState(() { - rememberMe = value!; - }); - }, - activeColor: - const Color.fromARGB(255, 12, 78, 170), - ), - const Text( - 'Manter conectado', - style: TextStyle( - color: Color.fromARGB(255, 0, 0, 0), - ), - ), - ], - ), - GestureDetector( - child: const Text( - 'Esqueceu a senha?', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xff123c75), - ), - ), - ), - ], - ), - const SizedBox(height: 20), - SizedBox( - width: 200, - height: 50, - child: ElevatedButton( - onPressed: isLoading ? null : _login, - style: ElevatedButton.styleFrom( - elevation: 6, - backgroundColor: - const Color.fromARGB(255, 244, 248, 0), - foregroundColor: const Color(0xff123c75), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: isLoading - ? const CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Color(0xff123c75)), - ) - : const Text( - 'Login', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold), - ), - ), - ), - const SizedBox(height: 30), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Não tem uma conta? ', - style: TextStyle( - color: Color.fromARGB(255, 0, 0, 0)), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/registerScreen'); - }, - child: const Text( - 'Registre-se', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xff123c75), - ), - ), - ), - ], - ), - ], - ), - ), - ), - ), - ), - ], - ), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/core/feature/register/register.dart b/frontend/sige_ie/lib/core/feature/register/register.dart deleted file mode 100644 index 34da9010..00000000 --- a/frontend/sige_ie/lib/core/feature/register/register.dart +++ /dev/null @@ -1,355 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/users/data/user_request_model.dart'; -import 'package:sige_ie/users/data/user_service.dart'; - -class RegisterScreen extends StatefulWidget { - const RegisterScreen({super.key}); - @override - State createState() => _RegisterScreenState(); -} - -class _RegisterScreenState extends State { - UserService userService = UserService(); - bool terms = true; - bool isLoading = false; - final _registerScreen = GlobalKey(); - final usernameController = TextEditingController(); - final nameController = TextEditingController(); - final passwordController = TextEditingController(); - final emailController = TextEditingController(); - - Future _register() async { - if (!_registerScreen.currentState!.validate()) { - return; - } - - if (!terms) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Por Favor, concorde com o processamento de dados pessoais'), - ), - ); - return; - } - - setState(() { - isLoading = true; - }); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text('Processando Dados')), - ); - - final user = UserRequestModel( - username: usernameController.text, - firstname: nameController.text, - password: passwordController.text, - email: emailController.text, - ); - - bool success = await userService.register(user); - ScaffoldMessenger.of(context).hideCurrentSnackBar(); - - setState(() { - isLoading = false; - }); - - if (success) { - FocusScope.of(context).unfocus(); - Navigator.of(context).pushReplacementNamed('/loginScreen'); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Registro falhou, por favor tente novamente.'), - ), - ); - } - } - - @override - void dispose() { - usernameController.dispose(); - nameController.dispose(); - passwordController.dispose(); - emailController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: const Color(0xff123c75), - appBar: AppBar( - iconTheme: const IconThemeData(color: Colors.white), - backgroundColor: const Color(0xff123c75), - ), - body: Center( - child: Column( - children: [ - Expanded( - flex: 2, - child: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/1000x1000.png'), - fit: BoxFit.cover, - ), - ), - ), - ), - Expanded( - flex: 6, - child: Container( - padding: const EdgeInsets.fromLTRB(25.0, 50.0, 25.0, 20.0), - decoration: const BoxDecoration( - color: Colors.white, - borderRadius: - BorderRadius.only(topLeft: Radius.circular(50.0))), - child: SingleChildScrollView( - child: Form( - key: _registerScreen, - child: Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const Text('Registro', - style: TextStyle( - fontSize: 30.0, - fontWeight: FontWeight.w900, - color: Colors.black)), - const SizedBox(height: 35), - TextFormField( - controller: usernameController, - decoration: InputDecoration( - label: const Text('Username'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Insira o seu username', - hintStyle: const TextStyle( - color: Colors.black, - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 39, 38, 38), - ), - borderRadius: BorderRadius.circular(10), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 0, 0, 0), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por favor, insira um username válido'; - } - return null; - }, - ), - const SizedBox(height: 20), - TextFormField( - controller: nameController, - decoration: InputDecoration( - label: const Text('Nome'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Insira seu Nome', - hintStyle: const TextStyle( - color: Colors.black, - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 39, 38, 38), - ), - borderRadius: BorderRadius.circular(10), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 0, 0, 0), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por Favor Insira seu Nome'; - } - return null; - }, - ), - const SizedBox(height: 20), - TextFormField( - controller: emailController, - validator: (value) { - if (value == null || value.isEmpty) { - return 'Insira um email valido'; - } - return null; - }, - decoration: InputDecoration( - label: const Text('Email'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Insira o Email', - hintStyle: const TextStyle( - color: Colors.black, - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 39, 38, 38), - ), - borderRadius: BorderRadius.circular(10), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 0, 0, 0), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - ), - const SizedBox(height: 20), - TextFormField( - controller: passwordController, - obscureText: true, - obscuringCharacter: '*', - validator: (value) { - if (value == null || value.isEmpty) { - return 'Por Favor, insira uma senha valida'; - } - return null; - }, - decoration: InputDecoration( - label: const Text('Senha'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Insira a senha', - hintStyle: const TextStyle( - color: Color.fromARGB(255, 0, 0, 0), - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(31, 255, 3, 3), - ), - borderRadius: BorderRadius.circular(10), - ), - enabledBorder: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(255, 0, 0, 0), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - ), - const SizedBox(height: 20), - TextFormField( - obscureText: true, - obscuringCharacter: '*', - validator: (value) { - if (value == null || - value.isEmpty || - value != passwordController.text) { - return 'As senhas não coincidem'; - } - return null; - }, - decoration: InputDecoration( - label: const Text('Confirmar Senha'), - labelStyle: const TextStyle(color: Colors.black), - hintText: 'Confirme sua senha', - hintStyle: const TextStyle( - color: Color.fromARGB(255, 0, 0, 0), - ), - border: OutlineInputBorder( - borderSide: const BorderSide( - color: Color.fromARGB(31, 255, 3, 3), - ), - borderRadius: BorderRadius.circular(10), - ), - ), - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - children: [ - Checkbox( - value: terms, - onChanged: (bool? value) { - setState(() { - terms = value!; - }); - }, - activeColor: - const Color.fromARGB(255, 12, 78, 170), - ), - const Text( - 'Aceite os Termos', - style: TextStyle( - color: Color(0xff123c75), - ), - ), - ], - ), - ], - ), - const SizedBox(height: 20), - SizedBox( - width: 200, - height: 50, - child: ElevatedButton( - onPressed: isLoading ? null : _register, - style: ElevatedButton.styleFrom( - elevation: 6, - backgroundColor: - const Color.fromARGB(255, 244, 248, 0), - foregroundColor: const Color(0xff123c75), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: isLoading - ? const CircularProgressIndicator( - valueColor: AlwaysStoppedAnimation( - Color(0xff123c75)), - ) - : const Text( - 'Registro', - style: TextStyle( - fontSize: 20, - fontWeight: FontWeight.bold), - ), - ), - ), - const SizedBox(height: 30), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const Text( - 'Já tem uma conta? ', - style: TextStyle( - color: Color.fromARGB(255, 0, 0, 0)), - ), - GestureDetector( - onTap: () { - Navigator.pushNamed(context, '/loginScreen'); - }, - child: const Text( - 'Fazer login', - style: TextStyle( - fontWeight: FontWeight.bold, - color: Color(0xff123c75), - ), - ), - ), - ], - ), - const SizedBox(height: 10), - ], - ), - )), - )) - ], - ), - )); - } -} diff --git a/frontend/sige_ie/lib/core/ui/first_scren.dart b/frontend/sige_ie/lib/core/ui/first_scren.dart deleted file mode 100644 index cc91a5e5..00000000 --- a/frontend/sige_ie/lib/core/ui/first_scren.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter/material.dart'; - -class FirstScreen extends StatelessWidget { - const FirstScreen({super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Color(0xFF6399BE), - body: Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.asset('assets/UNB.png'), - Image.asset('assets/1000x1000Horizontal.png'), - const SizedBox( - height: 140, - ), - ElevatedButton( - onPressed: () { - Navigator.pushNamed(context, '/loginScreen'); - }, - style: ElevatedButton.styleFrom( - elevation: 6, - minimumSize: const Size(200, 50), - backgroundColor: const Color(0xfff1f60e), - foregroundColor: const Color(0xff123c75), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - "Login", - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - ), - const SizedBox( - height: 15, - ), - ElevatedButton( - onPressed: () { - Navigator.pushNamed(context, '/registerScreen'); - }, - style: ElevatedButton.styleFrom( - elevation: 6, - minimumSize: const Size(200, 50), - backgroundColor: const Color(0xfff1f60e), - foregroundColor: const Color(0xff123c75), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(12), - ), - ), - child: const Text( - "Registro", - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - ), - ], - ), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/core/ui/splash_screen.dart b/frontend/sige_ie/lib/core/ui/splash_screen.dart deleted file mode 100644 index 519d9d9f..00000000 --- a/frontend/sige_ie/lib/core/ui/splash_screen.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:video_player/video_player.dart'; - -class SplashScreen extends StatefulWidget { - const SplashScreen({super.key}); - - @override - _SplashScreenState createState() => _SplashScreenState(); -} - -class _SplashScreenState extends State { - VideoPlayerController? _controller; - - @override - void initState() { - super.initState(); - _controller = VideoPlayerController.asset('assets/Loading.mp4') - ..initialize().then((_) { - setState(() {}); - _controller!.play(); - _controller!.setLooping(false); - _controller!.addListener(checkVideo); - }); - } - - void checkVideo() { - if (_controller!.value.position == _controller!.value.duration) { - Navigator.pushReplacementNamed(context, '/first'); - } - } - - @override - void dispose() { - _controller!.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - backgroundColor: Colors.black, - body: Center( - child: _controller != null && _controller!.value.isInitialized - ? SizedBox.expand( - child: FittedBox( - fit: BoxFit.cover, - child: SizedBox( - width: _controller!.value.size.width, - height: _controller!.value.size.height, - child: VideoPlayer(_controller!), - ), - ), - ) - : const CircularProgressIndicator(), // Mostra o indicador de carregamento enquanto o vídeo está carregando - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_equipment_request_model.dart deleted file mode 100644 index 12b9ed71..00000000 --- a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/atmospheric/atmospheric_request_model.dart'; - -class AtmosphericEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - AtmosphericRequestModel? atmosphericRequestModel; - - AtmosphericEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.atmosphericRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'atmospheric_discharge_equipment': atmosphericRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_request_model.dart b/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_request_model.dart deleted file mode 100644 index b5be154e..00000000 --- a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class AtmosphericRequestModel { - int? area; - int? system; - - AtmosphericRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_response_model.dart b/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_response_model.dart deleted file mode 100644 index dab15cc6..00000000 --- a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class AtmosphericEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - AtmosphericEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory AtmosphericEquipmentResponseModel.fromJson( - Map json) { - return AtmosphericEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_service.dart b/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_service.dart deleted file mode 100644 index b58013e8..00000000 --- a/frontend/sige_ie/lib/equipments/data/atmospheric/atmospheric_service.dart +++ /dev/null @@ -1,41 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class AtmosphericEquipmentService { - final Logger _logger = Logger('AtmosphericEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getAtmosphericListByArea(int areaId) async { - final url = '${baseUrl}atmospheric-discharges/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load atmospheric-discharges equipment'); - } - } catch (e) { - _logger - .info('Error during get atmospheric-discharges equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/distribution/distribution_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/distribution/distribution_equipment_request_model.dart deleted file mode 100644 index eda6a289..00000000 --- a/frontend/sige_ie/lib/equipments/data/distribution/distribution_equipment_request_model.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:sige_ie/equipments/data/distribution/distribution_request_model.dart'; - -class DistributionEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - DistributionRequestModel? distributionRequestModel; - String? power; - bool dr; - bool dps; - bool grounding; - String? typeMaterial; - String? methodInstallation; - - DistributionEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.distributionRequestModel, - this.power, - this.dr = false, - this.dps = false, - this.grounding = false, - this.typeMaterial, - this.methodInstallation, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'distribution_board_equipment': distributionRequestModel?.toJson(), - 'power': power, - 'dr': dr, - 'dps': dps, - 'grounding': grounding, - 'type_material': typeMaterial, - 'method_installation': methodInstallation, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/distribution/distribution_request_model.dart b/frontend/sige_ie/lib/equipments/data/distribution/distribution_request_model.dart deleted file mode 100644 index 031a4684..00000000 --- a/frontend/sige_ie/lib/equipments/data/distribution/distribution_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class DistributionRequestModel { - int? area; - int? system; - - DistributionRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/distribution/distribution_response_model.dart b/frontend/sige_ie/lib/equipments/data/distribution/distribution_response_model.dart deleted file mode 100644 index c0c300a0..00000000 --- a/frontend/sige_ie/lib/equipments/data/distribution/distribution_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class DistributionEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - DistributionEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory DistributionEquipmentResponseModel.fromJson( - Map json) { - return DistributionEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/distribution/distribution_service.dart b/frontend/sige_ie/lib/equipments/data/distribution/distribution_service.dart deleted file mode 100644 index baefcef3..00000000 --- a/frontend/sige_ie/lib/equipments/data/distribution/distribution_service.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class DistributionEquipmentService { - final Logger _logger = Logger('DistributionEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getDistributionListByArea(int areaId) async { - final url = '${baseUrl}distribution-boards/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load distribution-boards equipment'); - } - } catch (e) { - _logger.info('Error during get distribution-boards equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_equipment_request_model.dart deleted file mode 100644 index f894742e..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/eletrical-load/eletrical_load_request_model.dart.dart'; - -class EletricalLoadEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - EletricalLoadRequestModel? eletricalLoadRequestModel; - - EletricalLoadEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.eletricalLoadRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'electrical_load_equipment': eletricalLoadRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_request_model.dart.dart b/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_request_model.dart.dart deleted file mode 100644 index 50d38722..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_request_model.dart.dart +++ /dev/null @@ -1,16 +0,0 @@ -class EletricalLoadRequestModel { - int? area; - int? system; - - EletricalLoadRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_response_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_response_model.dart deleted file mode 100644 index 9a950c3a..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class EletricalLoadEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - EletricalLoadEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory EletricalLoadEquipmentResponseModel.fromJson( - Map json) { - return EletricalLoadEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_service.dart b/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_service.dart deleted file mode 100644 index 189b2b54..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical-load/eletrical_load_service.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class EletricalLoadEquipmentService { - final Logger _logger = Logger('EletricalLoadEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getEletricalLoadListByArea(int areaId) async { - final url = '${baseUrl}electrical-loads/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load electrical-loads equipment'); - } - } catch (e) { - _logger.info('Error during get electrical-loads equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_equipment_request_model.dart deleted file mode 100644 index 7ecf5095..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/eletrical_circuit/eletrical_circuit_request_model.dart'; - -class EletricalCircuitEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - EletricalCircuitRequestModel? eletricalCircuitRequestModel; - - EletricalCircuitEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.eletricalCircuitRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'electrical_circuit_equipment': eletricalCircuitRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_request_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_request_model.dart deleted file mode 100644 index 8068d3c5..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class EletricalCircuitRequestModel { - int? area; - int? system; - - EletricalCircuitRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_response_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_response_model.dart deleted file mode 100644 index 926c7a8f..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class EletricalCircuitEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - EletricalCircuitEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory EletricalCircuitEquipmentResponseModel.fromJson( - Map json) { - return EletricalCircuitEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_service.dart b/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_service.dart deleted file mode 100644 index 48c34588..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_circuit/eletrical_circuit_service.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class EletricalCircuitEquipmentService { - final Logger _logger = Logger('EletricalCircuitEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getEletricalCircuitListByArea(int areaId) async { - final url = '${baseUrl}electrical-circuits/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load electrical-circuits equipment'); - } - } catch (e) { - _logger.info('Error during get electrical-circuits equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_equipment_request_model.dart deleted file mode 100644 index 9377f5f6..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/eletrical_line/eletrical_line_request_model.dart'; - -class EletricalLineEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - EletricalLineRequestModel? eletricalLineRequestModel; - - EletricalLineEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.eletricalLineRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'electrical_line_equipment': eletricalLineRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_request_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_request_model.dart deleted file mode 100644 index 9bb93058..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class EletricalLineRequestModel { - int? area; - int? system; - - EletricalLineRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_response_model.dart b/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_response_model.dart deleted file mode 100644 index c1653dbf..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class EletricalLineEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - EletricalLineEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory EletricalLineEquipmentResponseModel.fromJson( - Map json) { - return EletricalLineEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_service.dart b/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_service.dart deleted file mode 100644 index 53db71ea..00000000 --- a/frontend/sige_ie/lib/equipments/data/eletrical_line/eletrical_line_service.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class EletricalLineEquipmentService { - final Logger _logger = Logger('EletricalLineEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getElectricalLineListByArea(int areaId) async { - final url = '${baseUrl}electrical-lines/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load electrical-lines equipment'); - } - } catch (e) { - _logger.info('Error during get electrical-lines equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/equipment_service.dart b/frontend/sige_ie/lib/equipments/data/equipment_service.dart deleted file mode 100644 index be56b2f0..00000000 --- a/frontend/sige_ie/lib/equipments/data/equipment_service.dart +++ /dev/null @@ -1,332 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/equipments/data/atmospheric/atmospheric_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/distribution/distribution_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/eletrical-load/eletrical_load_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/eletrical_circuit/eletrical_circuit_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/eletrical_line/eletrical_line_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/refrigerations/refrigerations_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/iluminations/ilumination__equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_equipment_request_model.dart'; -import 'package:sige_ie/main.dart'; - -class EquipmentService { - final Logger _logger = Logger('EquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/equipments/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getEquipmentById(int equipmentId) async { - var url = Uri.parse('http://10.0.2.2:8000/api/equipments/$equipmentId/'); - try { - var response = await client.get(url); - if (response.statusCode == 200) { - return jsonDecode(response.body); - } else { - _logger.info( - 'Failed to load equipment with status code: ${response.statusCode}'); - throw Exception('Failed to load equipment'); - } - } catch (e) { - _logger.info('Error during get equipment: $e'); - throw Exception('Failed to load equipment'); - } - } - - Future updateEquipment(int id, Map data) async { - var url = Uri.parse('http://10.0.2.2:8000/api/equipments/$id/'); - - try { - var response = await client.put( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(data), - ); - - if (response.statusCode == 200) { - _logger.info('Successfully updated equipment type with ID: $id'); - return true; - } else { - _logger.info( - 'Failed to update equipment type with status code: ${response.statusCode}'); - return false; - } - } catch (e) { - _logger.info('Error during update equipment type: $e'); - return false; - } - } - - Future createFireAlarm( - FireAlarmEquipmentRequestModel fireAlarmEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(fireAlarmEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register fire alarm equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createStructuredCabling( - StructuredCablingEquipmentRequestModel - structuredCablingEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(structuredCablingEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register structured cabling equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createIlumination( - IluminationEquipmentRequestModel - illuminationEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(illuminationEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register illumination equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createElectricalLoad( - EletricalLoadEquipmentRequestModel - electricalLoadEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(electricalLoadEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register electrical load equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createElectricalLine( - EletricalLineEquipmentRequestModel - electricalLineEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(electricalLineEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register electrical line equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createElectricalCircuit( - EletricalCircuitEquipmentRequestModel - electricalCircuitEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(electricalCircuitEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register electrical circuit equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createDistribution( - DistributionEquipmentRequestModel - distributionEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(distributionEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register distribution equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createRefrigerations( - RefrigerationsEquipmentRequestModel - refrigerationsEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(refrigerationsEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register refrigeration equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - Future createAtmospheric( - AtmosphericEquipmentRequestModel atmosphericEquipmentRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(atmosphericEquipmentRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register atmospheric equipment: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_equipment_request_model.dart deleted file mode 100644 index 175b868d..00000000 --- a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_request_model.dart'; - -class FireAlarmEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - FireAlarmRequestModel? fireAlarmRequestModel; - - FireAlarmEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.fireAlarmRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'fire_alarm_equipment': fireAlarmRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_request_model.dart b/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_request_model.dart deleted file mode 100644 index b84ecd16..00000000 --- a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_request_model.dart +++ /dev/null @@ -1,19 +0,0 @@ -class FireAlarmRequestModel { - int? area; - int? system; - int? quantity; - - FireAlarmRequestModel({ - required this.area, - required this.system, - this.quantity, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - 'quantity': quantity, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_response_by_area_model.dart b/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_response_by_area_model.dart deleted file mode 100644 index ef320836..00000000 --- a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_response_by_area_model.dart +++ /dev/null @@ -1,26 +0,0 @@ -class FireAlarmEquipmentResponseByAreaModel { - int id; - int area; - String equipmentCategory; - int system; - int quantity; - - FireAlarmEquipmentResponseByAreaModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - required this.quantity, - }); - - factory FireAlarmEquipmentResponseByAreaModel.fromJson( - Map json) { - return FireAlarmEquipmentResponseByAreaModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - quantity: json['quantity'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_response_model.dart b/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_response_model.dart deleted file mode 100644 index c6430edf..00000000 --- a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_response_model.dart +++ /dev/null @@ -1,25 +0,0 @@ -class FireAlarmResponseModel { - int id; - int area; - int equipment; - int system; - int quantity; - - FireAlarmResponseModel({ - required this.id, - required this.area, - required this.equipment, - required this.system, - required this.quantity, - }); - - factory FireAlarmResponseModel.fromJson(Map json) { - return FireAlarmResponseModel( - id: json['id'], - area: json['area'], - equipment: json['equipment'], - system: json['system'], - quantity: json['quantity'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_service.dart b/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_service.dart deleted file mode 100644 index 579ca036..00000000 --- a/frontend/sige_ie/lib/equipments/data/fire_alarm/fire_alarm_service.dart +++ /dev/null @@ -1,103 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_request_model.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_response_by_area_model.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_response_model.dart'; -import 'package:sige_ie/main.dart'; - -class FireAlarmEquipmentService { - final Logger _logger = Logger('FireAlarmEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getFireAlarmListByArea( - int areaId) async { - var url = Uri.parse('${baseUrl}fire-alarms/by-area/$areaId/'); - try { - var response = await client.get(url); - - if (response.statusCode == 200) { - List dataList = jsonDecode(response.body); - return dataList - .map((data) => FireAlarmEquipmentResponseByAreaModel.fromJson(data)) - .toList(); - } else { - _logger.info( - 'Failed to load fire alarm equipment with status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - throw Exception('Failed to load fire alarm equipment'); - } - } catch (e) { - _logger.info('Error during get fire alarm equipment list: $e'); - throw Exception('Failed to load fire alarm equipment'); - } - } - - Future deleteFireAlarm(int fireAlarmId) async { - var url = Uri.parse('${baseUrl}fire-alarms/$fireAlarmId/'); - try { - var response = await client.delete(url); - if (response.statusCode == 204) { - _logger.info( - 'Successfully deleted fire alarm equipment with ID: $fireAlarmId'); - } else { - _logger.info( - 'Failed to delete fire alarm equipment with status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - throw Exception('Failed to delete fire alarm equipment'); - } - } catch (e) { - _logger.info('Error during delete fire alarm equipment: $e'); - throw Exception('Failed to delete fire alarm equipment'); - } - } - - Future getFireAlarmById(int fireAlarmId) async { - var url = Uri.parse('${baseUrl}fire-alarms/$fireAlarmId/'); - try { - var response = await client.get(url); - if (response.statusCode == 200) { - var jsonResponse = jsonDecode(response.body); - return FireAlarmResponseModel.fromJson(jsonResponse); - } else { - _logger.info( - 'Failed to load fire alarm with status code: ${response.statusCode}'); - throw Exception('Failed to load fire alarm'); - } - } catch (e) { - _logger.info('Error during get fire alarm: $e'); - throw Exception('Failed to load fire alarm'); - } - } - - Future updateFireAlarm( - int fireAlarmId, FireAlarmRequestModel fireAlarmRequestModel) async { - var url = Uri.parse('${baseUrl}fire-alarms/$fireAlarmId/'); - - try { - var response = await client.put( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(fireAlarmRequestModel.toJson()), - ); - - if (response.statusCode == 200) { - _logger.info( - 'Successfully updated fire alarm equipment with ID: $fireAlarmId'); - return true; - } else { - _logger.info( - 'Failed to update fire alarm equipment with status code: ${response.statusCode}'); - return false; - } - } catch (e) { - _logger.info('Error during update fire alarm equipment: $e'); - return false; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination__equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/iluminations/ilumination__equipment_request_model.dart deleted file mode 100644 index efd20485..00000000 --- a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination__equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/iluminations/ilumination_request_model.dart'; - -class IluminationEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - IluminationRequestModel? iluminationRequestModel; - - IluminationEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.iluminationRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'ilumination_equipment': iluminationRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_request_model.dart b/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_request_model.dart deleted file mode 100644 index c3b44740..00000000 --- a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class IluminationRequestModel { - int? area; - int? system; - - IluminationRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_request_response.dart b/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_request_response.dart deleted file mode 100644 index 66238ad1..00000000 --- a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_request_response.dart +++ /dev/null @@ -1,23 +0,0 @@ -class IluminationEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - IluminationEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory IluminationEquipmentResponseModel.fromJson( - Map json) { - return IluminationEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_service.dart b/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_service.dart deleted file mode 100644 index 28f20cdd..00000000 --- a/frontend/sige_ie/lib/equipments/data/iluminations/ilumination_service.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class IluminationEquipmentService { - final Logger _logger = Logger('IluminationEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getIluminationListByArea(int areaId) async { - final url = '${baseUrl}iluminations/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load ilumination equipment'); - } - } catch (e) { - _logger.info('Error during get ilumination equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_equipment_request_model.dart deleted file mode 100644 index ad35b02b..00000000 --- a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/refrigerations/refrigerations_request_model.dart'; - -class RefrigerationsEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - RefrigerationsRequestModel? refrigerationsRequestModel; - - RefrigerationsEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.refrigerationsRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'refrigeration_equipment': refrigerationsRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_request_model.dart b/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_request_model.dart deleted file mode 100644 index 231942f8..00000000 --- a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class RefrigerationsRequestModel { - int? area; - int? system; - - RefrigerationsRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_response_model.dart b/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_response_model.dart deleted file mode 100644 index 9e03c896..00000000 --- a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class RefrigerationsEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - RefrigerationsEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory RefrigerationsEquipmentResponseModel.fromJson( - Map json) { - return RefrigerationsEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_service.dart b/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_service.dart deleted file mode 100644 index 32eabb58..00000000 --- a/frontend/sige_ie/lib/equipments/data/refrigerations/refrigerations_service.dart +++ /dev/null @@ -1,40 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; - -class RefrigerationsEquipmentService { - final Logger _logger = Logger('RefrigerationsEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> getRefrigerationsListByArea(int areaId) async { - final url = '${baseUrl}refrigeration/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data.map((item) { - if (item['equipment'].containsKey('generic_equipment_category')) { - return item['equipment']['generic_equipment_category'] as String; - } else if (item['equipment'] - .containsKey('personal_equipment_category')) { - return item['equipment']['personal_equipment_category'] as String; - } else { - return 'Unknown Equipment'; - } - }).toList(); - } else { - throw Exception('Failed to load ilumination equipment'); - } - } catch (e) { - _logger.info('Error during get ilumination equipment list: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_equipment_request_model.dart b/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_equipment_request_model.dart deleted file mode 100644 index 64cad126..00000000 --- a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_equipment_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_request_model.dart'; - -class StructuredCablingEquipmentRequestModel { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - StructuredCablingRequestModel? structuredCablingRequestModel; - - StructuredCablingEquipmentRequestModel({ - required this.genericEquipmentCategory, - required this.personalEquipmentCategory, - required this.structuredCablingRequestModel, - }); - - Map toJson() { - return { - 'generic_equipment_category': genericEquipmentCategory, - 'personal_equipment_category': personalEquipmentCategory, - 'structured_cabling_equipment': structuredCablingRequestModel?.toJson(), - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_request_model.dart b/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_request_model.dart deleted file mode 100644 index df7c53b9..00000000 --- a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class StructuredCablingRequestModel { - int? area; - int? system; - - StructuredCablingRequestModel({ - required this.area, - required this.system, - }); - - Map toJson() { - return { - 'area': area, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_response_model.dart b/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_response_model.dart deleted file mode 100644 index 7d3c05e8..00000000 --- a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_response_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class StructuredCablingEquipmentResponseModel { - int id; - int area; - String equipmentCategory; - int system; - - StructuredCablingEquipmentResponseModel({ - required this.id, - required this.area, - required this.equipmentCategory, - required this.system, - }); - - factory StructuredCablingEquipmentResponseModel.fromJson( - Map json) { - return StructuredCablingEquipmentResponseModel( - id: json['id'], - area: json['area'], - equipmentCategory: json['equipment_category'], - system: json['system'], - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_service.dart b/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_service.dart deleted file mode 100644 index 59d278a1..00000000 --- a/frontend/sige_ie/lib/equipments/data/structured_cabling/structured_cabling_service.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_response_model.dart'; - -class StructuredCablingEquipmentService { - final Logger _logger = Logger('StructuredCablingEquipmentService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> - getStructuredCablingListByArea(int areaId) async { - final url = '${baseUrl}structured-cabling/by-area/$areaId'; - try { - final response = await client.get(Uri.parse(url)); - if (response.statusCode == 200) { - final List data = json.decode(response.body); - _logger.info('API response data: $data'); - return data - .map((item) => - StructuredCablingEquipmentResponseModel.fromJson(item)) - .toList(); - } else { - _logger.severe( - 'Failed to load structured-cabling equipment with status code: ${response.statusCode}, response body: ${response.body}'); - throw Exception( - 'Failed to load structured-cabling equipment with status code: ${response.statusCode}'); - } - } catch (e) { - _logger.severe('Error during get structured-cabling equipment list: $e'); - throw Exception('Failed to load structured-cabling equipment. Error: $e'); - } - } - - Future deleteStructuredCabling(int structuredCablingId) async { - var url = Uri.parse('${baseUrl}structured-cabling/$structuredCablingId/'); - try { - var response = await client.delete(url); - if (response.statusCode == 204) { - _logger.info( - 'Successfully deleted structured cabling equipment with ID: $structuredCablingId'); - } else { - _logger.info( - 'Failed to delete structured cabling equipment with status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - throw Exception('Failed to delete structured cabling equipment'); - } - } catch (e) { - _logger.info('Error during delete structured cabling equipment: $e'); - throw Exception('Failed to delete structured cabling equipment'); - } - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/atmospheric-discharges/add_atmospheric_discharges_equipment.dart b/frontend/sige_ie/lib/equipments/feature/atmospheric-discharges/add_atmospheric_discharges_equipment.dart deleted file mode 100644 index 9d27d064..00000000 --- a/frontend/sige_ie/lib/equipments/feature/atmospheric-discharges/add_atmospheric_discharges_equipment.dart +++ /dev/null @@ -1,800 +0,0 @@ -import 'dart:io'; -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/atmospheric/atmospheric_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/atmospheric/atmospheric_request_model.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddAtmosphericEquipmentScreen extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddAtmosphericEquipmentScreen({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddEquipmentScreenState createState() => _AddEquipmentScreenState(); -} - -class _AddEquipmentScreenState extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentQuantityController = TextEditingController(); - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentQuantityController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int personalCategoryId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(personalCategoryId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentQuantityController.text.isEmpty || - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final AtmosphericRequestModel atmosphericModel = AtmosphericRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final AtmosphericEquipmentRequestModel atmosphericEquipmentDetail = - AtmosphericEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - atmosphericRequestModel: atmosphericModel, - ); - - int? equipmentId = - await equipmentService.createAtmospheric(atmosphericEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listatmosphericEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentQuantityController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentQuantityController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listatmosphericEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar equipamento', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de equipamento', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': 'Selecione o tipo de equipamento', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != 'Selecione o tipo de equipamento') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de equipamento', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de equipamento' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/atmospheric-discharges/atmospheric_discharges_list.dart b/frontend/sige_ie/lib/equipments/feature/atmospheric-discharges/atmospheric_discharges_list.dart deleted file mode 100644 index 67a461b8..00000000 --- a/frontend/sige_ie/lib/equipments/feature/atmospheric-discharges/atmospheric_discharges_list.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/atmospheric/atmospheric_service.dart'; -import 'package:sige_ie/equipments/feature/atmospheric-discharges/add_atmospheric_discharges_equipment.dart'; - -class ListAtmosphericEquipment extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListAtmosphericEquipment({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListAtmosphericEquipmentState createState() => - _ListAtmosphericEquipmentState(); -} - -class _ListAtmosphericEquipmentState extends State { - List equipmentList = []; - bool isLoading = true; - final AtmosphericEquipmentService _service = AtmosphericEquipmentService(); - - @override - void initState() { - super.initState(); - fetchEquipmentList(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getAtmosphericListByArea(widget.areaId); - if (mounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (mounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddAtmosphericEquipmentScreen( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Descargas Atmosféricas'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/distribuition_board/add_distribuition_board.dart b/frontend/sige_ie/lib/equipments/feature/distribuition_board/add_distribuition_board.dart deleted file mode 100644 index 9af8f245..00000000 --- a/frontend/sige_ie/lib/equipments/feature/distribuition_board/add_distribuition_board.dart +++ /dev/null @@ -1,940 +0,0 @@ -import 'dart:io'; -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/distribution/distribution_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/distribution/distribution_request_model.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddDistribuitionBoard extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddDistribuitionBoard({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddDistribuitionBoardState createState() => _AddDistribuitionBoardState(); -} - -class _AddDistribuitionBoardState extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentChargeController = TextEditingController(); - final _equipmentQuantityController = TextEditingController(); - final _powerController = TextEditingController(); - final _typeMaterialController = TextEditingController(); - final _methodInstallationController = TextEditingController(); - bool _dr = false; - bool _dps = false; - bool _grounding = false; - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentChargeController.dispose(); - _equipmentQuantityController.dispose(); - _powerController.dispose(); - _typeMaterialController.dispose(); - _methodInstallationController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentChargeController.text.isEmpty || - _equipmentQuantityController.text.isEmpty || - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Especificação:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentChargeController.text), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final DistributionRequestModel distributionModel = DistributionRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final DistributionEquipmentRequestModel distributionEquipmentDetail = - DistributionEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - distributionRequestModel: distributionModel, - power: _powerController.text, - dr: _dr, - dps: _dps, - grounding: _grounding, - typeMaterial: _typeMaterialController.text, - methodInstallation: _methodInstallationController.text, - ); - - int? equipmentId = - await equipmentService.createDistribution(distributionEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listDistribuitionBoard', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentChargeController.clear(); - _equipmentQuantityController.clear(); - _powerController.clear(); - _typeMaterialController.clear(); - _methodInstallationController.clear(); - _dr = false; - _dps = false; - _grounding = false; - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentChargeController.clear(); - _equipmentQuantityController.clear(); - _powerController.clear(); - _typeMaterialController.clear(); - _methodInstallationController.clear(); - _dr = false; - _dps = false; - _grounding = false; - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listDistribuitionBoard', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar equipamento', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de equipamento', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': 'Selecione o tipo de equipamento', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != 'Selecione o tipo de equipamento') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 8), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - const Text('Potência', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _powerController, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text('DR', style: TextStyle(fontSize: 16)), - Checkbox( - value: _dr, - onChanged: (bool? newValue) { - setState(() { - _dr = newValue ?? false; - }); - }, - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text('DPS', style: TextStyle(fontSize: 16)), - Checkbox( - value: _dps, - onChanged: (bool? newValue) { - setState(() { - _dps = newValue ?? false; - }); - }, - ), - ], - ), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Text('Aterramento', - style: TextStyle(fontSize: 16)), - Checkbox( - value: _grounding, - onChanged: (bool? newValue) { - setState(() { - _grounding = newValue ?? false; - }); - }, - ), - ], - ), - ], - ), - const Text('Tipo de Material', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _typeMaterialController, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - const Text('Método de Instalação', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _methodInstallationController, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de equipamento', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de equipamento' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/distribuition_board/distribuition_board_equipment_list.dart b/frontend/sige_ie/lib/equipments/feature/distribuition_board/distribuition_board_equipment_list.dart deleted file mode 100644 index 07cf41c2..00000000 --- a/frontend/sige_ie/lib/equipments/feature/distribuition_board/distribuition_board_equipment_list.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/distribution/distribution_service.dart'; -import 'package:sige_ie/equipments/feature/distribuition_board/add_distribuition_board.dart'; - -class ListDistributionBoard extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListDistributionBoard({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListDistributionBoardState createState() => _ListDistributionBoardState(); -} - -class _ListDistributionBoardState extends State { - List equipmentList = []; - bool isLoading = true; - final DistributionEquipmentService _service = DistributionEquipmentService(); - - @override - void initState() { - super.initState(); - fetchEquipmentList(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getDistributionListByArea(widget.areaId); - if (mounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (mounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddDistribuitionBoard( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Quadro de Distribuição'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/electrical_circuit/add_electrical_circuit.dart b/frontend/sige_ie/lib/equipments/feature/electrical_circuit/add_electrical_circuit.dart deleted file mode 100644 index 3dfe3dd3..00000000 --- a/frontend/sige_ie/lib/equipments/feature/electrical_circuit/add_electrical_circuit.dart +++ /dev/null @@ -1,907 +0,0 @@ -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'dart:io'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/eletrical_circuit/eletrical_circuit_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/eletrical_circuit/eletrical_circuit_request_model.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - File imageFile; - int id; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddElectricalCircuitEquipmentScreen extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddElectricalCircuitEquipmentScreen({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddElectricalCircuitEquipmentScreenState createState() => - _AddElectricalCircuitEquipmentScreenState(); -} - -class _AddElectricalCircuitEquipmentScreenState - extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentQuantityController = TextEditingController(); - final _breakerLocationController = TextEditingController(); - final _breakerStateController = TextEditingController(); - final _wireTypeController = TextEditingController(); - final _dimensionController = TextEditingController(); - String? _selectedTypeToDelete; - String? _selectCircuitType; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentQuantityController.dispose(); - _breakerLocationController.dispose(); - _breakerStateController.dispose(); - _wireTypeController.dispose(); - _dimensionController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de Circuito Elétrico'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de Circuito Elétrico'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectCircuitType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentQuantityController.text.isEmpty || - _breakerLocationController.text.isEmpty || - _breakerStateController.text.isEmpty || - _wireTypeController.text.isEmpty || - _dimensionController.text.isEmpty || - (_selectCircuitType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectCircuitType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Disjuntor(Local):', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_breakerLocationController.text), - const SizedBox(height: 10), - const Text('Disjuntor(Estado):', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_breakerStateController.text), - const SizedBox(height: 10), - const Text('Tipo de Fio:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_wireTypeController.text), - const SizedBox(height: 10), - const Text('Dimensão:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_dimensionController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file(imageData.imageFile, - width: 100, height: 100, fit: BoxFit.cover), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final EletricalCircuitRequestModel electricalCircuitModel = - EletricalCircuitRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final EletricalCircuitEquipmentRequestModel - electricalCircuitEquipmentDetail = - EletricalCircuitEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - eletricalCircuitRequestModel: electricalCircuitModel, - ); - - int? equipmentId = await equipmentService - .createElectricalCircuit(electricalCircuitEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/electricalCircuitList', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentQuantityController.clear(); - _breakerLocationController.clear(); - _breakerStateController.clear(); - _wireTypeController.clear(); - _dimensionController.clear(); - _selectCircuitType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/electricalCircuitList', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar Circuito Elétrico', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de Circuito Elétrico', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': - 'Selecione o tipo de Circuito Elétrico', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectCircuitType, - onChanged: (newValue) { - if (newValue != - 'Selecione o tipo de Circuito Elétrico') { - setState(() { - _selectCircuitType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectCircuitType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Disjuntor(Local)', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _breakerLocationController, - keyboardType: TextInputType.text, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Disjuntor(Estado)', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _breakerStateController, - keyboardType: TextInputType.text, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Tipo de Fio', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _wireTypeController, - keyboardType: TextInputType.text, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Dimensão', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _dimensionController, - keyboardType: TextInputType.text, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de Circuito Elétrico'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um tipo de Circuito Elétrico para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de Circuito Elétrico', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de Circuito Elétrico' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/electrical_circuit/electrical_circuit_list.dart b/frontend/sige_ie/lib/equipments/feature/electrical_circuit/electrical_circuit_list.dart deleted file mode 100644 index 83429d43..00000000 --- a/frontend/sige_ie/lib/equipments/feature/electrical_circuit/electrical_circuit_list.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/eletrical_circuit/eletrical_circuit_service.dart'; -import 'package:sige_ie/equipments/feature/electrical_circuit/add_electrical_circuit.dart'; - -class ListCircuitEquipment extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListCircuitEquipment({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListCircuitEquipmentState createState() => _ListCircuitEquipmentState(); -} - -class _ListCircuitEquipmentState extends State { - List equipmentList = []; - bool isLoading = true; - final EletricalCircuitEquipmentService _service = - EletricalCircuitEquipmentService(); - - @override - void initState() { - super.initState(); - fetchEquipmentList(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getEletricalCircuitListByArea(widget.areaId); - if (mounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (mounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddElectricalCircuitEquipmentScreen( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Circuito Elétrico'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/electrical_line/add_electrical_line.dart b/frontend/sige_ie/lib/equipments/feature/electrical_line/add_electrical_line.dart deleted file mode 100644 index ffad9bab..00000000 --- a/frontend/sige_ie/lib/equipments/feature/electrical_line/add_electrical_line.dart +++ /dev/null @@ -1,802 +0,0 @@ -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'dart:io'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/eletrical_line/eletrical_line_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/eletrical_line/eletrical_line_request_model.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; - -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddElectricalLineScreen extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddElectricalLineScreen({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddEquipmentScreenState createState() => _AddEquipmentScreenState(); -} - -class _AddEquipmentScreenState extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentQuantityController = TextEditingController(); - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentQuantityController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewElectricalType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de linha elétrica'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de linha elétrica'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteElectricalType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentQuantityController.text.isEmpty || _selectedType == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final EletricalLineRequestModel electricalLineModel = - EletricalLineRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final EletricalLineEquipmentRequestModel electricalLineEquipmentDetail = - EletricalLineEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - eletricalLineRequestModel: electricalLineModel, - ); - - int? equipmentId = await equipmentService - .createElectricalLine(electricalLineEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/electricalLineList', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentQuantityController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentQuantityController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/electricalLineList', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar equipamento', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de linha elétrica', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': 'Selecione o tipo de linha elétrica', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != - 'Selecione o tipo de linha elétrica') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewElectricalType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de linha elétrica'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um tipo de linha elétrica para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteElectricalType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de linha elétrica', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de linha elétrica' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/electrical_line/electrical_line_list.dart b/frontend/sige_ie/lib/equipments/feature/electrical_line/electrical_line_list.dart deleted file mode 100644 index 7d159643..00000000 --- a/frontend/sige_ie/lib/equipments/feature/electrical_line/electrical_line_list.dart +++ /dev/null @@ -1,208 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/eletrical_line/eletrical_line_service.dart'; -import 'package:sige_ie/equipments/feature/electrical_line/add_electrical_line.dart'; - -class ListElectricalLineEquipment extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListElectricalLineEquipment({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListElectricalLineEquipmentState createState() => - _ListElectricalLineEquipmentState(); -} - -class _ListElectricalLineEquipmentState - extends State { - List equipmentList = []; - bool isLoading = true; - final EletricalLineEquipmentService _service = - EletricalLineEquipmentService(); - - @override - void initState() { - super.initState(); - fetchEquipmentList(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getElectricalLineListByArea(widget.areaId); - if (mounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (mounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddElectricalLineScreen( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Linhas Elétricas'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/electrical_load/add_electrical_load.dart b/frontend/sige_ie/lib/equipments/feature/electrical_load/add_electrical_load.dart deleted file mode 100644 index 5d8ac559..00000000 --- a/frontend/sige_ie/lib/equipments/feature/electrical_load/add_electrical_load.dart +++ /dev/null @@ -1,888 +0,0 @@ -import 'dart:io'; -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/eletrical-load/eletrical_load_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/eletrical-load/eletrical_load_request_model.dart.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddElectricalLoadEquipmentScreen extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddElectricalLoadEquipmentScreen({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddElectricalLoadEquipmentScreenState createState() => - _AddElectricalLoadEquipmentScreenState(); -} - -class _AddElectricalLoadEquipmentScreenState - extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentBrandController = TextEditingController(); - final _equipmentModelController = TextEditingController(); - final _equipmentQuantityController = TextEditingController(); - final _equipmentLoadController = TextEditingController(); - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentBrandController.dispose(); - _equipmentModelController.dispose(); - _equipmentQuantityController.dispose(); - _equipmentLoadController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentBrandController.text.isEmpty || - _equipmentModelController.text.isEmpty || - _equipmentQuantityController.text.isEmpty || - _equipmentLoadController.text.isEmpty || - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Marca:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentBrandController.text), - const SizedBox(height: 10), - const Text('Modelo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentModelController.text), - const SizedBox(height: 10), - const Text('Carga:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentLoadController.text), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final EletricalLoadRequestModel EletricalLoadModel = - EletricalLoadRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final EletricalLoadEquipmentRequestModel EletricalLoadEquipmentDetail = - EletricalLoadEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - eletricalLoadRequestModel: EletricalLoadModel, - ); - - int? equipmentId = await equipmentService - .createElectricalLoad(EletricalLoadEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listelectricalLoadEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentBrandController.clear(); - _equipmentModelController.clear(); - _equipmentQuantityController.clear(); - _equipmentLoadController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentBrandController.clear(); - _equipmentModelController.clear(); - _equipmentQuantityController.clear(); - _equipmentLoadController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listelectricalLoadEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar equipamentos', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de equipamento', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': 'Selecione o tipo de equipamento', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != 'Selecione o tipo de equipamento') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Marca', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentBrandController, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Modelo', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentModelController, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Carga (KW)', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentLoadController, - keyboardType: TextInputType.number, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de equipamento', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de equipamento' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/electrical_load/eletrical_load_list.dart b/frontend/sige_ie/lib/equipments/feature/electrical_load/eletrical_load_list.dart deleted file mode 100644 index 97eaee52..00000000 --- a/frontend/sige_ie/lib/equipments/feature/electrical_load/eletrical_load_list.dart +++ /dev/null @@ -1,216 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/eletrical-load/eletrical_load_service.dart'; -import 'package:sige_ie/equipments/feature/electrical_load/add_electrical_load.dart'; - -class ListElectricalLoadEquipment extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListElectricalLoadEquipment({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListElectricalLoadEquipmentState createState() => - _ListElectricalLoadEquipmentState(); -} - -class _ListElectricalLoadEquipmentState - extends State { - List equipmentList = []; - bool isLoading = true; - // You may need to replace this with actual service integration - final EletricalLoadEquipmentService _service = - EletricalLoadEquipmentService(); - bool _isMounted = false; - - @override - void initState() { - super.initState(); - _isMounted = true; - fetchEquipmentList(); - } - - @override - void dispose() { - _isMounted = false; - super.dispose(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getEletricalLoadListByArea(widget.areaId); - if (_isMounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (_isMounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddElectricalLoadEquipmentScreen( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - @override - Widget build(BuildContext context) { - String systemTitle = 'Cargas Elétricas'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/fire_alarm/add_fire_alarm.dart b/frontend/sige_ie/lib/equipments/feature/fire_alarm/add_fire_alarm.dart deleted file mode 100644 index 80692949..00000000 --- a/frontend/sige_ie/lib/equipments/feature/fire_alarm/add_fire_alarm.dart +++ /dev/null @@ -1,1030 +0,0 @@ -import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_response_model.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_service.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_response_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - bool toDelete; - - ImageData({ - int? id, - required this.imageFile, - required this.description, - this.toDelete = false, - }) : id = id ?? -1; // Valor padrão indicando ID inexistente -} - -List _images = []; - -class AddFireAlarm extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - final int? fireAlarmId; - final bool isEdit; - - const AddFireAlarm({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - this.fireAlarmId, - this.isEdit = false, - }); - - @override - _AddEquipmentScreenState createState() => _AddEquipmentScreenState(); -} - -class _AddEquipmentScreenState extends State { - EquipmentService equipmentService = EquipmentService(); - FireAlarmEquipmentService fireAlarmService = FireAlarmEquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - final TextEditingController _quantity = TextEditingController(); - String? _selectedType; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - String? _newEquipmentTypeName; - String? _selectedTypeToDelete; - int? equipmentId; - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - FireAlarmResponseModel? fireAlarmResponseModel; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - if (widget.isEdit && widget.fireAlarmId != null) { - _initializeData(widget.fireAlarmId!); - } - } - - Future _initializeData(int fireAlarmId) async { - try { - await _fetchFireAlarmEquipment(fireAlarmId); - - if (fireAlarmResponseModel != null) { - setState(() { - equipmentId = fireAlarmResponseModel!.equipment; - _quantity.text = fireAlarmResponseModel!.quantity.toString(); - print('Loaded quantity: ${_quantity.text}'); - }); - - _fetchEquipmentDetails(fireAlarmResponseModel!.equipment); - _fetchExistingPhotos(fireAlarmResponseModel!.equipment); - } - } catch (error) { - print('Error: $error'); - } - } - - Future _fetchFireAlarmEquipment(int fireAlarmId) async { - fireAlarmResponseModel = - await fireAlarmService.getFireAlarmById(fireAlarmId); - } - - Future _fetchEquipmentDetails(int equipmentId) async { - try { - final equipmentDetails = - await equipmentService.getEquipmentById(equipmentId); - - setState(() { - _isPersonalEquipmentCategorySelected = - equipmentDetails['personal_equipment_category'] != null; - - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - equipmentDetails['personal_equipment_category']; - _selectedType = personalEquipmentTypes.firstWhere((element) => - element['id'] == _selectedPersonalEquipmentCategoryId)['name'] - as String; - } else { - _selectedGenericEquipmentCategoryId = - equipmentDetails['generic_equipment_category']; - _selectedType = genericEquipmentTypes.firstWhere((element) => - element['id'] == _selectedGenericEquipmentCategoryId)['name'] - as String; - } - }); - } catch (e) { - print('Erro ao buscar detalhes do equipamento: $e'); - } - } - - void _fetchExistingPhotos(int equipmentId) async { - try { - List photos = - await equipmentPhotoService.getPhotosByEquipmentId(equipmentId); - - List imageList = []; - - for (var photo in photos) { - File imageFile = await photo.toFile(); - imageList.add(ImageData( - id: photo.id, - imageFile: imageFile, - description: photo.description ?? '', - )); - } - - setState(() { - _images = imageList; - }); - } catch (e) { - print('Erro ao buscar fotos existentes: $e'); - } - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - - @override - void dispose() { - _quantity.dispose(); - _images.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = TextEditingController( - text: existingImage?.description ?? '', - ); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - String? description = descriptionController.text.isEmpty - ? null - : descriptionController.text; - if (existingImage != null) { - existingImage.description = description ?? ''; - } else { - final imageData = ImageData( - imageFile: imageFile, - description: description ?? '', - ); - _images.add(imageData); - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - void _updateEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final Map equipmentTypeUpdate = { - "generic_equipment_category": genericEquipmentCategory, - "personal_equipment_category": personalEquipmentCategory, - }; - - print('Quantity: ${_quantity.text}'); - print('Equipment Type Update: $equipmentTypeUpdate'); - - bool typeUpdateSuccess = await equipmentService.updateEquipment( - equipmentId!, equipmentTypeUpdate); - - if (typeUpdateSuccess) { - final FireAlarmRequestModel fireAlarmModel = FireAlarmRequestModel( - area: widget.areaId, - system: widget.systemId, - quantity: int.tryParse(_quantity.text), - ); - - print('Fire Alarm Model: ${fireAlarmModel.toJson()}'); - - bool fireAlarmUpdateSuccess = await fireAlarmService.updateFireAlarm( - widget.fireAlarmId!, fireAlarmModel); - - if (fireAlarmUpdateSuccess) { - await Future.wait(_images - .where((imageData) => imageData.toDelete) - .map((imageData) async { - await equipmentPhotoService.deletePhoto(imageData.id); - })); - - await Future.wait(_images - .where((imageData) => !imageData.toDelete) - .map((imageData) async { - if (imageData.id == -1) { - // Verifique se o ID é -1 (não atribuído) - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description.isEmpty - ? null - : imageData.description, - equipment: equipmentId!, - ), - ); - } else { - await equipmentPhotoService.updatePhoto( - imageData.id, - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description.isEmpty - ? null - : imageData.description, - equipment: equipmentId!, - ), - ); - } - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento atualizados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listFireAlarms', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _quantity.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao atualizar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao atualizar o tipo do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Equipamento de alarme de incêndio registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Falha ao registrar o equipamento de alarme de incêndio.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int personalCategoryId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(personalCategoryId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _selectedType = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_quantity.text.isEmpty || - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_quantity.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images - .where((imageData) => !imageData.toDelete) - .map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: widget.isEdit - ? const Text('Atualizar') - : const Text('Adicionar'), - onPressed: () { - if (widget.isEdit) { - _updateEquipment(); - } else { - _registerEquipment(); - } - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final FireAlarmRequestModel fireAlarmModel = FireAlarmRequestModel( - area: widget.areaId, - system: widget.systemId, - quantity: int.tryParse(_quantity.text), - ); - - final FireAlarmEquipmentRequestModel fireAlarmEquipmentDetail = - FireAlarmEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - fireAlarmRequestModel: fireAlarmModel, - ); - - int? id = await equipmentService.createFireAlarm(fireAlarmEquipmentDetail); - setState(() { - equipmentId = id; - }); - - if (equipmentId != null && equipmentId != 0) { - print('Registering photos for equipment ID: $equipmentId'); - await Future.wait(_images.map((imageData) async { - print('Creating photo with description: "${imageData.description}"'); - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: - imageData.description.isEmpty ? null : imageData.description, - equipment: equipmentId!, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listFireAlarms', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _quantity.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - Future _deletePhoto(int photoId) async { - setState(() { - _images.firstWhere((imageData) => imageData.id == photoId).toDelete = - true; - }); - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _quantity.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listFireAlarms', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - widget.fireAlarmId == null - ? 'Adicionar Equipamento' - : 'Editar Equipamento', - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de alarme de incêndio', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': - 'Selecione o tipo de alarme de incêndio', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != - 'Selecione o tipo de alarme de incêndio') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _quantity, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - onChanged: (value) { - print('Quantity changed: $value'); - }, - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images - .where((imageData) => !imageData.toDelete) - .map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - _deletePhoto(imageData.id); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: Text( - widget.isEdit - ? 'ATUALIZAR EQUIPAMENTO' - : 'ADICIONAR EQUIPAMENTO', - style: const TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de alarme de incêndio', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de alarme de incêndio' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/fire_alarm/list_fire_alarms.dart b/frontend/sige_ie/lib/equipments/feature/fire_alarm/list_fire_alarms.dart deleted file mode 100644 index 61b8b48f..00000000 --- a/frontend/sige_ie/lib/equipments/feature/fire_alarm/list_fire_alarms.dart +++ /dev/null @@ -1,253 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_response_by_area_model.dart'; -import 'package:sige_ie/equipments/data/fire_alarm/fire_alarm_service.dart'; -import 'package:sige_ie/equipments/feature/fire_alarm/add_fire_alarm.dart'; - -class ListFireAlarms extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListFireAlarms({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _ListFireAlarmsState createState() => _ListFireAlarmsState(); -} - -class _ListFireAlarmsState extends State { - late Future> _fireAlarmList; - final FireAlarmEquipmentService _fireAlarmService = - FireAlarmEquipmentService(); - - final GlobalKey _scaffoldMessengerKey = - GlobalKey(); - - @override - void initState() { - super.initState(); - _fireAlarmList = _fireAlarmService.getFireAlarmListByArea(widget.areaId); - } - - void navigateToAddFireAlarm(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddFireAlarm( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - fireAlarmId: null, - ), - ), - ); - } - - void _editFireAlarm(BuildContext context, int fireAlarmId) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddFireAlarm( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - fireAlarmId: fireAlarmId, - isEdit: true, - ), - ), - ); - } - - Future _deleteFireAlarm(BuildContext context, int fireAlarmId) async { - try { - await _fireAlarmService.deleteFireAlarm(fireAlarmId); - setState(() { - _fireAlarmList = - _fireAlarmService.getFireAlarmListByArea(widget.areaId); - }); - _scaffoldMessengerKey.currentState?.showSnackBar( - const SnackBar( - content: Text('Equipamento deletado com sucesso'), - backgroundColor: Colors.green, - ), - ); - } catch (e) { - _scaffoldMessengerKey.currentState?.showSnackBar( - const SnackBar( - content: Text('Falha ao deletar o equipamento'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _confirmDelete(BuildContext context, int fireAlarmId) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: const Text( - 'Você tem certeza que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - Navigator.of(context).pop(); - _deleteFireAlarm(context, fireAlarmId); - }, - ), - ], - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Alarme de Incêndio'; - - return ScaffoldMessenger( - key: _scaffoldMessengerKey, - child: Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - FutureBuilder>( - future: _fireAlarmList, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return Center(child: Text('Erro: ${snapshot.error}')); - } else if (snapshot.hasData && snapshot.data!.isNotEmpty) { - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: snapshot.data!.length, - itemBuilder: (context, index) { - var fireAlarmEquipment = snapshot.data![index]; - return Container( - margin: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: ListTile( - contentPadding: const EdgeInsets.symmetric( - horizontal: 20, vertical: 10), - title: Text( - fireAlarmEquipment.equipmentCategory, - style: const TextStyle( - color: AppColors.lightText, - fontWeight: FontWeight.bold), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => - _editFireAlarm(context, fireAlarmEquipment.id), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => - _confirmDelete(context, fireAlarmEquipment.id), - ), - ], - ), - ), - ); - }, - ); - } else { - return const Padding( - padding: EdgeInsets.all(10.0), - child: Center( - child: Text( - 'Nenhum equipamento encontrado.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54), - ), - ), - ); - } - }, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddFireAlarm(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/iluminations/add_ilumination_equipment.dart b/frontend/sige_ie/lib/equipments/feature/iluminations/add_ilumination_equipment.dart deleted file mode 100644 index f031fa27..00000000 --- a/frontend/sige_ie/lib/equipments/feature/iluminations/add_ilumination_equipment.dart +++ /dev/null @@ -1,830 +0,0 @@ -import 'dart:io'; -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; - -import 'package:sige_ie/equipments/data/iluminations/ilumination__equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/iluminations/ilumination_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddIluminationEquipmentScreen extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddIluminationEquipmentScreen({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddIlluminationScreenState createState() => _AddIlluminationScreenState(); -} - -class _AddIlluminationScreenState extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentQuantityController = TextEditingController(); - final _equipmentPowerController = TextEditingController(); - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentQuantityController.dispose(); - _equipmentPowerController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentQuantityController.text.isEmpty || - _equipmentPowerController.text.isEmpty || - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Potência (KW):', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentPowerController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final IluminationRequestModel iluminationModel = IluminationRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final IluminationEquipmentRequestModel iluminationEquipmentDetail = - IluminationEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - iluminationRequestModel: iluminationModel, - ); - - int? equipmentId = - await equipmentService.createIlumination(iluminationEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listIluminationEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentQuantityController.clear(); - _equipmentPowerController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentQuantityController.clear(); - _equipmentPowerController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listIluminationEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar equipamento', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de equipamento', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': 'Selecione o tipo de equipamento', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != 'Selecione o tipo de equipamento') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Potência (KW)', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentPowerController, - keyboardType: TextInputType.number, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de equipamento', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de equipamento' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/iluminations/ilumination_equipment_list.dart b/frontend/sige_ie/lib/equipments/feature/iluminations/ilumination_equipment_list.dart deleted file mode 100644 index 45910396..00000000 --- a/frontend/sige_ie/lib/equipments/feature/iluminations/ilumination_equipment_list.dart +++ /dev/null @@ -1,206 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/iluminations/ilumination_service.dart'; -import 'package:sige_ie/equipments/feature/iluminations/add_ilumination_equipment.dart'; - -class ListIluminationEquipment extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListIluminationEquipment({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListIluminationEquipmentState createState() => - _ListIluminationEquipmentState(); -} - -class _ListIluminationEquipmentState extends State { - List equipmentList = []; - bool isLoading = true; - final IluminationEquipmentService _service = IluminationEquipmentService(); - - @override - void initState() { - super.initState(); - fetchEquipmentList(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getIluminationListByArea(widget.areaId); - if (mounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (mounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddIluminationEquipmentScreen( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Iluminação'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/refrigerations/add_refrigeration.dart b/frontend/sige_ie/lib/equipments/feature/refrigerations/add_refrigeration.dart deleted file mode 100644 index 2d2f7472..00000000 --- a/frontend/sige_ie/lib/equipments/feature/refrigerations/add_refrigeration.dart +++ /dev/null @@ -1,830 +0,0 @@ -import 'dart:io'; -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/refrigerations/refrigerations_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/refrigerations/refrigerations_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddRefrigeration extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddRefrigeration({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddRefrigerationState createState() => _AddRefrigerationState(); -} - -class _AddRefrigerationState extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentQuantityController = TextEditingController(); - final _equipmentPowerController = TextEditingController(); - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentQuantityController.dispose(); - _equipmentPowerController.dispose(); - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentQuantityController.text.isEmpty || - _equipmentPowerController.text.isEmpty || - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Potência (KW):', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentPowerController.text), - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final RefrigerationsRequestModel refrigerationsModel = - RefrigerationsRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final RefrigerationsEquipmentRequestModel refrigerationsEquipmentDetail = - RefrigerationsEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - refrigerationsRequestModel: refrigerationsModel, - ); - - int? equipmentId = await equipmentService - .createRefrigerations(refrigerationsEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listRefrigerationEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentQuantityController.clear(); - _equipmentPowerController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentQuantityController.clear(); - _equipmentPowerController.clear(); - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listRefrigerationEquipment', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar equipamento', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de equipamento', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': 'Selecione o tipo de equipamento', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != 'Selecione o tipo de equipamento') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Potência (KW)', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentPowerController, - keyboardType: TextInputType.number, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: value['name'] != 'Selecione o tipo de equipamento', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == 'Selecione o tipo de equipamento' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/refrigerations/refrigeration_equipment_list.dart b/frontend/sige_ie/lib/equipments/feature/refrigerations/refrigeration_equipment_list.dart deleted file mode 100644 index 059546c0..00000000 --- a/frontend/sige_ie/lib/equipments/feature/refrigerations/refrigeration_equipment_list.dart +++ /dev/null @@ -1,208 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/refrigerations/refrigerations_service.dart'; -import 'package:sige_ie/equipments/feature/refrigerations/add_refrigeration.dart'; - -class ListRefrigerationEquipment extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListRefrigerationEquipment({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListRefrigerationEquipmentState createState() => - _ListRefrigerationEquipmentState(); -} - -class _ListRefrigerationEquipmentState - extends State { - List equipmentList = []; - bool isLoading = true; - final RefrigerationsEquipmentService _service = - RefrigerationsEquipmentService(); - - @override - void initState() { - super.initState(); - fetchEquipmentList(); - } - - Future fetchEquipmentList() async { - try { - final List equipmentList = - await _service.getRefrigerationsListByArea(widget.areaId); - if (mounted) { - setState(() { - this.equipmentList = equipmentList; - isLoading = false; - }); - } - } catch (e) { - print('Error fetching equipment list: $e'); - if (mounted) { - setState(() { - isLoading = false; - }); - } - } - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddRefrigeration( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, String equipment) { - // Implement the logic to edit the equipment - } - - void _deleteEquipment(BuildContext context, String equipment) { - // Implement the logic to delete the equipment - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Refrigeração'; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - isLoading - ? const Center( - child: CircularProgressIndicator(), - ) - : equipmentList.isNotEmpty - ? Column( - children: equipmentList.map((equipment) { - return Container( - margin: - const EdgeInsets.symmetric(vertical: 5), - child: Container( - padding: const EdgeInsets.all(10), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: Padding( - padding: - const EdgeInsets.only(left: 10), - child: Text( - equipment, - style: const TextStyle( - color: Colors.white, - fontSize: 18, - ), - ), - ), - ), - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => _editEquipment( - context, equipment), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => _deleteEquipment( - context, equipment), - ), - ], - ), - ), - ); - }).toList(), - ) - : const Center( - child: Text( - 'Você ainda não tem equipamentos', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54, - ), - ), - ), - const SizedBox(height: 40), - ], - ), - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/structured_cabling/add_structured_cabling.dart b/frontend/sige_ie/lib/equipments/feature/structured_cabling/add_structured_cabling.dart deleted file mode 100644 index 30e7bb43..00000000 --- a/frontend/sige_ie/lib/equipments/feature/structured_cabling/add_structured_cabling.dart +++ /dev/null @@ -1,841 +0,0 @@ -import 'dart:io'; -import 'dart:math'; -import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; -import 'package:image_picker/image_picker.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_equipment_request_model.dart'; -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_service.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_service.dart'; -import 'package:sige_ie/equipments/data/equipment_service.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_service.dart'; - -class ImageData { - int id; - File imageFile; - String description; - - ImageData(this.imageFile, this.description) : id = Random().nextInt(1000000); -} - -List _images = []; -Map> categoryImagesMap = {}; - -class AddStructuredCabling extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int systemId; - final int areaId; - - const AddStructuredCabling({ - super.key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _AddStructuredCablingScreenState createState() => - _AddStructuredCablingScreenState(); -} - -class _AddStructuredCablingScreenState extends State { - EquipmentService equipmentService = EquipmentService(); - EquipmentPhotoService equipmentPhotoService = EquipmentPhotoService(); - PersonalEquipmentCategoryService personalEquipmentCategoryService = - PersonalEquipmentCategoryService(); - GenericEquipmentCategoryService genericEquipmentCategoryService = - GenericEquipmentCategoryService(); - - final _equipmentQuantityController = TextEditingController(); - final _equipmentDimensionController = - TextEditingController(); // Adicionado para a dimensão - String? _selectedType; - String? _selectedTypeToDelete; - String? _newEquipmentTypeName; - int? _selectedGenericEquipmentCategoryId; - int? _selectedPersonalEquipmentCategoryId; - bool _isPersonalEquipmentCategorySelected = false; - - List> genericEquipmentTypes = []; - List> personalEquipmentTypes = []; - Map personalEquipmentMap = {}; - - @override - void initState() { - super.initState(); - _fetchEquipmentCategory(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _fetchEquipmentCategory(); - } - - Future _fetchEquipmentCategory() async { - List genericEquipmentCategoryList = - await genericEquipmentCategoryService - .getAllGenericEquipmentCategoryBySystem(widget.systemId); - - List personalEquipmentCategoryList = - await personalEquipmentCategoryService - .getAllPersonalEquipmentCategoryBySystem(widget.systemId); - - if (mounted) { - setState(() { - genericEquipmentTypes = genericEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'generico'}) - .toList(); - personalEquipmentTypes = personalEquipmentCategoryList - .map((e) => {'id': e.id, 'name': e.name, 'type': 'pessoal'}) - .toList(); - personalEquipmentMap = { - for (var equipment in personalEquipmentCategoryList) - equipment.name: equipment.id - }; - }); - } - } - - @override - void dispose() { - _equipmentQuantityController.dispose(); - _equipmentDimensionController.dispose(); // Adicionado para a dimensão - categoryImagesMap[widget.systemId]?.clear(); - super.dispose(); - } - - Future _pickImage() async { - final picker = ImagePicker(); - try { - final pickedFile = await picker.pickImage(source: ImageSource.camera); - if (pickedFile != null) { - _showImageDialog(File(pickedFile.path)); - } - } catch (e) { - print('Erro ao capturar a imagem: $e'); - } - } - - void _showImageDialog(File imageFile, {ImageData? existingImage}) { - TextEditingController descriptionController = - TextEditingController(text: existingImage?.description ?? ''); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar descrição da imagem'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Image.file(imageFile, width: 100, height: 100, fit: BoxFit.cover), - TextField( - controller: descriptionController, - decoration: const InputDecoration( - hintText: 'Digite a descrição da imagem (opcional)'), - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () { - setState(() { - if (existingImage != null) { - existingImage.description = descriptionController.text; - } else { - final imageData = - ImageData(imageFile, descriptionController.text); - final systemId = widget.systemId; - if (!categoryImagesMap.containsKey(systemId)) { - categoryImagesMap[systemId] = []; - } - categoryImagesMap[systemId]!.add(imageData); - _images = categoryImagesMap[systemId]!; - } - }); - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - - void _addNewEquipmentType() { - TextEditingController typeController = TextEditingController(); - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Adicionar novo tipo de equipamento'), - content: TextField( - controller: typeController, - decoration: const InputDecoration( - hintText: 'Digite o novo tipo de equipamento'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - if (typeController.text.isNotEmpty) { - setState(() { - _newEquipmentTypeName = typeController.text; - }); - _registerPersonalEquipmentType().then((_) { - setState(() { - _selectedType = null; - _selectedGenericEquipmentCategoryId = null; - _fetchEquipmentCategory(); - }); - }); - Navigator.of(context).pop(); - } - }, - ), - ], - ); - }, - ); - } - - Future _registerPersonalEquipmentType() async { - int systemId = widget.systemId; - PersonalEquipmentCategoryRequestModel personalEquipmentTypeRequestModel = - PersonalEquipmentCategoryRequestModel( - name: _newEquipmentTypeName ?? '', system: systemId); - - int id = await personalEquipmentCategoryService - .createPersonalEquipmentCategory(personalEquipmentTypeRequestModel); - - if (id != -1) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento registrado com sucesso.'), - backgroundColor: Colors.green, - ), - ); - - setState(() { - personalEquipmentTypes - .add({'name': _newEquipmentTypeName!, 'id': id, 'type': 'pessoal'}); - personalEquipmentMap[_newEquipmentTypeName!] = id; - _newEquipmentTypeName = null; - _fetchEquipmentCategory(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _deleteEquipmentType() async { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: - Text('Não existem categorias de equipamentos a serem excluídas.'), - ), - ); - return; - } - - if (_selectedTypeToDelete == null) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Selecione uma categoria de equipamento válida para excluir.'), - ), - ); - return; - } - - int equipmentId = personalEquipmentMap[_selectedTypeToDelete]!; - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Tem certeza de que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await personalEquipmentCategoryService - .deletePersonalEquipmentCategory(equipmentId); - - if (success) { - setState(() { - personalEquipmentTypes.removeWhere( - (element) => element['name'] == _selectedTypeToDelete); - _selectedTypeToDelete = null; - _fetchEquipmentCategory(); - }); - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Equipamento excluído com sucesso.'), - backgroundColor: Colors.green, - ), - ); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao excluir o equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - }, - ), - ], - ); - }, - ); - } - - void _showConfirmationDialog() { - if (_equipmentQuantityController.text.isEmpty || - _equipmentDimensionController - .text.isEmpty || // Adicionado para a dimensão - (_selectedType == null && _newEquipmentTypeName == null)) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Por favor, preencha todos os campos.'), - ), - ); - return; - } - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Dados do Equipamento'), - content: SingleChildScrollView( - child: ListBody( - children: [ - const Text('Tipo:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_selectedType ?? _newEquipmentTypeName ?? ''), - const SizedBox(height: 10), - const Text('Quantidade:', - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentQuantityController.text), - const SizedBox(height: 10), - const Text('Dimensão:', // Adicionado para a dimensão - style: TextStyle(fontWeight: FontWeight.bold)), - Text(_equipmentDimensionController - .text), // Adicionado para a dimensão - const SizedBox(height: 10), - const Text('Imagens:', - style: TextStyle(fontWeight: FontWeight.bold)), - Wrap( - children: _images.map((imageData) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Column( - children: [ - Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - Text(imageData.description), - ], - ), - ), - ); - }).toList(), - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Editar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Adicionar'), - onPressed: () { - _registerEquipment(); - }, - ), - ], - ); - }, - ); - } - - void _registerEquipment() async { - int? genericEquipmentCategory; - int? personalEquipmentCategory; - - if (_isPersonalEquipmentCategorySelected) { - genericEquipmentCategory = null; - personalEquipmentCategory = _selectedPersonalEquipmentCategoryId; - } else { - genericEquipmentCategory = _selectedGenericEquipmentCategoryId; - personalEquipmentCategory = null; - } - - final StructuredCablingRequestModel structuredCablingModel = - StructuredCablingRequestModel( - area: widget.areaId, - system: widget.systemId, - ); - - final StructuredCablingEquipmentRequestModel - structuredCablingEquipmentDetail = - StructuredCablingEquipmentRequestModel( - genericEquipmentCategory: genericEquipmentCategory, - personalEquipmentCategory: personalEquipmentCategory, - structuredCablingRequestModel: structuredCablingModel, - ); - - int? equipmentId = await equipmentService - .createStructuredCabling(structuredCablingEquipmentDetail); - - if (equipmentId != null) { - await Future.wait(_images.map((imageData) async { - await equipmentPhotoService.createPhoto( - EquipmentPhotoRequestModel( - photo: imageData.imageFile, - description: imageData.description, - equipment: equipmentId, - ), - ); - })); - - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Detalhes do equipamento registrados com sucesso.'), - backgroundColor: Colors.green, - ), - ); - Navigator.pushReplacementNamed( - context, - '/listStruturedCabling', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - setState(() { - _equipmentQuantityController.clear(); - _equipmentDimensionController.clear(); // Adicionado para a dimensão - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - } else { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text('Falha ao registrar os detalhes do equipamento.'), - backgroundColor: Colors.red, - ), - ); - } - } - - @override - Widget build(BuildContext context) { - List> combinedTypes = [ - ...genericEquipmentTypes, - ...personalEquipmentTypes - ]; - - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - foregroundColor: Colors.white, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - setState(() { - _equipmentQuantityController.clear(); - _equipmentDimensionController - .clear(); // Adicionado para a dimensão - _selectedType = null; - _selectedPersonalEquipmentCategoryId = null; - _selectedGenericEquipmentCategoryId = null; - _images.clear(); - }); - Navigator.pushReplacementNamed( - context, - '/listStruturedCabling', - arguments: { - 'areaName': widget.areaName, - 'systemId': widget.systemId, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Adicionar cabeamento estruturado', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - Padding( - padding: const EdgeInsets.all(20.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Tipos de cabeamento estruturado', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Row( - children: [ - Expanded( - flex: 4, - child: _buildStyledDropdown( - items: [ - { - 'name': - 'Selecione o tipo de cabeamento estruturado', - 'id': -1, - 'type': -1 - } - ] + - combinedTypes, - value: _selectedType, - onChanged: (newValue) { - if (newValue != - 'Selecione o tipo de cabeamento estruturado') { - setState(() { - _selectedType = newValue; - Map selected = - combinedTypes.firstWhere((element) => - element['name'] == newValue); - _isPersonalEquipmentCategorySelected = - selected['type'] == 'pessoal'; - if (_isPersonalEquipmentCategorySelected) { - _selectedPersonalEquipmentCategoryId = - selected['id'] as int; - _selectedGenericEquipmentCategoryId = null; - } else { - _selectedGenericEquipmentCategoryId = - selected['id'] as int; - _selectedPersonalEquipmentCategoryId = null; - } - }); - } - }, - enabled: true, - ), - ), - Expanded( - flex: 0, - child: Row( - children: [ - IconButton( - icon: const Icon(Icons.add), - onPressed: _addNewEquipmentType, - ), - IconButton( - icon: const Icon(Icons.delete), - onPressed: () { - if (personalEquipmentTypes.isEmpty) { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar( - content: Text( - 'Não existem equipamentos pessoais a serem excluídos.'), - ), - ); - } else { - setState(() { - _selectedTypeToDelete = null; - }); - _showDeleteDialog(); - } - }, - ), - ], - ), - ), - ], - ), - const SizedBox(height: 8), - TextButton( - onPressed: () { - setState(() { - _selectedType = null; - }); - }, - child: const Text('Limpar seleção'), - ), - const SizedBox(height: 30), - const Text('Dimensão:', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: - _equipmentDimensionController, // Adicionado para a dimensão - keyboardType: TextInputType.text, - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 30), - const Text('Quantidade', - style: - TextStyle(fontWeight: FontWeight.bold, fontSize: 14)), - const SizedBox(height: 8), - Container( - decoration: BoxDecoration( - color: Colors.grey[300], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: _equipmentQuantityController, - keyboardType: TextInputType.number, - inputFormatters: [ - FilteringTextInputFormatter.digitsOnly - ], - decoration: const InputDecoration( - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10, vertical: 15), - ), - ), - ), - const SizedBox(height: 15), - IconButton( - icon: const Icon(Icons.camera_alt), - onPressed: _pickImage, - ), - Wrap( - children: _images.map((imageData) { - return Stack( - alignment: Alignment.topRight, - children: [ - GestureDetector( - onTap: () => _showImageDialog(imageData.imageFile, - existingImage: imageData), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Image.file( - imageData.imageFile, - width: 100, - height: 100, - fit: BoxFit.cover, - ), - ), - ), - IconButton( - icon: const Icon(Icons.remove_circle, - color: AppColors.warn), - onPressed: () { - setState(() { - _images.removeWhere( - (element) => element.id == imageData.id); - }); - }, - ), - ], - ); - }).toList(), - ), - const SizedBox(height: 15), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(185, 55)), - shape: - MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: _showConfirmationDialog, - child: const Text( - 'ADICIONAR EQUIPAMENTO', - style: TextStyle( - fontSize: 17, fontWeight: FontWeight.bold), - ), - ), - ) - ], - ), - ), - ], - ), - ), - ); - } - - void _showDeleteDialog() { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Excluir tipo de equipamento'), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text( - 'Selecione um equipamento para excluir:', - textAlign: TextAlign.center, - ), - StatefulBuilder( - builder: (BuildContext context, StateSetter setState) { - return DropdownButton( - isExpanded: true, - value: _selectedTypeToDelete, - onChanged: (String? newValue) { - setState(() { - _selectedTypeToDelete = newValue; - }); - }, - items: personalEquipmentTypes.map>( - (Map value) { - return DropdownMenuItem( - value: value['name'] as String, - child: Text( - value['name'] as String, - style: const TextStyle(color: Colors.black), - ), - ); - }).toList(), - ); - }, - ), - ], - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - if (_selectedTypeToDelete != null) { - Navigator.of(context).pop(); - _deleteEquipmentType(); - } - }, - ), - ], - ); - }, - ); - } - - Widget _buildStyledDropdown({ - required List> items, - String? value, - required Function(String?) onChanged, - bool enabled = true, - }) { - return Container( - decoration: BoxDecoration( - color: enabled ? Colors.grey[300] : Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - child: DropdownButton( - hint: Text(items.first['name'] as String, - style: const TextStyle(color: Colors.grey)), - value: value, - isExpanded: true, - underline: Container(), - onChanged: enabled ? onChanged : null, - items: items.map>((Map value) { - return DropdownMenuItem( - value: value['name'] as String, - enabled: - value['name'] != 'Selecione o tipo de cabeamento estruturado', - child: Text( - value['name'] as String, - style: TextStyle( - color: value['name'] == - 'Selecione o tipo de cabeamento estruturado' - ? Colors.grey - : Colors.black, - ), - ), - ); - }).toList(), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/structured_cabling/structured_cabling_equipment_list.dart b/frontend/sige_ie/lib/equipments/feature/structured_cabling/structured_cabling_equipment_list.dart deleted file mode 100644 index 8f65b074..00000000 --- a/frontend/sige_ie/lib/equipments/feature/structured_cabling/structured_cabling_equipment_list.dart +++ /dev/null @@ -1,239 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_response_model.dart'; -import 'package:sige_ie/equipments/data/structured_cabling/structured_cabling_service.dart'; -import 'package:sige_ie/equipments/feature/structured_cabling/add_structured_cabling.dart'; - -class ListStructuredCabling extends StatefulWidget { - final String areaName; - final String localName; - final int systemId; - final int localId; - final int areaId; - - const ListStructuredCabling({ - Key? key, - required this.areaName, - required this.systemId, - required this.localName, - required this.localId, - required this.areaId, - }) : super(key: key); - - @override - _ListStructuredCablingState createState() => _ListStructuredCablingState(); -} - -class _ListStructuredCablingState extends State { - late Future> _equipmentList; - final StructuredCablingEquipmentService _service = - StructuredCablingEquipmentService(); - - // Chave global para ScaffoldMessenger - final GlobalKey _scaffoldMessengerKey = - GlobalKey(); - - @override - void initState() { - super.initState(); - _equipmentList = _service.getStructuredCablingListByArea(widget.areaId); - } - - void navigateToAddEquipment(BuildContext context) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) => AddStructuredCabling( - areaName: widget.areaName, - systemId: widget.systemId, - localName: widget.localName, - localId: widget.localId, - areaId: widget.areaId, - ), - ), - ); - } - - void _editEquipment(BuildContext context, int equipmentId) { - // Implement the logic to edit the equipment - } - - Future _deleteEquipment(BuildContext context, int equipmentId) async { - try { - await _service.deleteStructuredCabling(equipmentId); - setState(() { - _equipmentList = _service.getStructuredCablingListByArea(widget.areaId); - }); - _scaffoldMessengerKey.currentState?.showSnackBar( - const SnackBar( - content: Text('Equipamento deletado com sucesso'), - backgroundColor: Colors.green, - ), - ); - } catch (e) { - _scaffoldMessengerKey.currentState?.showSnackBar( - const SnackBar( - content: Text('Falha ao deletar o equipamento'), - backgroundColor: Colors.red, - ), - ); - } - } - - void _confirmDelete(BuildContext context, int equipmentId) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: const Text( - 'Você tem certeza que deseja excluir este equipamento?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - Navigator.of(context).pop(); - _deleteEquipment(context, equipmentId); - }, - ), - ], - ); - }, - ); - } - - @override - Widget build(BuildContext context) { - String systemTitle = 'Cabeamento Estruturado'; - - return ScaffoldMessenger( - key: _scaffoldMessengerKey, - child: Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () { - Navigator.pushReplacementNamed( - context, - '/systemLocation', - arguments: { - 'areaName': widget.areaName, - 'localName': widget.localName, - 'localId': widget.localId, - 'areaId': widget.areaId, - }, - ); - }, - ), - ), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - '${widget.areaName} - $systemTitle', - textAlign: TextAlign.center, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: AppColors.lightText, - ), - ), - ), - ), - const SizedBox(height: 20), - FutureBuilder>( - future: _equipmentList, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return Center(child: Text('Erro: ${snapshot.error}')); - } else if (snapshot.hasData && snapshot.data!.isNotEmpty) { - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: snapshot.data!.length, - itemBuilder: (context, index) { - var equipment = snapshot.data![index]; - return Container( - margin: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: ListTile( - contentPadding: const EdgeInsets.symmetric( - horizontal: 20, vertical: 10), - title: Text( - equipment.equipmentCategory, - style: const TextStyle( - color: AppColors.lightText, - fontWeight: FontWeight.bold), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => - _editEquipment(context, equipment.id), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => - _confirmDelete(context, equipment.id), - ), - ], - ), - ), - ); - }, - ); - } else { - return const Padding( - padding: EdgeInsets.all(10.0), - child: Center( - child: Text( - 'Nenhum equipamento encontrado.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54), - ), - ), - ); - } - }, - ), - ], - ), - ), - floatingActionButton: FloatingActionButton( - onPressed: () => navigateToAddEquipment(context), - backgroundColor: AppColors.sigeIeYellow, - child: const Icon(Icons.add, color: AppColors.sigeIeBlue), - ), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/equipments/feature/system_configuration.dart b/frontend/sige_ie/lib/equipments/feature/system_configuration.dart deleted file mode 100644 index 9fa29789..00000000 --- a/frontend/sige_ie/lib/equipments/feature/system_configuration.dart +++ /dev/null @@ -1,356 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/equipments/feature/refrigerations/refrigeration_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/distribuition_board/distribuition_board_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/electrical_circuit/electrical_circuit_list.dart'; -import 'package:sige_ie/equipments/feature/electrical_line/electrical_line_list.dart'; -import 'package:sige_ie/equipments/feature/iluminations/ilumination_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/atmospheric-discharges/atmospheric_discharges_list.dart'; -import 'package:sige_ie/equipments/feature/electrical_load/eletrical_load_list.dart'; -import 'package:sige_ie/equipments/feature/structured_cabling/structured_cabling_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/fire_alarm/list_fire_alarms.dart'; - -class SystemConfiguration extends StatefulWidget { - final String areaName; - final String localName; - final int localId; - final int areaId; - - const SystemConfiguration({ - super.key, - required this.areaName, - required this.localName, - required this.localId, - required this.areaId, - }); - - @override - _SystemConfigurationState createState() => _SystemConfigurationState(); -} - -class _SystemConfigurationState extends State { - void navigateTo(String routeName, String areaName, String localName, - int localId, int areaId, int systemId) { - Navigator.push( - context, - MaterialPageRoute( - builder: (context) { - switch (routeName) { - case '/structuredCabling': - return ListStructuredCabling( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/atmosphericDischarges': - return ListAtmosphericEquipment( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/fireAlarm': - return ListFireAlarms( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/electricLoads': - return ListElectricalLoadEquipment( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/electricLines': - return ListElectricalLineEquipment( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/circuits': - return ListCircuitEquipment( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/distributionBoard': - return ListDistributionBoard( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/cooling': - return ListRefrigerationEquipment( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - case '/lighting': - return ListIluminationEquipment( - areaName: areaName, - localName: localName, - localId: localId, - systemId: systemId, - areaId: areaId, - ); - default: - return Scaffold( - body: Center(child: Text('No route defined for $routeName')), - ); - } - }, - ), - ); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - backgroundColor: AppColors.sigeIeBlue, - ), - body: SingleChildScrollView( - child: Column( - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: Center( - child: Text( - widget.areaName, - style: const TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ), - ), - const Padding( - padding: EdgeInsets.all(30.0), - child: Text( - 'Quais sistemas deseja configurar?', - style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold), - ), - ), - GridView.count( - shrinkWrap: true, - crossAxisCount: 3, - childAspectRatio: 1.0, - padding: const EdgeInsets.all(10.0), - mainAxisSpacing: 10.0, - crossAxisSpacing: 10.0, - children: [ - SystemIcon( - icon: Icons.local_fire_department, - label: 'ALARME DE INCÊNDIO', - onPressed: () => navigateTo('/fireAlarm', widget.areaName, - widget.localName, widget.localId, widget.areaId, 8), - ), - SystemIcon( - icon: Icons.cable, - label: 'CABEAMENTO ESTRUTURADO', - onPressed: () => navigateTo( - '/structuredCabling', - widget.areaName, - widget.localName, - widget.localId, - widget.areaId, - 6), - ), - SystemIcon( - icon: Icons.electrical_services, - label: 'CARGAS ELÉTRICAS', - onPressed: () => navigateTo('/electricLoads', widget.areaName, - widget.localName, widget.localId, widget.areaId, 2), - ), - SystemIcon( - icon: Icons.electric_meter, - label: 'CIRCUITOS', - onPressed: () => navigateTo('/circuits', widget.areaName, - widget.localName, widget.localId, widget.areaId, 4), - ), - SystemIcon( - icon: Icons.bolt, - label: 'DESCARGAS ATMOSFÉRICAS', - onPressed: () => navigateTo( - '/atmosphericDischarges', - widget.areaName, - widget.localName, - widget.localId, - widget.areaId, - 7), - ), - SystemIcon( - icon: Icons.lightbulb, - label: 'ILUMINAÇÃO', - onPressed: () => navigateTo('/lighting', widget.areaName, - widget.localName, widget.localId, widget.areaId, 1), - ), - SystemIcon( - icon: Icons.power, - label: 'LINHAS ELÉTRICAS', - onPressed: () => navigateTo('/electricLines', widget.areaName, - widget.localName, widget.localId, widget.areaId, 3), - ), - SystemIcon( - icon: Icons.dashboard, - label: 'QUADRO DE DISTRIBUIÇÃO', - onPressed: () => navigateTo( - '/distributionBoard', - widget.areaName, - widget.localName, - widget.localId, - widget.areaId, - 5), - ), - SystemIcon( - icon: Icons.ac_unit, - label: 'REFRIGERAÇÃO', - onPressed: () => navigateTo('/cooling', widget.areaName, - widget.localName, widget.localId, widget.areaId, 9), - ), - ], - ), - const SizedBox( - height: 30, - ), - Center( - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ElevatedButton( - style: ElevatedButton.styleFrom( - foregroundColor: AppColors.lightText, - backgroundColor: AppColors.warn, - minimumSize: const Size(150, 50), - textStyle: const TextStyle( - fontWeight: FontWeight.bold, - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - onPressed: () { - Navigator.of(context).popUntil((route) => route.isFirst); - Navigator.pushReplacementNamed( - context, - '/homeScreen', - arguments: {'initialPage': 1}, - ); - }, - child: const Text('SAIR DA SALA'), - ), - const SizedBox(width: 10), - ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - foregroundColor: - MaterialStateProperty.all(AppColors.lightText), - minimumSize: - MaterialStateProperty.all(const Size(150, 50)), - shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - )), - ), - onPressed: () { - Navigator.of(context).pushNamed('/arealocation', - arguments: { - 'placeName': widget.localName, - 'placeId': widget.localId - }); - }, - child: const Text( - 'CRIAR NOVA SALA', - style: - TextStyle(fontSize: 16, fontWeight: FontWeight.bold), - ), - ), - ], - ), - ), - const SizedBox( - height: 30, - ), - ], - ), - ), - ); - } -} - -class SystemIcon extends StatelessWidget { - final IconData icon; - final String label; - final VoidCallback onPressed; - - const SystemIcon({ - super.key, - required this.icon, - required this.label, - required this.onPressed, - }); - - @override - Widget build(BuildContext context) { - return GestureDetector( - onTap: onPressed, - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - width: 80, - height: 80, - decoration: const BoxDecoration( - shape: BoxShape.circle, - color: AppColors.sigeIeYellow, - ), - child: Icon( - icon, - size: 40.0, - color: AppColors.sigeIeBlue, - ), - ), - const SizedBox(height: 10), - SizedBox( - width: 80, - child: Text( - label, - textAlign: TextAlign.center, - style: const TextStyle( - color: AppColors.sigeIeBlue, - fontSize: 9, - fontWeight: FontWeight.bold, - ), - softWrap: true, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - ), - ], - ), - ); - } -} diff --git a/frontend/sige_ie/lib/facilities/ui/facilities.dart b/frontend/sige_ie/lib/facilities/ui/facilities.dart deleted file mode 100644 index 5595f6d6..00000000 --- a/frontend/sige_ie/lib/facilities/ui/facilities.dart +++ /dev/null @@ -1,606 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/areas/data/area_request_model.dart'; -import 'package:sige_ie/areas/data/area_response_model.dart'; -import 'package:sige_ie/places/data/place_request_model.dart'; -import 'package:sige_ie/places/data/place_response_model.dart'; -import 'package:sige_ie/places/data/place_service.dart'; -import '../../config/app_styles.dart'; -import '../../areas/data/area_service.dart'; -import 'dart:io'; -import 'package:http/http.dart' as http; -import 'package:path_provider/path_provider.dart'; -import 'package:path/path.dart' as path; - -class FacilitiesPage extends StatefulWidget { - const FacilitiesPage({super.key}); - - @override - _FacilitiesPageState createState() => _FacilitiesPageState(); -} - -class _FacilitiesPageState extends State { - late Future> _placesList; - final PlaceService _placeService = PlaceService(); - final AreaService _areaService = AreaService(); - late BuildContext _scaffoldContext; - - @override - void initState() { - super.initState(); - _placesList = _placeService.fetchAllPlaces(); - } - - @override - void didChangeDependencies() { - super.didChangeDependencies(); - _scaffoldContext = context; - } - - Future> _loadAreasForPlace(int placeId) async { - try { - return await _areaService.fetchAreasByPlaceId(placeId); - } catch (e) { - print('Erro ao carregar áreas: $e'); - return []; // Retorna uma lista vazia em caso de erro - } - } - - Map> _groupAreasByFloor( - List areas) { - Map> groupedAreas = {}; - for (var area in areas) { - if (groupedAreas[area.floor ?? 0] == null) { - groupedAreas[area.floor ?? 0] = []; - } - groupedAreas[area.floor ?? 0]!.add(area); - } - return groupedAreas; - } - - Future _showAreasForPlace( - BuildContext context, PlaceResponseModel place) async { - try { - List areasForPlace = - await _areaService.fetchAreasByPlaceId(place.id); - Map> groupedAreas = - _groupAreasByFloor(areasForPlace); - - showModalBottomSheet( - context: context, - builder: (context) { - return StatefulBuilder( - builder: (BuildContext context, StateSetter modalSetState) { - return FloorAreaWidget( - groupedAreas: groupedAreas, - placeName: place.name, - placeId: place.id, - onAddFloor: () { - Navigator.of(context) - .pushNamed('/arealocation', arguments: { - 'placeName': place.name, - 'placeId': place.id, - }); - }, - onEditArea: (int areaId) async { - try { - AreaResponseModel area = - await _areaService.fetchArea(areaId); - TextEditingController nameController = - TextEditingController(text: area.name); - - showDialog( - context: context, - builder: (context) { - return AlertDialog( - title: const Text('Editar Área'), - content: TextField( - controller: nameController, - decoration: const InputDecoration( - labelText: 'Nome da Área'), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () async { - Navigator.of(context).pop(); - if (area.floor != null) { - AreaRequestModel updatedArea = - AreaRequestModel( - name: nameController.text, - floor: area.floor!, - place: area.place, - ); - - bool success = await _areaService - .updateArea(areaId, updatedArea); - if (success) { - modalSetState(() { - groupedAreas[area.floor ?? -1] = - groupedAreas[area.floor ?? -1]! - .map((a) => a.id == areaId - ? AreaResponseModel( - id: area.id, - name: updatedArea.name, - floor: - updatedArea.floor ?? - -1, - place: - updatedArea.place ?? - -1, - ) - : a) - .toList(); - }); - ScaffoldMessenger.of(_scaffoldContext) - .showSnackBar( - const SnackBar( - content: Text( - 'Área atualizada com sucesso')), - ); - } else { - ScaffoldMessenger.of(_scaffoldContext) - .showSnackBar( - const SnackBar( - content: Text( - 'Falha ao atualizar a área')), - ); - } - } else { - ScaffoldMessenger.of(_scaffoldContext) - .showSnackBar( - const SnackBar( - content: Text( - 'Dados inválidos para a área')), - ); - } - }, - ), - ], - ); - }, - ); - } catch (e) { - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - SnackBar(content: Text('Erro ao editar a área: $e')), - ); - } - }, - onDeleteArea: (int areaId) async { - bool confirmDelete = await showDialog( - context: context, - builder: (BuildContext dialogContext) { - return AlertDialog( - title: const Text('Confirmar Exclusão'), - content: - const Text('Realmente deseja excluir esta área?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(dialogContext).pop(false); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () { - Navigator.of(dialogContext).pop(true); - }, - ), - ], - ); - }, - ); - - if (confirmDelete) { - bool success = await _areaService.deleteArea(areaId); - if (success) { - modalSetState(() { - groupedAreas.forEach((key, value) { - value.removeWhere((a) => a.id == areaId); - }); - }); - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - const SnackBar( - content: Text('Área excluída com sucesso')), - ); - } else { - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - const SnackBar( - content: Text('Erro ao excluir a área')), - ); - } - } - }, - onTapArea: (int areaId) async { - AreaResponseModel area = - await _areaService.fetchArea(areaId); - Navigator.pushNamed(context, '/systemLocation', arguments: { - 'areaName': area.name, - 'localName': place.name, - 'localId': place.id, - 'areaId': area.id, - }); - }); - }, - ); - }, - ); - } catch (e) { - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - SnackBar(content: Text('Erro ao carregar as áreas: $e')), - ); - } - } - - void _confirmDelete(BuildContext context, PlaceResponseModel place) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Confirmação'), - content: - Text('Você realmente deseja excluir o local "${place.name}"?'), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Excluir'), - onPressed: () async { - Navigator.of(context).pop(); - bool success = await _placeService.deletePlace(place.id); - if (success) { - if (mounted) { - setState(() { - _placesList = _placeService.fetchAllPlaces(); - }); - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - SnackBar( - content: Text( - 'Local "${place.name}" excluído com sucesso')), - ); - } - } else { - if (mounted) { - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - SnackBar( - content: - Text('Falha ao excluir o local "${place.name}"')), - ); - } - } - }, - ), - ], - ); - }, - ); - } - - void _editPlace(BuildContext context, PlaceResponseModel place) { - final TextEditingController nameController = - TextEditingController(text: place.name); - final TextEditingController lonController = - TextEditingController(text: place.lon.toString()); - final TextEditingController latController = - TextEditingController(text: place.lat.toString()); - - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('Editar Local'), - content: SingleChildScrollView( - child: Column( - children: [ - TextField( - controller: nameController, - decoration: const InputDecoration(labelText: 'Nome do Local'), - ), - TextField( - controller: lonController, - decoration: const InputDecoration(labelText: 'Longitude'), - keyboardType: TextInputType.number, - ), - TextField( - controller: latController, - decoration: const InputDecoration(labelText: 'Latitude'), - keyboardType: TextInputType.number, - ), - ], - ), - ), - actions: [ - TextButton( - child: const Text('Cancelar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - TextButton( - child: const Text('Salvar'), - onPressed: () async { - String newName = nameController.text; - double? newLon = double.tryParse(lonController.text); - double? newLat = double.tryParse(latController.text); - Navigator.of(context).pop(); - - if (newName.isNotEmpty && newLon != null && newLat != null) { - PlaceRequestModel updatedPlace = PlaceRequestModel( - name: newName, - lon: newLon, - lat: newLat, - ); - bool success = - await _placeService.updatePlace(place.id, updatedPlace); - if (success) { - if (mounted) { - setState(() { - _placesList = _placeService.fetchAllPlaces(); - }); - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - SnackBar( - content: Text('Local atualizado para "$newName"')), - ); - } - } else { - if (mounted) { - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - const SnackBar( - content: Text('Falha ao atualizar o local')), - ); - } - } - } - }, - ), - ], - ); - }, - ); - } - - Future _exportToPDF(int placeId) async { - final response = await http - .get(Uri.parse('http://10.0.2.2:8000/api/places/$placeId/report')); - - if (response.statusCode == 200) { - final directory = await getApplicationDocumentsDirectory(); - final filePath = path.join(directory.path, 'report_$placeId.pdf'); - final file = File(filePath); - await file.writeAsBytes(response.bodyBytes); - - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - SnackBar(content: Text('PDF baixado com sucesso: $filePath')), - ); - } else { - ScaffoldMessenger.of(_scaffoldContext).showSnackBar( - const SnackBar(content: Text('Falha ao baixar o PDF')), - ); - } - } - - void _exportToExcel(int placeId) { - // Implement your Excel export logic here - print("Export to Excel for place $placeId"); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - backgroundColor: const Color(0xff123c75), - elevation: 0, - ), - body: Builder( - builder: (BuildContext context) { - _scaffoldContext = context; - return SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 20), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Edificações', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - const SizedBox(height: 15), - FutureBuilder>( - future: _placesList, - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return Center(child: Text('Erro: ${snapshot.error}')); - } else if (snapshot.hasData && snapshot.data!.isNotEmpty) { - return ListView.builder( - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemCount: snapshot.data!.length, - itemBuilder: (context, index) { - var place = snapshot.data![index]; - return Container( - margin: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.circular(10), - ), - child: ListTile( - contentPadding: const EdgeInsets.symmetric( - horizontal: 20, vertical: 10), - title: Text( - place.name, - style: const TextStyle( - color: AppColors.lightText, - fontWeight: FontWeight.bold), - ), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: const Icon(Icons.edit, - color: Colors.blue), - onPressed: () => - _editPlace(_scaffoldContext, place), - ), - IconButton( - icon: const Icon(Icons.delete, - color: Colors.red), - onPressed: () => - _confirmDelete(_scaffoldContext, place), - ), - PopupMenuButton( - icon: const Icon(Icons.description, - color: AppColors.lightText), - onSelected: (value) { - if (value == 'pdf') { - _exportToPDF(place.id); - } else if (value == 'excel') { - _exportToExcel(place.id); - } - }, - itemBuilder: (BuildContext context) => - >[ - const PopupMenuItem( - value: 'pdf', - child: Text('Exportar para PDF'), - ), - const PopupMenuItem( - value: 'excel', - child: Text('Exportar para Excel'), - ), - ], - ), - ], - ), - onTap: () => - _showAreasForPlace(_scaffoldContext, place), - ), - ); - }, - ); - } else { - return const Padding( - padding: EdgeInsets.all(10.0), - child: Text( - 'Nenhum local encontrado.', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black54), - ), - ); - } - }, - ), - const SizedBox(height: 15), - ], - ), - ); - }, - ), - ); - } -} - -class FloorAreaWidget extends StatelessWidget { - final Map> groupedAreas; - final String placeName; - final int placeId; - final VoidCallback onAddFloor; - final Function(int) onEditArea; - final Function(int) onDeleteArea; - final Function(int) onTapArea; - - const FloorAreaWidget({ - super.key, - required this.groupedAreas, - required this.placeName, - required this.placeId, - required this.onAddFloor, - required this.onEditArea, - required this.onDeleteArea, - required this.onTapArea, - }); - - @override - Widget build(BuildContext context) { - var sortedKeys = groupedAreas.keys.toList()..sort(); - return Column( - children: [ - Expanded( - child: groupedAreas.isEmpty - ? Center( - child: Padding( - padding: const EdgeInsets.all(16.0), - child: Text( - 'Você ainda não tem uma sala neste local.', - style: TextStyle( - fontSize: 18, - color: Colors.grey[600], - ), - ), - ), - ) - : ListView( - children: sortedKeys.map((floor) { - List areas = groupedAreas[floor]!; - String floorName = floor == 0 ? "Térreo" : "$floor° andar"; - return ExpansionTile( - title: Text(floorName), - children: areas.map((area) { - return ListTile( - title: Text(area.name), - onTap: () => onTapArea(area.id), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - IconButton( - icon: - const Icon(Icons.edit, color: Colors.blue), - onPressed: () => onEditArea(area.id), - ), - IconButton( - icon: - const Icon(Icons.delete, color: Colors.red), - onPressed: () => onDeleteArea(area.id), - ), - ], - ), - ); - }).toList(), - ); - }).toList(), - ), - ), - ListTile( - leading: const Icon(Icons.add), - title: const Text('Adicionar sala'), - onTap: onAddFloor, - ), - ], - ); - } -} diff --git a/frontend/sige_ie/lib/home/ui/home.dart b/frontend/sige_ie/lib/home/ui/home.dart deleted file mode 100644 index 92d34e50..00000000 --- a/frontend/sige_ie/lib/home/ui/home.dart +++ /dev/null @@ -1,356 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/Teams/teams.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import '../../users/feature/profile.dart'; -import '../../facilities/ui/facilities.dart'; -import '../../maps/feature/maps.dart'; -import 'package:sige_ie/users/data/user_response_model.dart'; -import 'package:sige_ie/users/data/user_service.dart'; - -class HomePage extends StatefulWidget { - final int initialPage; - - const HomePage({super.key, this.initialPage = 0}); - - @override - _HomePageState createState() => _HomePageState(); -} - -class _HomePageState extends State { - late int _selectedIndex; - late PageController _pageController; - UserService userService = UserService(); - late UserResponseModel user; - - @override - void initState() { - super.initState(); - _selectedIndex = widget.initialPage; - _pageController = PageController(initialPage: widget.initialPage); - userService.fetchProfileData().then((fetchedUser) { - setState(() { - user = fetchedUser; - }); - }); - } - - @override - void dispose() { - _pageController.dispose(); - super.dispose(); - } - - void _onItemTapped(int index) { - setState(() { - _selectedIndex = index; - }); - _pageController.jumpToPage(index); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - body: Stack( - children: [ - PageView( - controller: _pageController, - onPageChanged: (index) { - setState(() { - _selectedIndex = index; - }); - }, - children: [ - buildHomePage(context), - const FacilitiesPage(), - const TeamsPage(), - const MapsPage(), - const ProfilePage() - ], - ), - ], - ), - bottomNavigationBar: buildBottomNavigationBar(), - ); - } - - Widget buildHomePage(BuildContext context) { - return FutureBuilder( - future: userService.fetchProfileData(), - builder: (context, snapshot) { - if (snapshot.connectionState == ConnectionState.waiting) { - return const Center(child: CircularProgressIndicator()); - } else if (snapshot.hasError) { - return const Center(child: Text('Erro ao carregar os dados')); - } else if (snapshot.hasData) { - var user = snapshot.data!; - return Stack( - children: [ - Column( - children: [ - AppBar( - automaticallyImplyLeading: false, - backgroundColor: const Color(0xff123c75), - elevation: 0, - ), - Expanded( - flex: 3, - child: Container( - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(20), - bottomRight: Radius.circular(20), - ), - ), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Expanded( - child: Container( - decoration: const BoxDecoration( - image: DecorationImage( - image: AssetImage('assets/1000x1000.png'), - fit: BoxFit.cover, - ), - ), - ), - ), - Container( - alignment: Alignment.centerLeft, - padding: const EdgeInsets.only(left: 20), - child: Text( - 'Olá, ${user.firstname}', - style: const TextStyle( - color: AppColors.sigeIeYellow, - fontSize: 20, - ), - ), - ), - const SizedBox(height: 10), - ], - ), - ), - ), - Expanded( - flex: 6, - child: Column( - children: [ - const Spacer(), - buildSmallRectangle( - context, 'Registrar novo local', 'Registrar', () { - Navigator.of(context).pushNamed('/newLocation'); - }), - const Spacer(), - ], - ), - ), - ], - ), - Positioned( - top: 20, - right: 20, - child: IconButton( - icon: const Icon(Icons.info, color: Colors.white, size: 30), - onPressed: () { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: - const Text('Informações sobre o Projeto Sigeie'), - content: const SingleChildScrollView( - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: - 'A criação do aplicativo Sigeie foi um esforço colaborativo de uma equipe dedicada de profissionais, cada um trazendo sua expertise para garantir o sucesso do projeto. Aqui está uma descrição detalhada da participação de cada membro, conforme a organização da equipe:\n\n', - ), - TextSpan( - text: - '1. Loana Nunes Velasco - Cliente do Projeto\n', - style: - TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '- Loana, docente do curso de Engenharia de Energia, atuou como cliente do projeto. Ela foi responsável por validar as entregas, garantindo que as necessidades e expectativas dos usuários finais fossem claramente comunicadas à equipe.\n\n', - ), - TextSpan( - text: - '2. Pedro Lucas - Desenvolvedor Backend (Engenharia de Software)\n', - style: - TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '- Pedro Lucas foi responsável por codificar o backend e configurar a infraestrutura necessária para o funcionamento do aplicativo. Ele contou com a colaboração de Kauan Jose e Oscar de Brito para garantir que o backend fosse seguro e escalável.\n\n', - ), - TextSpan( - text: - '3. Danilo de Melo Ribeiro - Desenvolvedor Frontend e UX Design (Engenharia de Software)\n', - style: - TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '- Danilo trabalhou no desenvolvimento do frontend do aplicativo, codificando a interface e realizando a integração com o backend. Ele projetou a interface do usuário, criou protótipos e realizou entrevistas com os clientes para garantir que o design fosse intuitivo e atendesse às necessidades dos usuários. Ele colaborou com Ramires Rocha e Pedro Lucas para construir uma interface responsiva e interativa.\n\n', - ), - TextSpan( - text: - '4. Oscar de Brito - Analista de Requisitos (Engenharia de Software)\n', - style: - TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '- Oscar levantou os requisitos do projeto, gerenciou a documentação e validou as especificações com o cliente. Ele contou com a colaboração de Ramires Rocha e Pedro Lucas para garantir que todos os requisitos fossem compreendidos e implementados corretamente.\n\n', - ), - TextSpan( - text: - '5. Kauan Jose - Colaborador Backend (Engenharia de Software)\n', - style: - TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '- Kauan colaborou no desenvolvimento do backend, fornecendo suporte essencial para Pedro Lucas. Ele ajudou a configurar a infraestrutura e garantir que o backend funcionasse de maneira eficiente e segura.\n\n', - ), - TextSpan( - text: - '6. Ramires Rocha - Colaborador Frontend (Engenharia Eletrônica)\n', - style: - TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: - '- Ramires colaborou no desenvolvimento do frontend, fornecendo suporte para Danilo de Melo Ribeiro. Ele ajudou a implementar funcionalidades e garantir que a interface fosse responsiva e interativa.\n\n', - ), - ], - ), - style: TextStyle(fontSize: 16), - ), - ), - actions: [ - TextButton( - child: const Text('Fechar'), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - }, - ), - ), - ], - ); - } else { - return const Center(child: Text('Estado desconhecido')); - } - }, - ); - } - - Widget buildSmallRectangle(BuildContext context, String text, - String buttonText, VoidCallback onPress) { - return Container( - decoration: BoxDecoration( - color: const Color(0xff123c75), - borderRadius: BorderRadius.circular(20), - boxShadow: const [ - BoxShadow(color: Colors.black, spreadRadius: 0, blurRadius: 10), - ], - ), - height: 135, - width: MediaQuery.of(context).size.width * 0.8, - margin: const EdgeInsets.symmetric(vertical: 15), - padding: const EdgeInsets.all(20), - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - text, - textAlign: TextAlign.center, - style: const TextStyle( - color: Colors.white, - fontSize: 20, - fontWeight: FontWeight.bold, - ), - ), - const SizedBox(height: 10), - ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: MaterialStateProperty.all(const Size(140, 50)), - shape: MaterialStateProperty.all(RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ))), - onPressed: onPress, - child: Text( - buttonText, - style: const TextStyle( - fontSize: 15, - fontWeight: FontWeight.w900, - ), - ), - ) - ], - ), - ); - } - - Widget buildBottomNavigationBar() { - return Container( - decoration: const BoxDecoration( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - boxShadow: [ - BoxShadow(color: Colors.black38, spreadRadius: 0, blurRadius: 10), - ], - ), - child: ClipRRect( - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(20), - topRight: Radius.circular(20), - ), - child: BottomNavigationBar( - items: const [ - BottomNavigationBarItem( - icon: Icon(Icons.home, size: 35), - label: 'Home', - backgroundColor: Color(0xFFF1F60E)), - BottomNavigationBarItem( - icon: Icon(Icons.build, size: 35), - label: 'Instalações', - backgroundColor: Color(0xFFF1F60E)), - BottomNavigationBarItem( - icon: Icon(Icons.group, size: 35), - label: 'Equipes', - backgroundColor: Color(0xFFF1F60E)), - BottomNavigationBarItem( - icon: Icon(Icons.map, size: 35), - label: 'Mapa', - backgroundColor: Color(0xFFF1F60E)), - BottomNavigationBarItem( - icon: Icon(Icons.person, size: 35), - label: 'Perfil', - backgroundColor: Color(0xFFF1F60E)), - ], - currentIndex: _selectedIndex, - selectedItemColor: const Color(0xFF123C75), - unselectedItemColor: const Color.fromARGB(255, 145, 142, 142), - onTap: _onItemTapped, - ), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/main.dart b/frontend/sige_ie/lib/main.dart deleted file mode 100644 index b3098a2a..00000000 --- a/frontend/sige_ie/lib/main.dart +++ /dev/null @@ -1,390 +0,0 @@ -import 'package:cookie_jar/cookie_jar.dart'; -import 'package:flutter/material.dart'; -import 'package:sige_ie/core/ui/first_scren.dart'; -import 'package:sige_ie/core/feature/register/register.dart'; -import 'package:sige_ie/core/ui/splash_screen.dart'; -import 'package:sige_ie/equipments/feature/atmospheric-discharges/atmospheric_discharges_list.dart'; -import 'package:sige_ie/equipments/feature/refrigerations/refrigeration_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/distribuition_board/distribuition_board_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/electrical_line/electrical_line_list.dart'; -import 'package:sige_ie/equipments/feature/electrical_load/eletrical_load_list.dart'; -import 'package:sige_ie/equipments/feature/fire_alarm/list_fire_alarms.dart'; -import 'package:sige_ie/equipments/feature/structured_cabling/structured_cabling_equipment_list.dart'; -import 'package:sige_ie/facilities/ui/facilities.dart'; -import 'package:sige_ie/home/ui/home.dart'; -import 'package:sige_ie/maps/feature/maps.dart'; -import 'package:sige_ie/equipments/feature/iluminations/ilumination_equipment_list.dart'; -import 'package:sige_ie/equipments/feature/system_configuration.dart'; -import 'package:sige_ie/places/feature/register/new_place.dart'; -import 'package:sige_ie/areas/feature/register/new_area.dart'; -import 'package:sige_ie/equipments/feature/electrical_circuit/electrical_circuit_list.dart'; -import 'core/feature/login/login.dart'; - -void main() { - runApp(const MyApp()); -} - -final cookieJar = CookieJar(); - -class MyApp extends StatelessWidget { - const MyApp({super.key}); - @override - Widget build(BuildContext context) { - return MaterialApp( - initialRoute: '/', - onGenerateRoute: (settings) { - switch (settings.name) { - case '/': - return MaterialPageRoute( - builder: (context) => const SplashScreen()); - case '/loginScreen': - return MaterialPageRoute(builder: (context) => const LoginScreen()); - case '/first': - return MaterialPageRoute(builder: (context) => const FirstScreen()); - case '/facilities': - return MaterialPageRoute( - builder: (context) => const FacilitiesPage()); - case '/registerScreen': - return MaterialPageRoute( - builder: (context) => const RegisterScreen()); - case '/homeScreen': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final int initialPage = args['initialPage'] ?? 0; - return MaterialPageRoute( - builder: (context) => HomePage(initialPage: initialPage), - ); - } - return MaterialPageRoute(builder: (context) => const HomePage()); - case '/MapsPage': - return MaterialPageRoute(builder: (context) => const MapsPage()); - case '/newLocation': - return MaterialPageRoute(builder: (context) => const NewPlace()); - case '/arealocation': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? localName = args['placeName']?.toString(); - final int? localId = args['placeId'] as int?; - - if (localName != null && localId != null) { - return MaterialPageRoute( - builder: (context) => - AreaLocation(localName: localName, localId: localId), - ); - } else { - throw Exception( - 'Invalid arguments: localName or localId is null in /arealocation.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /arealocation.'); - - case '/systemLocation': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int? areaId = args['areaId']; - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => SystemConfiguration( - areaName: areaName, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, localId, or areaId is null in /systemLocation.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /systemLocation.'); - - case '/listIluminationEquipment': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int systemId = args['systemId'] ?? 0; - final int? areaId = args['areaId']; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListIluminationEquipment( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, or localId is null in /equipmentScreen.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /equipmentScreen.'); - - case '/electricalCircuitList': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int systemId = args['systemId'] ?? 0; - final int? areaId = args['areaId']; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListCircuitEquipment( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, or localId is null in /electricalCircuitList.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /electricalCircuitList.'); - - case '/electricalLineList': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int systemId = args['systemId'] ?? 0; - final int? areaId = args['areaId']; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListElectricalLineEquipment( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, or localId is null in /electricalLineList.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /electricalLineList.'); - - case '/listatmosphericEquipment': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int systemId = args['systemId'] ?? 0; - final int? areaId = args['areaId']; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListAtmosphericEquipment( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, or localId is null in /electricalLineList.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /electricalLineList.'); - - case '/listDistribuitionBoard': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int systemId = args['systemId'] ?? 0; - final int? areaId = args['areaId']; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListDistributionBoard( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, or localId is null in /listDistribuitionBoard.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /listDistribuitionBoard.'); - - case '/listFireAlarms': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int? areaId = args['areaId']; - final int systemId = args['systemId'] ?? 0; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListFireAlarms( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - ), - ); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, localId, or areaId is null in /listFireAlarms.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /listFireAlarms.'); - - case '/listRefrigerationEquipment': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int? areaId = args['areaId']; - final int systemId = args['systemId'] ?? 0; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListRefrigerationEquipment( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, or localId is null in /listDistribuitionBoard.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /listDistribuitionBoard.'); - - case '/listStruturedCabling': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int? areaId = args['areaId']; - - final int systemId = args['systemId'] ?? 0; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListStructuredCabling( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, ou localId is null in /listStruturedCabling.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /listStruturedCabling.'); - - case '/listelectricalLoadEquipment': - if (settings.arguments is Map) { - final args = settings.arguments as Map; - final String? areaName = args['areaName']?.toString(); - final String? localName = args['localName']?.toString(); - final int? localId = args['localId']; - final int systemId = args['systemId'] ?? 0; - final int? areaId = args['areaId']; - - if (areaName != null && - localName != null && - localId != null && - areaId != null) { - return MaterialPageRoute( - builder: (context) => ListElectricalLoadEquipment( - areaName: areaName, - systemId: systemId, - localName: localName, - localId: localId, - areaId: areaId, - )); - } else { - throw Exception( - 'Invalid arguments: One of areaName, localName, ou localId is null in /electricalLineList.'); - } - } - throw Exception( - 'Invalid route: Expected Map arguments for /electricalLineList.'); - - default: - return MaterialPageRoute( - builder: (context) => UndefinedView(name: settings.name)); - } - }, - ); - } -} - -class UndefinedView extends StatelessWidget { - final String? name; - const UndefinedView({super.key, this.name}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(title: Text('No route defined for ${name ?? "unknown"}')), - ); - } -} diff --git a/frontend/sige_ie/lib/maps/controller/maps_controller.dart b/frontend/sige_ie/lib/maps/controller/maps_controller.dart deleted file mode 100644 index 5c0ccf2c..00000000 --- a/frontend/sige_ie/lib/maps/controller/maps_controller.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'dart:async'; -import 'dart:ui' as ui; -import 'package:flutter/services.dart'; -import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import 'package:geolocator/geolocator.dart'; -import '../../places/data/place_response_model.dart'; -import '../../places/data/place_service.dart'; - -class MapsController extends GetxController { - final latitude = 0.0.obs; - final longitude = 0.0.obs; - final markers = {}.obs; - final isLoading = true.obs; - - final PlaceService _placeService = PlaceService(); - late CameraPosition initialCameraPosition; - - @override - void onInit() { - super.onInit(); - _getCurrentLocation(); - fetchPlaces(); - } - - void onMapCreated(GoogleMapController controller) {} - - Future _getCurrentLocation() async { - bool serviceEnabled; - LocationPermission permission; - - // Verifique se o serviço de localização está habilitado - serviceEnabled = await Geolocator.isLocationServiceEnabled(); - if (!serviceEnabled) { - Get.snackbar('Erro', 'Serviço de localização está desabilitado.'); - return; - } - - // Verifique se a permissão de localização é concedida - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.denied) { - Get.snackbar('Erro', 'Permissão de localização negada.'); - return; - } - } - - if (permission == LocationPermission.deniedForever) { - Get.snackbar('Erro', 'Permissão de localização negada permanentemente.'); - return; - } - - // Obtenha a localização atual - final Position position = await Geolocator.getCurrentPosition( - desiredAccuracy: LocationAccuracy.high); - - latitude.value = position.latitude; - longitude.value = position.longitude; - - initialCameraPosition = CameraPosition( - target: LatLng(position.latitude, position.longitude), - zoom: 12, - ); - - isLoading.value = false; - } - - Future getBytesFromAsset(String path, int width) async { - try { - ByteData data = await rootBundle.load(path); - ui.Codec codec = await ui.instantiateImageCodec(data.buffer.asUint8List(), - targetWidth: width); - ui.FrameInfo fi = await codec.getNextFrame(); - return (await fi.image.toByteData(format: ui.ImageByteFormat.png)) - ?.buffer - .asUint8List(); - } catch (e) { - Get.snackbar('Erro', 'Falha ao carregar ícone: $e'); - return null; - } - } - - Future fetchPlaces() async { - try { - final List places = - await _placeService.fetchAllPlaces(); - for (var place in places) { - await addMarker(place); - } - } catch (e) { - Get.snackbar('Erro', 'Falha ao carregar locais: $e'); - } - } - - Future addMarker(PlaceResponseModel place) async { - final Uint8List? icon = await getBytesFromAsset('assets/lighting.png', 80); - if (icon != null) { - markers.add( - Marker( - markerId: MarkerId(place.id.toString()), - position: LatLng(place.lat, place.lon), - infoWindow: InfoWindow(title: place.name), - icon: BitmapDescriptor.fromBytes(icon), - ), - ); - } else { - Get.snackbar('Erro', 'Falha ao carregar ícone do marcador'); - } - } -} diff --git a/frontend/sige_ie/lib/maps/feature/maps.dart b/frontend/sige_ie/lib/maps/feature/maps.dart deleted file mode 100644 index ed19b902..00000000 --- a/frontend/sige_ie/lib/maps/feature/maps.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:get/get.dart'; -import 'package:google_maps_flutter/google_maps_flutter.dart'; -import '../controller/maps_controller.dart'; - -class MapsPage extends StatelessWidget { - const MapsPage({super.key}); - - @override - Widget build(BuildContext context) { - final MapsController controller = Get.put(MapsController()); - - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - backgroundColor: const Color(0xff123c75), - elevation: 0, - ), - body: Obx(() { - if (controller.isLoading.value) { - return const Center(child: CircularProgressIndicator()); - } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 20), - decoration: const BoxDecoration( - color: Color(0xff123c75), - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Column( - children: [ - Text( - 'Mapa', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - ), - Expanded( - child: GoogleMap( - onMapCreated: controller.onMapCreated, - initialCameraPosition: controller.initialCameraPosition, - markers: Set.of(controller.markers), - myLocationEnabled: true, - myLocationButtonEnabled: true, - ), - ), - ], - ); - }), - ); - } -} diff --git a/frontend/sige_ie/lib/places/data/place_request_model.dart b/frontend/sige_ie/lib/places/data/place_request_model.dart deleted file mode 100644 index f42ceb83..00000000 --- a/frontend/sige_ie/lib/places/data/place_request_model.dart +++ /dev/null @@ -1,23 +0,0 @@ -class PlaceRequestModel { - String name; - double lon; - double lat; - - PlaceRequestModel({required this.name, required this.lon, required this.lat}); - - Map toJson() { - return { - 'name': name, - 'lon': lon, - 'lat': lat, - }; - } - - factory PlaceRequestModel.fromJson(Map json) { - return PlaceRequestModel( - name: json['name'], - lon: json['lon'].toDouble(), - lat: json['lat'].toDouble(), - ); - } -} diff --git a/frontend/sige_ie/lib/places/data/place_response_model.dart b/frontend/sige_ie/lib/places/data/place_response_model.dart deleted file mode 100644 index 5664d7df..00000000 --- a/frontend/sige_ie/lib/places/data/place_response_model.dart +++ /dev/null @@ -1,35 +0,0 @@ -class PlaceResponseModel { - int id; - String name; - double lon; - double lat; - int placeOwner; - - PlaceResponseModel({ - required this.id, - required this.name, - required this.lon, - required this.lat, - required this.placeOwner, - }); - - factory PlaceResponseModel.fromJson(Map json) { - return PlaceResponseModel( - id: json['id'], - name: json['name'], - lon: json['lon'].toDouble(), - lat: json['lat'].toDouble(), - placeOwner: json['place_owner'], - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'lon': lon, - 'lat': lat, - 'place_owner': placeOwner, - }; - } -} diff --git a/frontend/sige_ie/lib/places/data/place_service.dart b/frontend/sige_ie/lib/places/data/place_service.dart deleted file mode 100644 index 57182a98..00000000 --- a/frontend/sige_ie/lib/places/data/place_service.dart +++ /dev/null @@ -1,112 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; -import 'package:sige_ie/places/data/place_request_model.dart'; -import 'package:sige_ie/places/data/place_response_model.dart'; - -class PlaceService { - final Logger _logger = Logger('PlaceService'); - final String baseUrl = 'http://10.0.2.2:8000/api/places/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - // POST - Future register(PlaceRequestModel placeRequestModel) async { - var url = Uri.parse(baseUrl); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(placeRequestModel.toJson()), - ); - - if (response.statusCode == 201) { - Map responseData = jsonDecode(response.body); - return responseData['id']; - } else { - _logger.info('Failed to register place: ${response.statusCode}'); - return null; - } - } catch (e) { - _logger.info('Error during register: $e'); - return null; - } - } - - // GET ALL - Future> fetchAllPlaces() async { - var url = Uri.parse(baseUrl); - try { - var response = await client.get(url); - - if (response.statusCode == 200) { - List dataList = jsonDecode(response.body); - return dataList - .map((data) => PlaceResponseModel.fromJson(data)) - .toList(); - } else { - throw Exception('Failed to load places'); - } - } catch (e) { - _logger.info('Error during fetchAllPlaces: $e'); - throw Exception('Failed to load places'); - } - } - - // GET - Future fetchPlace(int placeId) async { - var url = Uri.parse('$baseUrl$placeId/'); - - try { - var response = await client.get(url); - - if (response.statusCode == 200) { - var data = jsonDecode(response.body); - return PlaceResponseModel.fromJson(data); - } else { - throw Exception('Failed to load place with ID $placeId'); - } - } catch (e) { - _logger.info('Error during fetchPlace: $e'); - throw Exception('Failed to load place with ID $placeId'); - } - } - - // PUT - Future updatePlace( - int placeId, PlaceRequestModel placeRequestModel) async { - var url = Uri.parse('$baseUrl$placeId/'); - - try { - var response = await client.put( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(placeRequestModel.toJson()), - ); - - return response.statusCode == 200; - } catch (e) { - _logger.info('Error during updatePlace: $e'); - return false; - } - } - - // DELETE - Future deletePlace(int placeId) async { - var url = Uri.parse('$baseUrl$placeId/'); - - try { - var response = await client.delete(url); - - return response.statusCode == 204; - } catch (e) { - _logger.info('Error during deletePlace: $e'); - return false; - } - } -} diff --git a/frontend/sige_ie/lib/places/feature/register/new_place.dart b/frontend/sige_ie/lib/places/feature/register/new_place.dart deleted file mode 100644 index 755fa546..00000000 --- a/frontend/sige_ie/lib/places/feature/register/new_place.dart +++ /dev/null @@ -1,211 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/config/app_styles.dart'; -import 'package:sige_ie/places/data/place_request_model.dart'; -import 'package:sige_ie/places/data/place_service.dart'; -import 'position.dart'; - -class NewPlace extends StatefulWidget { - const NewPlace({super.key}); - - @override - NewPlaceState createState() => NewPlaceState(); -} - -class NewPlaceState extends State { - PlaceService placeService = PlaceService(); - String coordinates = ''; - bool coord = false; - final nameController = TextEditingController(); - late PositionController positionController; - late TextEditingController coordinatesController; - - @override - void initState() { - super.initState(); - positionController = PositionController(); - coordinatesController = TextEditingController(); - } - - void _getCoordinates() { - positionController.getPosition().then((_) { - setState(() { - if (positionController.error.isEmpty) { - coordinates = - "Latitude: ${positionController.lat}, Longitude: ${positionController.lon}"; - coordinatesController.text = coordinates; - coord = true; - } else { - coordinates = "Erro: ${positionController.error}"; - coordinatesController.text = coordinates; - coord = false; - } - }); - }).catchError((e) { - setState(() { - coordinates = "Erro ao obter localização: $e"; - coordinatesController.text = coordinates; - coord = false; - }); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: AppColors.sigeIeBlue, - leading: IconButton( - icon: const Icon(Icons.arrow_back, color: Colors.white), - onPressed: () => Navigator.of(context).pop(), - ), - ), - body: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - width: double.infinity, - padding: const EdgeInsets.fromLTRB(10, 10, 10, 35), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: - BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Text('Registrar Novo Local', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white)), - ), - ), - const SizedBox(height: 60), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const Text('Coordenadas', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black)), - const SizedBox(height: 10), - Container( - decoration: BoxDecoration( - color: Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - child: Row( - children: [ - Expanded( - child: TextField( - decoration: const InputDecoration( - hintText: - 'Clique na lupa para obter as coordenadas', - border: InputBorder.none, - contentPadding: - EdgeInsets.symmetric(horizontal: 10), - ), - controller: coordinatesController, - enabled: false, - ), - ), - IconButton( - icon: const Icon(Icons.search), - onPressed: _getCoordinates, - ), - ], - ), - ), - const SizedBox(height: 40), - const Text('Nome do Local', - style: TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - color: Colors.black)), - const SizedBox(height: 10), - Container( - decoration: BoxDecoration( - color: Colors.grey[200], - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: nameController, - decoration: const InputDecoration( - hintText: 'Digite o nome do local', - border: InputBorder.none, - contentPadding: EdgeInsets.symmetric(horizontal: 10), - ), - ), - ), - const SizedBox(height: 60), - Center( - child: ElevatedButton( - style: ButtonStyle( - backgroundColor: - MaterialStateProperty.all(AppColors.sigeIeYellow), - foregroundColor: - MaterialStateProperty.all(AppColors.sigeIeBlue), - minimumSize: - MaterialStateProperty.all(const Size(200, 50)), - textStyle: MaterialStateProperty.all( - const TextStyle( - fontSize: 16, - fontWeight: FontWeight.bold, - ), - ), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(8), - ), - ), - ), - onPressed: () async { - if (coord && nameController.text.trim().isNotEmpty) { - final PlaceService placeService = PlaceService(); - final PlaceRequestModel place = PlaceRequestModel( - name: nameController.text, - lon: positionController.lon, - lat: positionController.lat); - - int? placeId = await placeService.register(place); - if (placeId != null) { - Navigator.of(context) - .pushNamed('/arealocation', arguments: { - 'placeName': nameController.text.trim(), - 'placeId': placeId, - }); - } - } else if (nameController.text.trim().isEmpty || !coord) { - showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text("Erro"), - content: const Text( - "Por favor, clique na lupa e insira um nome para o local"), - actions: [ - TextButton( - child: const Text("OK"), - onPressed: () { - Navigator.of(context).pop(); - }, - ), - ], - ); - }, - ); - } - }, - child: const Text('REGISTRAR'), - )), - ], - ), - ), - ], - ), - ), - ); - } -} diff --git a/frontend/sige_ie/lib/places/feature/register/position.dart b/frontend/sige_ie/lib/places/feature/register/position.dart deleted file mode 100644 index 929a5176..00000000 --- a/frontend/sige_ie/lib/places/feature/register/position.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:geolocator/geolocator.dart'; - -class PositionController extends ChangeNotifier { - double lat = 0.0; - double lon = 0.0; - String error = ''; - - PositionController() { - getPosition(); - } - - getPosition() async { - try { - Position position = await _currentPostion(); - lat = position.latitude; - lon = position.longitude; - } catch (e) { - error = e.toString(); - } - notifyListeners(); - } -} - -Future _currentPostion() async { - LocationPermission permission; - bool active = await Geolocator.isLocationServiceEnabled(); - if (!active) { - return Future.error("Por favor, autorize o acesso a localização"); - } - permission = await Geolocator.checkPermission(); - if (permission == LocationPermission.denied) { - permission = await Geolocator.requestPermission(); - if (permission == LocationPermission.denied) { - return Future.error("Por favor, autorize o acesso a localização"); - } - } - - if (permission == LocationPermission.deniedForever) { - return Future.error("Autorize o acesso a localização"); - } - - return await Geolocator.getCurrentPosition(); -} diff --git a/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_request_model.dart b/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_request_model.dart deleted file mode 100644 index 63cbb1da..00000000 --- a/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_request_model.dart +++ /dev/null @@ -1,25 +0,0 @@ -import 'dart:io'; -import 'dart:convert'; - -class EquipmentPhotoRequestModel { - String? photoBase64; - String? description; - int? equipment; - - EquipmentPhotoRequestModel({ - required File photo, - required this.description, - required this.equipment, - }) { - String base64Image = base64Encode(photo.readAsBytesSync()); - photoBase64 = 'data:image/jpeg;base64,$base64Image'; - } - - Map toJson() { - return { - 'photo': photoBase64, - 'description': description, - 'equipment': equipment, - }; - } -} diff --git a/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_response_model.dart b/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_response_model.dart deleted file mode 100644 index a3c0a2b3..00000000 --- a/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_response_model.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'dart:typed_data'; -import 'package:path_provider/path_provider.dart'; - -class EquipmentPhotoResponseModel { - int id; - String? photoBase64; - String? description; - int? equipment; - - EquipmentPhotoResponseModel({ - required this.id, - required this.photoBase64, - required this.description, - required this.equipment, - }); - - factory EquipmentPhotoResponseModel.fromJson(Map json) { - return EquipmentPhotoResponseModel( - id: json['id'], - photoBase64: json['photo_base64'], - description: json['description'], - equipment: json['equipment'], - ); - } - - Future toFile() async { - Uint8List bytes = base64Decode(photoBase64!.split(',')[1]); - final tempDir = await getTemporaryDirectory(); - final filePath = '${tempDir.path}/photo_$id.jpg'; - File file = File(filePath); - await file.writeAsBytes(bytes); - return file; - } -} diff --git a/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_service.dart b/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_service.dart deleted file mode 100644 index a30d546c..00000000 --- a/frontend/sige_ie/lib/shared/data/equipment-photo/equipment_photo_service.dart +++ /dev/null @@ -1,140 +0,0 @@ -import 'dart:convert'; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:http/http.dart' as http; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_request_model.dart'; -import 'package:sige_ie/shared/data/equipment-photo/equipment_photo_response_model.dart'; - -class EquipmentPhotoService { - final Logger _logger = Logger('EquipmentPhotoService'); - final String baseUrl = 'http://10.0.2.2:8000/api/equipment-photos/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future createPhoto( - EquipmentPhotoRequestModel equipmentPhotoRequestModel) async { - var url = Uri.parse(baseUrl); - - _logger.info( - 'Sending request to: $url with body: ${jsonEncode(equipmentPhotoRequestModel.toJson())}'); - - try { - var response = await client.post( - url, - headers: { - 'Content-Type': 'application/json', - }, - body: jsonEncode(equipmentPhotoRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201 || response.statusCode == 200) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return true; - } else { - _logger - .info('Failed to register equipment photo: ${response.statusCode}'); - return false; - } - } catch (e) { - _logger.info('Error during register: $e'); - return false; - } - } - - Future> getPhotosByEquipmentId( - int equipmentId) async { - try { - var url = Uri.parse( - 'http://10.0.2.2:8000/api/equipment-photos/by-equipment/$equipmentId/'); - _logger.info('Fetching photos from: $url'); - var photosResponse = await client.get(url); - - if (photosResponse.statusCode != 200) { - _logger.warning( - 'Failed to fetch equipment photos: ${photosResponse.statusCode}'); - return []; - } - - List photosData = jsonDecode(photosResponse.body); - - _logger.info('Photos data: $photosData'); - - List photoModels = - photosData.map((photoData) { - return EquipmentPhotoResponseModel.fromJson(photoData); - }).toList(); - - _logger.info('Fetched equipment photos successfully'); - - return photoModels; - } catch (e) { - _logger.severe('Error fetching and converting photos: $e'); - return []; - } - } - - Future deletePhoto(int photoId) async { - var url = Uri.parse('$baseUrl$photoId/'); - - _logger.info('Sending DELETE request to: $url'); - - try { - var response = await client.delete(url, headers: { - 'Content-Type': 'application/json', - }); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 204 || response.statusCode == 200) { - _logger.info('Photo deleted successfully'); - return true; - } else { - _logger.info('Failed to delete photo: ${response.statusCode}'); - return false; - } - } catch (e) { - _logger.severe('Error during delete: $e'); - return false; - } - } - - Future updatePhoto(int photoId, - EquipmentPhotoRequestModel equipmentPhotoRequestModel) async { - var url = Uri.parse('$baseUrl$photoId/'); - - _logger.info( - 'Sending PUT request to: $url with body: ${jsonEncode(equipmentPhotoRequestModel.toJson())}'); - - try { - var response = await client.put( - url, - headers: { - 'Content-Type': 'application/json', - }, - body: jsonEncode(equipmentPhotoRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 200) { - _logger.info('Photo updated successfully'); - return true; - } else { - _logger.info('Failed to update photo: ${response.statusCode}'); - return false; - } - } catch (e) { - _logger.severe('Error during update: $e'); - return false; - } - } -} diff --git a/frontend/sige_ie/lib/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart b/frontend/sige_ie/lib/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart deleted file mode 100644 index ca97500b..00000000 --- a/frontend/sige_ie/lib/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart +++ /dev/null @@ -1,27 +0,0 @@ -class EquipmentCategoryResponseModel { - int id; - String name; - int system; - - EquipmentCategoryResponseModel({ - required this.id, - required this.name, - required this.system, - }); - - factory EquipmentCategoryResponseModel.fromJson(Map json) { - return EquipmentCategoryResponseModel( - id: json['id'], - name: json['name'], - system: json['system'], - ); - } - - Map toJson() { - return { - 'id': id, - 'name': name, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/shared/data/generic-equipment-category/generic_equipment_category_service.dart b/frontend/sige_ie/lib/shared/data/generic-equipment-category/generic_equipment_category_service.dart deleted file mode 100644 index 4c8bdb73..00000000 --- a/frontend/sige_ie/lib/shared/data/generic-equipment-category/generic_equipment_category_service.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/main.dart'; - -class GenericEquipmentCategoryService { - final Logger _logger = Logger('GenericEquipmentCategoryService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> - getAllGenericEquipmentCategoryBySystem(int systemId) async { - var url = Uri.parse('${baseUrl}equipment-types/by-system/$systemId/'); - - try { - _logger.info('Sending GET request to $url'); - var response = - await client.get(url, headers: {'Content-Type': 'application/json'}); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 200) { - List responseData = jsonDecode(response.body); - List equipmentList = responseData - .map((item) => EquipmentCategoryResponseModel.fromJson(item)) - .toList(); - _logger - .info('Request successful, received ${equipmentList.length} items'); - return equipmentList; - } else { - _logger - .info('Failed to get equipment by system: ${response.statusCode}'); - return []; - } - } catch (e) { - _logger.info('Error during get all equipment by system: $e'); - return []; - } - } -} diff --git a/frontend/sige_ie/lib/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart b/frontend/sige_ie/lib/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart deleted file mode 100644 index b1140335..00000000 --- a/frontend/sige_ie/lib/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart +++ /dev/null @@ -1,16 +0,0 @@ -class PersonalEquipmentCategoryRequestModel { - String name; - int? system; - - PersonalEquipmentCategoryRequestModel({ - required this.name, - required this.system, - }); - - Map toJson() { - return { - 'name': name, - 'system': system, - }; - } -} diff --git a/frontend/sige_ie/lib/shared/data/personal-equipment-category/personal_equipment_category_service.dart b/frontend/sige_ie/lib/shared/data/personal-equipment-category/personal_equipment_category_service.dart deleted file mode 100644 index 7d415cfc..00000000 --- a/frontend/sige_ie/lib/shared/data/personal-equipment-category/personal_equipment_category_service.dart +++ /dev/null @@ -1,92 +0,0 @@ -import 'dart:convert'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/shared/data/generic-equipment-category/generic_equipment_category_response_model.dart'; -import 'package:sige_ie/shared/data/personal-equipment-category/personal_equipment_category_request_model.dart'; -import 'package:sige_ie/main.dart'; - -class PersonalEquipmentCategoryService { - final Logger _logger = Logger('PersonalEquipmentCategoryService'); - final String baseUrl = 'http://10.0.2.2:8000/api/'; - http.Client client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - Future> - getAllPersonalEquipmentCategoryBySystem(int systemId) async { - var url = - Uri.parse('${baseUrl}personal-equipment-types/by-system/$systemId/'); - - try { - var response = - await client.get(url, headers: {'Content-Type': 'application/json'}); - - if (response.statusCode == 200) { - List responseData = jsonDecode(response.body); - List equipmentList = responseData - .map((item) => EquipmentCategoryResponseModel.fromJson(item)) - .toList(); - //_logger.info('Request successful, received ${equipmentList.length} items'); - return equipmentList; - } else { - _logger.info( - 'Failed to get personal equipment by system: ${response.statusCode}'); - return []; - } - } catch (e) { - _logger.info('Error during get all personal equipment by system: $e'); - return []; - } - } - - Future createPersonalEquipmentCategory( - PersonalEquipmentCategoryRequestModel - personalEquipmentTypeRequestModel) async { - var url = Uri.parse('${baseUrl}personal-equipment-types/'); - - try { - var response = await client.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(personalEquipmentTypeRequestModel.toJson()), - ); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - if (response.statusCode == 201) { - Map responseData = jsonDecode(response.body); - _logger.info('Request successful, received ID: ${responseData['id']}'); - return responseData['id']; - } else { - _logger.info( - 'Failed to register fire alarm equipment: ${response.statusCode}'); - return -1; - } - } catch (e) { - _logger.info('Error during register: $e'); - return -1; - } - } - - Future deletePersonalEquipmentCategory(int personalCategoryId) async { - var url = - Uri.parse('${baseUrl}personal-equipment-types/$personalCategoryId/'); - - try { - _logger.info('Sending DELETE request to $url'); - var response = await client - .delete(url, headers: {'Content-Type': 'application/json'}); - - _logger.info('Response status code: ${response.statusCode}'); - _logger.info('Response body: ${response.body}'); - - return response.statusCode == 204; - } catch (e) { - _logger.info('Error during delete equipment: $e'); - return false; - } - } -} diff --git a/frontend/sige_ie/lib/users/data/user_request_model.dart b/frontend/sige_ie/lib/users/data/user_request_model.dart deleted file mode 100644 index 082a00ea..00000000 --- a/frontend/sige_ie/lib/users/data/user_request_model.dart +++ /dev/null @@ -1,21 +0,0 @@ -class UserRequestModel { - String username; - String firstname; - String password; - String email; - - UserRequestModel( - {required this.username, - required this.firstname, - required this.password, - required this.email}); - - Map toJson() { - return { - 'username': username, - 'first_name': firstname, - 'password': password, - 'email': email, - }; - } -} diff --git a/frontend/sige_ie/lib/users/data/user_response_model.dart b/frontend/sige_ie/lib/users/data/user_response_model.dart deleted file mode 100644 index 19dcf868..00000000 --- a/frontend/sige_ie/lib/users/data/user_response_model.dart +++ /dev/null @@ -1,18 +0,0 @@ -class UserResponseModel { - String id; - String username; - String firstname; - String email; - - UserResponseModel( - {required this.id, - required this.username, - required this.firstname, - required this.email}); - - UserResponseModel.fromJson(Map json) - : id = json['id'].toString(), - username = json['username'].toString(), - firstname = json['first_name'].toString(), - email = json['email'].toString(); -} diff --git a/frontend/sige_ie/lib/users/data/user_service.dart b/frontend/sige_ie/lib/users/data/user_service.dart deleted file mode 100644 index 9ea00a24..00000000 --- a/frontend/sige_ie/lib/users/data/user_service.dart +++ /dev/null @@ -1,94 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; -import 'package:http/http.dart' as http; -import 'package:http_interceptor/http_interceptor.dart'; -import 'package:logging/logging.dart'; -import 'package:sige_ie/core/data/auth_interceptor.dart'; -import 'package:sige_ie/main.dart'; -import 'package:sige_ie/users/data/user_request_model.dart'; -import 'package:sige_ie/users/data/user_response_model.dart'; - -class UserService { - final Logger _logger = Logger('UserService'); - Future register(UserRequestModel userRequestModel) async { - var url = Uri.parse('http://10.0.2.2:8000/api/users/'); - - var response = await http.post( - url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode(userRequestModel.toJson()), - ); - return response.statusCode == 201; - } - - Future update(String id, String firstName, String email) async { - var client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - var url = Uri.parse('http://10.0.2.2:8000/api/users/$id/'); - try { - var response = await client.put(url, - headers: {'Content-Type': 'application/json'}, - body: jsonEncode({ - 'first_name': firstName, - 'email': email, - })); - if (response.statusCode == 200 || response.statusCode == 201) { - return true; - } else { - return false; - } - } catch (e) { - return false; - } - } - - Future delete(String id) async { - var client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - var url = Uri.parse('http://10.0.2.2:8000/api/users/$id/'); - try { - var response = await client - .delete(url, headers: {'Content-Type': 'application/json'}); - if (response.statusCode == 204) { - return true; - } else { - return false; - } - } catch (e) { - return false; - } - } - - Future fetchProfileData() async { - var client = InterceptedClient.build( - interceptors: [AuthInterceptor(cookieJar)], - ); - - try { - final response = - await client.get(Uri.parse('http://10.0.2.2:8000/api/userauth')); - - if (response.statusCode == 200) { - var data = jsonDecode(response.body); - return UserResponseModel.fromJson(data); - } else { - throw Exception('Falha ao carregar dados do perfil'); - } - } on http.ClientException catch (e) { - _logger.info('Erro ao carregar dados do perfil (ClientException): $e'); - throw Exception( - 'Erro na conexão com o servidor. Por favor, tente novamente mais tarde.'); - } on SocketException catch (e) { - _logger.info('Erro ao carregar dados do perfil (SocketException): $e'); - throw Exception('Erro de rede. Verifique sua conexão com a internet.'); - } catch (e) { - _logger.info('Erro ao carregar dados do perfil: $e'); - throw Exception( - 'Ocorreu um erro inesperado. Por favor, tente novamente.'); - } - } -} diff --git a/frontend/sige_ie/lib/users/feature/profile.dart b/frontend/sige_ie/lib/users/feature/profile.dart deleted file mode 100644 index e20fc75f..00000000 --- a/frontend/sige_ie/lib/users/feature/profile.dart +++ /dev/null @@ -1,270 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:sige_ie/core/data/auth_service.dart'; -import 'package:sige_ie/users/data/user_response_model.dart'; -import 'package:sige_ie/users/data/user_service.dart'; -import 'package:sige_ie/config/app_styles.dart'; - -class ProfilePage extends StatefulWidget { - const ProfilePage({super.key}); - - @override - _ProfilePageState createState() => _ProfilePageState(); -} - -class _ProfilePageState extends State { - UserService userService = UserService(); - AuthService authService = AuthService(); - UserResponseModel userResponseModel = - UserResponseModel(id: '', email: '', firstname: '', username: ''); - - @override - void initState() { - super.initState(); - userService.fetchProfileData().then((userResponseModel) { - setState(() { - this.userResponseModel = userResponseModel; - }); - }).catchError((error) { - print(error); - }); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - automaticallyImplyLeading: false, - backgroundColor: AppColors.sigeIeBlue, - ), - body: SingleChildScrollView( - child: - Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - padding: const EdgeInsets.fromLTRB(10, 10, 10, 20), - decoration: const BoxDecoration( - color: AppColors.sigeIeBlue, - borderRadius: BorderRadius.vertical(bottom: Radius.circular(20)), - ), - child: const Center( - child: Column( - children: [ - Text( - 'Editar perfil', - style: TextStyle( - fontSize: 26, - fontWeight: FontWeight.bold, - color: Colors.white, - ), - ), - ], - ), - ), - ), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - 'Email', - style: TextStyle( - color: Colors.grey[600], fontWeight: FontWeight.bold), - ), - const SizedBox(height: 5), - TextField( - decoration: InputDecoration( - filled: true, - fillColor: Colors.grey[300], - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8.0), - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - isDense: true, - ), - controller: - TextEditingController(text: userResponseModel.email), - onChanged: (value) => userResponseModel.email = value, - ), - const SizedBox(height: 15), - Text( - 'Nome', - style: TextStyle( - color: Colors.grey[600], fontWeight: FontWeight.bold), - ), - const SizedBox(height: 5), - TextField( - decoration: InputDecoration( - filled: true, - fillColor: Colors.grey[300], - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8.0), - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - isDense: true, - ), - controller: TextEditingController( - text: userResponseModel.firstname), - onChanged: (value) => userResponseModel.firstname = value, - ), - const SizedBox(height: 15), - Text( - 'Username', - style: TextStyle( - color: Colors.grey[600], fontWeight: FontWeight.bold), - ), - const SizedBox(height: 5), - TextField( - decoration: InputDecoration( - filled: true, - fillColor: Colors.grey[200], - border: OutlineInputBorder( - borderRadius: BorderRadius.circular(8.0), - borderSide: BorderSide.none, - ), - contentPadding: const EdgeInsets.symmetric( - vertical: 15.0, horizontal: 10.0), - isDense: true, - ), - controller: - TextEditingController(text: userResponseModel.username), - enabled: false, - ), - const SizedBox(height: 20), - Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - InkWell( - onTap: () {}, - child: const Text( - 'Mudar senha', - style: TextStyle(color: Colors.blue), - ), - ), - InkWell( - onTap: () {}, - child: const Text( - 'Mudar username', - style: TextStyle(color: Colors.blue), - ), - ), - ], - ), - const SizedBox(height: 60), - Center( - child: Column( - children: [ - SizedBox( - width: 150, - height: 50, - child: ElevatedButton( - onPressed: () async { - await userService.update( - userResponseModel.id, - userResponseModel.firstname, - userResponseModel.email); - }, - style: ElevatedButton.styleFrom( - backgroundColor: AppColors.sigeIeYellow, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - minimumSize: const Size(150, 50), - ), - child: const Text('Salvar', - style: TextStyle( - color: AppColors.sigeIeBlue, - fontSize: 15, - fontWeight: FontWeight.w900)), - ), - ), - const SizedBox(height: 50), - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - SizedBox( - width: 150, - height: 50, - child: ElevatedButton( - onPressed: () async { - await authService.logout(); - Navigator.pushReplacementNamed( - context, '/loginScreen'); - }, - style: ElevatedButton.styleFrom( - backgroundColor: - const Color.fromARGB(207, 231, 27, 27), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - minimumSize: const Size(150, 50), - ), - child: const Text('Sair da Conta', - style: TextStyle( - color: AppColors.lightText, - fontSize: 15, - fontWeight: FontWeight.w900)), - ), - ), - const SizedBox(width: 20), - SizedBox( - width: 150, - height: 50, - child: ElevatedButton( - onPressed: () async { - bool deleteConfirmed = await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: const Text('EXCLUIR'), - content: const Text( - 'Tem certeza que deseja excluir sua conta?'), - actions: [ - TextButton( - onPressed: () => Navigator.of(context) - .pop( - false), // Retorna falso para indicar que a exclusão não foi confirmada - child: const Text('Cancelar'), - ), - TextButton( - onPressed: () => Navigator.of(context) - .pop( - true), // Retorna verdadeiro para indicar que a exclusão foi confirmada - child: const Text('Confirmar'), - ), - ], - ); - }, - ); - - // Se a exclusão for confirmada, exclua a conta - if (deleteConfirmed) { - await userService - .delete(userResponseModel.id); - Navigator.pushReplacementNamed( - context, '/loginScreen'); - } - }, - style: AppButtonStyles.warnButton.copyWith( - minimumSize: MaterialStateProperty.all( - const Size(150, 50))), - child: const Text('Excluir Conta', - style: TextStyle( - color: AppColors.lightText, - fontSize: 15, - fontWeight: FontWeight.w900)), - ), - ), - ], - ), - ], - )) - ], - )), - ]))); - } -} diff --git a/frontend/sige_ie/linux/.gitignore b/frontend/sige_ie/linux/.gitignore deleted file mode 100644 index d3896c98..00000000 --- a/frontend/sige_ie/linux/.gitignore +++ /dev/null @@ -1 +0,0 @@ -flutter/ephemeral diff --git a/frontend/sige_ie/linux/CMakeLists.txt b/frontend/sige_ie/linux/CMakeLists.txt deleted file mode 100644 index f9c1bd91..00000000 --- a/frontend/sige_ie/linux/CMakeLists.txt +++ /dev/null @@ -1,145 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.10) -project(runner LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "sige_ie") -# The unique GTK application identifier for this application. See: -# https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.sige_ie") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(SET CMP0063 NEW) - -# Load bundled libraries from the lib/ directory relative to the binary. -set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") - -# Root filesystem for cross-building. -if(FLUTTER_TARGET_PLATFORM_SYSROOT) - set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) - set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endif() - -# Define build configuration options. -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") -endif() - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_14) - target_compile_options(${TARGET} PRIVATE -Wall -Werror) - target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") - target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) - -add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") - -# Define the application target. To change its name, change BINARY_NAME above, -# not the value here, or `flutter run` will no longer work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} - "main.cc" - "my_application.cc" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add dependency libraries. Add any application-specific dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter) -target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) - -# Only the install-generated bundle's copy of the executable will launch -# correctly, since the resources must in the right relative locations. To avoid -# people trying to run the unbundled copy, put it in a subdirectory instead of -# the default top-level location. -set_target_properties(${BINARY_NAME} - PROPERTIES - RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" -) - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# By default, "installing" just makes a relocatable bundle in the build -# directory. -set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -# Start with a clean build bundle directory every time. -install(CODE " - file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") - " COMPONENT Runtime) - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) - install(FILES "${bundled_library}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endforeach(bundled_library) - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") - install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() diff --git a/frontend/sige_ie/linux/flutter/CMakeLists.txt b/frontend/sige_ie/linux/flutter/CMakeLists.txt deleted file mode 100644 index d5bd0164..00000000 --- a/frontend/sige_ie/linux/flutter/CMakeLists.txt +++ /dev/null @@ -1,88 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.10) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. - -# Serves the same purpose as list(TRANSFORM ... PREPEND ...), -# which isn't available in 3.10. -function(list_prepend LIST_NAME PREFIX) - set(NEW_LIST "") - foreach(element ${${LIST_NAME}}) - list(APPEND NEW_LIST "${PREFIX}${element}") - endforeach(element) - set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) -endfunction() - -# === Flutter Library === -# System-level dependencies. -find_package(PkgConfig REQUIRED) -pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) -pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) -pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) - -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "fl_basic_message_channel.h" - "fl_binary_codec.h" - "fl_binary_messenger.h" - "fl_dart_project.h" - "fl_engine.h" - "fl_json_message_codec.h" - "fl_json_method_codec.h" - "fl_message_codec.h" - "fl_method_call.h" - "fl_method_channel.h" - "fl_method_codec.h" - "fl_method_response.h" - "fl_plugin_registrar.h" - "fl_plugin_registry.h" - "fl_standard_message_codec.h" - "fl_standard_method_codec.h" - "fl_string_codec.h" - "fl_value.h" - "fl_view.h" - "flutter_linux.h" -) -list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") -target_link_libraries(flutter INTERFACE - PkgConfig::GTK - PkgConfig::GLIB - PkgConfig::GIO -) -add_dependencies(flutter flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CMAKE_CURRENT_BINARY_DIR}/_phony_ - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" - ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} -) diff --git a/frontend/sige_ie/linux/flutter/generated_plugin_registrant.cc b/frontend/sige_ie/linux/flutter/generated_plugin_registrant.cc deleted file mode 100644 index 64a0ecea..00000000 --- a/frontend/sige_ie/linux/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include - -void fl_register_plugins(FlPluginRegistry* registry) { - g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); - file_selector_plugin_register_with_registrar(file_selector_linux_registrar); -} diff --git a/frontend/sige_ie/linux/flutter/generated_plugin_registrant.h b/frontend/sige_ie/linux/flutter/generated_plugin_registrant.h deleted file mode 100644 index e0f0a47b..00000000 --- a/frontend/sige_ie/linux/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void fl_register_plugins(FlPluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/sige_ie/linux/flutter/generated_plugins.cmake b/frontend/sige_ie/linux/flutter/generated_plugins.cmake deleted file mode 100644 index 2db3c22a..00000000 --- a/frontend/sige_ie/linux/flutter/generated_plugins.cmake +++ /dev/null @@ -1,24 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - file_selector_linux -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/frontend/sige_ie/linux/main.cc b/frontend/sige_ie/linux/main.cc deleted file mode 100644 index e7c5c543..00000000 --- a/frontend/sige_ie/linux/main.cc +++ /dev/null @@ -1,6 +0,0 @@ -#include "my_application.h" - -int main(int argc, char** argv) { - g_autoptr(MyApplication) app = my_application_new(); - return g_application_run(G_APPLICATION(app), argc, argv); -} diff --git a/frontend/sige_ie/linux/my_application.cc b/frontend/sige_ie/linux/my_application.cc deleted file mode 100644 index 4d226137..00000000 --- a/frontend/sige_ie/linux/my_application.cc +++ /dev/null @@ -1,124 +0,0 @@ -#include "my_application.h" - -#include -#ifdef GDK_WINDOWING_X11 -#include -#endif - -#include "flutter/generated_plugin_registrant.h" - -struct _MyApplication { - GtkApplication parent_instance; - char** dart_entrypoint_arguments; -}; - -G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) - -// Implements GApplication::activate. -static void my_application_activate(GApplication* application) { - MyApplication* self = MY_APPLICATION(application); - GtkWindow* window = - GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); - - // Use a header bar when running in GNOME as this is the common style used - // by applications and is the setup most users will be using (e.g. Ubuntu - // desktop). - // If running on X and not using GNOME then just use a traditional title bar - // in case the window manager does more exotic layout, e.g. tiling. - // If running on Wayland assume the header bar will work (may need changing - // if future cases occur). - gboolean use_header_bar = TRUE; -#ifdef GDK_WINDOWING_X11 - GdkScreen* screen = gtk_window_get_screen(window); - if (GDK_IS_X11_SCREEN(screen)) { - const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); - if (g_strcmp0(wm_name, "GNOME Shell") != 0) { - use_header_bar = FALSE; - } - } -#endif - if (use_header_bar) { - GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); - gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "sige_ie"); - gtk_header_bar_set_show_close_button(header_bar, TRUE); - gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); - } else { - gtk_window_set_title(window, "sige_ie"); - } - - gtk_window_set_default_size(window, 1280, 720); - gtk_widget_show(GTK_WIDGET(window)); - - g_autoptr(FlDartProject) project = fl_dart_project_new(); - fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); - - FlView* view = fl_view_new(project); - gtk_widget_show(GTK_WIDGET(view)); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); - - fl_register_plugins(FL_PLUGIN_REGISTRY(view)); - - gtk_widget_grab_focus(GTK_WIDGET(view)); -} - -// Implements GApplication::local_command_line. -static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { - MyApplication* self = MY_APPLICATION(application); - // Strip out the first argument as it is the binary name. - self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); - - g_autoptr(GError) error = nullptr; - if (!g_application_register(application, nullptr, &error)) { - g_warning("Failed to register: %s", error->message); - *exit_status = 1; - return TRUE; - } - - g_application_activate(application); - *exit_status = 0; - - return TRUE; -} - -// Implements GApplication::startup. -static void my_application_startup(GApplication* application) { - //MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application startup. - - G_APPLICATION_CLASS(my_application_parent_class)->startup(application); -} - -// Implements GApplication::shutdown. -static void my_application_shutdown(GApplication* application) { - //MyApplication* self = MY_APPLICATION(object); - - // Perform any actions required at application shutdown. - - G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); -} - -// Implements GObject::dispose. -static void my_application_dispose(GObject* object) { - MyApplication* self = MY_APPLICATION(object); - g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); - G_OBJECT_CLASS(my_application_parent_class)->dispose(object); -} - -static void my_application_class_init(MyApplicationClass* klass) { - G_APPLICATION_CLASS(klass)->activate = my_application_activate; - G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; - G_APPLICATION_CLASS(klass)->startup = my_application_startup; - G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; - G_OBJECT_CLASS(klass)->dispose = my_application_dispose; -} - -static void my_application_init(MyApplication* self) {} - -MyApplication* my_application_new() { - return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, - nullptr)); -} diff --git a/frontend/sige_ie/linux/my_application.h b/frontend/sige_ie/linux/my_application.h deleted file mode 100644 index 72271d5e..00000000 --- a/frontend/sige_ie/linux/my_application.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FLUTTER_MY_APPLICATION_H_ -#define FLUTTER_MY_APPLICATION_H_ - -#include - -G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, - GtkApplication) - -/** - * my_application_new: - * - * Creates a new Flutter-based application. - * - * Returns: a new #MyApplication. - */ -MyApplication* my_application_new(); - -#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/frontend/sige_ie/macos/.gitignore b/frontend/sige_ie/macos/.gitignore deleted file mode 100644 index 746adbb6..00000000 --- a/frontend/sige_ie/macos/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# Flutter-related -**/Flutter/ephemeral/ -**/Pods/ - -# Xcode-related -**/dgph -**/xcuserdata/ diff --git a/frontend/sige_ie/macos/Flutter/Flutter-Debug.xcconfig b/frontend/sige_ie/macos/Flutter/Flutter-Debug.xcconfig deleted file mode 100644 index c2efd0b6..00000000 --- a/frontend/sige_ie/macos/Flutter/Flutter-Debug.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/sige_ie/macos/Flutter/Flutter-Release.xcconfig b/frontend/sige_ie/macos/Flutter/Flutter-Release.xcconfig deleted file mode 100644 index c2efd0b6..00000000 --- a/frontend/sige_ie/macos/Flutter/Flutter-Release.xcconfig +++ /dev/null @@ -1 +0,0 @@ -#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/frontend/sige_ie/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/sige_ie/macos/Flutter/GeneratedPluginRegistrant.swift deleted file mode 100644 index 797a88c0..00000000 --- a/frontend/sige_ie/macos/Flutter/GeneratedPluginRegistrant.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// Generated file. Do not edit. -// - -import FlutterMacOS -import Foundation - -import file_selector_macos -import geolocator_apple -import path_provider_foundation -import shared_preferences_foundation -import video_player_avfoundation - -func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { - FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) - GeolocatorPlugin.register(with: registry.registrar(forPlugin: "GeolocatorPlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) - SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) - FVPVideoPlayerPlugin.register(with: registry.registrar(forPlugin: "FVPVideoPlayerPlugin")) -} diff --git a/frontend/sige_ie/macos/Runner.xcodeproj/project.pbxproj b/frontend/sige_ie/macos/Runner.xcodeproj/project.pbxproj deleted file mode 100644 index b1cb0e87..00000000 --- a/frontend/sige_ie/macos/Runner.xcodeproj/project.pbxproj +++ /dev/null @@ -1,705 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 54; - objects = { - -/* Begin PBXAggregateTarget section */ - 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; - buildPhases = ( - 33CC111E2044C6BF0003C045 /* ShellScript */, - ); - dependencies = ( - ); - name = "Flutter Assemble"; - productName = FLX; - }; -/* End PBXAggregateTarget section */ - -/* Begin PBXBuildFile section */ - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC10EC2044A3C60003C045; - remoteInfo = Runner; - }; - 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 33CC10E52044A3C60003C045 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 33CC111A2044C6BA0003C045; - remoteInfo = FLX; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 33CC110E2044A8840003C045 /* Bundle Framework */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Bundle Framework"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; - 33CC10ED2044A3C60003C045 /* sige_ie.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "sige_ie.app"; sourceTree = BUILT_PRODUCTS_DIR; }; - 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; - 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; - 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; - 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; - 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; - 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; - 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; - 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; -/* End PBXFileReference section */ - -/* Begin PBXFrameworksBuildPhase section */ - 331C80D2294CF70F00263BE5 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EA2044A3C60003C045 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 331C80D6294CF71000263BE5 /* RunnerTests */ = { - isa = PBXGroup; - children = ( - 331C80D7294CF71000263BE5 /* RunnerTests.swift */, - ); - path = RunnerTests; - sourceTree = ""; - }; - 33BA886A226E78AF003329D5 /* Configs */ = { - isa = PBXGroup; - children = ( - 33E5194F232828860026EE4D /* AppInfo.xcconfig */, - 9740EEB21CF90195004384FC /* Debug.xcconfig */, - 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, - 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, - ); - path = Configs; - sourceTree = ""; - }; - 33CC10E42044A3C60003C045 = { - isa = PBXGroup; - children = ( - 33FAB671232836740065AC1E /* Runner */, - 33CEB47122A05771004F2AC0 /* Flutter */, - 331C80D6294CF71000263BE5 /* RunnerTests */, - 33CC10EE2044A3C60003C045 /* Products */, - D73912EC22F37F3D000D13A0 /* Frameworks */, - ); - sourceTree = ""; - }; - 33CC10EE2044A3C60003C045 /* Products */ = { - isa = PBXGroup; - children = ( - 33CC10ED2044A3C60003C045 /* sige_ie.app */, - 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; - 33CC11242044D66E0003C045 /* Resources */ = { - isa = PBXGroup; - children = ( - 33CC10F22044A3C60003C045 /* Assets.xcassets */, - 33CC10F42044A3C60003C045 /* MainMenu.xib */, - 33CC10F72044A3C60003C045 /* Info.plist */, - ); - name = Resources; - path = ..; - sourceTree = ""; - }; - 33CEB47122A05771004F2AC0 /* Flutter */ = { - isa = PBXGroup; - children = ( - 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, - 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, - 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, - 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, - ); - path = Flutter; - sourceTree = ""; - }; - 33FAB671232836740065AC1E /* Runner */ = { - isa = PBXGroup; - children = ( - 33CC10F02044A3C60003C045 /* AppDelegate.swift */, - 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, - 33E51913231747F40026EE4D /* DebugProfile.entitlements */, - 33E51914231749380026EE4D /* Release.entitlements */, - 33CC11242044D66E0003C045 /* Resources */, - 33BA886A226E78AF003329D5 /* Configs */, - ); - path = Runner; - sourceTree = ""; - }; - D73912EC22F37F3D000D13A0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - 331C80D4294CF70F00263BE5 /* RunnerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; - buildPhases = ( - 331C80D1294CF70F00263BE5 /* Sources */, - 331C80D2294CF70F00263BE5 /* Frameworks */, - 331C80D3294CF70F00263BE5 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 331C80DA294CF71000263BE5 /* PBXTargetDependency */, - ); - name = RunnerTests; - productName = RunnerTests; - productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; - 33CC10EC2044A3C60003C045 /* Runner */ = { - isa = PBXNativeTarget; - buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; - buildPhases = ( - 33CC10E92044A3C60003C045 /* Sources */, - 33CC10EA2044A3C60003C045 /* Frameworks */, - 33CC10EB2044A3C60003C045 /* Resources */, - 33CC110E2044A8840003C045 /* Bundle Framework */, - 3399D490228B24CF009A79C7 /* ShellScript */, - ); - buildRules = ( - ); - dependencies = ( - 33CC11202044C79F0003C045 /* PBXTargetDependency */, - ); - name = Runner; - productName = Runner; - productReference = 33CC10ED2044A3C60003C045 /* sige_ie.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 33CC10E52044A3C60003C045 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = YES; - LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1510; - ORGANIZATIONNAME = ""; - TargetAttributes = { - 331C80D4294CF70F00263BE5 = { - CreatedOnToolsVersion = 14.0; - TestTargetID = 33CC10EC2044A3C60003C045; - }; - 33CC10EC2044A3C60003C045 = { - CreatedOnToolsVersion = 9.2; - LastSwiftMigration = 1100; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.Sandbox = { - enabled = 1; - }; - }; - }; - 33CC111A2044C6BA0003C045 = { - CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Manual; - }; - }; - }; - buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 33CC10E42044A3C60003C045; - productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 33CC10EC2044A3C60003C045 /* Runner */, - 331C80D4294CF70F00263BE5 /* RunnerTests */, - 33CC111A2044C6BA0003C045 /* Flutter Assemble */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 331C80D3294CF70F00263BE5 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10EB2044A3C60003C045 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, - 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXShellScriptBuildPhase section */ - 3399D490228B24CF009A79C7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - ); - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; - }; - 33CC111E2044C6BF0003C045 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - Flutter/ephemeral/FlutterInputs.xcfilelist, - ); - inputPaths = ( - Flutter/ephemeral/tripwire, - ); - outputFileListPaths = ( - Flutter/ephemeral/FlutterOutputs.xcfilelist, - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; - }; -/* End PBXShellScriptBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 331C80D1294CF70F00263BE5 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 33CC10E92044A3C60003C045 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, - 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, - 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC10EC2044A3C60003C045 /* Runner */; - targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; - }; - 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; - targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin PBXVariantGroup section */ - 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { - isa = PBXVariantGroup; - children = ( - 33CC10F52044A3C60003C045 /* Base */, - ); - name = MainMenu.xib; - path = Runner; - sourceTree = ""; - }; -/* End PBXVariantGroup section */ - -/* Begin XCBuildConfiguration section */ - 331C80DB294CF71000263BE5 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sige_ie.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sige_ie"; - }; - name = Debug; - }; - 331C80DC294CF71000263BE5 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sige_ie.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sige_ie"; - }; - name = Release; - }; - 331C80DD294CF71000263BE5 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe.RunnerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.0; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/sige_ie.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/sige_ie"; - }; - name = Profile; - }; - 338D0CE9231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Profile; - }; - 338D0CEA231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Profile; - }; - 338D0CEB231458BD00FA5F75 /* Profile */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Profile; - }; - 33CC10F92044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = macosx; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - 33CC10FA2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CODE_SIGN_IDENTITY = "-"; - COPY_PHASE_STRIP = NO; - DEAD_CODE_STRIPPING = YES; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.14; - MTL_ENABLE_DEBUG_INFO = NO; - SDKROOT = macosx; - SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_OPTIMIZATION_LEVEL = "-O"; - }; - name = Release; - }; - 33CC10FC2044A3C60003C045 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - }; - name = Debug; - }; - 33CC10FD2044A3C60003C045 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; - CODE_SIGN_STYLE = Automatic; - COMBINE_HIDPI_IMAGES = YES; - INFOPLIST_FILE = Runner/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/../Frameworks", - ); - PROVISIONING_PROFILE_SPECIFIER = ""; - SWIFT_VERSION = 5.0; - }; - name = Release; - }; - 33CC111C2044C6BA0003C045 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Manual; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Debug; - }; - 33CC111D2044C6BA0003C045 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - PRODUCT_NAME = "$(TARGET_NAME)"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 331C80DB294CF71000263BE5 /* Debug */, - 331C80DC294CF71000263BE5 /* Release */, - 331C80DD294CF71000263BE5 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10F92044A3C60003C045 /* Debug */, - 33CC10FA2044A3C60003C045 /* Release */, - 338D0CE9231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC10FC2044A3C60003C045 /* Debug */, - 33CC10FD2044A3C60003C045 /* Release */, - 338D0CEA231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 33CC111C2044C6BA0003C045 /* Debug */, - 33CC111D2044C6BA0003C045 /* Release */, - 338D0CEB231458BD00FA5F75 /* Profile */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 33CC10E52044A3C60003C045 /* Project object */; -} diff --git a/frontend/sige_ie/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/sige_ie/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/frontend/sige_ie/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/frontend/sige_ie/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/frontend/sige_ie/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme deleted file mode 100644 index b9a3b520..00000000 --- a/frontend/sige_ie/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/macos/Runner.xcworkspace/contents.xcworkspacedata b/frontend/sige_ie/macos/Runner.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 1d526a16..00000000 --- a/frontend/sige_ie/macos/Runner.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/frontend/sige_ie/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/frontend/sige_ie/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist deleted file mode 100644 index 18d98100..00000000 --- a/frontend/sige_ie/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +++ /dev/null @@ -1,8 +0,0 @@ - - - - - IDEDidComputeMac32BitWarning - - - diff --git a/frontend/sige_ie/macos/Runner/AppDelegate.swift b/frontend/sige_ie/macos/Runner/AppDelegate.swift deleted file mode 100644 index d53ef643..00000000 --- a/frontend/sige_ie/macos/Runner/AppDelegate.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Cocoa -import FlutterMacOS - -@NSApplicationMain -class AppDelegate: FlutterAppDelegate { - override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true - } -} diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index a2ec33f1..00000000 --- a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "images" : [ - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_16.png", - "scale" : "1x" - }, - { - "size" : "16x16", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "2x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_32.png", - "scale" : "1x" - }, - { - "size" : "32x32", - "idiom" : "mac", - "filename" : "app_icon_64.png", - "scale" : "2x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_128.png", - "scale" : "1x" - }, - { - "size" : "128x128", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "2x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_256.png", - "scale" : "1x" - }, - { - "size" : "256x256", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "2x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_512.png", - "scale" : "1x" - }, - { - "size" : "512x512", - "idiom" : "mac", - "filename" : "app_icon_1024.png", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png deleted file mode 100644 index 82b6f9d9..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png deleted file mode 100644 index 13b35eba..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png deleted file mode 100644 index 0a3f5fa4..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png deleted file mode 100644 index bdb57226..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png deleted file mode 100644 index f083318e..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png deleted file mode 100644 index 326c0e72..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png deleted file mode 100644 index 2f1632cf..00000000 Binary files a/frontend/sige_ie/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png and /dev/null differ diff --git a/frontend/sige_ie/macos/Runner/Base.lproj/MainMenu.xib b/frontend/sige_ie/macos/Runner/Base.lproj/MainMenu.xib deleted file mode 100644 index 80e867a4..00000000 --- a/frontend/sige_ie/macos/Runner/Base.lproj/MainMenu.xib +++ /dev/null @@ -1,343 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/macos/Runner/Configs/AppInfo.xcconfig b/frontend/sige_ie/macos/Runner/Configs/AppInfo.xcconfig deleted file mode 100644 index 21359f88..00000000 --- a/frontend/sige_ie/macos/Runner/Configs/AppInfo.xcconfig +++ /dev/null @@ -1,14 +0,0 @@ -// Application-level settings for the Runner target. -// -// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the -// future. If not, the values below would default to using the project name when this becomes a -// 'flutter create' template. - -// The application's name. By default this is also the title of the Flutter window. -PRODUCT_NAME = sige_ie - -// The application's bundle identifier -PRODUCT_BUNDLE_IDENTIFIER = com.example.sigeIe - -// The copyright displayed in application information -PRODUCT_COPYRIGHT = Copyright © 2024 com.example. All rights reserved. diff --git a/frontend/sige_ie/macos/Runner/Configs/Debug.xcconfig b/frontend/sige_ie/macos/Runner/Configs/Debug.xcconfig deleted file mode 100644 index 36b0fd94..00000000 --- a/frontend/sige_ie/macos/Runner/Configs/Debug.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Debug.xcconfig" -#include "Warnings.xcconfig" diff --git a/frontend/sige_ie/macos/Runner/Configs/Release.xcconfig b/frontend/sige_ie/macos/Runner/Configs/Release.xcconfig deleted file mode 100644 index dff4f495..00000000 --- a/frontend/sige_ie/macos/Runner/Configs/Release.xcconfig +++ /dev/null @@ -1,2 +0,0 @@ -#include "../../Flutter/Flutter-Release.xcconfig" -#include "Warnings.xcconfig" diff --git a/frontend/sige_ie/macos/Runner/Configs/Warnings.xcconfig b/frontend/sige_ie/macos/Runner/Configs/Warnings.xcconfig deleted file mode 100644 index 42bcbf47..00000000 --- a/frontend/sige_ie/macos/Runner/Configs/Warnings.xcconfig +++ /dev/null @@ -1,13 +0,0 @@ -WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings -GCC_WARN_UNDECLARED_SELECTOR = YES -CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES -CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE -CLANG_WARN__DUPLICATE_METHOD_MATCH = YES -CLANG_WARN_PRAGMA_PACK = YES -CLANG_WARN_STRICT_PROTOTYPES = YES -CLANG_WARN_COMMA = YES -GCC_WARN_STRICT_SELECTOR_MATCH = YES -CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES -CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES -GCC_WARN_SHADOW = YES -CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/frontend/sige_ie/macos/Runner/DebugProfile.entitlements b/frontend/sige_ie/macos/Runner/DebugProfile.entitlements deleted file mode 100644 index dddb8a30..00000000 --- a/frontend/sige_ie/macos/Runner/DebugProfile.entitlements +++ /dev/null @@ -1,12 +0,0 @@ - - - - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - - diff --git a/frontend/sige_ie/macos/Runner/Info.plist b/frontend/sige_ie/macos/Runner/Info.plist deleted file mode 100644 index 4789daa6..00000000 --- a/frontend/sige_ie/macos/Runner/Info.plist +++ /dev/null @@ -1,32 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIconFile - - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSMinimumSystemVersion - $(MACOSX_DEPLOYMENT_TARGET) - NSHumanReadableCopyright - $(PRODUCT_COPYRIGHT) - NSMainNibFile - MainMenu - NSPrincipalClass - NSApplication - - diff --git a/frontend/sige_ie/macos/Runner/MainFlutterWindow.swift b/frontend/sige_ie/macos/Runner/MainFlutterWindow.swift deleted file mode 100644 index 3cc05eb2..00000000 --- a/frontend/sige_ie/macos/Runner/MainFlutterWindow.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Cocoa -import FlutterMacOS - -class MainFlutterWindow: NSWindow { - override func awakeFromNib() { - let flutterViewController = FlutterViewController() - let windowFrame = self.frame - self.contentViewController = flutterViewController - self.setFrame(windowFrame, display: true) - - RegisterGeneratedPlugins(registry: flutterViewController) - - super.awakeFromNib() - } -} diff --git a/frontend/sige_ie/macos/Runner/Release.entitlements b/frontend/sige_ie/macos/Runner/Release.entitlements deleted file mode 100644 index 852fa1a4..00000000 --- a/frontend/sige_ie/macos/Runner/Release.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.app-sandbox - - - diff --git a/frontend/sige_ie/macos/RunnerTests/RunnerTests.swift b/frontend/sige_ie/macos/RunnerTests/RunnerTests.swift deleted file mode 100644 index 5418c9f5..00000000 --- a/frontend/sige_ie/macos/RunnerTests/RunnerTests.swift +++ /dev/null @@ -1,12 +0,0 @@ -import FlutterMacOS -import Cocoa -import XCTest - -class RunnerTests: XCTestCase { - - func testExample() { - // If you add code to the Runner application, consider adding tests here. - // See https://developer.apple.com/documentation/xctest for more information about using XCTest. - } - -} diff --git a/frontend/sige_ie/pubspec.lock b/frontend/sige_ie/pubspec.lock deleted file mode 100644 index 2508e2d9..00000000 --- a/frontend/sige_ie/pubspec.lock +++ /dev/null @@ -1,786 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - async: - dependency: transitive - description: - name: async - sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c" - url: "https://pub.dev" - source: hosted - version: "2.11.0" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - characters: - dependency: transitive - description: - name: characters - sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - clock: - dependency: transitive - description: - name: clock - sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf - url: "https://pub.dev" - source: hosted - version: "1.1.1" - collection: - dependency: transitive - description: - name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a - url: "https://pub.dev" - source: hosted - version: "1.18.0" - cookie_jar: - dependency: "direct main" - description: - name: cookie_jar - sha256: a6ac027d3ed6ed756bfce8f3ff60cb479e266f3b0fdabd6242b804b6765e52de - url: "https://pub.dev" - source: hosted - version: "4.0.8" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" - url: "https://pub.dev" - source: hosted - version: "0.3.4+1" - crypto: - dependency: transitive - description: - name: crypto - sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab - url: "https://pub.dev" - source: hosted - version: "3.0.3" - csslib: - dependency: transitive - description: - name: csslib - sha256: "706b5707578e0c1b4b7550f64078f0a0f19dec3f50a178ffae7006b0a9ca58fb" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - ffi: - dependency: transitive - description: - name: ffi - sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - file: - dependency: transitive - description: - name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - file_selector_linux: - dependency: transitive - description: - name: file_selector_linux - sha256: "045d372bf19b02aeb69cacf8b4009555fb5f6f0b7ad8016e5f46dd1387ddd492" - url: "https://pub.dev" - source: hosted - version: "0.9.2+1" - file_selector_macos: - dependency: transitive - description: - name: file_selector_macos - sha256: f42eacb83b318e183b1ae24eead1373ab1334084404c8c16e0354f9a3e55d385 - url: "https://pub.dev" - source: hosted - version: "0.9.4" - file_selector_platform_interface: - dependency: transitive - description: - name: file_selector_platform_interface - sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b - url: "https://pub.dev" - source: hosted - version: "2.6.2" - file_selector_windows: - dependency: transitive - description: - name: file_selector_windows - sha256: d3547240c20cabf205c7c7f01a50ecdbc413755814d6677f3cb366f04abcead0 - url: "https://pub.dev" - source: hosted - version: "0.9.3+1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: "25517a4deb0c03aa0f32fd12db525856438902d9c16536311e76cdc57b31d7d1" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - flutter_plugin_android_lifecycle: - dependency: transitive - description: - name: flutter_plugin_android_lifecycle - sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" - url: "https://pub.dev" - source: hosted - version: "2.0.19" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - geolocator: - dependency: "direct main" - description: - name: geolocator - sha256: "5c23f3613f50586c0bbb2b8f970240ae66b3bd992088cf60dd5ee2e6f7dde3a8" - url: "https://pub.dev" - source: hosted - version: "9.0.2" - geolocator_android: - dependency: transitive - description: - name: geolocator_android - sha256: "00c7177a95823dd3ee35ef42fd8666cd27d219ae14cea472ac76a21dff43000b" - url: "https://pub.dev" - source: hosted - version: "4.6.0" - geolocator_apple: - dependency: transitive - description: - name: geolocator_apple - sha256: bc2aca02423ad429cb0556121f56e60360a2b7d694c8570301d06ea0c00732fd - url: "https://pub.dev" - source: hosted - version: "2.3.7" - geolocator_platform_interface: - dependency: transitive - description: - name: geolocator_platform_interface - sha256: c6005787efe9e27cb0f6b50230c217e6f0ef8e1e7a8b854efb4f46489e502603 - url: "https://pub.dev" - source: hosted - version: "4.2.3" - geolocator_web: - dependency: transitive - description: - name: geolocator_web - sha256: "102e7da05b48ca6bf0a5bda0010f886b171d1a08059f01bfe02addd0175ebece" - url: "https://pub.dev" - source: hosted - version: "2.2.1" - geolocator_windows: - dependency: transitive - description: - name: geolocator_windows - sha256: "4f4218f122a6978d0ad655fa3541eea74c67417440b09f0657238810d5af6bdc" - url: "https://pub.dev" - source: hosted - version: "0.1.3" - get: - dependency: "direct main" - description: - name: get - sha256: e4e7335ede17452b391ed3b2ede016545706c01a02292a6c97619705e7d2a85e - url: "https://pub.dev" - source: hosted - version: "4.6.6" - google_maps: - dependency: transitive - description: - name: google_maps - sha256: "47eef3836b49bb030d5cb3afc60b8451408bf34cf753e571b645d6529eb4251a" - url: "https://pub.dev" - source: hosted - version: "7.1.0" - google_maps_flutter: - dependency: "direct main" - description: - name: google_maps_flutter - sha256: c1972cbad779bc5346c49045f26ae45550a0958b1cbca5b524dd3c8954995d28 - url: "https://pub.dev" - source: hosted - version: "2.6.1" - google_maps_flutter_android: - dependency: transitive - description: - name: google_maps_flutter_android - sha256: "0bcadb80eba39afda77dede89a6caafd3b68f2786b90491eceea4a01c3db181c" - url: "https://pub.dev" - source: hosted - version: "2.8.0" - google_maps_flutter_ios: - dependency: transitive - description: - name: google_maps_flutter_ios - sha256: d2d63ae17297a5b045ec115572c5a86fa4e53bb6eceaa0c6d200ac5ca69bfca4 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - google_maps_flutter_platform_interface: - dependency: transitive - description: - name: google_maps_flutter_platform_interface - sha256: "2bf21aa97edba4461282af5de693b354e589d09f695f7a6f80437d084a29687e" - url: "https://pub.dev" - source: hosted - version: "2.7.1" - google_maps_flutter_web: - dependency: transitive - description: - name: google_maps_flutter_web - sha256: f3155c12119d8a5c2732fdf39ceb5cc095bc662059a03b4ea23294ecebe1d199 - url: "https://pub.dev" - source: hosted - version: "0.5.8" - html: - dependency: transitive - description: - name: html - sha256: "3a7812d5bcd2894edf53dfaf8cd640876cf6cef50a8f238745c8b8120ea74d3a" - url: "https://pub.dev" - source: hosted - version: "0.15.4" - http: - dependency: "direct main" - description: - name: http - sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" - url: "https://pub.dev" - source: hosted - version: "0.13.6" - http_interceptor: - dependency: "direct main" - description: - name: http_interceptor - sha256: "5f3dde028e67789339c250252c09510a74aff21ce16b06d07d9096bda6582bab" - url: "https://pub.dev" - source: hosted - version: "1.0.2" - http_parser: - dependency: "direct main" - description: - name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" - url: "https://pub.dev" - source: hosted - version: "4.0.2" - image_picker: - dependency: "direct main" - description: - name: image_picker - sha256: b6951e25b795d053a6ba03af5f710069c99349de9341af95155d52665cb4607c - url: "https://pub.dev" - source: hosted - version: "0.8.9" - image_picker_android: - dependency: transitive - description: - name: image_picker_android - sha256: "0f57fee1e8bfadf8cc41818bbcd7f72e53bb768a54d9496355d5e8a5681a19f1" - url: "https://pub.dev" - source: hosted - version: "0.8.12+1" - image_picker_for_web: - dependency: transitive - description: - name: image_picker_for_web - sha256: "869fe8a64771b7afbc99fc433a5f7be2fea4d1cb3d7c11a48b6b579eb9c797f0" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - image_picker_ios: - dependency: transitive - description: - name: image_picker_ios - sha256: "6703696ad49f5c3c8356d576d7ace84d1faf459afb07accbb0fae780753ff447" - url: "https://pub.dev" - source: hosted - version: "0.8.12" - image_picker_linux: - dependency: transitive - description: - name: image_picker_linux - sha256: "4ed1d9bb36f7cd60aa6e6cd479779cc56a4cb4e4de8f49d487b1aaad831300fa" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - image_picker_macos: - dependency: transitive - description: - name: image_picker_macos - sha256: "3f5ad1e8112a9a6111c46d0b57a7be2286a9a07fc6e1976fdf5be2bd31d4ff62" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - image_picker_platform_interface: - dependency: transitive - description: - name: image_picker_platform_interface - sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" - url: "https://pub.dev" - source: hosted - version: "2.10.0" - image_picker_windows: - dependency: transitive - description: - name: image_picker_windows - sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" - url: "https://pub.dev" - source: hosted - version: "0.2.1+1" - js: - dependency: transitive - description: - name: js - sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 - url: "https://pub.dev" - source: hosted - version: "0.6.7" - js_wrapping: - dependency: transitive - description: - name: js_wrapping - sha256: e385980f7c76a8c1c9a560dfb623b890975841542471eade630b2871d243851c - url: "https://pub.dev" - source: hosted - version: "0.7.4" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - lints: - dependency: transitive - description: - name: lints - sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 - url: "https://pub.dev" - source: hosted - version: "3.0.0" - logger: - dependency: "direct main" - description: - name: logger - sha256: "7ad7215c15420a102ec687bb320a7312afd449bac63bfb1c60d9787c27b9767f" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - logging: - dependency: "direct main" - description: - name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb - url: "https://pub.dev" - source: hosted - version: "0.12.16+1" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" - url: "https://pub.dev" - source: hosted - version: "0.8.0" - meta: - dependency: transitive - description: - name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 - url: "https://pub.dev" - source: hosted - version: "1.11.0" - mime: - dependency: "direct main" - description: - name: mime - sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" - url: "https://pub.dev" - source: hosted - version: "1.0.5" - path: - dependency: transitive - description: - name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" - url: "https://pub.dev" - source: hosted - version: "1.9.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 - url: "https://pub.dev" - source: hosted - version: "2.1.3" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d - url: "https://pub.dev" - source: hosted - version: "2.2.4" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16 - url: "https://pub.dev" - source: hosted - version: "2.4.0" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170" - url: "https://pub.dev" - source: hosted - version: "2.2.1" - platform: - dependency: transitive - description: - name: platform - sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - sanitize_html: - dependency: transitive - description: - name: sanitize_html - sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 - url: "https://pub.dev" - source: hosted - version: "2.2.3" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" - url: "https://pub.dev" - source: hosted - version: "2.2.2" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" - url: "https://pub.dev" - source: hosted - version: "2.3.0" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_span: - dependency: transitive - description: - name: source_span - sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" - url: "https://pub.dev" - source: hosted - version: "1.10.0" - sprintf: - dependency: transitive - description: - name: sprintf - sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" - url: "https://pub.dev" - source: hosted - version: "7.0.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" - url: "https://pub.dev" - source: hosted - version: "1.11.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 - url: "https://pub.dev" - source: hosted - version: "2.1.2" - stream_transform: - dependency: transitive - description: - name: stream_transform - sha256: "14a00e794c7c11aa145a170587321aedce29769c08d7f58b1d141da75e3b1c6f" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "556692adab6cfa87322a115640c11f13cb77b3f076ddcc5d6ae3c20242bedcde" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84 - url: "https://pub.dev" - source: hosted - version: "1.2.1" - test_api: - dependency: transitive - description: - name: test_api - sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" - url: "https://pub.dev" - source: hosted - version: "0.6.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c - url: "https://pub.dev" - source: hosted - version: "1.3.2" - universal_io: - dependency: transitive - description: - name: universal_io - sha256: "1722b2dcc462b4b2f3ee7d188dad008b6eb4c40bbd03a3de451d82c78bba9aad" - url: "https://pub.dev" - source: hosted - version: "2.2.2" - uuid: - dependency: transitive - description: - name: uuid - sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" - url: "https://pub.dev" - source: hosted - version: "4.4.0" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - video_player: - dependency: "direct main" - description: - name: video_player - sha256: aced48e701e24c02b0b7f881a8819e4937794e46b5a5821005e2bf3b40a324cc - url: "https://pub.dev" - source: hosted - version: "2.8.7" - video_player_android: - dependency: transitive - description: - name: video_player_android - sha256: "134e1ad410d67e18a19486ed9512c72dfc6d8ffb284d0e8f2e99e903d1ba8fa3" - url: "https://pub.dev" - source: hosted - version: "2.4.14" - video_player_avfoundation: - dependency: transitive - description: - name: video_player_avfoundation - sha256: d1e9a824f2b324000dc8fb2dcb2a3285b6c1c7c487521c63306cc5b394f68a7c - url: "https://pub.dev" - source: hosted - version: "2.6.1" - video_player_platform_interface: - dependency: transitive - description: - name: video_player_platform_interface - sha256: "236454725fafcacf98f0f39af0d7c7ab2ce84762e3b63f2cbb3ef9a7e0550bc6" - url: "https://pub.dev" - source: hosted - version: "6.2.2" - video_player_web: - dependency: transitive - description: - name: video_player_web - sha256: ff4d69a6614b03f055397c27a71c9d3ddea2b2a23d71b2ba0164f59ca32b8fe2 - url: "https://pub.dev" - source: hosted - version: "2.3.1" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 - url: "https://pub.dev" - source: hosted - version: "13.0.0" - web: - dependency: transitive - description: - name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" - url: "https://pub.dev" - source: hosted - version: "0.5.1" - win32: - dependency: transitive - description: - name: win32 - sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb" - url: "https://pub.dev" - source: hosted - version: "5.5.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d - url: "https://pub.dev" - source: hosted - version: "1.0.4" -sdks: - dart: ">=3.3.1 <4.0.0" - flutter: ">=3.19.0" diff --git a/frontend/sige_ie/pubspec.yaml b/frontend/sige_ie/pubspec.yaml deleted file mode 100644 index d53f4531..00000000 --- a/frontend/sige_ie/pubspec.yaml +++ /dev/null @@ -1,107 +0,0 @@ -name: sige_ie -description: "A new Flutter project." -# The following line prevents the package from being accidentally published to -# pub.dev using `flutter pub publish`. This is preferred for private packages. -publish_to: "none" # Remove this line if you wish to publish to pub.dev - -# The following defines the version and build number for your application. -# A version number is three numbers separated by dots, like 1.2.43 -# followed by an optional build number separated by a +. -# Both the version and the builder number may be overridden in flutter -# build by specifying --build-name and --build-number, respectively. -# In Android, build-name is used as versionName while build-number used as versionCode. -# Read more about Android versioning at https://developer.android.com/studio/publish/versioning -# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. -# Read more about iOS versioning at -# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html -# In Windows, build-name is used as the major, minor, and patch parts -# of the product and file versions while build-number is used as the build suffix. -version: 1.0.0+1 - -environment: - sdk: ">=3.3.1 <4.0.0" - -# Dependencies specify other packages that your package needs in order to work. -# To automatically upgrade your package dependencies to the latest versions -# consider running `flutter pub upgrade --major-versions`. Alternatively, -# dependencies can be manually updated by changing the version numbers below to -# the latest version available on pub.dev. To see which dependencies have newer -# versions available, run `flutter pub outdated`. -dependencies: - flutter: - sdk: flutter - shared_preferences: ^2.0.15 - video_player: ^2.2.14 - http: ^0.13.4 - cookie_jar: ^4.0.8 - http_interceptor: ^1.0.1 - image_picker: ^0.8.5 - mime: ^1.0.0 - http_parser: ^4.0.2 - cupertino_icons: ^1.0.6 - get: ^4.6.5 - google_maps_flutter: ^2.0.6 - geolocator: ^9.0.2 - logger: ^1.0.0 - logging: ^1.2.0 - path_provider: ^2.0.2 - - -dev_dependencies: - flutter_test: - sdk: flutter - - # The "flutter_lints" package below contains a set of recommended lints to - # encourage good coding practices. The lint set provided by the package is - # activated in the `analysis_options.yaml` file located at the root of your - # package. See that file for information about deactivating specific lint - # rules and activating additional ones. - flutter_lints: ^3.0.0 - -# For information on the generic Dart part of this file, see the -# following page: https://dart.dev/tools/pub/pubspec - -# The following section is specific to Flutter packages. -flutter: - assets: - - assets/Loading.mp4 - - assets/1000x1000Horizontal.png - - assets/1000x1000.png - - assets/lighting.png - - assets/UNB.png - - # The following line ensures that the Material Icons font is - # included with your application, so that you can use the icons in - # the material Icons class. - uses-material-design: true - - # To add assets to your application, add an assets section, like this: - # assets: - # - images/a_dot_burr.jpeg - # - images/a_dot_ham.jpeg - - # An image asset can refer to one or more resolution-specific "variants", see - # https://flutter.dev/assets-and-images/#resolution-aware - - # For details regarding adding assets from package dependencies, see - # https://flutter.dev/assets-and-images/#from-packages - - # To add custom fonts to your application, add a fonts section here, - # in this "flutter" section. Each entry in this list should have a - # "family" key with the font family name, and a "fonts" key with a - # list giving the asset and other descriptors for the font. For - # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # - # For details regarding fonts from package dependencies, - # see https://flutter.dev/custom-fonts/#from-packages diff --git a/frontend/sige_ie/test/widget_test.dart b/frontend/sige_ie/test/widget_test.dart deleted file mode 100644 index 6282fd7c..00000000 --- a/frontend/sige_ie/test/widget_test.dart +++ /dev/null @@ -1,30 +0,0 @@ -// This is a basic Flutter widget test. -// -// To perform an interaction with a widget in your test, use the WidgetTester -// utility in the flutter_test package. For example, you can send tap and scroll -// gestures. You can also use WidgetTester to find child widgets in the widget -// tree, read text, and verify that the values of widget properties are correct. - -import 'package:flutter/material.dart'; -import 'package:flutter_test/flutter_test.dart'; - -import 'package:sige_ie/main.dart'; - -void main() { - testWidgets('Counter increments smoke test', (WidgetTester tester) async { - // Build our app and trigger a frame. - await tester.pumpWidget(const MyApp()); - - // Verify that our counter starts at 0. - expect(find.text('0'), findsOneWidget); - expect(find.text('1'), findsNothing); - - // Tap the '+' icon and trigger a frame. - await tester.tap(find.byIcon(Icons.add)); - await tester.pump(); - - // Verify that our counter has incremented. - expect(find.text('0'), findsNothing); - expect(find.text('1'), findsOneWidget); - }); -} diff --git a/frontend/sige_ie/web/favicon.png b/frontend/sige_ie/web/favicon.png deleted file mode 100644 index 8aaa46ac..00000000 Binary files a/frontend/sige_ie/web/favicon.png and /dev/null differ diff --git a/frontend/sige_ie/web/icons/Icon-192.png b/frontend/sige_ie/web/icons/Icon-192.png deleted file mode 100644 index b749bfef..00000000 Binary files a/frontend/sige_ie/web/icons/Icon-192.png and /dev/null differ diff --git a/frontend/sige_ie/web/icons/Icon-512.png b/frontend/sige_ie/web/icons/Icon-512.png deleted file mode 100644 index 88cfd48d..00000000 Binary files a/frontend/sige_ie/web/icons/Icon-512.png and /dev/null differ diff --git a/frontend/sige_ie/web/icons/Icon-maskable-192.png b/frontend/sige_ie/web/icons/Icon-maskable-192.png deleted file mode 100644 index eb9b4d76..00000000 Binary files a/frontend/sige_ie/web/icons/Icon-maskable-192.png and /dev/null differ diff --git a/frontend/sige_ie/web/icons/Icon-maskable-512.png b/frontend/sige_ie/web/icons/Icon-maskable-512.png deleted file mode 100644 index d69c5669..00000000 Binary files a/frontend/sige_ie/web/icons/Icon-maskable-512.png and /dev/null differ diff --git a/frontend/sige_ie/web/index.html b/frontend/sige_ie/web/index.html deleted file mode 100644 index 334cff92..00000000 --- a/frontend/sige_ie/web/index.html +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - sige_ie - - - - - - - - - - diff --git a/frontend/sige_ie/web/manifest.json b/frontend/sige_ie/web/manifest.json deleted file mode 100644 index 3f8e5dc9..00000000 --- a/frontend/sige_ie/web/manifest.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "sige_ie", - "short_name": "sige_ie", - "start_url": ".", - "display": "standalone", - "background_color": "#0175C2", - "theme_color": "#0175C2", - "description": "A new Flutter project.", - "orientation": "portrait-primary", - "prefer_related_applications": false, - "icons": [ - { - "src": "icons/Icon-192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "icons/Icon-512.png", - "sizes": "512x512", - "type": "image/png" - }, - { - "src": "icons/Icon-maskable-192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "icons/Icon-maskable-512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/frontend/sige_ie/windows/.gitignore b/frontend/sige_ie/windows/.gitignore deleted file mode 100644 index d492d0d9..00000000 --- a/frontend/sige_ie/windows/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -flutter/ephemeral/ - -# Visual Studio user-specific files. -*.suo -*.user -*.userosscache -*.sln.docstates - -# Visual Studio build-related files. -x64/ -x86/ - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!*.[Cc]ache/ diff --git a/frontend/sige_ie/windows/CMakeLists.txt b/frontend/sige_ie/windows/CMakeLists.txt deleted file mode 100644 index 391b09b3..00000000 --- a/frontend/sige_ie/windows/CMakeLists.txt +++ /dev/null @@ -1,108 +0,0 @@ -# Project-level configuration. -cmake_minimum_required(VERSION 3.14) -project(sige_ie LANGUAGES CXX) - -# The name of the executable created for the application. Change this to change -# the on-disk name of your application. -set(BINARY_NAME "sige_ie") - -# Explicitly opt in to modern CMake behaviors to avoid warnings with recent -# versions of CMake. -cmake_policy(VERSION 3.14...3.25) - -# Define build configuration option. -get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) -if(IS_MULTICONFIG) - set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" - CACHE STRING "" FORCE) -else() - if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - set(CMAKE_BUILD_TYPE "Debug" CACHE - STRING "Flutter build mode" FORCE) - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Profile" "Release") - endif() -endif() -# Define settings for the Profile build mode. -set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") -set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") -set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") -set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") - -# Use Unicode for all projects. -add_definitions(-DUNICODE -D_UNICODE) - -# Compilation settings that should be applied to most targets. -# -# Be cautious about adding new options here, as plugins use this function by -# default. In most cases, you should add new options to specific targets instead -# of modifying this function. -function(APPLY_STANDARD_SETTINGS TARGET) - target_compile_features(${TARGET} PUBLIC cxx_std_17) - target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") - target_compile_options(${TARGET} PRIVATE /EHsc) - target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") - target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") -endfunction() - -# Flutter library and tool build rules. -set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") -add_subdirectory(${FLUTTER_MANAGED_DIR}) - -# Application build; see runner/CMakeLists.txt. -add_subdirectory("runner") - - -# Generated plugin build rules, which manage building the plugins and adding -# them to the application. -include(flutter/generated_plugins.cmake) - - -# === Installation === -# Support files are copied into place next to the executable, so that it can -# run in place. This is done instead of making a separate bundle (as on Linux) -# so that building and running from within Visual Studio will work. -set(BUILD_BUNDLE_DIR "$") -# Make the "install" step default, as it's required to run. -set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) -if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) -endif() - -set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") -set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") - -install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - COMPONENT Runtime) - -install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -if(PLUGIN_BUNDLED_LIBRARIES) - install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) -endif() - -# Copy the native assets provided by the build.dart from all packages. -set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") -install(DIRECTORY "${NATIVE_ASSETS_DIR}" - DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" - COMPONENT Runtime) - -# Fully re-copy the assets directory on each build to avoid having stale files -# from a previous install. -set(FLUTTER_ASSET_DIR_NAME "flutter_assets") -install(CODE " - file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") - " COMPONENT Runtime) -install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" - DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) - -# Install the AOT library on non-Debug builds only. -install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" - CONFIGURATIONS Profile;Release - COMPONENT Runtime) diff --git a/frontend/sige_ie/windows/flutter/CMakeLists.txt b/frontend/sige_ie/windows/flutter/CMakeLists.txt deleted file mode 100644 index 903f4899..00000000 --- a/frontend/sige_ie/windows/flutter/CMakeLists.txt +++ /dev/null @@ -1,109 +0,0 @@ -# This file controls Flutter-level build steps. It should not be edited. -cmake_minimum_required(VERSION 3.14) - -set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") - -# Configuration provided via flutter tool. -include(${EPHEMERAL_DIR}/generated_config.cmake) - -# TODO: Move the rest of this into files in ephemeral. See -# https://github.com/flutter/flutter/issues/57146. -set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") - -# Set fallback configurations for older versions of the flutter tool. -if (NOT DEFINED FLUTTER_TARGET_PLATFORM) - set(FLUTTER_TARGET_PLATFORM "windows-x64") -endif() - -# === Flutter Library === -set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") - -# Published to parent scope for install step. -set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) -set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) -set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) -set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) - -list(APPEND FLUTTER_LIBRARY_HEADERS - "flutter_export.h" - "flutter_windows.h" - "flutter_messenger.h" - "flutter_plugin_registrar.h" - "flutter_texture_registrar.h" -) -list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") -add_library(flutter INTERFACE) -target_include_directories(flutter INTERFACE - "${EPHEMERAL_DIR}" -) -target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") -add_dependencies(flutter flutter_assemble) - -# === Wrapper === -list(APPEND CPP_WRAPPER_SOURCES_CORE - "core_implementations.cc" - "standard_codec.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_PLUGIN - "plugin_registrar.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") -list(APPEND CPP_WRAPPER_SOURCES_APP - "flutter_engine.cc" - "flutter_view_controller.cc" -) -list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") - -# Wrapper sources needed for a plugin. -add_library(flutter_wrapper_plugin STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} -) -apply_standard_settings(flutter_wrapper_plugin) -set_target_properties(flutter_wrapper_plugin PROPERTIES - POSITION_INDEPENDENT_CODE ON) -set_target_properties(flutter_wrapper_plugin PROPERTIES - CXX_VISIBILITY_PRESET hidden) -target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) -target_include_directories(flutter_wrapper_plugin PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_plugin flutter_assemble) - -# Wrapper sources needed for the runner. -add_library(flutter_wrapper_app STATIC - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_APP} -) -apply_standard_settings(flutter_wrapper_app) -target_link_libraries(flutter_wrapper_app PUBLIC flutter) -target_include_directories(flutter_wrapper_app PUBLIC - "${WRAPPER_ROOT}/include" -) -add_dependencies(flutter_wrapper_app flutter_assemble) - -# === Flutter tool backend === -# _phony_ is a non-existent file to force this command to run every time, -# since currently there's no way to get a full input/output list from the -# flutter tool. -set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") -set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) -add_custom_command( - OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} - ${PHONY_OUTPUT} - COMMAND ${CMAKE_COMMAND} -E env - ${FLUTTER_TOOL_ENVIRONMENT} - "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - ${FLUTTER_TARGET_PLATFORM} $ - VERBATIM -) -add_custom_target(flutter_assemble DEPENDS - "${FLUTTER_LIBRARY}" - ${FLUTTER_LIBRARY_HEADERS} - ${CPP_WRAPPER_SOURCES_CORE} - ${CPP_WRAPPER_SOURCES_PLUGIN} - ${CPP_WRAPPER_SOURCES_APP} -) diff --git a/frontend/sige_ie/windows/flutter/generated_plugin_registrant.cc b/frontend/sige_ie/windows/flutter/generated_plugin_registrant.cc deleted file mode 100644 index f35b3a66..00000000 --- a/frontend/sige_ie/windows/flutter/generated_plugin_registrant.cc +++ /dev/null @@ -1,17 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#include "generated_plugin_registrant.h" - -#include -#include - -void RegisterPlugins(flutter::PluginRegistry* registry) { - FileSelectorWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("FileSelectorWindows")); - GeolocatorWindowsRegisterWithRegistrar( - registry->GetRegistrarForPlugin("GeolocatorWindows")); -} diff --git a/frontend/sige_ie/windows/flutter/generated_plugin_registrant.h b/frontend/sige_ie/windows/flutter/generated_plugin_registrant.h deleted file mode 100644 index dc139d85..00000000 --- a/frontend/sige_ie/windows/flutter/generated_plugin_registrant.h +++ /dev/null @@ -1,15 +0,0 @@ -// -// Generated file. Do not edit. -// - -// clang-format off - -#ifndef GENERATED_PLUGIN_REGISTRANT_ -#define GENERATED_PLUGIN_REGISTRANT_ - -#include - -// Registers Flutter plugins. -void RegisterPlugins(flutter::PluginRegistry* registry); - -#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/frontend/sige_ie/windows/flutter/generated_plugins.cmake b/frontend/sige_ie/windows/flutter/generated_plugins.cmake deleted file mode 100644 index 389222ba..00000000 --- a/frontend/sige_ie/windows/flutter/generated_plugins.cmake +++ /dev/null @@ -1,25 +0,0 @@ -# -# Generated file, do not edit. -# - -list(APPEND FLUTTER_PLUGIN_LIST - file_selector_windows - geolocator_windows -) - -list(APPEND FLUTTER_FFI_PLUGIN_LIST -) - -set(PLUGIN_BUNDLED_LIBRARIES) - -foreach(plugin ${FLUTTER_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) - target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) - list(APPEND PLUGIN_BUNDLED_LIBRARIES $) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) -endforeach(plugin) - -foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) - add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) - list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) -endforeach(ffi_plugin) diff --git a/frontend/sige_ie/windows/runner/CMakeLists.txt b/frontend/sige_ie/windows/runner/CMakeLists.txt deleted file mode 100644 index 394917c0..00000000 --- a/frontend/sige_ie/windows/runner/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -cmake_minimum_required(VERSION 3.14) -project(runner LANGUAGES CXX) - -# Define the application target. To change its name, change BINARY_NAME in the -# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer -# work. -# -# Any new source files that you add to the application should be added here. -add_executable(${BINARY_NAME} WIN32 - "flutter_window.cpp" - "main.cpp" - "utils.cpp" - "win32_window.cpp" - "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" - "Runner.rc" - "runner.exe.manifest" -) - -# Apply the standard set of build settings. This can be removed for applications -# that need different build settings. -apply_standard_settings(${BINARY_NAME}) - -# Add preprocessor definitions for the build version. -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") -target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") - -# Disable Windows macros that collide with C++ standard library functions. -target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") - -# Add dependency libraries and include directories. Add any application-specific -# dependencies here. -target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) -target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") -target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") - -# Run the Flutter tool portions of the build. This must not be removed. -add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/frontend/sige_ie/windows/runner/Runner.rc b/frontend/sige_ie/windows/runner/Runner.rc deleted file mode 100644 index 438f2120..00000000 --- a/frontend/sige_ie/windows/runner/Runner.rc +++ /dev/null @@ -1,121 +0,0 @@ -// Microsoft Visual C++ generated resource script. -// -#pragma code_page(65001) -#include "resource.h" - -#define APSTUDIO_READONLY_SYMBOLS -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 2 resource. -// -#include "winres.h" - -///////////////////////////////////////////////////////////////////////////// -#undef APSTUDIO_READONLY_SYMBOLS - -///////////////////////////////////////////////////////////////////////////// -// English (United States) resources - -#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) -LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US - -#ifdef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// TEXTINCLUDE -// - -1 TEXTINCLUDE -BEGIN - "resource.h\0" -END - -2 TEXTINCLUDE -BEGIN - "#include ""winres.h""\r\n" - "\0" -END - -3 TEXTINCLUDE -BEGIN - "\r\n" - "\0" -END - -#endif // APSTUDIO_INVOKED - - -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -IDI_APP_ICON ICON "resources\\app_icon.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// Version -// - -#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) -#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD -#else -#define VERSION_AS_NUMBER 1,0,0,0 -#endif - -#if defined(FLUTTER_VERSION) -#define VERSION_AS_STRING FLUTTER_VERSION -#else -#define VERSION_AS_STRING "1.0.0" -#endif - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VERSION_AS_NUMBER - PRODUCTVERSION VERSION_AS_NUMBER - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK -#ifdef _DEBUG - FILEFLAGS VS_FF_DEBUG -#else - FILEFLAGS 0x0L -#endif - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - BLOCK "040904e4" - BEGIN - VALUE "CompanyName", "com.example" "\0" - VALUE "FileDescription", "sige_ie" "\0" - VALUE "FileVersion", VERSION_AS_STRING "\0" - VALUE "InternalName", "sige_ie" "\0" - VALUE "LegalCopyright", "Copyright (C) 2024 com.example. All rights reserved." "\0" - VALUE "OriginalFilename", "sige_ie.exe" "\0" - VALUE "ProductName", "sige_ie" "\0" - VALUE "ProductVersion", VERSION_AS_STRING "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 1252 - END -END - -#endif // English (United States) resources -///////////////////////////////////////////////////////////////////////////// - - - -#ifndef APSTUDIO_INVOKED -///////////////////////////////////////////////////////////////////////////// -// -// Generated from the TEXTINCLUDE 3 resource. -// - - -///////////////////////////////////////////////////////////////////////////// -#endif // not APSTUDIO_INVOKED diff --git a/frontend/sige_ie/windows/runner/flutter_window.cpp b/frontend/sige_ie/windows/runner/flutter_window.cpp deleted file mode 100644 index 955ee303..00000000 --- a/frontend/sige_ie/windows/runner/flutter_window.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "flutter_window.h" - -#include - -#include "flutter/generated_plugin_registrant.h" - -FlutterWindow::FlutterWindow(const flutter::DartProject& project) - : project_(project) {} - -FlutterWindow::~FlutterWindow() {} - -bool FlutterWindow::OnCreate() { - if (!Win32Window::OnCreate()) { - return false; - } - - RECT frame = GetClientArea(); - - // The size here must match the window dimensions to avoid unnecessary surface - // creation / destruction in the startup path. - flutter_controller_ = std::make_unique( - frame.right - frame.left, frame.bottom - frame.top, project_); - // Ensure that basic setup of the controller was successful. - if (!flutter_controller_->engine() || !flutter_controller_->view()) { - return false; - } - RegisterPlugins(flutter_controller_->engine()); - SetChildContent(flutter_controller_->view()->GetNativeWindow()); - - flutter_controller_->engine()->SetNextFrameCallback([&]() { - this->Show(); - }); - - // Flutter can complete the first frame before the "show window" callback is - // registered. The following call ensures a frame is pending to ensure the - // window is shown. It is a no-op if the first frame hasn't completed yet. - flutter_controller_->ForceRedraw(); - - return true; -} - -void FlutterWindow::OnDestroy() { - if (flutter_controller_) { - flutter_controller_ = nullptr; - } - - Win32Window::OnDestroy(); -} - -LRESULT -FlutterWindow::MessageHandler(HWND hwnd, UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - // Give Flutter, including plugins, an opportunity to handle window messages. - if (flutter_controller_) { - std::optional result = - flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, - lparam); - if (result) { - return *result; - } - } - - switch (message) { - case WM_FONTCHANGE: - flutter_controller_->engine()->ReloadSystemFonts(); - break; - } - - return Win32Window::MessageHandler(hwnd, message, wparam, lparam); -} diff --git a/frontend/sige_ie/windows/runner/flutter_window.h b/frontend/sige_ie/windows/runner/flutter_window.h deleted file mode 100644 index 6da0652f..00000000 --- a/frontend/sige_ie/windows/runner/flutter_window.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef RUNNER_FLUTTER_WINDOW_H_ -#define RUNNER_FLUTTER_WINDOW_H_ - -#include -#include - -#include - -#include "win32_window.h" - -// A window that does nothing but host a Flutter view. -class FlutterWindow : public Win32Window { - public: - // Creates a new FlutterWindow hosting a Flutter view running |project|. - explicit FlutterWindow(const flutter::DartProject& project); - virtual ~FlutterWindow(); - - protected: - // Win32Window: - bool OnCreate() override; - void OnDestroy() override; - LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, - LPARAM const lparam) noexcept override; - - private: - // The project to run. - flutter::DartProject project_; - - // The Flutter instance hosted by this window. - std::unique_ptr flutter_controller_; -}; - -#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/frontend/sige_ie/windows/runner/main.cpp b/frontend/sige_ie/windows/runner/main.cpp deleted file mode 100644 index e56f7e6a..00000000 --- a/frontend/sige_ie/windows/runner/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include - -#include "flutter_window.h" -#include "utils.h" - -int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, - _In_ wchar_t *command_line, _In_ int show_command) { - // Attach to console when present (e.g., 'flutter run') or create a - // new console when running with a debugger. - if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { - CreateAndAttachConsole(); - } - - // Initialize COM, so that it is available for use in the library and/or - // plugins. - ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); - - flutter::DartProject project(L"data"); - - std::vector command_line_arguments = - GetCommandLineArguments(); - - project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); - - FlutterWindow window(project); - Win32Window::Point origin(10, 10); - Win32Window::Size size(1280, 720); - if (!window.Create(L"sige_ie", origin, size)) { - return EXIT_FAILURE; - } - window.SetQuitOnClose(true); - - ::MSG msg; - while (::GetMessage(&msg, nullptr, 0, 0)) { - ::TranslateMessage(&msg); - ::DispatchMessage(&msg); - } - - ::CoUninitialize(); - return EXIT_SUCCESS; -} diff --git a/frontend/sige_ie/windows/runner/resource.h b/frontend/sige_ie/windows/runner/resource.h deleted file mode 100644 index 66a65d1e..00000000 --- a/frontend/sige_ie/windows/runner/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by Runner.rc -// -#define IDI_APP_ICON 101 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 102 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/frontend/sige_ie/windows/runner/resources/app_icon.ico b/frontend/sige_ie/windows/runner/resources/app_icon.ico deleted file mode 100644 index c04e20ca..00000000 Binary files a/frontend/sige_ie/windows/runner/resources/app_icon.ico and /dev/null differ diff --git a/frontend/sige_ie/windows/runner/runner.exe.manifest b/frontend/sige_ie/windows/runner/runner.exe.manifest deleted file mode 100644 index a42ea768..00000000 --- a/frontend/sige_ie/windows/runner/runner.exe.manifest +++ /dev/null @@ -1,20 +0,0 @@ - - - - - PerMonitorV2 - - - - - - - - - - - - - - - diff --git a/frontend/sige_ie/windows/runner/utils.cpp b/frontend/sige_ie/windows/runner/utils.cpp deleted file mode 100644 index b2b08734..00000000 --- a/frontend/sige_ie/windows/runner/utils.cpp +++ /dev/null @@ -1,65 +0,0 @@ -#include "utils.h" - -#include -#include -#include -#include - -#include - -void CreateAndAttachConsole() { - if (::AllocConsole()) { - FILE *unused; - if (freopen_s(&unused, "CONOUT$", "w", stdout)) { - _dup2(_fileno(stdout), 1); - } - if (freopen_s(&unused, "CONOUT$", "w", stderr)) { - _dup2(_fileno(stdout), 2); - } - std::ios::sync_with_stdio(); - FlutterDesktopResyncOutputStreams(); - } -} - -std::vector GetCommandLineArguments() { - // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. - int argc; - wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); - if (argv == nullptr) { - return std::vector(); - } - - std::vector command_line_arguments; - - // Skip the first argument as it's the binary name. - for (int i = 1; i < argc; i++) { - command_line_arguments.push_back(Utf8FromUtf16(argv[i])); - } - - ::LocalFree(argv); - - return command_line_arguments; -} - -std::string Utf8FromUtf16(const wchar_t* utf16_string) { - if (utf16_string == nullptr) { - return std::string(); - } - int target_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - -1, nullptr, 0, nullptr, nullptr) - -1; // remove the trailing null character - int input_length = (int)wcslen(utf16_string); - std::string utf8_string; - if (target_length <= 0 || target_length > utf8_string.max_size()) { - return utf8_string; - } - utf8_string.resize(target_length); - int converted_length = ::WideCharToMultiByte( - CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, - input_length, utf8_string.data(), target_length, nullptr, nullptr); - if (converted_length == 0) { - return std::string(); - } - return utf8_string; -} diff --git a/frontend/sige_ie/windows/runner/utils.h b/frontend/sige_ie/windows/runner/utils.h deleted file mode 100644 index 3879d547..00000000 --- a/frontend/sige_ie/windows/runner/utils.h +++ /dev/null @@ -1,19 +0,0 @@ -#ifndef RUNNER_UTILS_H_ -#define RUNNER_UTILS_H_ - -#include -#include - -// Creates a console for the process, and redirects stdout and stderr to -// it for both the runner and the Flutter library. -void CreateAndAttachConsole(); - -// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string -// encoded in UTF-8. Returns an empty std::string on failure. -std::string Utf8FromUtf16(const wchar_t* utf16_string); - -// Gets the command line arguments passed in as a std::vector, -// encoded in UTF-8. Returns an empty std::vector on failure. -std::vector GetCommandLineArguments(); - -#endif // RUNNER_UTILS_H_ diff --git a/frontend/sige_ie/windows/runner/win32_window.cpp b/frontend/sige_ie/windows/runner/win32_window.cpp deleted file mode 100644 index 60608d0f..00000000 --- a/frontend/sige_ie/windows/runner/win32_window.cpp +++ /dev/null @@ -1,288 +0,0 @@ -#include "win32_window.h" - -#include -#include - -#include "resource.h" - -namespace { - -/// Window attribute that enables dark mode window decorations. -/// -/// Redefined in case the developer's machine has a Windows SDK older than -/// version 10.0.22000.0. -/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute -#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE -#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 -#endif - -constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; - -/// Registry key for app theme preference. -/// -/// A value of 0 indicates apps should use dark mode. A non-zero or missing -/// value indicates apps should use light mode. -constexpr const wchar_t kGetPreferredBrightnessRegKey[] = - L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; -constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; - -// The number of Win32Window objects that currently exist. -static int g_active_window_count = 0; - -using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); - -// Scale helper to convert logical scaler values to physical using passed in -// scale factor -int Scale(int source, double scale_factor) { - return static_cast(source * scale_factor); -} - -// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. -// This API is only needed for PerMonitor V1 awareness mode. -void EnableFullDpiSupportIfAvailable(HWND hwnd) { - HMODULE user32_module = LoadLibraryA("User32.dll"); - if (!user32_module) { - return; - } - auto enable_non_client_dpi_scaling = - reinterpret_cast( - GetProcAddress(user32_module, "EnableNonClientDpiScaling")); - if (enable_non_client_dpi_scaling != nullptr) { - enable_non_client_dpi_scaling(hwnd); - } - FreeLibrary(user32_module); -} - -} // namespace - -// Manages the Win32Window's window class registration. -class WindowClassRegistrar { - public: - ~WindowClassRegistrar() = default; - - // Returns the singleton registrar instance. - static WindowClassRegistrar* GetInstance() { - if (!instance_) { - instance_ = new WindowClassRegistrar(); - } - return instance_; - } - - // Returns the name of the window class, registering the class if it hasn't - // previously been registered. - const wchar_t* GetWindowClass(); - - // Unregisters the window class. Should only be called if there are no - // instances of the window. - void UnregisterWindowClass(); - - private: - WindowClassRegistrar() = default; - - static WindowClassRegistrar* instance_; - - bool class_registered_ = false; -}; - -WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; - -const wchar_t* WindowClassRegistrar::GetWindowClass() { - if (!class_registered_) { - WNDCLASS window_class{}; - window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); - window_class.lpszClassName = kWindowClassName; - window_class.style = CS_HREDRAW | CS_VREDRAW; - window_class.cbClsExtra = 0; - window_class.cbWndExtra = 0; - window_class.hInstance = GetModuleHandle(nullptr); - window_class.hIcon = - LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); - window_class.hbrBackground = 0; - window_class.lpszMenuName = nullptr; - window_class.lpfnWndProc = Win32Window::WndProc; - RegisterClass(&window_class); - class_registered_ = true; - } - return kWindowClassName; -} - -void WindowClassRegistrar::UnregisterWindowClass() { - UnregisterClass(kWindowClassName, nullptr); - class_registered_ = false; -} - -Win32Window::Win32Window() { - ++g_active_window_count; -} - -Win32Window::~Win32Window() { - --g_active_window_count; - Destroy(); -} - -bool Win32Window::Create(const std::wstring& title, - const Point& origin, - const Size& size) { - Destroy(); - - const wchar_t* window_class = - WindowClassRegistrar::GetInstance()->GetWindowClass(); - - const POINT target_point = {static_cast(origin.x), - static_cast(origin.y)}; - HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); - UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); - double scale_factor = dpi / 96.0; - - HWND window = CreateWindow( - window_class, title.c_str(), WS_OVERLAPPEDWINDOW, - Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), - Scale(size.width, scale_factor), Scale(size.height, scale_factor), - nullptr, nullptr, GetModuleHandle(nullptr), this); - - if (!window) { - return false; - } - - UpdateTheme(window); - - return OnCreate(); -} - -bool Win32Window::Show() { - return ShowWindow(window_handle_, SW_SHOWNORMAL); -} - -// static -LRESULT CALLBACK Win32Window::WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - if (message == WM_NCCREATE) { - auto window_struct = reinterpret_cast(lparam); - SetWindowLongPtr(window, GWLP_USERDATA, - reinterpret_cast(window_struct->lpCreateParams)); - - auto that = static_cast(window_struct->lpCreateParams); - EnableFullDpiSupportIfAvailable(window); - that->window_handle_ = window; - } else if (Win32Window* that = GetThisFromHandle(window)) { - return that->MessageHandler(window, message, wparam, lparam); - } - - return DefWindowProc(window, message, wparam, lparam); -} - -LRESULT -Win32Window::MessageHandler(HWND hwnd, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept { - switch (message) { - case WM_DESTROY: - window_handle_ = nullptr; - Destroy(); - if (quit_on_close_) { - PostQuitMessage(0); - } - return 0; - - case WM_DPICHANGED: { - auto newRectSize = reinterpret_cast(lparam); - LONG newWidth = newRectSize->right - newRectSize->left; - LONG newHeight = newRectSize->bottom - newRectSize->top; - - SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, - newHeight, SWP_NOZORDER | SWP_NOACTIVATE); - - return 0; - } - case WM_SIZE: { - RECT rect = GetClientArea(); - if (child_content_ != nullptr) { - // Size and position the child window. - MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, - rect.bottom - rect.top, TRUE); - } - return 0; - } - - case WM_ACTIVATE: - if (child_content_ != nullptr) { - SetFocus(child_content_); - } - return 0; - - case WM_DWMCOLORIZATIONCOLORCHANGED: - UpdateTheme(hwnd); - return 0; - } - - return DefWindowProc(window_handle_, message, wparam, lparam); -} - -void Win32Window::Destroy() { - OnDestroy(); - - if (window_handle_) { - DestroyWindow(window_handle_); - window_handle_ = nullptr; - } - if (g_active_window_count == 0) { - WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); - } -} - -Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { - return reinterpret_cast( - GetWindowLongPtr(window, GWLP_USERDATA)); -} - -void Win32Window::SetChildContent(HWND content) { - child_content_ = content; - SetParent(content, window_handle_); - RECT frame = GetClientArea(); - - MoveWindow(content, frame.left, frame.top, frame.right - frame.left, - frame.bottom - frame.top, true); - - SetFocus(child_content_); -} - -RECT Win32Window::GetClientArea() { - RECT frame; - GetClientRect(window_handle_, &frame); - return frame; -} - -HWND Win32Window::GetHandle() { - return window_handle_; -} - -void Win32Window::SetQuitOnClose(bool quit_on_close) { - quit_on_close_ = quit_on_close; -} - -bool Win32Window::OnCreate() { - // No-op; provided for subclasses. - return true; -} - -void Win32Window::OnDestroy() { - // No-op; provided for subclasses. -} - -void Win32Window::UpdateTheme(HWND const window) { - DWORD light_mode; - DWORD light_mode_size = sizeof(light_mode); - LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, - kGetPreferredBrightnessRegValue, - RRF_RT_REG_DWORD, nullptr, &light_mode, - &light_mode_size); - - if (result == ERROR_SUCCESS) { - BOOL enable_dark_mode = light_mode == 0; - DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, - &enable_dark_mode, sizeof(enable_dark_mode)); - } -} diff --git a/frontend/sige_ie/windows/runner/win32_window.h b/frontend/sige_ie/windows/runner/win32_window.h deleted file mode 100644 index e901dde6..00000000 --- a/frontend/sige_ie/windows/runner/win32_window.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef RUNNER_WIN32_WINDOW_H_ -#define RUNNER_WIN32_WINDOW_H_ - -#include - -#include -#include -#include - -// A class abstraction for a high DPI-aware Win32 Window. Intended to be -// inherited from by classes that wish to specialize with custom -// rendering and input handling -class Win32Window { - public: - struct Point { - unsigned int x; - unsigned int y; - Point(unsigned int x, unsigned int y) : x(x), y(y) {} - }; - - struct Size { - unsigned int width; - unsigned int height; - Size(unsigned int width, unsigned int height) - : width(width), height(height) {} - }; - - Win32Window(); - virtual ~Win32Window(); - - // Creates a win32 window with |title| that is positioned and sized using - // |origin| and |size|. New windows are created on the default monitor. Window - // sizes are specified to the OS in physical pixels, hence to ensure a - // consistent size this function will scale the inputted width and height as - // as appropriate for the default monitor. The window is invisible until - // |Show| is called. Returns true if the window was created successfully. - bool Create(const std::wstring& title, const Point& origin, const Size& size); - - // Show the current window. Returns true if the window was successfully shown. - bool Show(); - - // Release OS resources associated with window. - void Destroy(); - - // Inserts |content| into the window tree. - void SetChildContent(HWND content); - - // Returns the backing Window handle to enable clients to set icon and other - // window properties. Returns nullptr if the window has been destroyed. - HWND GetHandle(); - - // If true, closing this window will quit the application. - void SetQuitOnClose(bool quit_on_close); - - // Return a RECT representing the bounds of the current client area. - RECT GetClientArea(); - - protected: - // Processes and route salient window messages for mouse handling, - // size change and DPI. Delegates handling of these to member overloads that - // inheriting classes can handle. - virtual LRESULT MessageHandler(HWND window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Called when CreateAndShow is called, allowing subclass window-related - // setup. Subclasses should return false if setup fails. - virtual bool OnCreate(); - - // Called when Destroy is called. - virtual void OnDestroy(); - - private: - friend class WindowClassRegistrar; - - // OS callback called by message pump. Handles the WM_NCCREATE message which - // is passed when the non-client area is being created and enables automatic - // non-client DPI scaling so that the non-client area automatically - // responds to changes in DPI. All other messages are handled by - // MessageHandler. - static LRESULT CALLBACK WndProc(HWND const window, - UINT const message, - WPARAM const wparam, - LPARAM const lparam) noexcept; - - // Retrieves a class instance pointer for |window| - static Win32Window* GetThisFromHandle(HWND const window) noexcept; - - // Update the window frame's theme to match the system theme. - static void UpdateTheme(HWND const window); - - bool quit_on_close_ = false; - - // window handle for top level window. - HWND window_handle_ = nullptr; - - // window handle for hosted content. - HWND child_content_ = nullptr; -}; - -#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 00000000..ac95b4b3 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,51 @@ +site_name: "SIGE IE" + +theme: + name: lux + favicon: assets/favicon.ico + logo: assets/favicon.ico + font: + text: Roboto + language: pt + features: + - content.code.annotate + - content.tabs.link + - header.autohide + - navigation.instant + - navigation.sections + - navigation.tabs + - navigation.top + - navigation.tracking + - navigation.tabs.sticky + extra_css: + - theme/bootstrap.min.css + - css/custom.css + +nav: + - Ínicio: info/home.md + - Subir o projeto: + - Backend: info/backend.md + - Frontend: info/frontend.md + - Contribuições: info/contribuir.md + - Atas de Reunião: + - Ata 1: atas/ata1.md + - Ata 2: atas/ata2.md + - Ata 3: atas/ata3.md + - Arquitetura e Protótipo: + - Arquitetura: info/arquitetura.md + - Modelagem Banco de dados: info/modelagemBD.md + - RoadMap: + - RoadMap: info/Roadmap.md + - Cronograma: + - Cronograma: info/cronograma.md + - Releases: + - Release 1: releases/Release1.md + - Release 2: releases/release2.md + - Release 3: releases/release3.md + - Release 4: releases/release4.md + - Requisitos de Software: + - Épicos: info/requisitosEpicos.md + - Features: info/requisitosFeatures.md + +plugins: + - search \ No newline at end of file diff --git a/site/assets/1.png b/site/assets/1.png new file mode 100644 index 00000000..d6d1d464 Binary files /dev/null and b/site/assets/1.png differ diff --git a/site/assets/Login Page Wireframe Mobile UI Prototype-2_page-0019.jpg b/site/assets/Login Page Wireframe Mobile UI Prototype-2_page-0019.jpg new file mode 100644 index 00000000..5b806049 Binary files /dev/null and b/site/assets/Login Page Wireframe Mobile UI Prototype-2_page-0019.jpg differ diff --git a/site/assets/R1.png b/site/assets/R1.png new file mode 100644 index 00000000..05513eb9 Binary files /dev/null and b/site/assets/R1.png differ diff --git a/site/assets/R2.png b/site/assets/R2.png new file mode 100644 index 00000000..6ba88dc3 Binary files /dev/null and b/site/assets/R2.png differ diff --git a/site/assets/R3.png b/site/assets/R3.png new file mode 100644 index 00000000..b33c593d Binary files /dev/null and b/site/assets/R3.png differ diff --git a/site/assets/R4.png b/site/assets/R4.png new file mode 100644 index 00000000..ceee2344 Binary files /dev/null and b/site/assets/R4.png differ diff --git a/site/assets/adicionar.equipamentos.jpeg b/site/assets/adicionar.equipamentos.jpeg new file mode 100644 index 00000000..f3c7f2b0 Binary files /dev/null and b/site/assets/adicionar.equipamentos.jpeg differ diff --git a/site/assets/arquitetura.png b/site/assets/arquitetura.png new file mode 100644 index 00000000..48f40df0 Binary files /dev/null and b/site/assets/arquitetura.png differ diff --git a/site/assets/default_765x625.png b/site/assets/default_765x625.png new file mode 100644 index 00000000..424e36dd Binary files /dev/null and b/site/assets/default_765x625.png differ diff --git a/site/assets/default_transparent_1000x1000.png b/site/assets/default_transparent_1000x1000.png new file mode 100644 index 00000000..957a0749 Binary files /dev/null and b/site/assets/default_transparent_1000x1000.png differ diff --git a/site/assets/favicon.ico b/site/assets/favicon.ico new file mode 100644 index 00000000..cf72f904 Binary files /dev/null and b/site/assets/favicon.ico differ diff --git a/site/assets/imagem.mapa.jpeg b/site/assets/imagem.mapa.jpeg new file mode 100644 index 00000000..4a28853c Binary files /dev/null and b/site/assets/imagem.mapa.jpeg differ diff --git a/site/assets/locais.jpeg b/site/assets/locais.jpeg new file mode 100644 index 00000000..7def1cf1 Binary files /dev/null and b/site/assets/locais.jpeg differ diff --git a/site/assets/logo.png b/site/assets/logo.png new file mode 100644 index 00000000..cf72f904 Binary files /dev/null and b/site/assets/logo.png differ diff --git "a/site/assets/menu.instala\303\247oes.jpeg" "b/site/assets/menu.instala\303\247oes.jpeg" new file mode 100644 index 00000000..70b5db5b Binary files /dev/null and "b/site/assets/menu.instala\303\247oes.jpeg" differ diff --git a/site/assets/pp.pdf b/site/assets/pp.pdf new file mode 100644 index 00000000..8e84a862 Binary files /dev/null and b/site/assets/pp.pdf differ diff --git a/site/assets/release2.1.png b/site/assets/release2.1.png new file mode 100644 index 00000000..ca9e15c0 Binary files /dev/null and b/site/assets/release2.1.png differ diff --git a/site/assets/release2.png b/site/assets/release2.png new file mode 100644 index 00000000..4c987d0d Binary files /dev/null and b/site/assets/release2.png differ diff --git a/site/landingPages/.html b/site/landingPages/.html new file mode 100644 index 00000000..ee49ca8c --- /dev/null +++ b/site/landingPages/.html @@ -0,0 +1,286 @@ + + + + + + + + SIGE IE - Electrical Maintenance + + + + + + + + + +
+
+ +
+

+

+ Sistema de Auxilio para Operação e Manutenção de Instalação Elétrica. +

+

+ Uma ferramenta concebida para facilitar o processo de coleta de dados, essencial no suporte às operações e manutenções e sistemas de instalação elétrica. Este sistema foi desenvolvido com o propósito específico de agilizar a obtenção de informações cruciais, aprimorando assim a eficiência nas operações e garantindo uma gestão mais eficaz das instalações elétricas. +

+ +
+ +
+ +
+
+
+ +
+ + + + + + + + + + + + + +
+ + +
+
+

+ Features +

+
+
+
+
+
+
+
+

+ Gerenciamento de Instalações em Locais. +

+

+ Cadastre Locais e Gerenciar os sistemas de instalações elétricas, sistema de iluminação, cargas elétricas, linhas elétricas, + cabeamento estruturado, sistema de refrigeração, sistema de alarme de proteção contra incêndio, quadro de distribuição, circuitos + elétricos e sistema de proteção contra Descargas Atmosféricas. +
+
+

+
+
+ Gerenciamento de Instalações +
+
+
+
+
+
+

+ Cadastro de Locais. +

+

+ Crie e mantenha um registro detalhado de todos os locais e salas dentro da instalação, facilitando a gestão e manutenção das instalações elétricas. +
+
+

+
+
+ Cadastro de Locais +
+
+
+
+
+
+
+
+

+ Menu de Instalações. +

+

+ Acesse rapidamente todas as instalações registradas e visualize informações detalhadas sobre cada uma delas, incluindo status de manutenção e histórico de serviços. +
+
+

+
+
+ Menu de Instalações +
+
+
+
+
+
+
+

+ Integração com Mapas +

+

+ O aplicativo conta com uma funcionalidade de integração + em tempo real, permitindo o acompanhamento de localizações e salas + registradas. Os usuários podem criar e atualizar locais + instantaneamente, garantindo que todas as mudanças sejam refletidas no sistema + sem atrasos. Essa funcionalidade é essencial para uma gestão eficiente de ambientes dinâmicos, + proporcionando uma visão atualizada e precisa de todas as localizações e salas + monitoradas pelo aplicativo. +
+
+

+
+
+ Map Integration +
+
+
+
+
+
+
+ + +
+

+ SIGE IE +

+
+
+
+

+ Conheça nosso Projeto. +

+ +
+ + + + diff --git a/site/landingPages/about.html b/site/landingPages/about.html new file mode 100644 index 00000000..324bf579 --- /dev/null +++ b/site/landingPages/about.html @@ -0,0 +1,390 @@ + + + + + + + + SIGE IE - Electrical Maintenance + + + + + + + + + +
+
+ +
+

+

+ Sistema de Auxilio para Operação e Manutenção de Instalação Elétrica. +

+

+ Uma ferramenta concebida para facilitar o processo de coleta de dados, essencial no suporte às operações e manutenções e sistemas de instalação elétrica. Este sistema foi desenvolvido com o propósito específico de agilizar a obtenção de informações cruciais, aprimorando assim a eficiência nas operações e garantindo uma gestão mais eficaz das instalações elétricas. +

+
+ +
+ +
+
+
+ +
+ + + + + + + + + + + + +
+ + +
+
+

+ Descrição do Produto. +

+
+
+
+
+
+
+
+

+ Introdução. +

+

+ Cadastre Locais e Gerenciar os sistemas de instalações elétricas, sistema de iluminação, cargas elétricas, linhas elétricas, + cabeamento estruturado, sistema de refrigeração, sistema de alarme de proteção contra incêndio, quadro de distribuição, circuitos + elétricos e sistema de proteção contra Descargas Atmosféricas. +
+
+

+
+
+
+
+
+
+

+ Detalhamento do Problema. +

+

+ Crie e mantenha um registro detalhado de todos os locais e salas dentro da instalação, facilitando a gestão e manutenção das instalações elétricas. +
+
+

+
+
+
+
+
+
+
+
+

+ Identificação de Soluções. +

+

+ Acesse rapidamente todas as instalações registradas e visualize informações detalhadas sobre cada uma delas, incluindo status de manutenção e histórico de serviços. +
+
+

+
+
+
+
+
+
+
+

+ Objetivo Geral do Projeto. +

+

+ O aplicativo conta com uma funcionalidade de integração + em tempo real, permitindo o acompanhamento de localizações e salas + registradas. Os usuários podem criar e atualizar locais + instantaneamente, garantindo que todas as mudanças sejam refletidas no sistema + sem atrasos. Essa funcionalidade é essencial para uma gestão eficiente de ambientes dinâmicos, + proporcionando uma visão atualizada e precisa de todas as localizações e salas + monitoradas pelo aplicativo. +
+
+

+
+
+
+
+
+
+
+ + +
+
+

+ Project Images +

+
+
+
+
+
+
+ Project Image 1 +
+
+
+
+ Project Image 2 +
+
+
+
+ Project Image 3 +
+
+
+
+
+ + +
+
+

+ Team +

+
+
+
+
+
+
+ +
+

+ Danilo Melo +

+

+ Desenvolvedor Frontend(codifica o frontend e realiza integração com backend), + UX Design(Projeta a interface do usuário, cria protótipos), +

+
+
+
+
+
+ +
+

+ Kauan José +

+

+ Desenvolvedor backend. +

+
+
+
+
+
+ +
+

+ Oscar de Brito +

+

+ Desenvolvedor backend +

+
+
+
+
+
+ +
+

+ Pedro Lucas +

+

+ Responsável pela codificação do backend, configuração da infraestrutura, + e participação na codificação do frontend e integração com o backend. +

+
+
+
+
+
+ +
+

+ Ramires Rocha +

+

+ Levantamento de requisitos,gerenciamento da documentação e + validação com a cliente. +

+
+
+
+
+
+
+ + +
+

+ SIGE IE +

+
+
+
+

+ Conheça nosso Projeto. +

+ +
+ + + + + diff --git a/site/search/lunr.js b/site/search/lunr.js new file mode 100644 index 00000000..aca0a167 --- /dev/null +++ b/site/search/lunr.js @@ -0,0 +1,3475 @@ +/** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + */ + +;(function(){ + +/** + * A convenience function for configuring and constructing + * a new lunr Index. + * + * A lunr.Builder instance is created and the pipeline setup + * with a trimmer, stop word filter and stemmer. + * + * This builder object is yielded to the configuration function + * that is passed as a parameter, allowing the list of fields + * and other builder parameters to be customised. + * + * All documents _must_ be added within the passed config function. + * + * @example + * var idx = lunr(function () { + * this.field('title') + * this.field('body') + * this.ref('id') + * + * documents.forEach(function (doc) { + * this.add(doc) + * }, this) + * }) + * + * @see {@link lunr.Builder} + * @see {@link lunr.Pipeline} + * @see {@link lunr.trimmer} + * @see {@link lunr.stopWordFilter} + * @see {@link lunr.stemmer} + * @namespace {function} lunr + */ +var lunr = function (config) { + var builder = new lunr.Builder + + builder.pipeline.add( + lunr.trimmer, + lunr.stopWordFilter, + lunr.stemmer + ) + + builder.searchPipeline.add( + lunr.stemmer + ) + + config.call(builder, builder) + return builder.build() +} + +lunr.version = "2.3.9" +/*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A namespace containing utils for the rest of the lunr library + * @namespace lunr.utils + */ +lunr.utils = {} + +/** + * Print a warning message to the console. + * + * @param {String} message The message to be printed. + * @memberOf lunr.utils + * @function + */ +lunr.utils.warn = (function (global) { + /* eslint-disable no-console */ + return function (message) { + if (global.console && console.warn) { + console.warn(message) + } + } + /* eslint-enable no-console */ +})(this) + +/** + * Convert an object to a string. + * + * In the case of `null` and `undefined` the function returns + * the empty string, in all other cases the result of calling + * `toString` on the passed object is returned. + * + * @param {Any} obj The object to convert to a string. + * @return {String} string representation of the passed object. + * @memberOf lunr.utils + */ +lunr.utils.asString = function (obj) { + if (obj === void 0 || obj === null) { + return "" + } else { + return obj.toString() + } +} + +/** + * Clones an object. + * + * Will create a copy of an existing object such that any mutations + * on the copy cannot affect the original. + * + * Only shallow objects are supported, passing a nested object to this + * function will cause a TypeError. + * + * Objects with primitives, and arrays of primitives are supported. + * + * @param {Object} obj The object to clone. + * @return {Object} a clone of the passed object. + * @throws {TypeError} when a nested object is passed. + * @memberOf Utils + */ +lunr.utils.clone = function (obj) { + if (obj === null || obj === undefined) { + return obj + } + + var clone = Object.create(null), + keys = Object.keys(obj) + + for (var i = 0; i < keys.length; i++) { + var key = keys[i], + val = obj[key] + + if (Array.isArray(val)) { + clone[key] = val.slice() + continue + } + + if (typeof val === 'string' || + typeof val === 'number' || + typeof val === 'boolean') { + clone[key] = val + continue + } + + throw new TypeError("clone is not deep and does not support nested objects") + } + + return clone +} +lunr.FieldRef = function (docRef, fieldName, stringValue) { + this.docRef = docRef + this.fieldName = fieldName + this._stringValue = stringValue +} + +lunr.FieldRef.joiner = "/" + +lunr.FieldRef.fromString = function (s) { + var n = s.indexOf(lunr.FieldRef.joiner) + + if (n === -1) { + throw "malformed field ref string" + } + + var fieldRef = s.slice(0, n), + docRef = s.slice(n + 1) + + return new lunr.FieldRef (docRef, fieldRef, s) +} + +lunr.FieldRef.prototype.toString = function () { + if (this._stringValue == undefined) { + this._stringValue = this.fieldName + lunr.FieldRef.joiner + this.docRef + } + + return this._stringValue +} +/*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A lunr set. + * + * @constructor + */ +lunr.Set = function (elements) { + this.elements = Object.create(null) + + if (elements) { + this.length = elements.length + + for (var i = 0; i < this.length; i++) { + this.elements[elements[i]] = true + } + } else { + this.length = 0 + } +} + +/** + * A complete set that contains all elements. + * + * @static + * @readonly + * @type {lunr.Set} + */ +lunr.Set.complete = { + intersect: function (other) { + return other + }, + + union: function () { + return this + }, + + contains: function () { + return true + } +} + +/** + * An empty set that contains no elements. + * + * @static + * @readonly + * @type {lunr.Set} + */ +lunr.Set.empty = { + intersect: function () { + return this + }, + + union: function (other) { + return other + }, + + contains: function () { + return false + } +} + +/** + * Returns true if this set contains the specified object. + * + * @param {object} object - Object whose presence in this set is to be tested. + * @returns {boolean} - True if this set contains the specified object. + */ +lunr.Set.prototype.contains = function (object) { + return !!this.elements[object] +} + +/** + * Returns a new set containing only the elements that are present in both + * this set and the specified set. + * + * @param {lunr.Set} other - set to intersect with this set. + * @returns {lunr.Set} a new set that is the intersection of this and the specified set. + */ + +lunr.Set.prototype.intersect = function (other) { + var a, b, elements, intersection = [] + + if (other === lunr.Set.complete) { + return this + } + + if (other === lunr.Set.empty) { + return other + } + + if (this.length < other.length) { + a = this + b = other + } else { + a = other + b = this + } + + elements = Object.keys(a.elements) + + for (var i = 0; i < elements.length; i++) { + var element = elements[i] + if (element in b.elements) { + intersection.push(element) + } + } + + return new lunr.Set (intersection) +} + +/** + * Returns a new set combining the elements of this and the specified set. + * + * @param {lunr.Set} other - set to union with this set. + * @return {lunr.Set} a new set that is the union of this and the specified set. + */ + +lunr.Set.prototype.union = function (other) { + if (other === lunr.Set.complete) { + return lunr.Set.complete + } + + if (other === lunr.Set.empty) { + return this + } + + return new lunr.Set(Object.keys(this.elements).concat(Object.keys(other.elements))) +} +/** + * A function to calculate the inverse document frequency for + * a posting. This is shared between the builder and the index + * + * @private + * @param {object} posting - The posting for a given term + * @param {number} documentCount - The total number of documents. + */ +lunr.idf = function (posting, documentCount) { + var documentsWithTerm = 0 + + for (var fieldName in posting) { + if (fieldName == '_index') continue // Ignore the term index, its not a field + documentsWithTerm += Object.keys(posting[fieldName]).length + } + + var x = (documentCount - documentsWithTerm + 0.5) / (documentsWithTerm + 0.5) + + return Math.log(1 + Math.abs(x)) +} + +/** + * A token wraps a string representation of a token + * as it is passed through the text processing pipeline. + * + * @constructor + * @param {string} [str=''] - The string token being wrapped. + * @param {object} [metadata={}] - Metadata associated with this token. + */ +lunr.Token = function (str, metadata) { + this.str = str || "" + this.metadata = metadata || {} +} + +/** + * Returns the token string that is being wrapped by this object. + * + * @returns {string} + */ +lunr.Token.prototype.toString = function () { + return this.str +} + +/** + * A token update function is used when updating or optionally + * when cloning a token. + * + * @callback lunr.Token~updateFunction + * @param {string} str - The string representation of the token. + * @param {Object} metadata - All metadata associated with this token. + */ + +/** + * Applies the given function to the wrapped string token. + * + * @example + * token.update(function (str, metadata) { + * return str.toUpperCase() + * }) + * + * @param {lunr.Token~updateFunction} fn - A function to apply to the token string. + * @returns {lunr.Token} + */ +lunr.Token.prototype.update = function (fn) { + this.str = fn(this.str, this.metadata) + return this +} + +/** + * Creates a clone of this token. Optionally a function can be + * applied to the cloned token. + * + * @param {lunr.Token~updateFunction} [fn] - An optional function to apply to the cloned token. + * @returns {lunr.Token} + */ +lunr.Token.prototype.clone = function (fn) { + fn = fn || function (s) { return s } + return new lunr.Token (fn(this.str, this.metadata), this.metadata) +} +/*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A function for splitting a string into tokens ready to be inserted into + * the search index. Uses `lunr.tokenizer.separator` to split strings, change + * the value of this property to change how strings are split into tokens. + * + * This tokenizer will convert its parameter to a string by calling `toString` and + * then will split this string on the character in `lunr.tokenizer.separator`. + * Arrays will have their elements converted to strings and wrapped in a lunr.Token. + * + * Optional metadata can be passed to the tokenizer, this metadata will be cloned and + * added as metadata to every token that is created from the object to be tokenized. + * + * @static + * @param {?(string|object|object[])} obj - The object to convert into tokens + * @param {?object} metadata - Optional metadata to associate with every token + * @returns {lunr.Token[]} + * @see {@link lunr.Pipeline} + */ +lunr.tokenizer = function (obj, metadata) { + if (obj == null || obj == undefined) { + return [] + } + + if (Array.isArray(obj)) { + return obj.map(function (t) { + return new lunr.Token( + lunr.utils.asString(t).toLowerCase(), + lunr.utils.clone(metadata) + ) + }) + } + + var str = obj.toString().toLowerCase(), + len = str.length, + tokens = [] + + for (var sliceEnd = 0, sliceStart = 0; sliceEnd <= len; sliceEnd++) { + var char = str.charAt(sliceEnd), + sliceLength = sliceEnd - sliceStart + + if ((char.match(lunr.tokenizer.separator) || sliceEnd == len)) { + + if (sliceLength > 0) { + var tokenMetadata = lunr.utils.clone(metadata) || {} + tokenMetadata["position"] = [sliceStart, sliceLength] + tokenMetadata["index"] = tokens.length + + tokens.push( + new lunr.Token ( + str.slice(sliceStart, sliceEnd), + tokenMetadata + ) + ) + } + + sliceStart = sliceEnd + 1 + } + + } + + return tokens +} + +/** + * The separator used to split a string into tokens. Override this property to change the behaviour of + * `lunr.tokenizer` behaviour when tokenizing strings. By default this splits on whitespace and hyphens. + * + * @static + * @see lunr.tokenizer + */ +lunr.tokenizer.separator = /[\s\-]+/ +/*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.Pipelines maintain an ordered list of functions to be applied to all + * tokens in documents entering the search index and queries being ran against + * the index. + * + * An instance of lunr.Index created with the lunr shortcut will contain a + * pipeline with a stop word filter and an English language stemmer. Extra + * functions can be added before or after either of these functions or these + * default functions can be removed. + * + * When run the pipeline will call each function in turn, passing a token, the + * index of that token in the original list of all tokens and finally a list of + * all the original tokens. + * + * The output of functions in the pipeline will be passed to the next function + * in the pipeline. To exclude a token from entering the index the function + * should return undefined, the rest of the pipeline will not be called with + * this token. + * + * For serialisation of pipelines to work, all functions used in an instance of + * a pipeline should be registered with lunr.Pipeline. Registered functions can + * then be loaded. If trying to load a serialised pipeline that uses functions + * that are not registered an error will be thrown. + * + * If not planning on serialising the pipeline then registering pipeline functions + * is not necessary. + * + * @constructor + */ +lunr.Pipeline = function () { + this._stack = [] +} + +lunr.Pipeline.registeredFunctions = Object.create(null) + +/** + * A pipeline function maps lunr.Token to lunr.Token. A lunr.Token contains the token + * string as well as all known metadata. A pipeline function can mutate the token string + * or mutate (or add) metadata for a given token. + * + * A pipeline function can indicate that the passed token should be discarded by returning + * null, undefined or an empty string. This token will not be passed to any downstream pipeline + * functions and will not be added to the index. + * + * Multiple tokens can be returned by returning an array of tokens. Each token will be passed + * to any downstream pipeline functions and all will returned tokens will be added to the index. + * + * Any number of pipeline functions may be chained together using a lunr.Pipeline. + * + * @interface lunr.PipelineFunction + * @param {lunr.Token} token - A token from the document being processed. + * @param {number} i - The index of this token in the complete list of tokens for this document/field. + * @param {lunr.Token[]} tokens - All tokens for this document/field. + * @returns {(?lunr.Token|lunr.Token[])} + */ + +/** + * Register a function with the pipeline. + * + * Functions that are used in the pipeline should be registered if the pipeline + * needs to be serialised, or a serialised pipeline needs to be loaded. + * + * Registering a function does not add it to a pipeline, functions must still be + * added to instances of the pipeline for them to be used when running a pipeline. + * + * @param {lunr.PipelineFunction} fn - The function to check for. + * @param {String} label - The label to register this function with + */ +lunr.Pipeline.registerFunction = function (fn, label) { + if (label in this.registeredFunctions) { + lunr.utils.warn('Overwriting existing registered function: ' + label) + } + + fn.label = label + lunr.Pipeline.registeredFunctions[fn.label] = fn +} + +/** + * Warns if the function is not registered as a Pipeline function. + * + * @param {lunr.PipelineFunction} fn - The function to check for. + * @private + */ +lunr.Pipeline.warnIfFunctionNotRegistered = function (fn) { + var isRegistered = fn.label && (fn.label in this.registeredFunctions) + + if (!isRegistered) { + lunr.utils.warn('Function is not registered with pipeline. This may cause problems when serialising the index.\n', fn) + } +} + +/** + * Loads a previously serialised pipeline. + * + * All functions to be loaded must already be registered with lunr.Pipeline. + * If any function from the serialised data has not been registered then an + * error will be thrown. + * + * @param {Object} serialised - The serialised pipeline to load. + * @returns {lunr.Pipeline} + */ +lunr.Pipeline.load = function (serialised) { + var pipeline = new lunr.Pipeline + + serialised.forEach(function (fnName) { + var fn = lunr.Pipeline.registeredFunctions[fnName] + + if (fn) { + pipeline.add(fn) + } else { + throw new Error('Cannot load unregistered function: ' + fnName) + } + }) + + return pipeline +} + +/** + * Adds new functions to the end of the pipeline. + * + * Logs a warning if the function has not been registered. + * + * @param {lunr.PipelineFunction[]} functions - Any number of functions to add to the pipeline. + */ +lunr.Pipeline.prototype.add = function () { + var fns = Array.prototype.slice.call(arguments) + + fns.forEach(function (fn) { + lunr.Pipeline.warnIfFunctionNotRegistered(fn) + this._stack.push(fn) + }, this) +} + +/** + * Adds a single function after a function that already exists in the + * pipeline. + * + * Logs a warning if the function has not been registered. + * + * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline. + * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline. + */ +lunr.Pipeline.prototype.after = function (existingFn, newFn) { + lunr.Pipeline.warnIfFunctionNotRegistered(newFn) + + var pos = this._stack.indexOf(existingFn) + if (pos == -1) { + throw new Error('Cannot find existingFn') + } + + pos = pos + 1 + this._stack.splice(pos, 0, newFn) +} + +/** + * Adds a single function before a function that already exists in the + * pipeline. + * + * Logs a warning if the function has not been registered. + * + * @param {lunr.PipelineFunction} existingFn - A function that already exists in the pipeline. + * @param {lunr.PipelineFunction} newFn - The new function to add to the pipeline. + */ +lunr.Pipeline.prototype.before = function (existingFn, newFn) { + lunr.Pipeline.warnIfFunctionNotRegistered(newFn) + + var pos = this._stack.indexOf(existingFn) + if (pos == -1) { + throw new Error('Cannot find existingFn') + } + + this._stack.splice(pos, 0, newFn) +} + +/** + * Removes a function from the pipeline. + * + * @param {lunr.PipelineFunction} fn The function to remove from the pipeline. + */ +lunr.Pipeline.prototype.remove = function (fn) { + var pos = this._stack.indexOf(fn) + if (pos == -1) { + return + } + + this._stack.splice(pos, 1) +} + +/** + * Runs the current list of functions that make up the pipeline against the + * passed tokens. + * + * @param {Array} tokens The tokens to run through the pipeline. + * @returns {Array} + */ +lunr.Pipeline.prototype.run = function (tokens) { + var stackLength = this._stack.length + + for (var i = 0; i < stackLength; i++) { + var fn = this._stack[i] + var memo = [] + + for (var j = 0; j < tokens.length; j++) { + var result = fn(tokens[j], j, tokens) + + if (result === null || result === void 0 || result === '') continue + + if (Array.isArray(result)) { + for (var k = 0; k < result.length; k++) { + memo.push(result[k]) + } + } else { + memo.push(result) + } + } + + tokens = memo + } + + return tokens +} + +/** + * Convenience method for passing a string through a pipeline and getting + * strings out. This method takes care of wrapping the passed string in a + * token and mapping the resulting tokens back to strings. + * + * @param {string} str - The string to pass through the pipeline. + * @param {?object} metadata - Optional metadata to associate with the token + * passed to the pipeline. + * @returns {string[]} + */ +lunr.Pipeline.prototype.runString = function (str, metadata) { + var token = new lunr.Token (str, metadata) + + return this.run([token]).map(function (t) { + return t.toString() + }) +} + +/** + * Resets the pipeline by removing any existing processors. + * + */ +lunr.Pipeline.prototype.reset = function () { + this._stack = [] +} + +/** + * Returns a representation of the pipeline ready for serialisation. + * + * Logs a warning if the function has not been registered. + * + * @returns {Array} + */ +lunr.Pipeline.prototype.toJSON = function () { + return this._stack.map(function (fn) { + lunr.Pipeline.warnIfFunctionNotRegistered(fn) + + return fn.label + }) +} +/*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A vector is used to construct the vector space of documents and queries. These + * vectors support operations to determine the similarity between two documents or + * a document and a query. + * + * Normally no parameters are required for initializing a vector, but in the case of + * loading a previously dumped vector the raw elements can be provided to the constructor. + * + * For performance reasons vectors are implemented with a flat array, where an elements + * index is immediately followed by its value. E.g. [index, value, index, value]. This + * allows the underlying array to be as sparse as possible and still offer decent + * performance when being used for vector calculations. + * + * @constructor + * @param {Number[]} [elements] - The flat list of element index and element value pairs. + */ +lunr.Vector = function (elements) { + this._magnitude = 0 + this.elements = elements || [] +} + + +/** + * Calculates the position within the vector to insert a given index. + * + * This is used internally by insert and upsert. If there are duplicate indexes then + * the position is returned as if the value for that index were to be updated, but it + * is the callers responsibility to check whether there is a duplicate at that index + * + * @param {Number} insertIdx - The index at which the element should be inserted. + * @returns {Number} + */ +lunr.Vector.prototype.positionForIndex = function (index) { + // For an empty vector the tuple can be inserted at the beginning + if (this.elements.length == 0) { + return 0 + } + + var start = 0, + end = this.elements.length / 2, + sliceLength = end - start, + pivotPoint = Math.floor(sliceLength / 2), + pivotIndex = this.elements[pivotPoint * 2] + + while (sliceLength > 1) { + if (pivotIndex < index) { + start = pivotPoint + } + + if (pivotIndex > index) { + end = pivotPoint + } + + if (pivotIndex == index) { + break + } + + sliceLength = end - start + pivotPoint = start + Math.floor(sliceLength / 2) + pivotIndex = this.elements[pivotPoint * 2] + } + + if (pivotIndex == index) { + return pivotPoint * 2 + } + + if (pivotIndex > index) { + return pivotPoint * 2 + } + + if (pivotIndex < index) { + return (pivotPoint + 1) * 2 + } +} + +/** + * Inserts an element at an index within the vector. + * + * Does not allow duplicates, will throw an error if there is already an entry + * for this index. + * + * @param {Number} insertIdx - The index at which the element should be inserted. + * @param {Number} val - The value to be inserted into the vector. + */ +lunr.Vector.prototype.insert = function (insertIdx, val) { + this.upsert(insertIdx, val, function () { + throw "duplicate index" + }) +} + +/** + * Inserts or updates an existing index within the vector. + * + * @param {Number} insertIdx - The index at which the element should be inserted. + * @param {Number} val - The value to be inserted into the vector. + * @param {function} fn - A function that is called for updates, the existing value and the + * requested value are passed as arguments + */ +lunr.Vector.prototype.upsert = function (insertIdx, val, fn) { + this._magnitude = 0 + var position = this.positionForIndex(insertIdx) + + if (this.elements[position] == insertIdx) { + this.elements[position + 1] = fn(this.elements[position + 1], val) + } else { + this.elements.splice(position, 0, insertIdx, val) + } +} + +/** + * Calculates the magnitude of this vector. + * + * @returns {Number} + */ +lunr.Vector.prototype.magnitude = function () { + if (this._magnitude) return this._magnitude + + var sumOfSquares = 0, + elementsLength = this.elements.length + + for (var i = 1; i < elementsLength; i += 2) { + var val = this.elements[i] + sumOfSquares += val * val + } + + return this._magnitude = Math.sqrt(sumOfSquares) +} + +/** + * Calculates the dot product of this vector and another vector. + * + * @param {lunr.Vector} otherVector - The vector to compute the dot product with. + * @returns {Number} + */ +lunr.Vector.prototype.dot = function (otherVector) { + var dotProduct = 0, + a = this.elements, b = otherVector.elements, + aLen = a.length, bLen = b.length, + aVal = 0, bVal = 0, + i = 0, j = 0 + + while (i < aLen && j < bLen) { + aVal = a[i], bVal = b[j] + if (aVal < bVal) { + i += 2 + } else if (aVal > bVal) { + j += 2 + } else if (aVal == bVal) { + dotProduct += a[i + 1] * b[j + 1] + i += 2 + j += 2 + } + } + + return dotProduct +} + +/** + * Calculates the similarity between this vector and another vector. + * + * @param {lunr.Vector} otherVector - The other vector to calculate the + * similarity with. + * @returns {Number} + */ +lunr.Vector.prototype.similarity = function (otherVector) { + return this.dot(otherVector) / this.magnitude() || 0 +} + +/** + * Converts the vector to an array of the elements within the vector. + * + * @returns {Number[]} + */ +lunr.Vector.prototype.toArray = function () { + var output = new Array (this.elements.length / 2) + + for (var i = 1, j = 0; i < this.elements.length; i += 2, j++) { + output[j] = this.elements[i] + } + + return output +} + +/** + * A JSON serializable representation of the vector. + * + * @returns {Number[]} + */ +lunr.Vector.prototype.toJSON = function () { + return this.elements +} +/* eslint-disable */ +/*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + */ + +/** + * lunr.stemmer is an english language stemmer, this is a JavaScript + * implementation of the PorterStemmer taken from http://tartarus.org/~martin + * + * @static + * @implements {lunr.PipelineFunction} + * @param {lunr.Token} token - The string to stem + * @returns {lunr.Token} + * @see {@link lunr.Pipeline} + * @function + */ +lunr.stemmer = (function(){ + var step2list = { + "ational" : "ate", + "tional" : "tion", + "enci" : "ence", + "anci" : "ance", + "izer" : "ize", + "bli" : "ble", + "alli" : "al", + "entli" : "ent", + "eli" : "e", + "ousli" : "ous", + "ization" : "ize", + "ation" : "ate", + "ator" : "ate", + "alism" : "al", + "iveness" : "ive", + "fulness" : "ful", + "ousness" : "ous", + "aliti" : "al", + "iviti" : "ive", + "biliti" : "ble", + "logi" : "log" + }, + + step3list = { + "icate" : "ic", + "ative" : "", + "alize" : "al", + "iciti" : "ic", + "ical" : "ic", + "ful" : "", + "ness" : "" + }, + + c = "[^aeiou]", // consonant + v = "[aeiouy]", // vowel + C = c + "[^aeiouy]*", // consonant sequence + V = v + "[aeiou]*", // vowel sequence + + mgr0 = "^(" + C + ")?" + V + C, // [C]VC... is m>0 + meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$", // [C]VC[V] is m=1 + mgr1 = "^(" + C + ")?" + V + C + V + C, // [C]VCVC... is m>1 + s_v = "^(" + C + ")?" + v; // vowel in stem + + var re_mgr0 = new RegExp(mgr0); + var re_mgr1 = new RegExp(mgr1); + var re_meq1 = new RegExp(meq1); + var re_s_v = new RegExp(s_v); + + var re_1a = /^(.+?)(ss|i)es$/; + var re2_1a = /^(.+?)([^s])s$/; + var re_1b = /^(.+?)eed$/; + var re2_1b = /^(.+?)(ed|ing)$/; + var re_1b_2 = /.$/; + var re2_1b_2 = /(at|bl|iz)$/; + var re3_1b_2 = new RegExp("([^aeiouylsz])\\1$"); + var re4_1b_2 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + + var re_1c = /^(.+?[^aeiou])y$/; + var re_2 = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/; + + var re_3 = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/; + + var re_4 = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/; + var re2_4 = /^(.+?)(s|t)(ion)$/; + + var re_5 = /^(.+?)e$/; + var re_5_1 = /ll$/; + var re3_5 = new RegExp("^" + C + v + "[^aeiouwxy]$"); + + var porterStemmer = function porterStemmer(w) { + var stem, + suffix, + firstch, + re, + re2, + re3, + re4; + + if (w.length < 3) { return w; } + + firstch = w.substr(0,1); + if (firstch == "y") { + w = firstch.toUpperCase() + w.substr(1); + } + + // Step 1a + re = re_1a + re2 = re2_1a; + + if (re.test(w)) { w = w.replace(re,"$1$2"); } + else if (re2.test(w)) { w = w.replace(re2,"$1$2"); } + + // Step 1b + re = re_1b; + re2 = re2_1b; + if (re.test(w)) { + var fp = re.exec(w); + re = re_mgr0; + if (re.test(fp[1])) { + re = re_1b_2; + w = w.replace(re,""); + } + } else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1]; + re2 = re_s_v; + if (re2.test(stem)) { + w = stem; + re2 = re2_1b_2; + re3 = re3_1b_2; + re4 = re4_1b_2; + if (re2.test(w)) { w = w + "e"; } + else if (re3.test(w)) { re = re_1b_2; w = w.replace(re,""); } + else if (re4.test(w)) { w = w + "e"; } + } + } + + // Step 1c - replace suffix y or Y by i if preceded by a non-vowel which is not the first letter of the word (so cry -> cri, by -> by, say -> say) + re = re_1c; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + w = stem + "i"; + } + + // Step 2 + re = re_2; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = re_mgr0; + if (re.test(stem)) { + w = stem + step2list[suffix]; + } + } + + // Step 3 + re = re_3; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + suffix = fp[2]; + re = re_mgr0; + if (re.test(stem)) { + w = stem + step3list[suffix]; + } + } + + // Step 4 + re = re_4; + re2 = re2_4; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = re_mgr1; + if (re.test(stem)) { + w = stem; + } + } else if (re2.test(w)) { + var fp = re2.exec(w); + stem = fp[1] + fp[2]; + re2 = re_mgr1; + if (re2.test(stem)) { + w = stem; + } + } + + // Step 5 + re = re_5; + if (re.test(w)) { + var fp = re.exec(w); + stem = fp[1]; + re = re_mgr1; + re2 = re_meq1; + re3 = re3_5; + if (re.test(stem) || (re2.test(stem) && !(re3.test(stem)))) { + w = stem; + } + } + + re = re_5_1; + re2 = re_mgr1; + if (re.test(w) && re2.test(w)) { + re = re_1b_2; + w = w.replace(re,""); + } + + // and turn initial Y back to y + + if (firstch == "y") { + w = firstch.toLowerCase() + w.substr(1); + } + + return w; + }; + + return function (token) { + return token.update(porterStemmer); + } +})(); + +lunr.Pipeline.registerFunction(lunr.stemmer, 'stemmer') +/*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.generateStopWordFilter builds a stopWordFilter function from the provided + * list of stop words. + * + * The built in lunr.stopWordFilter is built using this generator and can be used + * to generate custom stopWordFilters for applications or non English languages. + * + * @function + * @param {Array} token The token to pass through the filter + * @returns {lunr.PipelineFunction} + * @see lunr.Pipeline + * @see lunr.stopWordFilter + */ +lunr.generateStopWordFilter = function (stopWords) { + var words = stopWords.reduce(function (memo, stopWord) { + memo[stopWord] = stopWord + return memo + }, {}) + + return function (token) { + if (token && words[token.toString()] !== token.toString()) return token + } +} + +/** + * lunr.stopWordFilter is an English language stop word list filter, any words + * contained in the list will not be passed through the filter. + * + * This is intended to be used in the Pipeline. If the token does not pass the + * filter then undefined will be returned. + * + * @function + * @implements {lunr.PipelineFunction} + * @params {lunr.Token} token - A token to check for being a stop word. + * @returns {lunr.Token} + * @see {@link lunr.Pipeline} + */ +lunr.stopWordFilter = lunr.generateStopWordFilter([ + 'a', + 'able', + 'about', + 'across', + 'after', + 'all', + 'almost', + 'also', + 'am', + 'among', + 'an', + 'and', + 'any', + 'are', + 'as', + 'at', + 'be', + 'because', + 'been', + 'but', + 'by', + 'can', + 'cannot', + 'could', + 'dear', + 'did', + 'do', + 'does', + 'either', + 'else', + 'ever', + 'every', + 'for', + 'from', + 'get', + 'got', + 'had', + 'has', + 'have', + 'he', + 'her', + 'hers', + 'him', + 'his', + 'how', + 'however', + 'i', + 'if', + 'in', + 'into', + 'is', + 'it', + 'its', + 'just', + 'least', + 'let', + 'like', + 'likely', + 'may', + 'me', + 'might', + 'most', + 'must', + 'my', + 'neither', + 'no', + 'nor', + 'not', + 'of', + 'off', + 'often', + 'on', + 'only', + 'or', + 'other', + 'our', + 'own', + 'rather', + 'said', + 'say', + 'says', + 'she', + 'should', + 'since', + 'so', + 'some', + 'than', + 'that', + 'the', + 'their', + 'them', + 'then', + 'there', + 'these', + 'they', + 'this', + 'tis', + 'to', + 'too', + 'twas', + 'us', + 'wants', + 'was', + 'we', + 'were', + 'what', + 'when', + 'where', + 'which', + 'while', + 'who', + 'whom', + 'why', + 'will', + 'with', + 'would', + 'yet', + 'you', + 'your' +]) + +lunr.Pipeline.registerFunction(lunr.stopWordFilter, 'stopWordFilter') +/*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.trimmer is a pipeline function for trimming non word + * characters from the beginning and end of tokens before they + * enter the index. + * + * This implementation may not work correctly for non latin + * characters and should either be removed or adapted for use + * with languages with non-latin characters. + * + * @static + * @implements {lunr.PipelineFunction} + * @param {lunr.Token} token The token to pass through the filter + * @returns {lunr.Token} + * @see lunr.Pipeline + */ +lunr.trimmer = function (token) { + return token.update(function (s) { + return s.replace(/^\W+/, '').replace(/\W+$/, '') + }) +} + +lunr.Pipeline.registerFunction(lunr.trimmer, 'trimmer') +/*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * A token set is used to store the unique list of all tokens + * within an index. Token sets are also used to represent an + * incoming query to the index, this query token set and index + * token set are then intersected to find which tokens to look + * up in the inverted index. + * + * A token set can hold multiple tokens, as in the case of the + * index token set, or it can hold a single token as in the + * case of a simple query token set. + * + * Additionally token sets are used to perform wildcard matching. + * Leading, contained and trailing wildcards are supported, and + * from this edit distance matching can also be provided. + * + * Token sets are implemented as a minimal finite state automata, + * where both common prefixes and suffixes are shared between tokens. + * This helps to reduce the space used for storing the token set. + * + * @constructor + */ +lunr.TokenSet = function () { + this.final = false + this.edges = {} + this.id = lunr.TokenSet._nextId + lunr.TokenSet._nextId += 1 +} + +/** + * Keeps track of the next, auto increment, identifier to assign + * to a new tokenSet. + * + * TokenSets require a unique identifier to be correctly minimised. + * + * @private + */ +lunr.TokenSet._nextId = 1 + +/** + * Creates a TokenSet instance from the given sorted array of words. + * + * @param {String[]} arr - A sorted array of strings to create the set from. + * @returns {lunr.TokenSet} + * @throws Will throw an error if the input array is not sorted. + */ +lunr.TokenSet.fromArray = function (arr) { + var builder = new lunr.TokenSet.Builder + + for (var i = 0, len = arr.length; i < len; i++) { + builder.insert(arr[i]) + } + + builder.finish() + return builder.root +} + +/** + * Creates a token set from a query clause. + * + * @private + * @param {Object} clause - A single clause from lunr.Query. + * @param {string} clause.term - The query clause term. + * @param {number} [clause.editDistance] - The optional edit distance for the term. + * @returns {lunr.TokenSet} + */ +lunr.TokenSet.fromClause = function (clause) { + if ('editDistance' in clause) { + return lunr.TokenSet.fromFuzzyString(clause.term, clause.editDistance) + } else { + return lunr.TokenSet.fromString(clause.term) + } +} + +/** + * Creates a token set representing a single string with a specified + * edit distance. + * + * Insertions, deletions, substitutions and transpositions are each + * treated as an edit distance of 1. + * + * Increasing the allowed edit distance will have a dramatic impact + * on the performance of both creating and intersecting these TokenSets. + * It is advised to keep the edit distance less than 3. + * + * @param {string} str - The string to create the token set from. + * @param {number} editDistance - The allowed edit distance to match. + * @returns {lunr.Vector} + */ +lunr.TokenSet.fromFuzzyString = function (str, editDistance) { + var root = new lunr.TokenSet + + var stack = [{ + node: root, + editsRemaining: editDistance, + str: str + }] + + while (stack.length) { + var frame = stack.pop() + + // no edit + if (frame.str.length > 0) { + var char = frame.str.charAt(0), + noEditNode + + if (char in frame.node.edges) { + noEditNode = frame.node.edges[char] + } else { + noEditNode = new lunr.TokenSet + frame.node.edges[char] = noEditNode + } + + if (frame.str.length == 1) { + noEditNode.final = true + } + + stack.push({ + node: noEditNode, + editsRemaining: frame.editsRemaining, + str: frame.str.slice(1) + }) + } + + if (frame.editsRemaining == 0) { + continue + } + + // insertion + if ("*" in frame.node.edges) { + var insertionNode = frame.node.edges["*"] + } else { + var insertionNode = new lunr.TokenSet + frame.node.edges["*"] = insertionNode + } + + if (frame.str.length == 0) { + insertionNode.final = true + } + + stack.push({ + node: insertionNode, + editsRemaining: frame.editsRemaining - 1, + str: frame.str + }) + + // deletion + // can only do a deletion if we have enough edits remaining + // and if there are characters left to delete in the string + if (frame.str.length > 1) { + stack.push({ + node: frame.node, + editsRemaining: frame.editsRemaining - 1, + str: frame.str.slice(1) + }) + } + + // deletion + // just removing the last character from the str + if (frame.str.length == 1) { + frame.node.final = true + } + + // substitution + // can only do a substitution if we have enough edits remaining + // and if there are characters left to substitute + if (frame.str.length >= 1) { + if ("*" in frame.node.edges) { + var substitutionNode = frame.node.edges["*"] + } else { + var substitutionNode = new lunr.TokenSet + frame.node.edges["*"] = substitutionNode + } + + if (frame.str.length == 1) { + substitutionNode.final = true + } + + stack.push({ + node: substitutionNode, + editsRemaining: frame.editsRemaining - 1, + str: frame.str.slice(1) + }) + } + + // transposition + // can only do a transposition if there are edits remaining + // and there are enough characters to transpose + if (frame.str.length > 1) { + var charA = frame.str.charAt(0), + charB = frame.str.charAt(1), + transposeNode + + if (charB in frame.node.edges) { + transposeNode = frame.node.edges[charB] + } else { + transposeNode = new lunr.TokenSet + frame.node.edges[charB] = transposeNode + } + + if (frame.str.length == 1) { + transposeNode.final = true + } + + stack.push({ + node: transposeNode, + editsRemaining: frame.editsRemaining - 1, + str: charA + frame.str.slice(2) + }) + } + } + + return root +} + +/** + * Creates a TokenSet from a string. + * + * The string may contain one or more wildcard characters (*) + * that will allow wildcard matching when intersecting with + * another TokenSet. + * + * @param {string} str - The string to create a TokenSet from. + * @returns {lunr.TokenSet} + */ +lunr.TokenSet.fromString = function (str) { + var node = new lunr.TokenSet, + root = node + + /* + * Iterates through all characters within the passed string + * appending a node for each character. + * + * When a wildcard character is found then a self + * referencing edge is introduced to continually match + * any number of any characters. + */ + for (var i = 0, len = str.length; i < len; i++) { + var char = str[i], + final = (i == len - 1) + + if (char == "*") { + node.edges[char] = node + node.final = final + + } else { + var next = new lunr.TokenSet + next.final = final + + node.edges[char] = next + node = next + } + } + + return root +} + +/** + * Converts this TokenSet into an array of strings + * contained within the TokenSet. + * + * This is not intended to be used on a TokenSet that + * contains wildcards, in these cases the results are + * undefined and are likely to cause an infinite loop. + * + * @returns {string[]} + */ +lunr.TokenSet.prototype.toArray = function () { + var words = [] + + var stack = [{ + prefix: "", + node: this + }] + + while (stack.length) { + var frame = stack.pop(), + edges = Object.keys(frame.node.edges), + len = edges.length + + if (frame.node.final) { + /* In Safari, at this point the prefix is sometimes corrupted, see: + * https://github.com/olivernn/lunr.js/issues/279 Calling any + * String.prototype method forces Safari to "cast" this string to what + * it's supposed to be, fixing the bug. */ + frame.prefix.charAt(0) + words.push(frame.prefix) + } + + for (var i = 0; i < len; i++) { + var edge = edges[i] + + stack.push({ + prefix: frame.prefix.concat(edge), + node: frame.node.edges[edge] + }) + } + } + + return words +} + +/** + * Generates a string representation of a TokenSet. + * + * This is intended to allow TokenSets to be used as keys + * in objects, largely to aid the construction and minimisation + * of a TokenSet. As such it is not designed to be a human + * friendly representation of the TokenSet. + * + * @returns {string} + */ +lunr.TokenSet.prototype.toString = function () { + // NOTE: Using Object.keys here as this.edges is very likely + // to enter 'hash-mode' with many keys being added + // + // avoiding a for-in loop here as it leads to the function + // being de-optimised (at least in V8). From some simple + // benchmarks the performance is comparable, but allowing + // V8 to optimize may mean easy performance wins in the future. + + if (this._str) { + return this._str + } + + var str = this.final ? '1' : '0', + labels = Object.keys(this.edges).sort(), + len = labels.length + + for (var i = 0; i < len; i++) { + var label = labels[i], + node = this.edges[label] + + str = str + label + node.id + } + + return str +} + +/** + * Returns a new TokenSet that is the intersection of + * this TokenSet and the passed TokenSet. + * + * This intersection will take into account any wildcards + * contained within the TokenSet. + * + * @param {lunr.TokenSet} b - An other TokenSet to intersect with. + * @returns {lunr.TokenSet} + */ +lunr.TokenSet.prototype.intersect = function (b) { + var output = new lunr.TokenSet, + frame = undefined + + var stack = [{ + qNode: b, + output: output, + node: this + }] + + while (stack.length) { + frame = stack.pop() + + // NOTE: As with the #toString method, we are using + // Object.keys and a for loop instead of a for-in loop + // as both of these objects enter 'hash' mode, causing + // the function to be de-optimised in V8 + var qEdges = Object.keys(frame.qNode.edges), + qLen = qEdges.length, + nEdges = Object.keys(frame.node.edges), + nLen = nEdges.length + + for (var q = 0; q < qLen; q++) { + var qEdge = qEdges[q] + + for (var n = 0; n < nLen; n++) { + var nEdge = nEdges[n] + + if (nEdge == qEdge || qEdge == '*') { + var node = frame.node.edges[nEdge], + qNode = frame.qNode.edges[qEdge], + final = node.final && qNode.final, + next = undefined + + if (nEdge in frame.output.edges) { + // an edge already exists for this character + // no need to create a new node, just set the finality + // bit unless this node is already final + next = frame.output.edges[nEdge] + next.final = next.final || final + + } else { + // no edge exists yet, must create one + // set the finality bit and insert it + // into the output + next = new lunr.TokenSet + next.final = final + frame.output.edges[nEdge] = next + } + + stack.push({ + qNode: qNode, + output: next, + node: node + }) + } + } + } + } + + return output +} +lunr.TokenSet.Builder = function () { + this.previousWord = "" + this.root = new lunr.TokenSet + this.uncheckedNodes = [] + this.minimizedNodes = {} +} + +lunr.TokenSet.Builder.prototype.insert = function (word) { + var node, + commonPrefix = 0 + + if (word < this.previousWord) { + throw new Error ("Out of order word insertion") + } + + for (var i = 0; i < word.length && i < this.previousWord.length; i++) { + if (word[i] != this.previousWord[i]) break + commonPrefix++ + } + + this.minimize(commonPrefix) + + if (this.uncheckedNodes.length == 0) { + node = this.root + } else { + node = this.uncheckedNodes[this.uncheckedNodes.length - 1].child + } + + for (var i = commonPrefix; i < word.length; i++) { + var nextNode = new lunr.TokenSet, + char = word[i] + + node.edges[char] = nextNode + + this.uncheckedNodes.push({ + parent: node, + char: char, + child: nextNode + }) + + node = nextNode + } + + node.final = true + this.previousWord = word +} + +lunr.TokenSet.Builder.prototype.finish = function () { + this.minimize(0) +} + +lunr.TokenSet.Builder.prototype.minimize = function (downTo) { + for (var i = this.uncheckedNodes.length - 1; i >= downTo; i--) { + var node = this.uncheckedNodes[i], + childKey = node.child.toString() + + if (childKey in this.minimizedNodes) { + node.parent.edges[node.char] = this.minimizedNodes[childKey] + } else { + // Cache the key for this node since + // we know it can't change anymore + node.child._str = childKey + + this.minimizedNodes[childKey] = node.child + } + + this.uncheckedNodes.pop() + } +} +/*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * An index contains the built index of all documents and provides a query interface + * to the index. + * + * Usually instances of lunr.Index will not be created using this constructor, instead + * lunr.Builder should be used to construct new indexes, or lunr.Index.load should be + * used to load previously built and serialized indexes. + * + * @constructor + * @param {Object} attrs - The attributes of the built search index. + * @param {Object} attrs.invertedIndex - An index of term/field to document reference. + * @param {Object} attrs.fieldVectors - Field vectors + * @param {lunr.TokenSet} attrs.tokenSet - An set of all corpus tokens. + * @param {string[]} attrs.fields - The names of indexed document fields. + * @param {lunr.Pipeline} attrs.pipeline - The pipeline to use for search terms. + */ +lunr.Index = function (attrs) { + this.invertedIndex = attrs.invertedIndex + this.fieldVectors = attrs.fieldVectors + this.tokenSet = attrs.tokenSet + this.fields = attrs.fields + this.pipeline = attrs.pipeline +} + +/** + * A result contains details of a document matching a search query. + * @typedef {Object} lunr.Index~Result + * @property {string} ref - The reference of the document this result represents. + * @property {number} score - A number between 0 and 1 representing how similar this document is to the query. + * @property {lunr.MatchData} matchData - Contains metadata about this match including which term(s) caused the match. + */ + +/** + * Although lunr provides the ability to create queries using lunr.Query, it also provides a simple + * query language which itself is parsed into an instance of lunr.Query. + * + * For programmatically building queries it is advised to directly use lunr.Query, the query language + * is best used for human entered text rather than program generated text. + * + * At its simplest queries can just be a single term, e.g. `hello`, multiple terms are also supported + * and will be combined with OR, e.g `hello world` will match documents that contain either 'hello' + * or 'world', though those that contain both will rank higher in the results. + * + * Wildcards can be included in terms to match one or more unspecified characters, these wildcards can + * be inserted anywhere within the term, and more than one wildcard can exist in a single term. Adding + * wildcards will increase the number of documents that will be found but can also have a negative + * impact on query performance, especially with wildcards at the beginning of a term. + * + * Terms can be restricted to specific fields, e.g. `title:hello`, only documents with the term + * hello in the title field will match this query. Using a field not present in the index will lead + * to an error being thrown. + * + * Modifiers can also be added to terms, lunr supports edit distance and boost modifiers on terms. A term + * boost will make documents matching that term score higher, e.g. `foo^5`. Edit distance is also supported + * to provide fuzzy matching, e.g. 'hello~2' will match documents with hello with an edit distance of 2. + * Avoid large values for edit distance to improve query performance. + * + * Each term also supports a presence modifier. By default a term's presence in document is optional, however + * this can be changed to either required or prohibited. For a term's presence to be required in a document the + * term should be prefixed with a '+', e.g. `+foo bar` is a search for documents that must contain 'foo' and + * optionally contain 'bar'. Conversely a leading '-' sets the terms presence to prohibited, i.e. it must not + * appear in a document, e.g. `-foo bar` is a search for documents that do not contain 'foo' but may contain 'bar'. + * + * To escape special characters the backslash character '\' can be used, this allows searches to include + * characters that would normally be considered modifiers, e.g. `foo\~2` will search for a term "foo~2" instead + * of attempting to apply a boost of 2 to the search term "foo". + * + * @typedef {string} lunr.Index~QueryString + * @example Simple single term query + * hello + * @example Multiple term query + * hello world + * @example term scoped to a field + * title:hello + * @example term with a boost of 10 + * hello^10 + * @example term with an edit distance of 2 + * hello~2 + * @example terms with presence modifiers + * -foo +bar baz + */ + +/** + * Performs a search against the index using lunr query syntax. + * + * Results will be returned sorted by their score, the most relevant results + * will be returned first. For details on how the score is calculated, please see + * the {@link https://lunrjs.com/guides/searching.html#scoring|guide}. + * + * For more programmatic querying use lunr.Index#query. + * + * @param {lunr.Index~QueryString} queryString - A string containing a lunr query. + * @throws {lunr.QueryParseError} If the passed query string cannot be parsed. + * @returns {lunr.Index~Result[]} + */ +lunr.Index.prototype.search = function (queryString) { + return this.query(function (query) { + var parser = new lunr.QueryParser(queryString, query) + parser.parse() + }) +} + +/** + * A query builder callback provides a query object to be used to express + * the query to perform on the index. + * + * @callback lunr.Index~queryBuilder + * @param {lunr.Query} query - The query object to build up. + * @this lunr.Query + */ + +/** + * Performs a query against the index using the yielded lunr.Query object. + * + * If performing programmatic queries against the index, this method is preferred + * over lunr.Index#search so as to avoid the additional query parsing overhead. + * + * A query object is yielded to the supplied function which should be used to + * express the query to be run against the index. + * + * Note that although this function takes a callback parameter it is _not_ an + * asynchronous operation, the callback is just yielded a query object to be + * customized. + * + * @param {lunr.Index~queryBuilder} fn - A function that is used to build the query. + * @returns {lunr.Index~Result[]} + */ +lunr.Index.prototype.query = function (fn) { + // for each query clause + // * process terms + // * expand terms from token set + // * find matching documents and metadata + // * get document vectors + // * score documents + + var query = new lunr.Query(this.fields), + matchingFields = Object.create(null), + queryVectors = Object.create(null), + termFieldCache = Object.create(null), + requiredMatches = Object.create(null), + prohibitedMatches = Object.create(null) + + /* + * To support field level boosts a query vector is created per + * field. An empty vector is eagerly created to support negated + * queries. + */ + for (var i = 0; i < this.fields.length; i++) { + queryVectors[this.fields[i]] = new lunr.Vector + } + + fn.call(query, query) + + for (var i = 0; i < query.clauses.length; i++) { + /* + * Unless the pipeline has been disabled for this term, which is + * the case for terms with wildcards, we need to pass the clause + * term through the search pipeline. A pipeline returns an array + * of processed terms. Pipeline functions may expand the passed + * term, which means we may end up performing multiple index lookups + * for a single query term. + */ + var clause = query.clauses[i], + terms = null, + clauseMatches = lunr.Set.empty + + if (clause.usePipeline) { + terms = this.pipeline.runString(clause.term, { + fields: clause.fields + }) + } else { + terms = [clause.term] + } + + for (var m = 0; m < terms.length; m++) { + var term = terms[m] + + /* + * Each term returned from the pipeline needs to use the same query + * clause object, e.g. the same boost and or edit distance. The + * simplest way to do this is to re-use the clause object but mutate + * its term property. + */ + clause.term = term + + /* + * From the term in the clause we create a token set which will then + * be used to intersect the indexes token set to get a list of terms + * to lookup in the inverted index + */ + var termTokenSet = lunr.TokenSet.fromClause(clause), + expandedTerms = this.tokenSet.intersect(termTokenSet).toArray() + + /* + * If a term marked as required does not exist in the tokenSet it is + * impossible for the search to return any matches. We set all the field + * scoped required matches set to empty and stop examining any further + * clauses. + */ + if (expandedTerms.length === 0 && clause.presence === lunr.Query.presence.REQUIRED) { + for (var k = 0; k < clause.fields.length; k++) { + var field = clause.fields[k] + requiredMatches[field] = lunr.Set.empty + } + + break + } + + for (var j = 0; j < expandedTerms.length; j++) { + /* + * For each term get the posting and termIndex, this is required for + * building the query vector. + */ + var expandedTerm = expandedTerms[j], + posting = this.invertedIndex[expandedTerm], + termIndex = posting._index + + for (var k = 0; k < clause.fields.length; k++) { + /* + * For each field that this query term is scoped by (by default + * all fields are in scope) we need to get all the document refs + * that have this term in that field. + * + * The posting is the entry in the invertedIndex for the matching + * term from above. + */ + var field = clause.fields[k], + fieldPosting = posting[field], + matchingDocumentRefs = Object.keys(fieldPosting), + termField = expandedTerm + "/" + field, + matchingDocumentsSet = new lunr.Set(matchingDocumentRefs) + + /* + * if the presence of this term is required ensure that the matching + * documents are added to the set of required matches for this clause. + * + */ + if (clause.presence == lunr.Query.presence.REQUIRED) { + clauseMatches = clauseMatches.union(matchingDocumentsSet) + + if (requiredMatches[field] === undefined) { + requiredMatches[field] = lunr.Set.complete + } + } + + /* + * if the presence of this term is prohibited ensure that the matching + * documents are added to the set of prohibited matches for this field, + * creating that set if it does not yet exist. + */ + if (clause.presence == lunr.Query.presence.PROHIBITED) { + if (prohibitedMatches[field] === undefined) { + prohibitedMatches[field] = lunr.Set.empty + } + + prohibitedMatches[field] = prohibitedMatches[field].union(matchingDocumentsSet) + + /* + * Prohibited matches should not be part of the query vector used for + * similarity scoring and no metadata should be extracted so we continue + * to the next field + */ + continue + } + + /* + * The query field vector is populated using the termIndex found for + * the term and a unit value with the appropriate boost applied. + * Using upsert because there could already be an entry in the vector + * for the term we are working with. In that case we just add the scores + * together. + */ + queryVectors[field].upsert(termIndex, clause.boost, function (a, b) { return a + b }) + + /** + * If we've already seen this term, field combo then we've already collected + * the matching documents and metadata, no need to go through all that again + */ + if (termFieldCache[termField]) { + continue + } + + for (var l = 0; l < matchingDocumentRefs.length; l++) { + /* + * All metadata for this term/field/document triple + * are then extracted and collected into an instance + * of lunr.MatchData ready to be returned in the query + * results + */ + var matchingDocumentRef = matchingDocumentRefs[l], + matchingFieldRef = new lunr.FieldRef (matchingDocumentRef, field), + metadata = fieldPosting[matchingDocumentRef], + fieldMatch + + if ((fieldMatch = matchingFields[matchingFieldRef]) === undefined) { + matchingFields[matchingFieldRef] = new lunr.MatchData (expandedTerm, field, metadata) + } else { + fieldMatch.add(expandedTerm, field, metadata) + } + + } + + termFieldCache[termField] = true + } + } + } + + /** + * If the presence was required we need to update the requiredMatches field sets. + * We do this after all fields for the term have collected their matches because + * the clause terms presence is required in _any_ of the fields not _all_ of the + * fields. + */ + if (clause.presence === lunr.Query.presence.REQUIRED) { + for (var k = 0; k < clause.fields.length; k++) { + var field = clause.fields[k] + requiredMatches[field] = requiredMatches[field].intersect(clauseMatches) + } + } + } + + /** + * Need to combine the field scoped required and prohibited + * matching documents into a global set of required and prohibited + * matches + */ + var allRequiredMatches = lunr.Set.complete, + allProhibitedMatches = lunr.Set.empty + + for (var i = 0; i < this.fields.length; i++) { + var field = this.fields[i] + + if (requiredMatches[field]) { + allRequiredMatches = allRequiredMatches.intersect(requiredMatches[field]) + } + + if (prohibitedMatches[field]) { + allProhibitedMatches = allProhibitedMatches.union(prohibitedMatches[field]) + } + } + + var matchingFieldRefs = Object.keys(matchingFields), + results = [], + matches = Object.create(null) + + /* + * If the query is negated (contains only prohibited terms) + * we need to get _all_ fieldRefs currently existing in the + * index. This is only done when we know that the query is + * entirely prohibited terms to avoid any cost of getting all + * fieldRefs unnecessarily. + * + * Additionally, blank MatchData must be created to correctly + * populate the results. + */ + if (query.isNegated()) { + matchingFieldRefs = Object.keys(this.fieldVectors) + + for (var i = 0; i < matchingFieldRefs.length; i++) { + var matchingFieldRef = matchingFieldRefs[i] + var fieldRef = lunr.FieldRef.fromString(matchingFieldRef) + matchingFields[matchingFieldRef] = new lunr.MatchData + } + } + + for (var i = 0; i < matchingFieldRefs.length; i++) { + /* + * Currently we have document fields that match the query, but we + * need to return documents. The matchData and scores are combined + * from multiple fields belonging to the same document. + * + * Scores are calculated by field, using the query vectors created + * above, and combined into a final document score using addition. + */ + var fieldRef = lunr.FieldRef.fromString(matchingFieldRefs[i]), + docRef = fieldRef.docRef + + if (!allRequiredMatches.contains(docRef)) { + continue + } + + if (allProhibitedMatches.contains(docRef)) { + continue + } + + var fieldVector = this.fieldVectors[fieldRef], + score = queryVectors[fieldRef.fieldName].similarity(fieldVector), + docMatch + + if ((docMatch = matches[docRef]) !== undefined) { + docMatch.score += score + docMatch.matchData.combine(matchingFields[fieldRef]) + } else { + var match = { + ref: docRef, + score: score, + matchData: matchingFields[fieldRef] + } + matches[docRef] = match + results.push(match) + } + } + + /* + * Sort the results objects by score, highest first. + */ + return results.sort(function (a, b) { + return b.score - a.score + }) +} + +/** + * Prepares the index for JSON serialization. + * + * The schema for this JSON blob will be described in a + * separate JSON schema file. + * + * @returns {Object} + */ +lunr.Index.prototype.toJSON = function () { + var invertedIndex = Object.keys(this.invertedIndex) + .sort() + .map(function (term) { + return [term, this.invertedIndex[term]] + }, this) + + var fieldVectors = Object.keys(this.fieldVectors) + .map(function (ref) { + return [ref, this.fieldVectors[ref].toJSON()] + }, this) + + return { + version: lunr.version, + fields: this.fields, + fieldVectors: fieldVectors, + invertedIndex: invertedIndex, + pipeline: this.pipeline.toJSON() + } +} + +/** + * Loads a previously serialized lunr.Index + * + * @param {Object} serializedIndex - A previously serialized lunr.Index + * @returns {lunr.Index} + */ +lunr.Index.load = function (serializedIndex) { + var attrs = {}, + fieldVectors = {}, + serializedVectors = serializedIndex.fieldVectors, + invertedIndex = Object.create(null), + serializedInvertedIndex = serializedIndex.invertedIndex, + tokenSetBuilder = new lunr.TokenSet.Builder, + pipeline = lunr.Pipeline.load(serializedIndex.pipeline) + + if (serializedIndex.version != lunr.version) { + lunr.utils.warn("Version mismatch when loading serialised index. Current version of lunr '" + lunr.version + "' does not match serialized index '" + serializedIndex.version + "'") + } + + for (var i = 0; i < serializedVectors.length; i++) { + var tuple = serializedVectors[i], + ref = tuple[0], + elements = tuple[1] + + fieldVectors[ref] = new lunr.Vector(elements) + } + + for (var i = 0; i < serializedInvertedIndex.length; i++) { + var tuple = serializedInvertedIndex[i], + term = tuple[0], + posting = tuple[1] + + tokenSetBuilder.insert(term) + invertedIndex[term] = posting + } + + tokenSetBuilder.finish() + + attrs.fields = serializedIndex.fields + + attrs.fieldVectors = fieldVectors + attrs.invertedIndex = invertedIndex + attrs.tokenSet = tokenSetBuilder.root + attrs.pipeline = pipeline + + return new lunr.Index(attrs) +} +/*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + */ + +/** + * lunr.Builder performs indexing on a set of documents and + * returns instances of lunr.Index ready for querying. + * + * All configuration of the index is done via the builder, the + * fields to index, the document reference, the text processing + * pipeline and document scoring parameters are all set on the + * builder before indexing. + * + * @constructor + * @property {string} _ref - Internal reference to the document reference field. + * @property {string[]} _fields - Internal reference to the document fields to index. + * @property {object} invertedIndex - The inverted index maps terms to document fields. + * @property {object} documentTermFrequencies - Keeps track of document term frequencies. + * @property {object} documentLengths - Keeps track of the length of documents added to the index. + * @property {lunr.tokenizer} tokenizer - Function for splitting strings into tokens for indexing. + * @property {lunr.Pipeline} pipeline - The pipeline performs text processing on tokens before indexing. + * @property {lunr.Pipeline} searchPipeline - A pipeline for processing search terms before querying the index. + * @property {number} documentCount - Keeps track of the total number of documents indexed. + * @property {number} _b - A parameter to control field length normalization, setting this to 0 disabled normalization, 1 fully normalizes field lengths, the default value is 0.75. + * @property {number} _k1 - A parameter to control how quickly an increase in term frequency results in term frequency saturation, the default value is 1.2. + * @property {number} termIndex - A counter incremented for each unique term, used to identify a terms position in the vector space. + * @property {array} metadataWhitelist - A list of metadata keys that have been whitelisted for entry in the index. + */ +lunr.Builder = function () { + this._ref = "id" + this._fields = Object.create(null) + this._documents = Object.create(null) + this.invertedIndex = Object.create(null) + this.fieldTermFrequencies = {} + this.fieldLengths = {} + this.tokenizer = lunr.tokenizer + this.pipeline = new lunr.Pipeline + this.searchPipeline = new lunr.Pipeline + this.documentCount = 0 + this._b = 0.75 + this._k1 = 1.2 + this.termIndex = 0 + this.metadataWhitelist = [] +} + +/** + * Sets the document field used as the document reference. Every document must have this field. + * The type of this field in the document should be a string, if it is not a string it will be + * coerced into a string by calling toString. + * + * The default ref is 'id'. + * + * The ref should _not_ be changed during indexing, it should be set before any documents are + * added to the index. Changing it during indexing can lead to inconsistent results. + * + * @param {string} ref - The name of the reference field in the document. + */ +lunr.Builder.prototype.ref = function (ref) { + this._ref = ref +} + +/** + * A function that is used to extract a field from a document. + * + * Lunr expects a field to be at the top level of a document, if however the field + * is deeply nested within a document an extractor function can be used to extract + * the right field for indexing. + * + * @callback fieldExtractor + * @param {object} doc - The document being added to the index. + * @returns {?(string|object|object[])} obj - The object that will be indexed for this field. + * @example Extracting a nested field + * function (doc) { return doc.nested.field } + */ + +/** + * Adds a field to the list of document fields that will be indexed. Every document being + * indexed should have this field. Null values for this field in indexed documents will + * not cause errors but will limit the chance of that document being retrieved by searches. + * + * All fields should be added before adding documents to the index. Adding fields after + * a document has been indexed will have no effect on already indexed documents. + * + * Fields can be boosted at build time. This allows terms within that field to have more + * importance when ranking search results. Use a field boost to specify that matches within + * one field are more important than other fields. + * + * @param {string} fieldName - The name of a field to index in all documents. + * @param {object} attributes - Optional attributes associated with this field. + * @param {number} [attributes.boost=1] - Boost applied to all terms within this field. + * @param {fieldExtractor} [attributes.extractor] - Function to extract a field from a document. + * @throws {RangeError} fieldName cannot contain unsupported characters '/' + */ +lunr.Builder.prototype.field = function (fieldName, attributes) { + if (/\//.test(fieldName)) { + throw new RangeError ("Field '" + fieldName + "' contains illegal character '/'") + } + + this._fields[fieldName] = attributes || {} +} + +/** + * A parameter to tune the amount of field length normalisation that is applied when + * calculating relevance scores. A value of 0 will completely disable any normalisation + * and a value of 1 will fully normalise field lengths. The default is 0.75. Values of b + * will be clamped to the range 0 - 1. + * + * @param {number} number - The value to set for this tuning parameter. + */ +lunr.Builder.prototype.b = function (number) { + if (number < 0) { + this._b = 0 + } else if (number > 1) { + this._b = 1 + } else { + this._b = number + } +} + +/** + * A parameter that controls the speed at which a rise in term frequency results in term + * frequency saturation. The default value is 1.2. Setting this to a higher value will give + * slower saturation levels, a lower value will result in quicker saturation. + * + * @param {number} number - The value to set for this tuning parameter. + */ +lunr.Builder.prototype.k1 = function (number) { + this._k1 = number +} + +/** + * Adds a document to the index. + * + * Before adding fields to the index the index should have been fully setup, with the document + * ref and all fields to index already having been specified. + * + * The document must have a field name as specified by the ref (by default this is 'id') and + * it should have all fields defined for indexing, though null or undefined values will not + * cause errors. + * + * Entire documents can be boosted at build time. Applying a boost to a document indicates that + * this document should rank higher in search results than other documents. + * + * @param {object} doc - The document to add to the index. + * @param {object} attributes - Optional attributes associated with this document. + * @param {number} [attributes.boost=1] - Boost applied to all terms within this document. + */ +lunr.Builder.prototype.add = function (doc, attributes) { + var docRef = doc[this._ref], + fields = Object.keys(this._fields) + + this._documents[docRef] = attributes || {} + this.documentCount += 1 + + for (var i = 0; i < fields.length; i++) { + var fieldName = fields[i], + extractor = this._fields[fieldName].extractor, + field = extractor ? extractor(doc) : doc[fieldName], + tokens = this.tokenizer(field, { + fields: [fieldName] + }), + terms = this.pipeline.run(tokens), + fieldRef = new lunr.FieldRef (docRef, fieldName), + fieldTerms = Object.create(null) + + this.fieldTermFrequencies[fieldRef] = fieldTerms + this.fieldLengths[fieldRef] = 0 + + // store the length of this field for this document + this.fieldLengths[fieldRef] += terms.length + + // calculate term frequencies for this field + for (var j = 0; j < terms.length; j++) { + var term = terms[j] + + if (fieldTerms[term] == undefined) { + fieldTerms[term] = 0 + } + + fieldTerms[term] += 1 + + // add to inverted index + // create an initial posting if one doesn't exist + if (this.invertedIndex[term] == undefined) { + var posting = Object.create(null) + posting["_index"] = this.termIndex + this.termIndex += 1 + + for (var k = 0; k < fields.length; k++) { + posting[fields[k]] = Object.create(null) + } + + this.invertedIndex[term] = posting + } + + // add an entry for this term/fieldName/docRef to the invertedIndex + if (this.invertedIndex[term][fieldName][docRef] == undefined) { + this.invertedIndex[term][fieldName][docRef] = Object.create(null) + } + + // store all whitelisted metadata about this token in the + // inverted index + for (var l = 0; l < this.metadataWhitelist.length; l++) { + var metadataKey = this.metadataWhitelist[l], + metadata = term.metadata[metadataKey] + + if (this.invertedIndex[term][fieldName][docRef][metadataKey] == undefined) { + this.invertedIndex[term][fieldName][docRef][metadataKey] = [] + } + + this.invertedIndex[term][fieldName][docRef][metadataKey].push(metadata) + } + } + + } +} + +/** + * Calculates the average document length for this index + * + * @private + */ +lunr.Builder.prototype.calculateAverageFieldLengths = function () { + + var fieldRefs = Object.keys(this.fieldLengths), + numberOfFields = fieldRefs.length, + accumulator = {}, + documentsWithField = {} + + for (var i = 0; i < numberOfFields; i++) { + var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]), + field = fieldRef.fieldName + + documentsWithField[field] || (documentsWithField[field] = 0) + documentsWithField[field] += 1 + + accumulator[field] || (accumulator[field] = 0) + accumulator[field] += this.fieldLengths[fieldRef] + } + + var fields = Object.keys(this._fields) + + for (var i = 0; i < fields.length; i++) { + var fieldName = fields[i] + accumulator[fieldName] = accumulator[fieldName] / documentsWithField[fieldName] + } + + this.averageFieldLength = accumulator +} + +/** + * Builds a vector space model of every document using lunr.Vector + * + * @private + */ +lunr.Builder.prototype.createFieldVectors = function () { + var fieldVectors = {}, + fieldRefs = Object.keys(this.fieldTermFrequencies), + fieldRefsLength = fieldRefs.length, + termIdfCache = Object.create(null) + + for (var i = 0; i < fieldRefsLength; i++) { + var fieldRef = lunr.FieldRef.fromString(fieldRefs[i]), + fieldName = fieldRef.fieldName, + fieldLength = this.fieldLengths[fieldRef], + fieldVector = new lunr.Vector, + termFrequencies = this.fieldTermFrequencies[fieldRef], + terms = Object.keys(termFrequencies), + termsLength = terms.length + + + var fieldBoost = this._fields[fieldName].boost || 1, + docBoost = this._documents[fieldRef.docRef].boost || 1 + + for (var j = 0; j < termsLength; j++) { + var term = terms[j], + tf = termFrequencies[term], + termIndex = this.invertedIndex[term]._index, + idf, score, scoreWithPrecision + + if (termIdfCache[term] === undefined) { + idf = lunr.idf(this.invertedIndex[term], this.documentCount) + termIdfCache[term] = idf + } else { + idf = termIdfCache[term] + } + + score = idf * ((this._k1 + 1) * tf) / (this._k1 * (1 - this._b + this._b * (fieldLength / this.averageFieldLength[fieldName])) + tf) + score *= fieldBoost + score *= docBoost + scoreWithPrecision = Math.round(score * 1000) / 1000 + // Converts 1.23456789 to 1.234. + // Reducing the precision so that the vectors take up less + // space when serialised. Doing it now so that they behave + // the same before and after serialisation. Also, this is + // the fastest approach to reducing a number's precision in + // JavaScript. + + fieldVector.insert(termIndex, scoreWithPrecision) + } + + fieldVectors[fieldRef] = fieldVector + } + + this.fieldVectors = fieldVectors +} + +/** + * Creates a token set of all tokens in the index using lunr.TokenSet + * + * @private + */ +lunr.Builder.prototype.createTokenSet = function () { + this.tokenSet = lunr.TokenSet.fromArray( + Object.keys(this.invertedIndex).sort() + ) +} + +/** + * Builds the index, creating an instance of lunr.Index. + * + * This completes the indexing process and should only be called + * once all documents have been added to the index. + * + * @returns {lunr.Index} + */ +lunr.Builder.prototype.build = function () { + this.calculateAverageFieldLengths() + this.createFieldVectors() + this.createTokenSet() + + return new lunr.Index({ + invertedIndex: this.invertedIndex, + fieldVectors: this.fieldVectors, + tokenSet: this.tokenSet, + fields: Object.keys(this._fields), + pipeline: this.searchPipeline + }) +} + +/** + * Applies a plugin to the index builder. + * + * A plugin is a function that is called with the index builder as its context. + * Plugins can be used to customise or extend the behaviour of the index + * in some way. A plugin is just a function, that encapsulated the custom + * behaviour that should be applied when building the index. + * + * The plugin function will be called with the index builder as its argument, additional + * arguments can also be passed when calling use. The function will be called + * with the index builder as its context. + * + * @param {Function} plugin The plugin to apply. + */ +lunr.Builder.prototype.use = function (fn) { + var args = Array.prototype.slice.call(arguments, 1) + args.unshift(this) + fn.apply(this, args) +} +/** + * Contains and collects metadata about a matching document. + * A single instance of lunr.MatchData is returned as part of every + * lunr.Index~Result. + * + * @constructor + * @param {string} term - The term this match data is associated with + * @param {string} field - The field in which the term was found + * @param {object} metadata - The metadata recorded about this term in this field + * @property {object} metadata - A cloned collection of metadata associated with this document. + * @see {@link lunr.Index~Result} + */ +lunr.MatchData = function (term, field, metadata) { + var clonedMetadata = Object.create(null), + metadataKeys = Object.keys(metadata || {}) + + // Cloning the metadata to prevent the original + // being mutated during match data combination. + // Metadata is kept in an array within the inverted + // index so cloning the data can be done with + // Array#slice + for (var i = 0; i < metadataKeys.length; i++) { + var key = metadataKeys[i] + clonedMetadata[key] = metadata[key].slice() + } + + this.metadata = Object.create(null) + + if (term !== undefined) { + this.metadata[term] = Object.create(null) + this.metadata[term][field] = clonedMetadata + } +} + +/** + * An instance of lunr.MatchData will be created for every term that matches a + * document. However only one instance is required in a lunr.Index~Result. This + * method combines metadata from another instance of lunr.MatchData with this + * objects metadata. + * + * @param {lunr.MatchData} otherMatchData - Another instance of match data to merge with this one. + * @see {@link lunr.Index~Result} + */ +lunr.MatchData.prototype.combine = function (otherMatchData) { + var terms = Object.keys(otherMatchData.metadata) + + for (var i = 0; i < terms.length; i++) { + var term = terms[i], + fields = Object.keys(otherMatchData.metadata[term]) + + if (this.metadata[term] == undefined) { + this.metadata[term] = Object.create(null) + } + + for (var j = 0; j < fields.length; j++) { + var field = fields[j], + keys = Object.keys(otherMatchData.metadata[term][field]) + + if (this.metadata[term][field] == undefined) { + this.metadata[term][field] = Object.create(null) + } + + for (var k = 0; k < keys.length; k++) { + var key = keys[k] + + if (this.metadata[term][field][key] == undefined) { + this.metadata[term][field][key] = otherMatchData.metadata[term][field][key] + } else { + this.metadata[term][field][key] = this.metadata[term][field][key].concat(otherMatchData.metadata[term][field][key]) + } + + } + } + } +} + +/** + * Add metadata for a term/field pair to this instance of match data. + * + * @param {string} term - The term this match data is associated with + * @param {string} field - The field in which the term was found + * @param {object} metadata - The metadata recorded about this term in this field + */ +lunr.MatchData.prototype.add = function (term, field, metadata) { + if (!(term in this.metadata)) { + this.metadata[term] = Object.create(null) + this.metadata[term][field] = metadata + return + } + + if (!(field in this.metadata[term])) { + this.metadata[term][field] = metadata + return + } + + var metadataKeys = Object.keys(metadata) + + for (var i = 0; i < metadataKeys.length; i++) { + var key = metadataKeys[i] + + if (key in this.metadata[term][field]) { + this.metadata[term][field][key] = this.metadata[term][field][key].concat(metadata[key]) + } else { + this.metadata[term][field][key] = metadata[key] + } + } +} +/** + * A lunr.Query provides a programmatic way of defining queries to be performed + * against a {@link lunr.Index}. + * + * Prefer constructing a lunr.Query using the {@link lunr.Index#query} method + * so the query object is pre-initialized with the right index fields. + * + * @constructor + * @property {lunr.Query~Clause[]} clauses - An array of query clauses. + * @property {string[]} allFields - An array of all available fields in a lunr.Index. + */ +lunr.Query = function (allFields) { + this.clauses = [] + this.allFields = allFields +} + +/** + * Constants for indicating what kind of automatic wildcard insertion will be used when constructing a query clause. + * + * This allows wildcards to be added to the beginning and end of a term without having to manually do any string + * concatenation. + * + * The wildcard constants can be bitwise combined to select both leading and trailing wildcards. + * + * @constant + * @default + * @property {number} wildcard.NONE - The term will have no wildcards inserted, this is the default behaviour + * @property {number} wildcard.LEADING - Prepend the term with a wildcard, unless a leading wildcard already exists + * @property {number} wildcard.TRAILING - Append a wildcard to the term, unless a trailing wildcard already exists + * @see lunr.Query~Clause + * @see lunr.Query#clause + * @see lunr.Query#term + * @example query term with trailing wildcard + * query.term('foo', { wildcard: lunr.Query.wildcard.TRAILING }) + * @example query term with leading and trailing wildcard + * query.term('foo', { + * wildcard: lunr.Query.wildcard.LEADING | lunr.Query.wildcard.TRAILING + * }) + */ + +lunr.Query.wildcard = new String ("*") +lunr.Query.wildcard.NONE = 0 +lunr.Query.wildcard.LEADING = 1 +lunr.Query.wildcard.TRAILING = 2 + +/** + * Constants for indicating what kind of presence a term must have in matching documents. + * + * @constant + * @enum {number} + * @see lunr.Query~Clause + * @see lunr.Query#clause + * @see lunr.Query#term + * @example query term with required presence + * query.term('foo', { presence: lunr.Query.presence.REQUIRED }) + */ +lunr.Query.presence = { + /** + * Term's presence in a document is optional, this is the default value. + */ + OPTIONAL: 1, + + /** + * Term's presence in a document is required, documents that do not contain + * this term will not be returned. + */ + REQUIRED: 2, + + /** + * Term's presence in a document is prohibited, documents that do contain + * this term will not be returned. + */ + PROHIBITED: 3 +} + +/** + * A single clause in a {@link lunr.Query} contains a term and details on how to + * match that term against a {@link lunr.Index}. + * + * @typedef {Object} lunr.Query~Clause + * @property {string[]} fields - The fields in an index this clause should be matched against. + * @property {number} [boost=1] - Any boost that should be applied when matching this clause. + * @property {number} [editDistance] - Whether the term should have fuzzy matching applied, and how fuzzy the match should be. + * @property {boolean} [usePipeline] - Whether the term should be passed through the search pipeline. + * @property {number} [wildcard=lunr.Query.wildcard.NONE] - Whether the term should have wildcards appended or prepended. + * @property {number} [presence=lunr.Query.presence.OPTIONAL] - The terms presence in any matching documents. + */ + +/** + * Adds a {@link lunr.Query~Clause} to this query. + * + * Unless the clause contains the fields to be matched all fields will be matched. In addition + * a default boost of 1 is applied to the clause. + * + * @param {lunr.Query~Clause} clause - The clause to add to this query. + * @see lunr.Query~Clause + * @returns {lunr.Query} + */ +lunr.Query.prototype.clause = function (clause) { + if (!('fields' in clause)) { + clause.fields = this.allFields + } + + if (!('boost' in clause)) { + clause.boost = 1 + } + + if (!('usePipeline' in clause)) { + clause.usePipeline = true + } + + if (!('wildcard' in clause)) { + clause.wildcard = lunr.Query.wildcard.NONE + } + + if ((clause.wildcard & lunr.Query.wildcard.LEADING) && (clause.term.charAt(0) != lunr.Query.wildcard)) { + clause.term = "*" + clause.term + } + + if ((clause.wildcard & lunr.Query.wildcard.TRAILING) && (clause.term.slice(-1) != lunr.Query.wildcard)) { + clause.term = "" + clause.term + "*" + } + + if (!('presence' in clause)) { + clause.presence = lunr.Query.presence.OPTIONAL + } + + this.clauses.push(clause) + + return this +} + +/** + * A negated query is one in which every clause has a presence of + * prohibited. These queries require some special processing to return + * the expected results. + * + * @returns boolean + */ +lunr.Query.prototype.isNegated = function () { + for (var i = 0; i < this.clauses.length; i++) { + if (this.clauses[i].presence != lunr.Query.presence.PROHIBITED) { + return false + } + } + + return true +} + +/** + * Adds a term to the current query, under the covers this will create a {@link lunr.Query~Clause} + * to the list of clauses that make up this query. + * + * The term is used as is, i.e. no tokenization will be performed by this method. Instead conversion + * to a token or token-like string should be done before calling this method. + * + * The term will be converted to a string by calling `toString`. Multiple terms can be passed as an + * array, each term in the array will share the same options. + * + * @param {object|object[]} term - The term(s) to add to the query. + * @param {object} [options] - Any additional properties to add to the query clause. + * @returns {lunr.Query} + * @see lunr.Query#clause + * @see lunr.Query~Clause + * @example adding a single term to a query + * query.term("foo") + * @example adding a single term to a query and specifying search fields, term boost and automatic trailing wildcard + * query.term("foo", { + * fields: ["title"], + * boost: 10, + * wildcard: lunr.Query.wildcard.TRAILING + * }) + * @example using lunr.tokenizer to convert a string to tokens before using them as terms + * query.term(lunr.tokenizer("foo bar")) + */ +lunr.Query.prototype.term = function (term, options) { + if (Array.isArray(term)) { + term.forEach(function (t) { this.term(t, lunr.utils.clone(options)) }, this) + return this + } + + var clause = options || {} + clause.term = term.toString() + + this.clause(clause) + + return this +} +lunr.QueryParseError = function (message, start, end) { + this.name = "QueryParseError" + this.message = message + this.start = start + this.end = end +} + +lunr.QueryParseError.prototype = new Error +lunr.QueryLexer = function (str) { + this.lexemes = [] + this.str = str + this.length = str.length + this.pos = 0 + this.start = 0 + this.escapeCharPositions = [] +} + +lunr.QueryLexer.prototype.run = function () { + var state = lunr.QueryLexer.lexText + + while (state) { + state = state(this) + } +} + +lunr.QueryLexer.prototype.sliceString = function () { + var subSlices = [], + sliceStart = this.start, + sliceEnd = this.pos + + for (var i = 0; i < this.escapeCharPositions.length; i++) { + sliceEnd = this.escapeCharPositions[i] + subSlices.push(this.str.slice(sliceStart, sliceEnd)) + sliceStart = sliceEnd + 1 + } + + subSlices.push(this.str.slice(sliceStart, this.pos)) + this.escapeCharPositions.length = 0 + + return subSlices.join('') +} + +lunr.QueryLexer.prototype.emit = function (type) { + this.lexemes.push({ + type: type, + str: this.sliceString(), + start: this.start, + end: this.pos + }) + + this.start = this.pos +} + +lunr.QueryLexer.prototype.escapeCharacter = function () { + this.escapeCharPositions.push(this.pos - 1) + this.pos += 1 +} + +lunr.QueryLexer.prototype.next = function () { + if (this.pos >= this.length) { + return lunr.QueryLexer.EOS + } + + var char = this.str.charAt(this.pos) + this.pos += 1 + return char +} + +lunr.QueryLexer.prototype.width = function () { + return this.pos - this.start +} + +lunr.QueryLexer.prototype.ignore = function () { + if (this.start == this.pos) { + this.pos += 1 + } + + this.start = this.pos +} + +lunr.QueryLexer.prototype.backup = function () { + this.pos -= 1 +} + +lunr.QueryLexer.prototype.acceptDigitRun = function () { + var char, charCode + + do { + char = this.next() + charCode = char.charCodeAt(0) + } while (charCode > 47 && charCode < 58) + + if (char != lunr.QueryLexer.EOS) { + this.backup() + } +} + +lunr.QueryLexer.prototype.more = function () { + return this.pos < this.length +} + +lunr.QueryLexer.EOS = 'EOS' +lunr.QueryLexer.FIELD = 'FIELD' +lunr.QueryLexer.TERM = 'TERM' +lunr.QueryLexer.EDIT_DISTANCE = 'EDIT_DISTANCE' +lunr.QueryLexer.BOOST = 'BOOST' +lunr.QueryLexer.PRESENCE = 'PRESENCE' + +lunr.QueryLexer.lexField = function (lexer) { + lexer.backup() + lexer.emit(lunr.QueryLexer.FIELD) + lexer.ignore() + return lunr.QueryLexer.lexText +} + +lunr.QueryLexer.lexTerm = function (lexer) { + if (lexer.width() > 1) { + lexer.backup() + lexer.emit(lunr.QueryLexer.TERM) + } + + lexer.ignore() + + if (lexer.more()) { + return lunr.QueryLexer.lexText + } +} + +lunr.QueryLexer.lexEditDistance = function (lexer) { + lexer.ignore() + lexer.acceptDigitRun() + lexer.emit(lunr.QueryLexer.EDIT_DISTANCE) + return lunr.QueryLexer.lexText +} + +lunr.QueryLexer.lexBoost = function (lexer) { + lexer.ignore() + lexer.acceptDigitRun() + lexer.emit(lunr.QueryLexer.BOOST) + return lunr.QueryLexer.lexText +} + +lunr.QueryLexer.lexEOS = function (lexer) { + if (lexer.width() > 0) { + lexer.emit(lunr.QueryLexer.TERM) + } +} + +// This matches the separator used when tokenising fields +// within a document. These should match otherwise it is +// not possible to search for some tokens within a document. +// +// It is possible for the user to change the separator on the +// tokenizer so it _might_ clash with any other of the special +// characters already used within the search string, e.g. :. +// +// This means that it is possible to change the separator in +// such a way that makes some words unsearchable using a search +// string. +lunr.QueryLexer.termSeparator = lunr.tokenizer.separator + +lunr.QueryLexer.lexText = function (lexer) { + while (true) { + var char = lexer.next() + + if (char == lunr.QueryLexer.EOS) { + return lunr.QueryLexer.lexEOS + } + + // Escape character is '\' + if (char.charCodeAt(0) == 92) { + lexer.escapeCharacter() + continue + } + + if (char == ":") { + return lunr.QueryLexer.lexField + } + + if (char == "~") { + lexer.backup() + if (lexer.width() > 0) { + lexer.emit(lunr.QueryLexer.TERM) + } + return lunr.QueryLexer.lexEditDistance + } + + if (char == "^") { + lexer.backup() + if (lexer.width() > 0) { + lexer.emit(lunr.QueryLexer.TERM) + } + return lunr.QueryLexer.lexBoost + } + + // "+" indicates term presence is required + // checking for length to ensure that only + // leading "+" are considered + if (char == "+" && lexer.width() === 1) { + lexer.emit(lunr.QueryLexer.PRESENCE) + return lunr.QueryLexer.lexText + } + + // "-" indicates term presence is prohibited + // checking for length to ensure that only + // leading "-" are considered + if (char == "-" && lexer.width() === 1) { + lexer.emit(lunr.QueryLexer.PRESENCE) + return lunr.QueryLexer.lexText + } + + if (char.match(lunr.QueryLexer.termSeparator)) { + return lunr.QueryLexer.lexTerm + } + } +} + +lunr.QueryParser = function (str, query) { + this.lexer = new lunr.QueryLexer (str) + this.query = query + this.currentClause = {} + this.lexemeIdx = 0 +} + +lunr.QueryParser.prototype.parse = function () { + this.lexer.run() + this.lexemes = this.lexer.lexemes + + var state = lunr.QueryParser.parseClause + + while (state) { + state = state(this) + } + + return this.query +} + +lunr.QueryParser.prototype.peekLexeme = function () { + return this.lexemes[this.lexemeIdx] +} + +lunr.QueryParser.prototype.consumeLexeme = function () { + var lexeme = this.peekLexeme() + this.lexemeIdx += 1 + return lexeme +} + +lunr.QueryParser.prototype.nextClause = function () { + var completedClause = this.currentClause + this.query.clause(completedClause) + this.currentClause = {} +} + +lunr.QueryParser.parseClause = function (parser) { + var lexeme = parser.peekLexeme() + + if (lexeme == undefined) { + return + } + + switch (lexeme.type) { + case lunr.QueryLexer.PRESENCE: + return lunr.QueryParser.parsePresence + case lunr.QueryLexer.FIELD: + return lunr.QueryParser.parseField + case lunr.QueryLexer.TERM: + return lunr.QueryParser.parseTerm + default: + var errorMessage = "expected either a field or a term, found " + lexeme.type + + if (lexeme.str.length >= 1) { + errorMessage += " with value '" + lexeme.str + "'" + } + + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } +} + +lunr.QueryParser.parsePresence = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + switch (lexeme.str) { + case "-": + parser.currentClause.presence = lunr.Query.presence.PROHIBITED + break + case "+": + parser.currentClause.presence = lunr.Query.presence.REQUIRED + break + default: + var errorMessage = "unrecognised presence operator'" + lexeme.str + "'" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + var errorMessage = "expecting term or field, found nothing" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.FIELD: + return lunr.QueryParser.parseField + case lunr.QueryLexer.TERM: + return lunr.QueryParser.parseTerm + default: + var errorMessage = "expecting term or field, found '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseField = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + if (parser.query.allFields.indexOf(lexeme.str) == -1) { + var possibleFields = parser.query.allFields.map(function (f) { return "'" + f + "'" }).join(', '), + errorMessage = "unrecognised field '" + lexeme.str + "', possible fields: " + possibleFields + + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + parser.currentClause.fields = [lexeme.str] + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + var errorMessage = "expecting term, found nothing" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + return lunr.QueryParser.parseTerm + default: + var errorMessage = "expecting term, found '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseTerm = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + parser.currentClause.term = lexeme.str.toLowerCase() + + if (lexeme.str.indexOf("*") != -1) { + parser.currentClause.usePipeline = false + } + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + parser.nextClause() + return + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + parser.nextClause() + return lunr.QueryParser.parseTerm + case lunr.QueryLexer.FIELD: + parser.nextClause() + return lunr.QueryParser.parseField + case lunr.QueryLexer.EDIT_DISTANCE: + return lunr.QueryParser.parseEditDistance + case lunr.QueryLexer.BOOST: + return lunr.QueryParser.parseBoost + case lunr.QueryLexer.PRESENCE: + parser.nextClause() + return lunr.QueryParser.parsePresence + default: + var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseEditDistance = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + var editDistance = parseInt(lexeme.str, 10) + + if (isNaN(editDistance)) { + var errorMessage = "edit distance must be numeric" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + parser.currentClause.editDistance = editDistance + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + parser.nextClause() + return + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + parser.nextClause() + return lunr.QueryParser.parseTerm + case lunr.QueryLexer.FIELD: + parser.nextClause() + return lunr.QueryParser.parseField + case lunr.QueryLexer.EDIT_DISTANCE: + return lunr.QueryParser.parseEditDistance + case lunr.QueryLexer.BOOST: + return lunr.QueryParser.parseBoost + case lunr.QueryLexer.PRESENCE: + parser.nextClause() + return lunr.QueryParser.parsePresence + default: + var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + +lunr.QueryParser.parseBoost = function (parser) { + var lexeme = parser.consumeLexeme() + + if (lexeme == undefined) { + return + } + + var boost = parseInt(lexeme.str, 10) + + if (isNaN(boost)) { + var errorMessage = "boost must be numeric" + throw new lunr.QueryParseError (errorMessage, lexeme.start, lexeme.end) + } + + parser.currentClause.boost = boost + + var nextLexeme = parser.peekLexeme() + + if (nextLexeme == undefined) { + parser.nextClause() + return + } + + switch (nextLexeme.type) { + case lunr.QueryLexer.TERM: + parser.nextClause() + return lunr.QueryParser.parseTerm + case lunr.QueryLexer.FIELD: + parser.nextClause() + return lunr.QueryParser.parseField + case lunr.QueryLexer.EDIT_DISTANCE: + return lunr.QueryParser.parseEditDistance + case lunr.QueryLexer.BOOST: + return lunr.QueryParser.parseBoost + case lunr.QueryLexer.PRESENCE: + parser.nextClause() + return lunr.QueryParser.parsePresence + default: + var errorMessage = "Unexpected lexeme type '" + nextLexeme.type + "'" + throw new lunr.QueryParseError (errorMessage, nextLexeme.start, nextLexeme.end) + } +} + + /** + * export the module via AMD, CommonJS or as a browser global + * Export code from https://github.com/umdjs/umd/blob/master/returnExports.js + */ + ;(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(factory) + } else if (typeof exports === 'object') { + /** + * Node. Does not work with strict CommonJS, but + * only CommonJS-like environments that support module.exports, + * like Node. + */ + module.exports = factory() + } else { + // Browser globals (root is window) + root.lunr = factory() + } + }(this, function () { + /** + * Just return a value to define the module export. + * This example returns an object, but the module + * can return a function as the exported value. + */ + return lunr + })) +})(); diff --git a/site/search/main.js b/site/search/main.js new file mode 100644 index 00000000..a5e469d7 --- /dev/null +++ b/site/search/main.js @@ -0,0 +1,109 @@ +function getSearchTermFromLocation() { + var sPageURL = window.location.search.substring(1); + var sURLVariables = sPageURL.split('&'); + for (var i = 0; i < sURLVariables.length; i++) { + var sParameterName = sURLVariables[i].split('='); + if (sParameterName[0] == 'q') { + return decodeURIComponent(sParameterName[1].replace(/\+/g, '%20')); + } + } +} + +function joinUrl (base, path) { + if (path.substring(0, 1) === "/") { + // path starts with `/`. Thus it is absolute. + return path; + } + if (base.substring(base.length-1) === "/") { + // base ends with `/` + return base + path; + } + return base + "/" + path; +} + +function escapeHtml (value) { + return value.replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +} + +function formatResult (location, title, summary) { + return ''; +} + +function displayResults (results) { + var search_results = document.getElementById("mkdocs-search-results"); + while (search_results.firstChild) { + search_results.removeChild(search_results.firstChild); + } + if (results.length > 0){ + for (var i=0; i < results.length; i++){ + var result = results[i]; + var html = formatResult(result.location, result.title, result.summary); + search_results.insertAdjacentHTML('beforeend', html); + } + } else { + var noResultsText = search_results.getAttribute('data-no-results-text'); + if (!noResultsText) { + noResultsText = "No results found"; + } + search_results.insertAdjacentHTML('beforeend', '

' + noResultsText + '

'); + } +} + +function doSearch () { + var query = document.getElementById('mkdocs-search-query').value; + if (query.length > min_search_length) { + if (!window.Worker) { + displayResults(search(query)); + } else { + searchWorker.postMessage({query: query}); + } + } else { + // Clear results for short queries + displayResults([]); + } +} + +function initSearch () { + var search_input = document.getElementById('mkdocs-search-query'); + if (search_input) { + search_input.addEventListener("keyup", doSearch); + } + var term = getSearchTermFromLocation(); + if (term) { + search_input.value = term; + doSearch(); + } +} + +function onWorkerMessage (e) { + if (e.data.allowSearch) { + initSearch(); + } else if (e.data.results) { + var results = e.data.results; + displayResults(results); + } else if (e.data.config) { + min_search_length = e.data.config.min_search_length-1; + } +} + +if (!window.Worker) { + console.log('Web Worker API not supported'); + // load index in main thread + $.getScript(joinUrl(base_url, "search/worker.js")).done(function () { + console.log('Loaded worker'); + init(); + window.postMessage = function (msg) { + onWorkerMessage({data: msg}); + }; + }).fail(function (jqxhr, settings, exception) { + console.error('Could not load worker.js'); + }); +} else { + // Wrap search in a web worker + var searchWorker = new Worker(joinUrl(base_url, "search/worker.js")); + searchWorker.postMessage({init: true}); + searchWorker.onmessage = onWorkerMessage; +} diff --git a/site/search/worker.js b/site/search/worker.js new file mode 100644 index 00000000..8628dbce --- /dev/null +++ b/site/search/worker.js @@ -0,0 +1,133 @@ +var base_path = 'function' === typeof importScripts ? '.' : '/search/'; +var allowSearch = false; +var index; +var documents = {}; +var lang = ['en']; +var data; + +function getScript(script, callback) { + console.log('Loading script: ' + script); + $.getScript(base_path + script).done(function () { + callback(); + }).fail(function (jqxhr, settings, exception) { + console.log('Error: ' + exception); + }); +} + +function getScriptsInOrder(scripts, callback) { + if (scripts.length === 0) { + callback(); + return; + } + getScript(scripts[0], function() { + getScriptsInOrder(scripts.slice(1), callback); + }); +} + +function loadScripts(urls, callback) { + if( 'function' === typeof importScripts ) { + importScripts.apply(null, urls); + callback(); + } else { + getScriptsInOrder(urls, callback); + } +} + +function onJSONLoaded () { + data = JSON.parse(this.responseText); + var scriptsToLoad = ['lunr.js']; + if (data.config && data.config.lang && data.config.lang.length) { + lang = data.config.lang; + } + if (lang.length > 1 || lang[0] !== "en") { + scriptsToLoad.push('lunr.stemmer.support.js'); + if (lang.length > 1) { + scriptsToLoad.push('lunr.multi.js'); + } + if (lang.includes("ja") || lang.includes("jp")) { + scriptsToLoad.push('tinyseg.js'); + } + for (var i=0; i < lang.length; i++) { + if (lang[i] != 'en') { + scriptsToLoad.push(['lunr', lang[i], 'js'].join('.')); + } + } + } + loadScripts(scriptsToLoad, onScriptsLoaded); +} + +function onScriptsLoaded () { + console.log('All search scripts loaded, building Lunr index...'); + if (data.config && data.config.separator && data.config.separator.length) { + lunr.tokenizer.separator = new RegExp(data.config.separator); + } + + if (data.index) { + index = lunr.Index.load(data.index); + data.docs.forEach(function (doc) { + documents[doc.location] = doc; + }); + console.log('Lunr pre-built index loaded, search ready'); + } else { + index = lunr(function () { + if (lang.length === 1 && lang[0] !== "en" && lunr[lang[0]]) { + this.use(lunr[lang[0]]); + } else if (lang.length > 1) { + this.use(lunr.multiLanguage.apply(null, lang)); // spread operator not supported in all browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator#Browser_compatibility + } + this.field('title'); + this.field('text'); + this.ref('location'); + + for (var i=0; i < data.docs.length; i++) { + var doc = data.docs[i]; + this.add(doc); + documents[doc.location] = doc; + } + }); + console.log('Lunr index built, search ready'); + } + allowSearch = true; + postMessage({config: data.config}); + postMessage({allowSearch: allowSearch}); +} + +function init () { + var oReq = new XMLHttpRequest(); + oReq.addEventListener("load", onJSONLoaded); + var index_path = base_path + '/search_index.json'; + if( 'function' === typeof importScripts ){ + index_path = 'search_index.json'; + } + oReq.open("GET", index_path); + oReq.send(); +} + +function search (query) { + if (!allowSearch) { + console.error('Assets for search still loading'); + return; + } + + var resultDocuments = []; + var results = index.search(query); + for (var i=0; i < results.length; i++){ + var result = results[i]; + doc = documents[result.ref]; + doc.summary = doc.text.substring(0, 200); + resultDocuments.push(doc); + } + return resultDocuments; +} + +if( 'function' === typeof importScripts ) { + onmessage = function (e) { + if (e.data.init) { + init(); + } else if (e.data.query) { + postMessage({ results: search(e.data.query) }); + } else { + console.error("Worker - Unrecognized message: " + e); + } + }; +} diff --git a/site/sitemap.xml b/site/sitemap.xml new file mode 100644 index 00000000..0f8724ef --- /dev/null +++ b/site/sitemap.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/site/sitemap.xml.gz b/site/sitemap.xml.gz new file mode 100644 index 00000000..f6b0f1d2 Binary files /dev/null and b/site/sitemap.xml.gz differ diff --git a/theme/bootstrap.min.css b/theme/bootstrap.min.css new file mode 100644 index 00000000..23923f3a --- /dev/null +++ b/theme/bootstrap.min.css @@ -0,0 +1,12 @@ +@charset "UTF-8";/*! + * Bootswatch v5.3.3 (https://bootswatch.com) + * Theme: lux + * Copyright 2012-2024 Thomas Park + * Licensed under MIT + * Based on Bootstrap +*//*! + * Bootstrap v5.3.3 (https://getbootstrap.com/) + * Copyright 2011-2024 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */@import url(https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@200;300;400;500;600;700&display=swap);:root,[data-bs-theme=light]{--bs-blue:#007bff;--bs-indigo:#6610f2;--bs-purple:#6f42c1;--bs-pink:#e83e8c;--bs-red:#d9534f;--bs-orange:#fd7e14;--bs-yellow:#f0ad4e;--bs-green:#4bbf73;--bs-teal:#20c997;--bs-cyan:#1f9bcf;--bs-black:#000;--bs-white:#fff;--bs-gray:#919aa1;--bs-gray-dark:#343a40;--bs-gray-100:#f8f9fa;--bs-gray-200:#f7f7f9;--bs-gray-300:#eceeef;--bs-gray-400:#ced4da;--bs-gray-500:#adb5bd;--bs-gray-600:#919aa1;--bs-gray-700:#55595c;--bs-gray-800:#343a40;--bs-gray-900:#1a1a1a;--bs-primary:#1a1a1a;--bs-secondary:#fff;--bs-success:#4bbf73;--bs-info:#1f9bcf;--bs-warning:#f0ad4e;--bs-danger:#d9534f;--bs-light:#fff;--bs-dark:#343a40;--bs-primary-rgb:26,26,26;--bs-secondary-rgb:255,255,255;--bs-success-rgb:75,191,115;--bs-info-rgb:31,155,207;--bs-warning-rgb:240,173,78;--bs-danger-rgb:217,83,79;--bs-light-rgb:255,255,255;--bs-dark-rgb:52,58,64;--bs-primary-text-emphasis:#0a0a0a;--bs-secondary-text-emphasis:#666666;--bs-success-text-emphasis:#1e4c2e;--bs-info-text-emphasis:#0c3e53;--bs-warning-text-emphasis:#60451f;--bs-danger-text-emphasis:#572120;--bs-light-text-emphasis:#55595c;--bs-dark-text-emphasis:#55595c;--bs-primary-bg-subtle:#d1d1d1;--bs-secondary-bg-subtle:white;--bs-success-bg-subtle:#dbf2e3;--bs-info-bg-subtle:#d2ebf5;--bs-warning-bg-subtle:#fcefdc;--bs-danger-bg-subtle:#f7dddc;--bs-light-bg-subtle:#fcfcfd;--bs-dark-bg-subtle:#ced4da;--bs-primary-border-subtle:#a3a3a3;--bs-secondary-border-subtle:white;--bs-success-border-subtle:#b7e5c7;--bs-info-border-subtle:#a5d7ec;--bs-warning-border-subtle:#f9deb8;--bs-danger-border-subtle:#f0bab9;--bs-light-border-subtle:#f7f7f9;--bs-dark-border-subtle:#adb5bd;--bs-white-rgb:255,255,255;--bs-black-rgb:0,0,0;--bs-font-sans-serif:"Nunito Sans",-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-body-font-family:var(--bs-font-sans-serif);--bs-body-font-size:1rem;--bs-body-font-weight:300;--bs-body-line-height:1.5;--bs-body-color:#55595c;--bs-body-color-rgb:85,89,92;--bs-body-bg:#fff;--bs-body-bg-rgb:255,255,255;--bs-emphasis-color:#000;--bs-emphasis-color-rgb:0,0,0;--bs-secondary-color:rgba(85, 89, 92, 0.75);--bs-secondary-color-rgb:85,89,92;--bs-secondary-bg:#f7f7f9;--bs-secondary-bg-rgb:247,247,249;--bs-tertiary-color:rgba(85, 89, 92, 0.5);--bs-tertiary-color-rgb:85,89,92;--bs-tertiary-bg:#f8f9fa;--bs-tertiary-bg-rgb:248,249,250;--bs-heading-color:#1a1a1a;--bs-link-color:#1a1a1a;--bs-link-color-rgb:26,26,26;--bs-link-decoration:underline;--bs-link-hover-color:#151515;--bs-link-hover-color-rgb:21,21,21;--bs-code-color:#e83e8c;--bs-highlight-color:#55595c;--bs-highlight-bg:#fcefdc;--bs-border-width:1px;--bs-border-style:solid;--bs-border-color:#eceeef;--bs-border-color-translucent:rgba(0, 0, 0, 0.175);--bs-border-radius:0.375rem;--bs-border-radius-sm:0.25rem;--bs-border-radius-lg:0.5rem;--bs-border-radius-xl:1rem;--bs-border-radius-xxl:2rem;--bs-border-radius-2xl:var(--bs-border-radius-xxl);--bs-border-radius-pill:50rem;--bs-box-shadow:0 0.5rem 1rem rgba(0, 0, 0, 0.15);--bs-box-shadow-sm:0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);--bs-box-shadow-lg:0 1rem 3rem rgba(0, 0, 0, 0.175);--bs-box-shadow-inset:inset 0 1px 2px rgba(0, 0, 0, 0.075);--bs-focus-ring-width:0.25rem;--bs-focus-ring-opacity:0.25;--bs-focus-ring-color:rgba(26, 26, 26, 0.25);--bs-form-valid-color:#4bbf73;--bs-form-valid-border-color:#4bbf73;--bs-form-invalid-color:#d9534f;--bs-form-invalid-border-color:#d9534f}[data-bs-theme=dark]{color-scheme:dark;--bs-body-color:#eceeef;--bs-body-color-rgb:236,238,239;--bs-body-bg:#1a1a1a;--bs-body-bg-rgb:26,26,26;--bs-emphasis-color:#fff;--bs-emphasis-color-rgb:255,255,255;--bs-secondary-color:rgba(236, 238, 239, 0.75);--bs-secondary-color-rgb:236,238,239;--bs-secondary-bg:#343a40;--bs-secondary-bg-rgb:52,58,64;--bs-tertiary-color:rgba(236, 238, 239, 0.5);--bs-tertiary-color-rgb:236,238,239;--bs-tertiary-bg:#272a2d;--bs-tertiary-bg-rgb:39,42,45;--bs-primary-text-emphasis:#767676;--bs-secondary-text-emphasis:white;--bs-success-text-emphasis:#93d9ab;--bs-info-text-emphasis:#79c3e2;--bs-warning-text-emphasis:#f6ce95;--bs-danger-text-emphasis:#e89895;--bs-light-text-emphasis:#f8f9fa;--bs-dark-text-emphasis:#eceeef;--bs-primary-bg-subtle:#050505;--bs-secondary-bg-subtle:#333333;--bs-success-bg-subtle:#0f2617;--bs-info-bg-subtle:#061f29;--bs-warning-bg-subtle:#302310;--bs-danger-bg-subtle:#2b1110;--bs-light-bg-subtle:#343a40;--bs-dark-bg-subtle:#1a1d20;--bs-primary-border-subtle:#101010;--bs-secondary-border-subtle:#999999;--bs-success-border-subtle:#2d7345;--bs-info-border-subtle:#135d7c;--bs-warning-border-subtle:#90682f;--bs-danger-border-subtle:#82322f;--bs-light-border-subtle:#55595c;--bs-dark-border-subtle:#343a40;--bs-heading-color:inherit;--bs-link-color:#767676;--bs-link-hover-color:#919191;--bs-link-color-rgb:118,118,118;--bs-link-hover-color-rgb:145,145,145;--bs-code-color:#f18bba;--bs-highlight-color:#eceeef;--bs-highlight-bg:#60451f;--bs-border-color:#55595c;--bs-border-color-translucent:rgba(255, 255, 255, 0.15);--bs-form-valid-color:#93d9ab;--bs-form-valid-border-color:#93d9ab;--bs-form-invalid-color:#e89895;--bs-form-invalid-border-color:#e89895}*,::after,::before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:transparent}hr{margin:1rem 0;color:inherit;border:0;border-top:var(--bs-border-width) solid;opacity:.25}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem;font-weight:600;line-height:1.2;color:var(--bs-heading-color)}.h1,h1{font-size:calc(1.325rem + .9vw)}@media (min-width:1200px){.h1,h1{font-size:2rem}}.h2,h2{font-size:calc(1.3rem + .6vw)}@media (min-width:1200px){.h2,h2{font-size:1.75rem}}.h3,h3{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h3,h3{font-size:1.5rem}}.h4,h4{font-size:1.25rem}.h5,h5{font-size:1rem}.h6,h6{font-size:.75rem}p{margin-top:0;margin-bottom:1rem}abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}dl,ol,ul{margin-top:0;margin-bottom:1rem}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:600}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:bolder}.small,small{font-size:.875em}.mark,mark{padding:.1875em;color:var(--bs-highlight-color);background-color:var(--bs-highlight-bg)}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,1));text-decoration:underline}a:hover{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{font-family:var(--bs-font-monospace);font-size:1em}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:.875em}pre code{font-size:inherit;color:inherit;word-break:normal}code{font-size:.875em;color:var(--bs-code-color);word-wrap:break-word}a>code{color:inherit}kbd{padding:.1875rem .375rem;font-size:.875em;color:var(--bs-body-bg);background-color:var(--bs-body-color)}kbd kbd{padding:0;font-size:1em}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-secondary-color);text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]:not([type=date]):not([type=datetime-local]):not([type=month]):not([type=week]):not([type=time])::-webkit-calendar-picker-indicator{display:none!important}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + .3vw);line-height:inherit}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}::file-selector-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none!important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:.875em;color:#919aa1}.blockquote-footer::before{content:"— "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color);max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:.875em;color:var(--bs-secondary-color)}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{--bs-gutter-x:1.5rem;--bs-gutter-y:0;width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-right:auto;margin-left:auto}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}:root{--bs-breakpoint-xs:0;--bs-breakpoint-sm:576px;--bs-breakpoint-md:768px;--bs-breakpoint-lg:992px;--bs-breakpoint-xl:1200px;--bs-breakpoint-xxl:1400px}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-top:calc(-1 * var(--bs-gutter-y));margin-right:calc(-.5 * var(--bs-gutter-x));margin-left:calc(-.5 * var(--bs-gutter-x))}.row>*{flex-shrink:0;width:100%;max-width:100%;padding-right:calc(var(--bs-gutter-x) * .5);padding-left:calc(var(--bs-gutter-x) * .5);margin-top:var(--bs-gutter-y)}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.66666667%}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.66666667%}.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.66666667%}.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.66666667%}.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.66666667%}.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.33333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.66666667%}.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}}.table{--bs-table-color-type:initial;--bs-table-bg-type:initial;--bs-table-color-state:initial;--bs-table-bg-state:initial;--bs-table-color:var(--bs-emphasis-color);--bs-table-bg:var(--bs-body-bg);--bs-table-border-color:rgba(0, 0, 0, 0.05);--bs-table-accent-bg:transparent;--bs-table-striped-color:var(--bs-emphasis-color);--bs-table-striped-bg:rgba(var(--bs-emphasis-color-rgb), 0.05);--bs-table-active-color:var(--bs-emphasis-color);--bs-table-active-bg:rgba(var(--bs-emphasis-color-rgb), 0.1);--bs-table-hover-color:var(--bs-emphasis-color);--bs-table-hover-bg:rgba(var(--bs-emphasis-color-rgb), 0.075);width:100%;margin-bottom:1rem;vertical-align:top;border-color:var(--bs-table-border-color)}.table>:not(caption)>*>*{padding:.5rem .5rem;color:var(--bs-table-color-state,var(--bs-table-color-type,var(--bs-table-color)));background-color:var(--bs-table-bg);border-bottom-width:var(--bs-border-width);box-shadow:inset 0 0 0 9999px var(--bs-table-bg-state,var(--bs-table-bg-type,var(--bs-table-accent-bg)))}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table-group-divider{border-top:calc(var(--bs-border-width) * 2) solid currentcolor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:var(--bs-border-width) 0}.table-bordered>:not(caption)>*>*{border-width:0 var(--bs-border-width)}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-striped-columns>:not(caption)>tr>:nth-child(2n){--bs-table-color-type:var(--bs-table-striped-color);--bs-table-bg-type:var(--bs-table-striped-bg)}.table-active{--bs-table-color-state:var(--bs-table-active-color);--bs-table-bg-state:var(--bs-table-active-bg)}.table-hover>tbody>tr:hover>*{--bs-table-color-state:var(--bs-table-hover-color);--bs-table-bg-state:var(--bs-table-hover-bg)}.table-primary{--bs-table-color:#000;--bs-table-bg:#d1d1d1;--bs-table-border-color:#a7a7a7;--bs-table-striped-bg:#c7c7c7;--bs-table-striped-color:#000;--bs-table-active-bg:#bcbcbc;--bs-table-active-color:#000;--bs-table-hover-bg:#c1c1c1;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-secondary{--bs-table-color:#000;--bs-table-bg:white;--bs-table-border-color:#cccccc;--bs-table-striped-bg:#f2f2f2;--bs-table-striped-color:#000;--bs-table-active-bg:#e6e6e6;--bs-table-active-color:#000;--bs-table-hover-bg:#ececec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-success{--bs-table-color:#000;--bs-table-bg:#dbf2e3;--bs-table-border-color:#afc2b6;--bs-table-striped-bg:#d0e6d8;--bs-table-striped-color:#000;--bs-table-active-bg:#c5dacc;--bs-table-active-color:#000;--bs-table-hover-bg:#cbe0d2;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-info{--bs-table-color:#000;--bs-table-bg:#d2ebf5;--bs-table-border-color:#a8bcc4;--bs-table-striped-bg:#c8dfe9;--bs-table-striped-color:#000;--bs-table-active-bg:#bdd4dd;--bs-table-active-color:#000;--bs-table-hover-bg:#c2d9e3;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-warning{--bs-table-color:#000;--bs-table-bg:#fcefdc;--bs-table-border-color:#cabfb0;--bs-table-striped-bg:#efe3d1;--bs-table-striped-color:#000;--bs-table-active-bg:#e3d7c6;--bs-table-active-color:#000;--bs-table-hover-bg:#e9ddcc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-danger{--bs-table-color:#000;--bs-table-bg:#f7dddc;--bs-table-border-color:#c6b1b0;--bs-table-striped-bg:#ebd2d1;--bs-table-striped-color:#000;--bs-table-active-bg:#dec7c6;--bs-table-active-color:#000;--bs-table-hover-bg:#e4cccc;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-light{--bs-table-color:#000;--bs-table-bg:#fff;--bs-table-border-color:#cccccc;--bs-table-striped-bg:#f2f2f2;--bs-table-striped-color:#000;--bs-table-active-bg:#e6e6e6;--bs-table-active-color:#000;--bs-table-hover-bg:#ececec;--bs-table-hover-color:#000;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-dark{--bs-table-color:#fff;--bs-table-bg:#343a40;--bs-table-border-color:#5d6166;--bs-table-striped-bg:#3e444a;--bs-table-striped-color:#fff;--bs-table-active-bg:#484e53;--bs-table-active-color:#fff;--bs-table-hover-bg:#43494e;--bs-table-hover-color:#fff;color:var(--bs-table-color);border-color:var(--bs-table-border-color)}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media (max-width:575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media (max-width:1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label{margin-bottom:.5rem}.col-form-label{padding-top:.75rem;padding-bottom:.75rem;margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:2rem;padding-bottom:2rem;font-size:1.25rem}.col-form-label-sm{padding-top:.5rem;padding-bottom:.5rem;font-size:.875rem}.form-text{margin-top:.25rem;font-size:.875em;color:var(--bs-secondary-color)}.form-control{display:block;width:100%;padding:.75rem 1.5rem;font-size:1rem;font-weight:300;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#f7f7f9;background-clip:padding-box;border:0 solid var(--bs-border-color);border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:var(--bs-body-color);background-color:#f7f7f9;border-color:#8d8d8d;outline:0;box-shadow:0 0 0 .25rem rgba(26,26,26,.25)}.form-control::-webkit-date-and-time-value{min-width:85px;height:1.5em;margin:0}.form-control::-webkit-datetime-edit{display:block;padding:0}.form-control::-moz-placeholder{color:var(--bs-secondary-color);opacity:1}.form-control::placeholder{color:var(--bs-secondary-color);opacity:1}.form-control:disabled{background-color:#eceeef;opacity:1}.form-control::-webkit-file-upload-button{padding:.75rem 1.5rem;margin:-.75rem -1.5rem;-webkit-margin-end:1.5rem;margin-inline-end:1.5rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:0;border-radius:0;-webkit-transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}.form-control::file-selector-button{padding:.75rem 1.5rem;margin:-.75rem -1.5rem;-webkit-margin-end:1.5rem;margin-inline-end:1.5rem;color:var(--bs-body-color);background-color:var(--bs-tertiary-bg);pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:0;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:var(--bs-secondary-bg)}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:var(--bs-secondary-bg)}.form-control-plaintext{display:block;width:100%;padding:.75rem 0;margin-bottom:0;line-height:1.5;color:var(--bs-body-color);background-color:transparent;border:solid transparent;border-width:0 0}.form-control-plaintext:focus{outline:0}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 1rem + calc(0 * 2));padding:.5rem 1rem;font-size:.875rem}.form-control-sm::-webkit-file-upload-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-sm::file-selector-button{padding:.5rem 1rem;margin:-.5rem -1rem;-webkit-margin-end:1rem;margin-inline-end:1rem}.form-control-lg{min-height:calc(1.5em + 4rem + calc(0 * 2));padding:2rem 2rem;font-size:1.25rem}.form-control-lg::-webkit-file-upload-button{padding:2rem 2rem;margin:-2rem -2rem;-webkit-margin-end:2rem;margin-inline-end:2rem}.form-control-lg::file-selector-button{padding:2rem 2rem;margin:-2rem -2rem;-webkit-margin-end:2rem;margin-inline-end:2rem}textarea.form-control{min-height:calc(1.5em + 1.5rem + calc(0 * 2))}textarea.form-control-sm{min-height:calc(1.5em + 1rem + calc(0 * 2))}textarea.form-control-lg{min-height:calc(1.5em + 4rem + calc(0 * 2))}.form-control-color{width:3rem;height:calc(1.5em + 1.5rem + calc(0 * 2));padding:.75rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border:0!important}.form-control-color::-webkit-color-swatch{border:0!important}.form-control-color.form-control-sm{height:calc(1.5em + 1rem + calc(0 * 2))}.form-control-color.form-control-lg{height:calc(1.5em + 4rem + calc(0 * 2))}.form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");display:block;width:100%;padding:.75rem 4.5rem .75rem 1.5rem;font-size:1rem;font-weight:300;line-height:1.5;color:var(--bs-body-color);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#f7f7f9;background-image:var(--bs-form-select-bg-img),var(--bs-form-select-bg-icon,none);background-repeat:no-repeat;background-position:right 1.5rem center;background-size:16px 12px;border:0 solid var(--bs-border-color);border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#8d8d8d;outline:0;box-shadow:0 0 0 .25rem rgba(26,26,26,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:1.5rem;background-image:none}.form-select:disabled{color:#919aa1;background-color:#eceeef}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--bs-body-color)}.form-select-sm{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:.875rem}.form-select-lg{padding-top:2rem;padding-bottom:2rem;padding-left:2rem;font-size:1.25rem}[data-bs-theme=dark] .form-select{--bs-form-select-bg-img:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23eceeef' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e")}.form-check{display:block;min-height:1.5rem;padding-left:1.5em;margin-bottom:.125rem}.form-check .form-check-input{float:left;margin-left:-1.5em}.form-check-reverse{padding-right:1.5em;padding-left:0;text-align:right}.form-check-reverse .form-check-input{float:right;margin-right:-1.5em;margin-left:0}.form-check-input{--bs-form-check-bg:#f7f7f9;flex-shrink:0;width:1em;height:1em;margin-top:.25em;vertical-align:top;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:var(--bs-form-check-bg);background-image:var(--bs-form-check-bg-image);background-repeat:no-repeat;background-position:center;background-size:contain;border:var(--bs-border-width) solid var(--bs-border-color);-webkit-print-color-adjust:exact;color-adjust:exact;print-color-adjust:exact}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(90%)}.form-check-input:focus{border-color:#8d8d8d;outline:0;box-shadow:0 0 0 .25rem rgba(26,26,26,.25)}.form-check-input:checked{background-color:#1a1a1a;border-color:#1a1a1a}.form-check-input:checked[type=checkbox]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio]{--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate{background-color:#1a1a1a;border-color:#1a1a1a;--bs-form-check-bg-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{cursor:default;opacity:.5}.form-switch{padding-left:2.5em}.form-switch .form-check-input{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");width:2em;margin-left:-2.5em;background-image:var(--bs-form-switch-bg);background-position:left center;border-radius:0;transition:background-position .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%238d8d8d'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-switch.form-check-reverse{padding-right:2.5em;padding-left:0}.form-switch.form-check-reverse .form-check-input{margin-right:-2.5em;margin-left:0}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{pointer-events:none;filter:none;opacity:.65}[data-bs-theme=dark] .form-switch .form-check-input:not(:checked):not(:focus){--bs-form-switch-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%28255, 255, 255, 0.25%29'/%3e%3c/svg%3e")}.form-range{width:100%;height:1.5rem;padding:0;-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(26,26,26,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(26,26,26,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;-webkit-appearance:none;appearance:none;background-color:#1a1a1a;border:0;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#bababa}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent}.form-range::-moz-range-thumb{width:1rem;height:1rem;-moz-appearance:none;appearance:none;background-color:#1a1a1a;border:0;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#bababa}.form-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:var(--bs-secondary-bg);border-color:transparent}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:var(--bs-secondary-color)}.form-range:disabled::-moz-range-thumb{background-color:var(--bs-secondary-color)}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-control-plaintext,.form-floating>.form-select{height:calc(3.5rem + calc(0 * 2));min-height:calc(3.5rem + calc(0 * 2));line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;z-index:2;height:100%;padding:1rem 1.5rem;overflow:hidden;text-align:start;text-overflow:ellipsis;white-space:nowrap;pointer-events:none;border:0 solid transparent;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control,.form-floating>.form-control-plaintext{padding:1rem 1.5rem}.form-floating>.form-control-plaintext::-moz-placeholder,.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control-plaintext::placeholder,.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control-plaintext:not(:-moz-placeholder-shown),.form-floating>.form-control:not(:-moz-placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:focus,.form-floating>.form-control-plaintext:not(:placeholder-shown),.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control-plaintext:-webkit-autofill,.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label,.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-moz-placeholder-shown)~label::after{position:absolute;inset:1rem 0.75rem;z-index:-1;height:1.5em;content:"";background-color:#f7f7f9}.form-floating>.form-control-plaintext~label::after,.form-floating>.form-control:focus~label::after,.form-floating>.form-control:not(:placeholder-shown)~label::after,.form-floating>.form-select~label::after{position:absolute;inset:1rem 0.75rem;z-index:-1;height:1.5em;content:"";background-color:#f7f7f9}.form-floating>.form-control:-webkit-autofill~label{color:rgba(var(--bs-body-color-rgb),.65);transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control-plaintext~label{border-width:0 0}.form-floating>.form-control:disabled~label,.form-floating>:disabled~label{color:#919aa1}.form-floating>.form-control:disabled~label::after,.form-floating>:disabled~label::after{background-color:#eceeef}.input-group{position:relative;display:flex;flex-wrap:wrap;align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-floating,.input-group>.form-select{position:relative;flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-floating:focus-within,.input-group>.form-select:focus{z-index:5}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:5}.input-group-text{display:flex;align-items:center;padding:.75rem 1.5rem;font-size:1rem;font-weight:300;line-height:1.5;color:var(--bs-body-color);text-align:center;white-space:nowrap;background-color:#eceeef;border:0 solid var(--bs-border-color)}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{padding:2rem 2rem;font-size:1.25rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{padding:.5rem 1rem;font-size:.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:6rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:calc(0 * -1)}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-valid-color)}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-success)}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{border-color:var(--bs-form-valid-border-color);padding-right:calc(1.5em + 1.5rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%234bbf73' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .375rem) center;background-size:calc(.75em + .75rem) calc(.75em + .75rem)}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 1.5rem);background-position:top calc(.375em + .375rem) right calc(.375em + .375rem)}.form-select.is-valid,.was-validated .form-select:valid{border-color:var(--bs-form-valid-border-color)}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%234bbf73' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");padding-right:8.25rem;background-position:right 1.5rem center,center right 4.5rem;background-size:16px 12px,calc(.75em + .75rem) calc(.75em + .75rem)}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:var(--bs-form-valid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-control-color.is-valid,.was-validated .form-control-color:valid{width:calc(3rem + calc(1.5em + 1.5rem))}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:var(--bs-form-valid-border-color)}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:var(--bs-form-valid-color)}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-success-rgb),.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:var(--bs-form-valid-color)}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-valid,.input-group>.form-floating:not(:focus-within).is-valid,.input-group>.form-select:not(:focus).is-valid,.was-validated .input-group>.form-control:not(:focus):valid,.was-validated .input-group>.form-floating:not(:focus-within):valid,.was-validated .input-group>.form-select:not(:focus):valid{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:.875em;color:var(--bs-form-invalid-color)}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:.875rem;color:#fff;background-color:var(--bs-danger)}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{border-color:var(--bs-form-invalid-border-color);padding-right:calc(1.5em + 1.5rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23d9534f'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23d9534f' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(.375em + .375rem) center;background-size:calc(.75em + .75rem) calc(.75em + .75rem)}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 1.5rem);background-position:top calc(.375em + .375rem) right calc(.375em + .375rem)}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:var(--bs-form-invalid-border-color)}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{--bs-form-select-bg-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23d9534f'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23d9534f' stroke='none'/%3e%3c/svg%3e");padding-right:8.25rem;background-position:right 1.5rem center,center right 4.5rem;background-size:16px 12px,calc(.75em + .75rem) calc(.75em + .75rem)}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:var(--bs-form-invalid-border-color);box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-control-color.is-invalid,.was-validated .form-control-color:invalid{width:calc(3rem + calc(1.5em + 1.5rem))}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:var(--bs-form-invalid-border-color)}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:var(--bs-form-invalid-color)}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 .25rem rgba(var(--bs-danger-rgb),.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:var(--bs-form-invalid-color)}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group>.form-control:not(:focus).is-invalid,.input-group>.form-floating:not(:focus-within).is-invalid,.input-group>.form-select:not(:focus).is-invalid,.was-validated .input-group>.form-control:not(:focus):invalid,.was-validated .input-group>.form-floating:not(:focus-within):invalid,.was-validated .input-group>.form-select:not(:focus):invalid{z-index:4}.btn{--bs-btn-padding-x:1.5rem;--bs-btn-padding-y:0.75rem;--bs-btn-font-family: ;--bs-btn-font-size:1rem;--bs-btn-font-weight:600;--bs-btn-line-height:1.5rem;--bs-btn-color:var(--bs-body-color);--bs-btn-bg:transparent;--bs-btn-border-width:0;--bs-btn-border-color:transparent;--bs-btn-border-radius:var(--bs-border-radius);--bs-btn-hover-border-color:transparent;--bs-btn-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.15),0 1px 1px rgba(0, 0, 0, 0.075);--bs-btn-disabled-opacity:0.65;--bs-btn-focus-box-shadow:0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);display:inline-block;padding:var(--bs-btn-padding-y) var(--bs-btn-padding-x);font-family:var(--bs-btn-font-family);font-size:var(--bs-btn-font-size);font-weight:var(--bs-btn-font-weight);line-height:var(--bs-btn-line-height);color:var(--bs-btn-color);text-align:center;text-decoration:none;vertical-align:middle;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;border:var(--bs-btn-border-width) solid var(--bs-btn-border-color);background-color:var(--bs-btn-bg);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color)}.btn-check+.btn:hover{color:var(--bs-btn-color);background-color:var(--bs-btn-bg);border-color:var(--bs-btn-border-color)}.btn:focus-visible{color:var(--bs-btn-hover-color);background-color:var(--bs-btn-hover-bg);border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:focus-visible+.btn{border-color:var(--bs-btn-hover-border-color);outline:0;box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked+.btn,.btn.active,.btn.show,.btn:first-child:active,:not(.btn-check)+.btn:active{color:var(--bs-btn-active-color);background-color:var(--bs-btn-active-bg);border-color:var(--bs-btn-active-border-color)}.btn-check:checked+.btn:focus-visible,.btn.active:focus-visible,.btn.show:focus-visible,.btn:first-child:active:focus-visible,:not(.btn-check)+.btn:active:focus-visible{box-shadow:var(--bs-btn-focus-box-shadow)}.btn-check:checked:focus-visible+.btn{box-shadow:var(--bs-btn-focus-box-shadow)}.btn.disabled,.btn:disabled,fieldset:disabled .btn{color:var(--bs-btn-disabled-color);pointer-events:none;background-color:var(--bs-btn-disabled-bg);border-color:var(--bs-btn-disabled-border-color);opacity:var(--bs-btn-disabled-opacity)}.btn-primary{--bs-btn-color:#fff;--bs-btn-bg:#1a1a1a;--bs-btn-border-color:#1a1a1a;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#161616;--bs-btn-hover-border-color:#151515;--bs-btn-focus-shadow-rgb:60,60,60;--bs-btn-active-color:#fff;--bs-btn-active-bg:#151515;--bs-btn-active-border-color:#141414;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#1a1a1a;--bs-btn-disabled-border-color:#1a1a1a}.btn-secondary{--bs-btn-color:#000;--bs-btn-bg:#fff;--bs-btn-border-color:#fff;--bs-btn-hover-color:#000;--bs-btn-hover-bg:white;--bs-btn-hover-border-color:white;--bs-btn-focus-shadow-rgb:217,217,217;--bs-btn-active-color:#000;--bs-btn-active-bg:white;--bs-btn-active-border-color:white;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#fff;--bs-btn-disabled-border-color:#fff}.btn-success{--bs-btn-color:#fff;--bs-btn-bg:#4bbf73;--bs-btn-border-color:#4bbf73;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#40a262;--bs-btn-hover-border-color:#3c995c;--bs-btn-focus-shadow-rgb:102,201,136;--bs-btn-active-color:#fff;--bs-btn-active-bg:#3c995c;--bs-btn-active-border-color:#388f56;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#4bbf73;--bs-btn-disabled-border-color:#4bbf73}.btn-info{--bs-btn-color:#fff;--bs-btn-bg:#1f9bcf;--bs-btn-border-color:#1f9bcf;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#1a84b0;--bs-btn-hover-border-color:#197ca6;--bs-btn-focus-shadow-rgb:65,170,214;--bs-btn-active-color:#fff;--bs-btn-active-bg:#197ca6;--bs-btn-active-border-color:#17749b;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#1f9bcf;--bs-btn-disabled-border-color:#1f9bcf}.btn-warning{--bs-btn-color:#000;--bs-btn-bg:#f0ad4e;--bs-btn-border-color:#f0ad4e;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f2b969;--bs-btn-hover-border-color:#f2b560;--bs-btn-focus-shadow-rgb:204,147,66;--bs-btn-active-color:#000;--bs-btn-active-bg:#f3bd71;--bs-btn-active-border-color:#f2b560;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#f0ad4e;--bs-btn-disabled-border-color:#f0ad4e}.btn-danger{--bs-btn-color:#fff;--bs-btn-bg:#d9534f;--bs-btn-border-color:#d9534f;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#b84743;--bs-btn-hover-border-color:#ae423f;--bs-btn-focus-shadow-rgb:223,109,105;--bs-btn-active-color:#fff;--bs-btn-active-bg:#ae423f;--bs-btn-active-border-color:#a33e3b;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#d9534f;--bs-btn-disabled-border-color:#d9534f}.btn-light{--bs-btn-color:#000;--bs-btn-bg:#fff;--bs-btn-border-color:#fff;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#d9d9d9;--bs-btn-hover-border-color:#cccccc;--bs-btn-focus-shadow-rgb:217,217,217;--bs-btn-active-color:#000;--bs-btn-active-bg:#cccccc;--bs-btn-active-border-color:#bfbfbf;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#000;--bs-btn-disabled-bg:#fff;--bs-btn-disabled-border-color:#fff}.btn-dark{--bs-btn-color:#fff;--bs-btn-bg:#343a40;--bs-btn-border-color:#343a40;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#52585d;--bs-btn-hover-border-color:#484e53;--bs-btn-focus-shadow-rgb:82,88,93;--bs-btn-active-color:#fff;--bs-btn-active-bg:#5d6166;--bs-btn-active-border-color:#484e53;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:#343a40;--bs-btn-disabled-border-color:#343a40}.btn-outline-primary{--bs-btn-color:#1a1a1a;--bs-btn-border-color:#1a1a1a;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#1a1a1a;--bs-btn-hover-border-color:#1a1a1a;--bs-btn-focus-shadow-rgb:26,26,26;--bs-btn-active-color:#fff;--bs-btn-active-bg:#1a1a1a;--bs-btn-active-border-color:#1a1a1a;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#1a1a1a;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#1a1a1a;--bs-gradient:none}.btn-outline-secondary{--bs-btn-color:#fff;--bs-btn-border-color:#fff;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#fff;--bs-btn-hover-border-color:#fff;--bs-btn-focus-shadow-rgb:255,255,255;--bs-btn-active-color:#000;--bs-btn-active-bg:#fff;--bs-btn-active-border-color:#fff;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#fff;--bs-gradient:none}.btn-outline-success{--bs-btn-color:#4bbf73;--bs-btn-border-color:#4bbf73;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#4bbf73;--bs-btn-hover-border-color:#4bbf73;--bs-btn-focus-shadow-rgb:75,191,115;--bs-btn-active-color:#fff;--bs-btn-active-bg:#4bbf73;--bs-btn-active-border-color:#4bbf73;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#4bbf73;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#4bbf73;--bs-gradient:none}.btn-outline-info{--bs-btn-color:#1f9bcf;--bs-btn-border-color:#1f9bcf;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#1f9bcf;--bs-btn-hover-border-color:#1f9bcf;--bs-btn-focus-shadow-rgb:31,155,207;--bs-btn-active-color:#fff;--bs-btn-active-bg:#1f9bcf;--bs-btn-active-border-color:#1f9bcf;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#1f9bcf;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#1f9bcf;--bs-gradient:none}.btn-outline-warning{--bs-btn-color:#f0ad4e;--bs-btn-border-color:#f0ad4e;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#f0ad4e;--bs-btn-hover-border-color:#f0ad4e;--bs-btn-focus-shadow-rgb:240,173,78;--bs-btn-active-color:#000;--bs-btn-active-bg:#f0ad4e;--bs-btn-active-border-color:#f0ad4e;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#f0ad4e;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#f0ad4e;--bs-gradient:none}.btn-outline-danger{--bs-btn-color:#d9534f;--bs-btn-border-color:#d9534f;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#d9534f;--bs-btn-hover-border-color:#d9534f;--bs-btn-focus-shadow-rgb:217,83,79;--bs-btn-active-color:#fff;--bs-btn-active-bg:#d9534f;--bs-btn-active-border-color:#d9534f;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#d9534f;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#d9534f;--bs-gradient:none}.btn-outline-light{--bs-btn-color:#fff;--bs-btn-border-color:#fff;--bs-btn-hover-color:#000;--bs-btn-hover-bg:#fff;--bs-btn-hover-border-color:#fff;--bs-btn-focus-shadow-rgb:255,255,255;--bs-btn-active-color:#000;--bs-btn-active-bg:#fff;--bs-btn-active-border-color:#fff;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#fff;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#fff;--bs-gradient:none}.btn-outline-dark{--bs-btn-color:#343a40;--bs-btn-border-color:#343a40;--bs-btn-hover-color:#fff;--bs-btn-hover-bg:#343a40;--bs-btn-hover-border-color:#343a40;--bs-btn-focus-shadow-rgb:52,58,64;--bs-btn-active-color:#fff;--bs-btn-active-bg:#343a40;--bs-btn-active-border-color:#343a40;--bs-btn-active-shadow:inset 0 3px 5px rgba(0, 0, 0, 0.125);--bs-btn-disabled-color:#343a40;--bs-btn-disabled-bg:transparent;--bs-btn-disabled-border-color:#343a40;--bs-gradient:none}.btn-link{--bs-btn-font-weight:300;--bs-btn-color:var(--bs-link-color);--bs-btn-bg:transparent;--bs-btn-border-color:transparent;--bs-btn-hover-color:var(--bs-link-hover-color);--bs-btn-hover-border-color:transparent;--bs-btn-active-color:var(--bs-link-hover-color);--bs-btn-active-border-color:transparent;--bs-btn-disabled-color:#919aa1;--bs-btn-disabled-border-color:transparent;--bs-btn-box-shadow:0 0 0 #000;--bs-btn-focus-shadow-rgb:60,60,60;text-decoration:underline}.btn-link:focus-visible{color:var(--bs-btn-color)}.btn-link:hover{color:var(--bs-btn-hover-color)}.btn-group-lg>.btn,.btn-lg{--bs-btn-padding-y:2rem;--bs-btn-padding-x:2rem;--bs-btn-font-size:1.25rem;--bs-btn-border-radius:var(--bs-border-radius-lg)}.btn-group-sm>.btn,.btn-sm{--bs-btn-padding-y:0.5rem;--bs-btn-padding-x:1rem;--bs-btn-font-size:0.875rem;--bs-btn-border-radius:var(--bs-border-radius-sm)}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media (prefers-reduced-motion:reduce){.collapsing.collapse-horizontal{transition:none}}.dropdown,.dropdown-center,.dropend,.dropstart,.dropup,.dropup-center{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid transparent;border-bottom:0;border-left:.3em solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{--bs-dropdown-zindex:1000;--bs-dropdown-min-width:10rem;--bs-dropdown-padding-x:0;--bs-dropdown-padding-y:0.5rem;--bs-dropdown-spacer:0.125rem;--bs-dropdown-font-size:1rem;--bs-dropdown-color:var(--bs-body-color);--bs-dropdown-bg:var(--bs-body-bg);--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-border-radius:var(--bs-border-radius);--bs-dropdown-border-width:var(--bs-border-width);--bs-dropdown-inner-border-radius:calc(var(--bs-border-radius) - var(--bs-border-width));--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-divider-margin-y:0.5rem;--bs-dropdown-box-shadow:var(--bs-box-shadow);--bs-dropdown-link-color:var(--bs-body-color);--bs-dropdown-link-hover-color:var(--bs-body-color);--bs-dropdown-link-hover-bg:var(--bs-tertiary-bg);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#1a1a1a;--bs-dropdown-link-disabled-color:var(--bs-tertiary-color);--bs-dropdown-item-padding-x:1rem;--bs-dropdown-item-padding-y:0.25rem;--bs-dropdown-header-color:#919aa1;--bs-dropdown-header-padding-x:1rem;--bs-dropdown-header-padding-y:0.5rem;position:absolute;z-index:var(--bs-dropdown-zindex);display:none;min-width:var(--bs-dropdown-min-width);padding:var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);margin:0;font-size:var(--bs-dropdown-font-size);color:var(--bs-dropdown-color);text-align:left;list-style:none;background-color:var(--bs-dropdown-bg);background-clip:padding-box;border:var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:var(--bs-dropdown-spacer)}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:var(--bs-dropdown-spacer)}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid transparent;border-bottom:.3em solid;border-left:.3em solid transparent}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:var(--bs-dropdown-spacer)}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:0;border-bottom:.3em solid transparent;border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:var(--bs-dropdown-spacer)}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid transparent;border-right:.3em solid;border-bottom:.3em solid transparent}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:var(--bs-dropdown-divider-margin-y) 0;overflow:hidden;border-top:1px solid var(--bs-dropdown-divider-bg);opacity:1}.dropdown-item{display:block;width:100%;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);clear:both;font-weight:300;color:var(--bs-dropdown-link-color);text-align:inherit;text-decoration:none;white-space:nowrap;background-color:transparent;border:0}.dropdown-item:focus,.dropdown-item:hover{color:var(--bs-dropdown-link-hover-color);background-color:var(--bs-dropdown-link-hover-bg)}.dropdown-item.active,.dropdown-item:active{color:var(--bs-dropdown-link-active-color);text-decoration:none;background-color:var(--bs-dropdown-link-active-bg)}.dropdown-item.disabled,.dropdown-item:disabled{color:var(--bs-dropdown-link-disabled-color);pointer-events:none;background-color:transparent}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:var(--bs-dropdown-header-padding-y) var(--bs-dropdown-header-padding-x);margin-bottom:0;font-size:.875rem;color:var(--bs-dropdown-header-color);white-space:nowrap}.dropdown-item-text{display:block;padding:var(--bs-dropdown-item-padding-y) var(--bs-dropdown-item-padding-x);color:var(--bs-dropdown-link-color)}.dropdown-menu-dark{--bs-dropdown-color:#eceeef;--bs-dropdown-bg:#343a40;--bs-dropdown-border-color:var(--bs-border-color-translucent);--bs-dropdown-box-shadow: ;--bs-dropdown-link-color:#eceeef;--bs-dropdown-link-hover-color:#fff;--bs-dropdown-divider-bg:var(--bs-border-color-translucent);--bs-dropdown-link-hover-bg:rgba(255, 255, 255, 0.15);--bs-dropdown-link-active-color:#fff;--bs-dropdown-link-active-bg:#1a1a1a;--bs-dropdown-link-disabled-color:#adb5bd;--bs-dropdown-header-color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex:1 1 auto}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>:not(.btn-check:first-child)+.btn{margin-left:calc(0 * -1)}.dropdown-toggle-split{padding-right:1.125rem;padding-left:1.125rem}.dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:1.5rem;padding-left:1.5rem}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:calc(0 * -1)}.nav{--bs-nav-link-padding-x:1rem;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-link-color);--bs-nav-link-hover-color:var(--bs-link-hover-color);--bs-nav-link-disabled-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:var(--bs-nav-link-padding-y) var(--bs-nav-link-padding-x);font-size:var(--bs-nav-link-font-size);font-weight:var(--bs-nav-link-font-weight);color:var(--bs-nav-link-color);text-decoration:none;background:0 0;border:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:var(--bs-nav-link-hover-color)}.nav-link:focus-visible{outline:0;box-shadow:0 0 0 .25rem rgba(26,26,26,.25)}.nav-link.disabled,.nav-link:disabled{color:var(--bs-nav-link-disabled-color);pointer-events:none;cursor:default}.nav-tabs{--bs-nav-tabs-border-width:var(--bs-border-width);--bs-nav-tabs-border-color:var(--bs-border-color);--bs-nav-tabs-border-radius:var(--bs-border-radius);--bs-nav-tabs-link-hover-border-color:var(--bs-secondary-bg) var(--bs-secondary-bg) var(--bs-border-color);--bs-nav-tabs-link-active-color:var(--bs-emphasis-color);--bs-nav-tabs-link-active-bg:var(--bs-body-bg);--bs-nav-tabs-link-active-border-color:var(--bs-border-color) var(--bs-border-color) var(--bs-body-bg);border-bottom:var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color)}.nav-tabs .nav-link{margin-bottom:calc(-1 * var(--bs-nav-tabs-border-width));border:var(--bs-nav-tabs-border-width) solid transparent}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{isolation:isolate;border-color:var(--bs-nav-tabs-link-hover-border-color)}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:var(--bs-nav-tabs-link-active-color);background-color:var(--bs-nav-tabs-link-active-bg);border-color:var(--bs-nav-tabs-link-active-border-color)}.nav-tabs .dropdown-menu{margin-top:calc(-1 * var(--bs-nav-tabs-border-width))}.nav-pills{--bs-nav-pills-border-radius:var(--bs-border-radius);--bs-nav-pills-link-active-color:#fff;--bs-nav-pills-link-active-bg:#1a1a1a}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}.nav-underline{--bs-nav-underline-gap:1rem;--bs-nav-underline-border-width:0.125rem;--bs-nav-underline-link-active-color:var(--bs-emphasis-color);gap:var(--bs-nav-underline-gap)}.nav-underline .nav-link{padding-right:0;padding-left:0;border-bottom:var(--bs-nav-underline-border-width) solid transparent}.nav-underline .nav-link:focus,.nav-underline .nav-link:hover{border-bottom-color:currentcolor}.nav-underline .nav-link.active,.nav-underline .show>.nav-link{font-weight:600;color:var(--bs-nav-underline-link-active-color);border-bottom-color:currentcolor}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{--bs-navbar-padding-x:0;--bs-navbar-padding-y:1.5rem;--bs-navbar-color:rgba(0, 0, 0, 0.3);--bs-navbar-hover-color:#1a1a1a;--bs-navbar-disabled-color:rgba(var(--bs-emphasis-color-rgb), 0.3);--bs-navbar-active-color:#1a1a1a;--bs-navbar-brand-padding-y:0.3125rem;--bs-navbar-brand-margin-end:1rem;--bs-navbar-brand-font-size:1.25rem;--bs-navbar-brand-color:#1a1a1a;--bs-navbar-brand-hover-color:#1a1a1a;--bs-navbar-nav-link-padding-x:0.5rem;--bs-navbar-toggler-padding-y:0.25rem;--bs-navbar-toggler-padding-x:0.75rem;--bs-navbar-toggler-font-size:1.25rem;--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%2885, 89, 92, 0.75%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");--bs-navbar-toggler-border-color:rgba(var(--bs-emphasis-color-rgb), 0.15);--bs-navbar-toggler-border-radius:var(--bs-border-radius);--bs-navbar-toggler-focus-width:0.25rem;--bs-navbar-toggler-transition:box-shadow 0.15s ease-in-out;position:relative;display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between;padding:var(--bs-navbar-padding-y) var(--bs-navbar-padding-x)}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{display:flex;flex-wrap:inherit;align-items:center;justify-content:space-between}.navbar-brand{padding-top:var(--bs-navbar-brand-padding-y);padding-bottom:var(--bs-navbar-brand-padding-y);margin-right:var(--bs-navbar-brand-margin-end);font-size:var(--bs-navbar-brand-font-size);color:var(--bs-navbar-brand-color);text-decoration:none;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{color:var(--bs-navbar-brand-hover-color)}.navbar-nav{--bs-nav-link-padding-x:0;--bs-nav-link-padding-y:0.5rem;--bs-nav-link-font-weight: ;--bs-nav-link-color:var(--bs-navbar-color);--bs-nav-link-hover-color:var(--bs-navbar-hover-color);--bs-nav-link-disabled-color:var(--bs-navbar-disabled-color);display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link.active,.navbar-nav .nav-link.show{color:var(--bs-navbar-active-color)}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem;color:var(--bs-navbar-color)}.navbar-text a,.navbar-text a:focus,.navbar-text a:hover{color:var(--bs-navbar-active-color)}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:var(--bs-navbar-toggler-padding-y) var(--bs-navbar-toggler-padding-x);font-size:var(--bs-navbar-toggler-font-size);line-height:1;color:var(--bs-navbar-color);background-color:transparent;border:var(--bs-border-width) solid var(--bs-navbar-toggler-border-color);transition:var(--bs-navbar-toggler-transition)}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 var(--bs-navbar-toggler-focus-width)}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-image:var(--bs-navbar-toggler-icon-bg);background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-sm .offcanvas .offcanvas-header{display:none}.navbar-expand-sm .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-md .offcanvas .offcanvas-header{display:none}.navbar-expand-md .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-lg .offcanvas .offcanvas-header{display:none}.navbar-expand-lg .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xl .offcanvas .offcanvas-header{display:none}.navbar-expand-xl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand-xxl .offcanvas .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:var(--bs-navbar-nav-link-padding-x);padding-left:var(--bs-navbar-nav-link-padding-x)}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas{position:static;z-index:auto;flex-grow:1;width:auto!important;height:auto!important;visibility:visible!important;background-color:transparent!important;border:0!important;transform:none!important;transition:none}.navbar-expand .offcanvas .offcanvas-header{display:none}.navbar-expand .offcanvas .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible}.navbar-dark,.navbar[data-bs-theme=dark]{--bs-navbar-color:rgba(255, 255, 255, 0.55);--bs-navbar-hover-color:#fff;--bs-navbar-disabled-color:rgba(255, 255, 255, 0.25);--bs-navbar-active-color:#fff;--bs-navbar-brand-color:#fff;--bs-navbar-brand-hover-color:#fff;--bs-navbar-toggler-border-color:rgba(255, 255, 255, 0.1);--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}[data-bs-theme=dark] .navbar-toggler-icon{--bs-navbar-toggler-icon-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.card{--bs-card-spacer-y:1rem;--bs-card-spacer-x:1rem;--bs-card-title-spacer-y:0.5rem;--bs-card-title-color: ;--bs-card-subtitle-color: ;--bs-card-border-width:var(--bs-border-width);--bs-card-border-color:var(--bs-border-color-translucent);--bs-card-border-radius:var(--bs-border-radius);--bs-card-box-shadow: ;--bs-card-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-card-cap-padding-y:0.5rem;--bs-card-cap-padding-x:1rem;--bs-card-cap-bg:rgba(var(--bs-body-color-rgb), 0.03);--bs-card-cap-color: ;--bs-card-height: ;--bs-card-color: ;--bs-card-bg:var(--bs-body-bg);--bs-card-img-overlay-padding:1rem;--bs-card-group-margin:0.75rem;position:relative;display:flex;flex-direction:column;min-width:0;height:var(--bs-card-height);color:var(--bs-body-color);word-wrap:break-word;background-color:var(--bs-card-bg);background-clip:border-box;border:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:var(--bs-card-spacer-y) var(--bs-card-spacer-x);color:var(--bs-card-color)}.card-title{margin-bottom:var(--bs-card-title-spacer-y);color:var(--bs-card-title-color)}.card-subtitle{margin-top:calc(-.5 * var(--bs-card-title-spacer-y));margin-bottom:0;color:var(--bs-card-subtitle-color)}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:var(--bs-card-spacer-x)}.card-header{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);margin-bottom:0;color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-bottom:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-footer{padding:var(--bs-card-cap-padding-y) var(--bs-card-cap-padding-x);color:var(--bs-card-cap-color);background-color:var(--bs-card-cap-bg);border-top:var(--bs-card-border-width) solid var(--bs-card-border-color)}.card-header-tabs{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-bottom:calc(-1 * var(--bs-card-cap-padding-y));margin-left:calc(-.5 * var(--bs-card-cap-padding-x));border-bottom:0}.card-header-tabs .nav-link.active{background-color:var(--bs-card-bg);border-bottom-color:var(--bs-card-bg)}.card-header-pills{margin-right:calc(-.5 * var(--bs-card-cap-padding-x));margin-left:calc(-.5 * var(--bs-card-cap-padding-x))}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:var(--bs-card-img-overlay-padding)}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-group>.card{margin-bottom:var(--bs-card-group-margin)}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion{--bs-accordion-color:var(--bs-body-color);--bs-accordion-bg:var(--bs-body-bg);--bs-accordion-transition:color 0.15s ease-in-out,background-color 0.15s ease-in-out,border-color 0.15s ease-in-out,box-shadow 0.15s ease-in-out,border-radius 0.15s ease;--bs-accordion-border-color:var(--bs-border-color);--bs-accordion-border-width:var(--bs-border-width);--bs-accordion-border-radius:var(--bs-border-radius);--bs-accordion-inner-border-radius:calc(var(--bs-border-radius) - (var(--bs-border-width)));--bs-accordion-btn-padding-x:1.25rem;--bs-accordion-btn-padding-y:1rem;--bs-accordion-btn-color:var(--bs-body-color);--bs-accordion-btn-bg:var(--bs-accordion-bg);--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%2355595c' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-icon-width:1.25rem;--bs-accordion-btn-icon-transform:rotate(-180deg);--bs-accordion-btn-icon-transition:transform 0.2s ease-in-out;--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%230a0a0a' stroke-linecap='round' stroke-linejoin='round'%3e%3cpath d='M2 5L8 11L14 5'/%3e%3c/svg%3e");--bs-accordion-btn-focus-box-shadow:0 0 0 0.25rem rgba(26, 26, 26, 0.25);--bs-accordion-body-padding-x:1.25rem;--bs-accordion-body-padding-y:1rem;--bs-accordion-active-color:var(--bs-primary-text-emphasis);--bs-accordion-active-bg:var(--bs-primary-bg-subtle)}.accordion-button{position:relative;display:flex;align-items:center;width:100%;padding:var(--bs-accordion-btn-padding-y) var(--bs-accordion-btn-padding-x);font-size:1rem;color:var(--bs-accordion-btn-color);text-align:left;background-color:var(--bs-accordion-btn-bg);border:0;overflow-anchor:none;transition:var(--bs-accordion-transition)}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:var(--bs-accordion-active-color);background-color:var(--bs-accordion-active-bg);box-shadow:inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color)}.accordion-button:not(.collapsed)::after{background-image:var(--bs-accordion-btn-active-icon);transform:var(--bs-accordion-btn-icon-transform)}.accordion-button::after{flex-shrink:0;width:var(--bs-accordion-btn-icon-width);height:var(--bs-accordion-btn-icon-width);margin-left:auto;content:"";background-image:var(--bs-accordion-btn-icon);background-repeat:no-repeat;background-size:var(--bs-accordion-btn-icon-width);transition:var(--bs-accordion-btn-icon-transition)}@media (prefers-reduced-motion:reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;outline:0;box-shadow:var(--bs-accordion-btn-focus-box-shadow)}.accordion-header{margin-bottom:0}.accordion-item{color:var(--bs-accordion-color);background-color:var(--bs-accordion-bg);border:var(--bs-accordion-border-width) solid var(--bs-accordion-border-color)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:var(--bs-accordion-body-padding-y) var(--bs-accordion-body-padding-x)}.accordion-flush>.accordion-item{border-right:0;border-left:0}.accordion-flush>.accordion-item:first-child{border-top:0}.accordion-flush>.accordion-item:last-child{border-bottom:0}[data-bs-theme=dark] .accordion-button::after{--bs-accordion-btn-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23767676'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");--bs-accordion-btn-active-icon:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23767676'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.breadcrumb{--bs-breadcrumb-padding-x:0;--bs-breadcrumb-padding-y:0;--bs-breadcrumb-margin-bottom:1rem;--bs-breadcrumb-bg: ;--bs-breadcrumb-border-radius: ;--bs-breadcrumb-divider-color:var(--bs-secondary-color);--bs-breadcrumb-item-padding-x:0.5rem;--bs-breadcrumb-item-active-color:var(--bs-secondary-color);display:flex;flex-wrap:wrap;padding:var(--bs-breadcrumb-padding-y) var(--bs-breadcrumb-padding-x);margin-bottom:var(--bs-breadcrumb-margin-bottom);font-size:var(--bs-breadcrumb-font-size);list-style:none;background-color:var(--bs-breadcrumb-bg)}.breadcrumb-item+.breadcrumb-item{padding-left:var(--bs-breadcrumb-item-padding-x)}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:var(--bs-breadcrumb-item-padding-x);color:var(--bs-breadcrumb-divider-color);content:var(--bs-breadcrumb-divider, "/")}.breadcrumb-item.active{color:var(--bs-breadcrumb-item-active-color)}.pagination{--bs-pagination-padding-x:0.75rem;--bs-pagination-padding-y:0.375rem;--bs-pagination-font-size:1rem;--bs-pagination-color:var(--bs-link-color);--bs-pagination-bg:var(--bs-body-bg);--bs-pagination-border-width:var(--bs-border-width);--bs-pagination-border-color:transparent;--bs-pagination-border-radius:var(--bs-border-radius);--bs-pagination-hover-color:var(--bs-link-hover-color);--bs-pagination-hover-bg:var(--bs-tertiary-bg);--bs-pagination-hover-border-color:transparent;--bs-pagination-focus-color:var(--bs-link-hover-color);--bs-pagination-focus-bg:var(--bs-secondary-bg);--bs-pagination-focus-box-shadow:0 0 0 0.25rem rgba(26, 26, 26, 0.25);--bs-pagination-active-color:#fff;--bs-pagination-active-bg:#1a1a1a;--bs-pagination-active-border-color:#1a1a1a;--bs-pagination-disabled-color:var(--bs-secondary-color);--bs-pagination-disabled-bg:var(--bs-secondary-bg);--bs-pagination-disabled-border-color:transparent;display:flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:var(--bs-pagination-padding-y) var(--bs-pagination-padding-x);font-size:var(--bs-pagination-font-size);color:var(--bs-pagination-color);text-decoration:none;background-color:var(--bs-pagination-bg);border:var(--bs-pagination-border-width) solid var(--bs-pagination-border-color);transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:var(--bs-pagination-hover-color);background-color:var(--bs-pagination-hover-bg);border-color:var(--bs-pagination-hover-border-color)}.page-link:focus{z-index:3;color:var(--bs-pagination-focus-color);background-color:var(--bs-pagination-focus-bg);outline:0;box-shadow:var(--bs-pagination-focus-box-shadow)}.active>.page-link,.page-link.active{z-index:3;color:var(--bs-pagination-active-color);background-color:var(--bs-pagination-active-bg);border-color:var(--bs-pagination-active-border-color)}.disabled>.page-link,.page-link.disabled{color:var(--bs-pagination-disabled-color);pointer-events:none;background-color:var(--bs-pagination-disabled-bg);border-color:var(--bs-pagination-disabled-border-color)}.page-item:not(:first-child) .page-link{margin-left:calc(var(--bs-border-width) * -1)}.pagination-lg{--bs-pagination-padding-x:1.5rem;--bs-pagination-padding-y:0.75rem;--bs-pagination-font-size:1.25rem;--bs-pagination-border-radius:var(--bs-border-radius-lg)}.pagination-sm{--bs-pagination-padding-x:0.5rem;--bs-pagination-padding-y:0.25rem;--bs-pagination-font-size:0.875rem;--bs-pagination-border-radius:var(--bs-border-radius-sm)}.badge{--bs-badge-padding-x:0.65em;--bs-badge-padding-y:0.35em;--bs-badge-font-size:0.75em;--bs-badge-font-weight:600;--bs-badge-color:#fff;--bs-badge-border-radius:var(--bs-border-radius);display:inline-block;padding:var(--bs-badge-padding-y) var(--bs-badge-padding-x);font-size:var(--bs-badge-font-size);font-weight:var(--bs-badge-font-weight);line-height:1;color:var(--bs-badge-color);text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{--bs-alert-bg:transparent;--bs-alert-padding-x:1rem;--bs-alert-padding-y:1rem;--bs-alert-margin-bottom:1rem;--bs-alert-color:inherit;--bs-alert-border-color:transparent;--bs-alert-border:var(--bs-border-width) solid var(--bs-alert-border-color);--bs-alert-border-radius:var(--bs-border-radius);--bs-alert-link-color:inherit;position:relative;padding:var(--bs-alert-padding-y) var(--bs-alert-padding-x);margin-bottom:var(--bs-alert-margin-bottom);color:var(--bs-alert-color);background-color:var(--bs-alert-bg);border:var(--bs-alert-border)}.alert-heading{color:inherit}.alert-link{font-weight:600;color:var(--bs-alert-link-color)}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-primary{--bs-alert-color:var(--bs-primary-text-emphasis);--bs-alert-bg:var(--bs-primary-bg-subtle);--bs-alert-border-color:var(--bs-primary-border-subtle);--bs-alert-link-color:var(--bs-primary-text-emphasis)}.alert-secondary{--bs-alert-color:var(--bs-secondary-text-emphasis);--bs-alert-bg:var(--bs-secondary-bg-subtle);--bs-alert-border-color:var(--bs-secondary-border-subtle);--bs-alert-link-color:var(--bs-secondary-text-emphasis)}.alert-success{--bs-alert-color:var(--bs-success-text-emphasis);--bs-alert-bg:var(--bs-success-bg-subtle);--bs-alert-border-color:var(--bs-success-border-subtle);--bs-alert-link-color:var(--bs-success-text-emphasis)}.alert-info{--bs-alert-color:var(--bs-info-text-emphasis);--bs-alert-bg:var(--bs-info-bg-subtle);--bs-alert-border-color:var(--bs-info-border-subtle);--bs-alert-link-color:var(--bs-info-text-emphasis)}.alert-warning{--bs-alert-color:var(--bs-warning-text-emphasis);--bs-alert-bg:var(--bs-warning-bg-subtle);--bs-alert-border-color:var(--bs-warning-border-subtle);--bs-alert-link-color:var(--bs-warning-text-emphasis)}.alert-danger{--bs-alert-color:var(--bs-danger-text-emphasis);--bs-alert-bg:var(--bs-danger-bg-subtle);--bs-alert-border-color:var(--bs-danger-border-subtle);--bs-alert-link-color:var(--bs-danger-text-emphasis)}.alert-light{--bs-alert-color:var(--bs-light-text-emphasis);--bs-alert-bg:var(--bs-light-bg-subtle);--bs-alert-border-color:var(--bs-light-border-subtle);--bs-alert-link-color:var(--bs-light-text-emphasis)}.alert-dark{--bs-alert-color:var(--bs-dark-text-emphasis);--bs-alert-bg:var(--bs-dark-bg-subtle);--bs-alert-border-color:var(--bs-dark-border-subtle);--bs-alert-link-color:var(--bs-dark-text-emphasis)}@keyframes progress-bar-stripes{0%{background-position-x:1rem}}.progress,.progress-stacked{--bs-progress-height:1rem;--bs-progress-font-size:0.75rem;--bs-progress-bg:var(--bs-secondary-bg);--bs-progress-border-radius:var(--bs-border-radius);--bs-progress-box-shadow:var(--bs-box-shadow-inset);--bs-progress-bar-color:#fff;--bs-progress-bar-bg:#1a1a1a;--bs-progress-bar-transition:width 0.6s ease;display:flex;height:var(--bs-progress-height);overflow:hidden;font-size:var(--bs-progress-font-size);background-color:var(--bs-progress-bg)}.progress-bar{display:flex;flex-direction:column;justify-content:center;overflow:hidden;color:var(--bs-progress-bar-color);text-align:center;white-space:nowrap;background-color:var(--bs-progress-bar-bg);transition:var(--bs-progress-bar-transition)}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-size:var(--bs-progress-height) var(--bs-progress-height)}.progress-stacked>.progress{overflow:visible}.progress-stacked>.progress>.progress-bar{width:100%}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media (prefers-reduced-motion:reduce){.progress-bar-animated{animation:none}}.list-group{--bs-list-group-color:var(--bs-body-color);--bs-list-group-bg:var(--bs-body-bg);--bs-list-group-border-color:var(--bs-border-color);--bs-list-group-border-width:var(--bs-border-width);--bs-list-group-border-radius:var(--bs-border-radius);--bs-list-group-item-padding-x:1rem;--bs-list-group-item-padding-y:0.5rem;--bs-list-group-action-color:var(--bs-secondary-color);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-tertiary-bg);--bs-list-group-action-active-color:var(--bs-body-color);--bs-list-group-action-active-bg:var(--bs-secondary-bg);--bs-list-group-disabled-color:var(--bs-secondary-color);--bs-list-group-disabled-bg:var(--bs-body-bg);--bs-list-group-active-color:#fff;--bs-list-group-active-bg:#1a1a1a;--bs-list-group-active-border-color:#1a1a1a;display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>.list-group-item::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:var(--bs-list-group-action-color);text-align:inherit}.list-group-item-action:focus,.list-group-item-action:hover{z-index:1;color:var(--bs-list-group-action-hover-color);text-decoration:none;background-color:var(--bs-list-group-action-hover-bg)}.list-group-item-action:active{color:var(--bs-list-group-action-active-color);background-color:var(--bs-list-group-action-active-bg)}.list-group-item{position:relative;display:block;padding:var(--bs-list-group-item-padding-y) var(--bs-list-group-item-padding-x);color:var(--bs-list-group-color);text-decoration:none;background-color:var(--bs-list-group-bg);border:var(--bs-list-group-border-width) solid var(--bs-list-group-border-color)}.list-group-item.disabled,.list-group-item:disabled{color:var(--bs-list-group-disabled-color);pointer-events:none;background-color:var(--bs-list-group-disabled-bg)}.list-group-item.active{z-index:2;color:var(--bs-list-group-active-color);background-color:var(--bs-list-group-active-bg);border-color:var(--bs-list-group-active-border-color)}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:calc(-1 * var(--bs-list-group-border-width));border-top-width:var(--bs-list-group-border-width)}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:var(--bs-list-group-border-width);border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:calc(-1 * var(--bs-list-group-border-width));border-left-width:var(--bs-list-group-border-width)}}.list-group-flush>.list-group-item{border-width:0 0 var(--bs-list-group-border-width)}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{--bs-list-group-color:var(--bs-primary-text-emphasis);--bs-list-group-bg:var(--bs-primary-bg-subtle);--bs-list-group-border-color:var(--bs-primary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-primary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-primary-border-subtle);--bs-list-group-active-color:var(--bs-primary-bg-subtle);--bs-list-group-active-bg:var(--bs-primary-text-emphasis);--bs-list-group-active-border-color:var(--bs-primary-text-emphasis)}.list-group-item-secondary{--bs-list-group-color:var(--bs-secondary-text-emphasis);--bs-list-group-bg:var(--bs-secondary-bg-subtle);--bs-list-group-border-color:var(--bs-secondary-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-secondary-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-secondary-border-subtle);--bs-list-group-active-color:var(--bs-secondary-bg-subtle);--bs-list-group-active-bg:var(--bs-secondary-text-emphasis);--bs-list-group-active-border-color:var(--bs-secondary-text-emphasis)}.list-group-item-success{--bs-list-group-color:var(--bs-success-text-emphasis);--bs-list-group-bg:var(--bs-success-bg-subtle);--bs-list-group-border-color:var(--bs-success-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-success-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-success-border-subtle);--bs-list-group-active-color:var(--bs-success-bg-subtle);--bs-list-group-active-bg:var(--bs-success-text-emphasis);--bs-list-group-active-border-color:var(--bs-success-text-emphasis)}.list-group-item-info{--bs-list-group-color:var(--bs-info-text-emphasis);--bs-list-group-bg:var(--bs-info-bg-subtle);--bs-list-group-border-color:var(--bs-info-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-info-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-info-border-subtle);--bs-list-group-active-color:var(--bs-info-bg-subtle);--bs-list-group-active-bg:var(--bs-info-text-emphasis);--bs-list-group-active-border-color:var(--bs-info-text-emphasis)}.list-group-item-warning{--bs-list-group-color:var(--bs-warning-text-emphasis);--bs-list-group-bg:var(--bs-warning-bg-subtle);--bs-list-group-border-color:var(--bs-warning-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-warning-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-warning-border-subtle);--bs-list-group-active-color:var(--bs-warning-bg-subtle);--bs-list-group-active-bg:var(--bs-warning-text-emphasis);--bs-list-group-active-border-color:var(--bs-warning-text-emphasis)}.list-group-item-danger{--bs-list-group-color:var(--bs-danger-text-emphasis);--bs-list-group-bg:var(--bs-danger-bg-subtle);--bs-list-group-border-color:var(--bs-danger-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-danger-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-danger-border-subtle);--bs-list-group-active-color:var(--bs-danger-bg-subtle);--bs-list-group-active-bg:var(--bs-danger-text-emphasis);--bs-list-group-active-border-color:var(--bs-danger-text-emphasis)}.list-group-item-light{--bs-list-group-color:var(--bs-light-text-emphasis);--bs-list-group-bg:var(--bs-light-bg-subtle);--bs-list-group-border-color:var(--bs-light-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-light-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-light-border-subtle);--bs-list-group-active-color:var(--bs-light-bg-subtle);--bs-list-group-active-bg:var(--bs-light-text-emphasis);--bs-list-group-active-border-color:var(--bs-light-text-emphasis)}.list-group-item-dark{--bs-list-group-color:var(--bs-dark-text-emphasis);--bs-list-group-bg:var(--bs-dark-bg-subtle);--bs-list-group-border-color:var(--bs-dark-border-subtle);--bs-list-group-action-hover-color:var(--bs-emphasis-color);--bs-list-group-action-hover-bg:var(--bs-dark-border-subtle);--bs-list-group-action-active-color:var(--bs-emphasis-color);--bs-list-group-action-active-bg:var(--bs-dark-border-subtle);--bs-list-group-active-color:var(--bs-dark-bg-subtle);--bs-list-group-active-bg:var(--bs-dark-text-emphasis);--bs-list-group-active-border-color:var(--bs-dark-text-emphasis)}.btn-close{--bs-btn-close-color:#000;--bs-btn-close-bg:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3e%3c/svg%3e");--bs-btn-close-opacity:0.5;--bs-btn-close-hover-opacity:0.75;--bs-btn-close-focus-shadow:0 0 0 0.25rem rgba(26, 26, 26, 0.25);--bs-btn-close-focus-opacity:1;--bs-btn-close-disabled-opacity:0.25;--bs-btn-close-white-filter:invert(1) grayscale(100%) brightness(200%);box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:var(--bs-btn-close-color);background:transparent var(--bs-btn-close-bg) center/1em auto no-repeat;border:0;opacity:var(--bs-btn-close-opacity)}.btn-close:hover{color:var(--bs-btn-close-color);text-decoration:none;opacity:var(--bs-btn-close-hover-opacity)}.btn-close:focus{outline:0;box-shadow:var(--bs-btn-close-focus-shadow);opacity:var(--bs-btn-close-focus-opacity)}.btn-close.disabled,.btn-close:disabled{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;opacity:var(--bs-btn-close-disabled-opacity)}.btn-close-white{filter:var(--bs-btn-close-white-filter)}[data-bs-theme=dark] .btn-close{filter:var(--bs-btn-close-white-filter)}.toast{--bs-toast-zindex:1090;--bs-toast-padding-x:0.75rem;--bs-toast-padding-y:0.5rem;--bs-toast-spacing:1.5rem;--bs-toast-max-width:350px;--bs-toast-font-size:0.875rem;--bs-toast-color: ;--bs-toast-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-border-width:var(--bs-border-width);--bs-toast-border-color:var(--bs-border-color-translucent);--bs-toast-border-radius:var(--bs-border-radius);--bs-toast-box-shadow:var(--bs-box-shadow);--bs-toast-header-color:var(--bs-secondary-color);--bs-toast-header-bg:rgba(var(--bs-body-bg-rgb), 0.85);--bs-toast-header-border-color:var(--bs-border-color-translucent);width:var(--bs-toast-max-width);max-width:100%;font-size:var(--bs-toast-font-size);color:var(--bs-toast-color);pointer-events:auto;background-color:var(--bs-toast-bg);background-clip:padding-box;border:var(--bs-toast-border-width) solid var(--bs-toast-border-color);box-shadow:var(--bs-toast-box-shadow)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{--bs-toast-zindex:1090;position:absolute;z-index:var(--bs-toast-zindex);width:-webkit-max-content;width:-moz-max-content;width:max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:var(--bs-toast-spacing)}.toast-header{display:flex;align-items:center;padding:var(--bs-toast-padding-y) var(--bs-toast-padding-x);color:var(--bs-toast-header-color);background-color:var(--bs-toast-header-bg);background-clip:padding-box;border-bottom:var(--bs-toast-border-width) solid var(--bs-toast-header-border-color)}.toast-header .btn-close{margin-right:calc(-.5 * var(--bs-toast-padding-x));margin-left:var(--bs-toast-padding-x)}.toast-body{padding:var(--bs-toast-padding-x);word-wrap:break-word}.modal{--bs-modal-zindex:1055;--bs-modal-width:500px;--bs-modal-padding:1rem;--bs-modal-margin:0.5rem;--bs-modal-color: ;--bs-modal-bg:var(--bs-body-bg);--bs-modal-border-color:var(--bs-border-color-translucent);--bs-modal-border-width:var(--bs-border-width);--bs-modal-border-radius:var(--bs-border-radius-lg);--bs-modal-box-shadow:var(--bs-box-shadow-sm);--bs-modal-inner-border-radius:calc(var(--bs-border-radius-lg) - (var(--bs-border-width)));--bs-modal-header-padding-x:1rem;--bs-modal-header-padding-y:1rem;--bs-modal-header-padding:1rem 1rem;--bs-modal-header-border-color:var(--bs-border-color);--bs-modal-header-border-width:var(--bs-border-width);--bs-modal-title-line-height:1.5;--bs-modal-footer-gap:0.5rem;--bs-modal-footer-bg: ;--bs-modal-footer-border-color:var(--bs-border-color);--bs-modal-footer-border-width:var(--bs-border-width);position:fixed;top:0;left:0;z-index:var(--bs-modal-zindex);display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:var(--bs-modal-margin);pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-50px)}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - var(--bs-modal-margin) * 2)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - var(--bs-modal-margin) * 2)}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;color:var(--bs-modal-color);pointer-events:auto;background-color:var(--bs-modal-bg);background-clip:padding-box;border:var(--bs-modal-border-width) solid var(--bs-modal-border-color);outline:0}.modal-backdrop{--bs-backdrop-zindex:1050;--bs-backdrop-bg:#000;--bs-backdrop-opacity:0.5;position:fixed;top:0;left:0;z-index:var(--bs-backdrop-zindex);width:100vw;height:100vh;background-color:var(--bs-backdrop-bg)}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:var(--bs-backdrop-opacity)}.modal-header{display:flex;flex-shrink:0;align-items:center;padding:var(--bs-modal-header-padding);border-bottom:var(--bs-modal-header-border-width) solid var(--bs-modal-header-border-color)}.modal-header .btn-close{padding:calc(var(--bs-modal-header-padding-y) * .5) calc(var(--bs-modal-header-padding-x) * .5);margin:calc(-.5 * var(--bs-modal-header-padding-y)) calc(-.5 * var(--bs-modal-header-padding-x)) calc(-.5 * var(--bs-modal-header-padding-y)) auto}.modal-title{margin-bottom:0;line-height:var(--bs-modal-title-line-height)}.modal-body{position:relative;flex:1 1 auto;padding:var(--bs-modal-padding)}.modal-footer{display:flex;flex-shrink:0;flex-wrap:wrap;align-items:center;justify-content:flex-end;padding:calc(var(--bs-modal-padding) - var(--bs-modal-footer-gap) * .5);background-color:var(--bs-modal-footer-bg);border-top:var(--bs-modal-footer-border-width) solid var(--bs-modal-footer-border-color)}.modal-footer>*{margin:calc(var(--bs-modal-footer-gap) * .5)}@media (min-width:576px){.modal{--bs-modal-margin:1.75rem;--bs-modal-box-shadow:var(--bs-box-shadow)}.modal-dialog{max-width:var(--bs-modal-width);margin-right:auto;margin-left:auto}.modal-sm{--bs-modal-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{--bs-modal-width:800px}}@media (min-width:1200px){.modal-xl{--bs-modal-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media (max-width:575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media (max-width:767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media (max-width:991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{--bs-tooltip-zindex:1080;--bs-tooltip-max-width:200px;--bs-tooltip-padding-x:0.5rem;--bs-tooltip-padding-y:0.25rem;--bs-tooltip-margin: ;--bs-tooltip-font-size:0.875rem;--bs-tooltip-color:var(--bs-body-bg);--bs-tooltip-bg:var(--bs-emphasis-color);--bs-tooltip-border-radius:var(--bs-border-radius);--bs-tooltip-opacity:0.9;--bs-tooltip-arrow-width:0.8rem;--bs-tooltip-arrow-height:0.4rem;z-index:var(--bs-tooltip-zindex);display:block;margin:var(--bs-tooltip-margin);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:300;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-tooltip-font-size);word-wrap:break-word;opacity:0}.tooltip.show{opacity:var(--bs-tooltip-opacity)}.tooltip .tooltip-arrow{display:block;width:var(--bs-tooltip-arrow-width);height:var(--bs-tooltip-arrow-height)}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before,.bs-tooltip-top .tooltip-arrow::before{top:-1px;border-width:var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-top-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{left:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before,.bs-tooltip-end .tooltip-arrow::before{right:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height) calc(var(--bs-tooltip-arrow-width) * .5) 0;border-right-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:calc(-1 * var(--bs-tooltip-arrow-height))}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before,.bs-tooltip-bottom .tooltip-arrow::before{bottom:-1px;border-width:0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-bottom-color:var(--bs-tooltip-bg)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{right:calc(-1 * var(--bs-tooltip-arrow-height));width:var(--bs-tooltip-arrow-height);height:var(--bs-tooltip-arrow-width)}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before,.bs-tooltip-start .tooltip-arrow::before{left:-1px;border-width:calc(var(--bs-tooltip-arrow-width) * .5) 0 calc(var(--bs-tooltip-arrow-width) * .5) var(--bs-tooltip-arrow-height);border-left-color:var(--bs-tooltip-bg)}.tooltip-inner{max-width:var(--bs-tooltip-max-width);padding:var(--bs-tooltip-padding-y) var(--bs-tooltip-padding-x);color:var(--bs-tooltip-color);text-align:center;background-color:var(--bs-tooltip-bg)}.popover{--bs-popover-zindex:1070;--bs-popover-max-width:276px;--bs-popover-font-size:0.875rem;--bs-popover-bg:var(--bs-body-bg);--bs-popover-border-width:var(--bs-border-width);--bs-popover-border-color:var(--bs-border-color-translucent);--bs-popover-border-radius:var(--bs-border-radius-lg);--bs-popover-inner-border-radius:calc(var(--bs-border-radius-lg) - var(--bs-border-width));--bs-popover-box-shadow:var(--bs-box-shadow);--bs-popover-header-padding-x:1rem;--bs-popover-header-padding-y:0.5rem;--bs-popover-header-font-size:1rem;--bs-popover-header-color:#1a1a1a;--bs-popover-header-bg:var(--bs-secondary-bg);--bs-popover-body-padding-x:1rem;--bs-popover-body-padding-y:1rem;--bs-popover-body-color:var(--bs-body-color);--bs-popover-arrow-width:1rem;--bs-popover-arrow-height:0.5rem;--bs-popover-arrow-border:var(--bs-popover-border-color);z-index:var(--bs-popover-zindex);display:block;max-width:var(--bs-popover-max-width);font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:300;line-height:1.5;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;white-space:normal;word-spacing:normal;line-break:auto;font-size:var(--bs-popover-font-size);word-wrap:break-word;background-color:var(--bs-popover-bg);background-clip:padding-box;border:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover .popover-arrow{display:block;width:var(--bs-popover-arrow-width);height:var(--bs-popover-arrow-height)}.popover .popover-arrow::after,.popover .popover-arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid;border-width:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::after,.bs-popover-top>.popover-arrow::before{border-width:var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before,.bs-popover-top>.popover-arrow::before{bottom:0;border-top-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after,.bs-popover-top>.popover-arrow::after{bottom:var(--bs-popover-border-width);border-top-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{left:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::after,.bs-popover-end>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * .5) 0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before,.bs-popover-end>.popover-arrow::before{left:0;border-right-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after,.bs-popover-end>.popover-arrow::after{left:var(--bs-popover-border-width);border-right-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width))}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::before{border-width:0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before,.bs-popover-bottom>.popover-arrow::before{top:0;border-bottom-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after,.bs-popover-bottom>.popover-arrow::after{top:var(--bs-popover-border-width);border-bottom-color:var(--bs-popover-bg)}.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before,.bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:var(--bs-popover-arrow-width);margin-left:calc(-.5 * var(--bs-popover-arrow-width));content:"";border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-header-bg)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{right:calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));width:var(--bs-popover-arrow-height);height:var(--bs-popover-arrow-width)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::after,.bs-popover-start>.popover-arrow::before{border-width:calc(var(--bs-popover-arrow-width) * .5) 0 calc(var(--bs-popover-arrow-width) * .5) var(--bs-popover-arrow-height)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before,.bs-popover-start>.popover-arrow::before{right:0;border-left-color:var(--bs-popover-arrow-border)}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after,.bs-popover-start>.popover-arrow::after{right:var(--bs-popover-border-width);border-left-color:var(--bs-popover-bg)}.popover-header{padding:var(--bs-popover-header-padding-y) var(--bs-popover-header-padding-x);margin-bottom:0;font-size:var(--bs-popover-header-font-size);color:var(--bs-popover-header-color);background-color:var(--bs-popover-header-bg);border-bottom:var(--bs-popover-border-width) solid var(--bs-popover-border-color)}.popover-header:empty{display:none}.popover-body{padding:var(--bs-popover-body-padding-y) var(--bs-popover-body-padding-x);color:var(--bs-popover-body-color)}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;-webkit-backface-visibility:hidden;backface-visibility:hidden;transition:transform .6s ease-in-out}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{z-index:1;opacity:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{z-index:0;opacity:0;transition:opacity 0s .6s}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{position:absolute;top:0;bottom:0;z-index:1;display:flex;align-items:center;justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:0 0;border:0;opacity:.5;transition:opacity .15s ease}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid transparent;border-bottom:10px solid transparent;opacity:.5;transition:opacity .6s ease}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}[data-bs-theme=dark] .carousel .carousel-control-next-icon,[data-bs-theme=dark] .carousel .carousel-control-prev-icon,[data-bs-theme=dark].carousel .carousel-control-next-icon,[data-bs-theme=dark].carousel .carousel-control-prev-icon{filter:invert(1) grayscale(100)}[data-bs-theme=dark] .carousel .carousel-indicators [data-bs-target],[data-bs-theme=dark].carousel .carousel-indicators [data-bs-target]{background-color:#000}[data-bs-theme=dark] .carousel .carousel-caption,[data-bs-theme=dark].carousel .carousel-caption{color:#000}.spinner-border,.spinner-grow{display:inline-block;width:var(--bs-spinner-width);height:var(--bs-spinner-height);vertical-align:var(--bs-spinner-vertical-align);border-radius:50%;animation:var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name)}@keyframes spinner-border{to{transform:rotate(360deg)}}.spinner-border{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-border-width:0.25em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-border;border:var(--bs-spinner-border-width) solid currentcolor;border-right-color:transparent}.spinner-border-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem;--bs-spinner-border-width:0.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{--bs-spinner-width:2rem;--bs-spinner-height:2rem;--bs-spinner-vertical-align:-0.125em;--bs-spinner-animation-speed:0.75s;--bs-spinner-animation-name:spinner-grow;background-color:currentcolor;opacity:0}.spinner-grow-sm{--bs-spinner-width:1rem;--bs-spinner-height:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{--bs-spinner-animation-speed:1.5s}}.offcanvas,.offcanvas-lg,.offcanvas-md,.offcanvas-sm,.offcanvas-xl,.offcanvas-xxl{--bs-offcanvas-zindex:1045;--bs-offcanvas-width:400px;--bs-offcanvas-height:30vh;--bs-offcanvas-padding-x:1rem;--bs-offcanvas-padding-y:1rem;--bs-offcanvas-color:var(--bs-body-color);--bs-offcanvas-bg:var(--bs-body-bg);--bs-offcanvas-border-width:var(--bs-border-width);--bs-offcanvas-border-color:var(--bs-border-color-translucent);--bs-offcanvas-box-shadow:var(--bs-box-shadow-sm);--bs-offcanvas-transition:transform 0.3s ease-in-out;--bs-offcanvas-title-line-height:1.5}@media (max-width:575.98px){.offcanvas-sm{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:575.98px) and (prefers-reduced-motion:reduce){.offcanvas-sm{transition:none}}@media (max-width:575.98px){.offcanvas-sm.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-sm.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-sm.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-sm.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-sm.show:not(.hiding),.offcanvas-sm.showing{transform:none}.offcanvas-sm.hiding,.offcanvas-sm.show,.offcanvas-sm.showing{visibility:visible}}@media (min-width:576px){.offcanvas-sm{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-sm .offcanvas-header{display:none}.offcanvas-sm .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:767.98px){.offcanvas-md{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:767.98px) and (prefers-reduced-motion:reduce){.offcanvas-md{transition:none}}@media (max-width:767.98px){.offcanvas-md.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-md.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-md.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-md.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-md.show:not(.hiding),.offcanvas-md.showing{transform:none}.offcanvas-md.hiding,.offcanvas-md.show,.offcanvas-md.showing{visibility:visible}}@media (min-width:768px){.offcanvas-md{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-md .offcanvas-header{display:none}.offcanvas-md .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:991.98px){.offcanvas-lg{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:991.98px) and (prefers-reduced-motion:reduce){.offcanvas-lg{transition:none}}@media (max-width:991.98px){.offcanvas-lg.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-lg.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-lg.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-lg.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-lg.show:not(.hiding),.offcanvas-lg.showing{transform:none}.offcanvas-lg.hiding,.offcanvas-lg.show,.offcanvas-lg.showing{visibility:visible}}@media (min-width:992px){.offcanvas-lg{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-lg .offcanvas-header{display:none}.offcanvas-lg .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1199.98px){.offcanvas-xl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1199.98px) and (prefers-reduced-motion:reduce){.offcanvas-xl{transition:none}}@media (max-width:1199.98px){.offcanvas-xl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xl.show:not(.hiding),.offcanvas-xl.showing{transform:none}.offcanvas-xl.hiding,.offcanvas-xl.show,.offcanvas-xl.showing{visibility:visible}}@media (min-width:1200px){.offcanvas-xl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xl .offcanvas-header{display:none}.offcanvas-xl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}@media (max-width:1399.98px){.offcanvas-xxl{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}}@media (max-width:1399.98px) and (prefers-reduced-motion:reduce){.offcanvas-xxl{transition:none}}@media (max-width:1399.98px){.offcanvas-xxl.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas-xxl.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas-xxl.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas-xxl.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas-xxl.show:not(.hiding),.offcanvas-xxl.showing{transform:none}.offcanvas-xxl.hiding,.offcanvas-xxl.show,.offcanvas-xxl.showing{visibility:visible}}@media (min-width:1400px){.offcanvas-xxl{--bs-offcanvas-height:auto;--bs-offcanvas-border-width:0;background-color:transparent!important}.offcanvas-xxl .offcanvas-header{display:none}.offcanvas-xxl .offcanvas-body{display:flex;flex-grow:0;padding:0;overflow-y:visible;background-color:transparent!important}}.offcanvas{position:fixed;bottom:0;z-index:var(--bs-offcanvas-zindex);display:flex;flex-direction:column;max-width:100%;color:var(--bs-offcanvas-color);visibility:hidden;background-color:var(--bs-offcanvas-bg);background-clip:padding-box;outline:0;transition:var(--bs-offcanvas-transition)}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas.offcanvas-start{top:0;left:0;width:var(--bs-offcanvas-width);border-right:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(-100%)}.offcanvas.offcanvas-end{top:0;right:0;width:var(--bs-offcanvas-width);border-left:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateX(100%)}.offcanvas.offcanvas-top{top:0;right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-bottom:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(-100%)}.offcanvas.offcanvas-bottom{right:0;left:0;height:var(--bs-offcanvas-height);max-height:100%;border-top:var(--bs-offcanvas-border-width) solid var(--bs-offcanvas-border-color);transform:translateY(100%)}.offcanvas.show:not(.hiding),.offcanvas.showing{transform:none}.offcanvas.hiding,.offcanvas.show,.offcanvas.showing{visibility:visible}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;align-items:center;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x)}.offcanvas-header .btn-close{padding:calc(var(--bs-offcanvas-padding-y) * .5) calc(var(--bs-offcanvas-padding-x) * .5);margin:calc(-.5 * var(--bs-offcanvas-padding-y)) calc(-.5 * var(--bs-offcanvas-padding-x)) calc(-.5 * var(--bs-offcanvas-padding-y)) auto}.offcanvas-title{margin-bottom:0;line-height:var(--bs-offcanvas-title-line-height)}.offcanvas-body{flex-grow:1;padding:var(--bs-offcanvas-padding-y) var(--bs-offcanvas-padding-x);overflow-y:auto}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentcolor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{-webkit-mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);mask-image:linear-gradient(130deg,#000 55%,rgba(0,0,0,0.8) 75%,#000 95%);-webkit-mask-size:200% 100%;mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{-webkit-mask-position:-200% 0%;mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.text-bg-primary{color:#fff!important;background-color:RGBA(var(--bs-primary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-secondary{color:#000!important;background-color:RGBA(var(--bs-secondary-rgb),var(--bs-bg-opacity,1))!important}.text-bg-success{color:#fff!important;background-color:RGBA(var(--bs-success-rgb),var(--bs-bg-opacity,1))!important}.text-bg-info{color:#fff!important;background-color:RGBA(var(--bs-info-rgb),var(--bs-bg-opacity,1))!important}.text-bg-warning{color:#000!important;background-color:RGBA(var(--bs-warning-rgb),var(--bs-bg-opacity,1))!important}.text-bg-danger{color:#fff!important;background-color:RGBA(var(--bs-danger-rgb),var(--bs-bg-opacity,1))!important}.text-bg-light{color:#000!important;background-color:RGBA(var(--bs-light-rgb),var(--bs-bg-opacity,1))!important}.text-bg-dark{color:#fff!important;background-color:RGBA(var(--bs-dark-rgb),var(--bs-bg-opacity,1))!important}.link-primary{color:RGBA(var(--bs-primary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-primary-rgb),var(--bs-link-underline-opacity,1))!important}.link-primary:focus,.link-primary:hover{color:RGBA(21,21,21,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(21,21,21,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(21,21,21,var(--bs-link-underline-opacity,1))!important}.link-secondary{color:RGBA(var(--bs-secondary-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-secondary-rgb),var(--bs-link-underline-opacity,1))!important}.link-secondary:focus,.link-secondary:hover{color:RGBA(255,255,255,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,255,255,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,255,255,var(--bs-link-underline-opacity,1))!important}.link-success{color:RGBA(var(--bs-success-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-success-rgb),var(--bs-link-underline-opacity,1))!important}.link-success:focus,.link-success:hover{color:RGBA(60,153,92,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(60,153,92,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(60,153,92,var(--bs-link-underline-opacity,1))!important}.link-info{color:RGBA(var(--bs-info-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-info-rgb),var(--bs-link-underline-opacity,1))!important}.link-info:focus,.link-info:hover{color:RGBA(25,124,166,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(25,124,166,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(25,124,166,var(--bs-link-underline-opacity,1))!important}.link-warning{color:RGBA(var(--bs-warning-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-warning-rgb),var(--bs-link-underline-opacity,1))!important}.link-warning:focus,.link-warning:hover{color:RGBA(243,189,113,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(243,189,113,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(243,189,113,var(--bs-link-underline-opacity,1))!important}.link-danger{color:RGBA(var(--bs-danger-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-danger-rgb),var(--bs-link-underline-opacity,1))!important}.link-danger:focus,.link-danger:hover{color:RGBA(174,66,63,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(174,66,63,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(174,66,63,var(--bs-link-underline-opacity,1))!important}.link-light{color:RGBA(var(--bs-light-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-light-rgb),var(--bs-link-underline-opacity,1))!important}.link-light:focus,.link-light:hover{color:RGBA(255,255,255,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(255,255,255,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(255,255,255,var(--bs-link-underline-opacity,1))!important}.link-dark{color:RGBA(var(--bs-dark-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-dark-rgb),var(--bs-link-underline-opacity,1))!important}.link-dark:focus,.link-dark:hover{color:RGBA(42,46,51,var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(42,46,51,var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(42,46,51,var(--bs-link-underline-opacity,1))!important}.link-body-emphasis{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,1))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-body-emphasis:focus,.link-body-emphasis:hover{color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-opacity,.75))!important;-webkit-text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important;text-decoration-color:RGBA(var(--bs-emphasis-color-rgb),var(--bs-link-underline-opacity,0.75))!important}.focus-ring:focus{outline:0;box-shadow:var(--bs-focus-ring-x,0) var(--bs-focus-ring-y,0) var(--bs-focus-ring-blur,0) var(--bs-focus-ring-width) var(--bs-focus-ring-color)}.icon-link{display:inline-flex;gap:.375rem;align-items:center;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-opacity,0.5));text-underline-offset:0.25em;-webkit-backface-visibility:hidden;backface-visibility:hidden}.icon-link>.bi{flex-shrink:0;width:1em;height:1em;fill:currentcolor;transition:.2s ease-in-out transform}@media (prefers-reduced-motion:reduce){.icon-link>.bi{transition:none}}.icon-link-hover:focus-visible>.bi,.icon-link-hover:hover>.bi{transform:var(--bs-icon-link-transform,translate3d(.25em,0,0))}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-sm-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-md-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-lg-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}.sticky-xxl-bottom{position:-webkit-sticky;position:sticky;bottom:0;z-index:1020}}.hstack{display:flex;flex-direction:row;align-items:center;align-self:stretch}.vstack{display:flex;flex:1 1 auto;flex-direction:column;align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.visually-hidden-focusable:not(:focus):not(:focus-within):not(caption),.visually-hidden:not(caption){position:absolute!important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;width:var(--bs-border-width);min-height:1em;background-color:currentcolor;opacity:.25}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.object-fit-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-none{-o-object-fit:none!important;object-fit:none!important}.opacity-0{opacity:0!important}.opacity-25{opacity:.25!important}.opacity-50{opacity:.5!important}.opacity-75{opacity:.75!important}.opacity-100{opacity:1!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-visible{overflow:visible!important}.overflow-scroll{overflow:scroll!important}.overflow-x-auto{overflow-x:auto!important}.overflow-x-hidden{overflow-x:hidden!important}.overflow-x-visible{overflow-x:visible!important}.overflow-x-scroll{overflow-x:scroll!important}.overflow-y-auto{overflow-y:auto!important}.overflow-y-hidden{overflow-y:hidden!important}.overflow-y-visible{overflow-y:visible!important}.overflow-y-scroll{overflow-y:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-inline-grid{display:inline-grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:var(--bs-box-shadow)!important}.shadow-sm{box-shadow:var(--bs-box-shadow-sm)!important}.shadow-lg{box-shadow:var(--bs-box-shadow-lg)!important}.shadow-none{box-shadow:none!important}.focus-ring-primary{--bs-focus-ring-color:rgba(var(--bs-primary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-secondary{--bs-focus-ring-color:rgba(var(--bs-secondary-rgb), var(--bs-focus-ring-opacity))}.focus-ring-success{--bs-focus-ring-color:rgba(var(--bs-success-rgb), var(--bs-focus-ring-opacity))}.focus-ring-info{--bs-focus-ring-color:rgba(var(--bs-info-rgb), var(--bs-focus-ring-opacity))}.focus-ring-warning{--bs-focus-ring-color:rgba(var(--bs-warning-rgb), var(--bs-focus-ring-opacity))}.focus-ring-danger{--bs-focus-ring-color:rgba(var(--bs-danger-rgb), var(--bs-focus-ring-opacity))}.focus-ring-light{--bs-focus-ring-color:rgba(var(--bs-light-rgb), var(--bs-focus-ring-opacity))}.focus-ring-dark{--bs-focus-ring-color:rgba(var(--bs-dark-rgb), var(--bs-focus-ring-opacity))}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-0{border:0!important}.border-top{border-top:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-top-0{border-top:0!important}.border-end{border-right:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:var(--bs-border-width) var(--bs-border-style) var(--bs-border-color)!important}.border-start-0{border-left:0!important}.border-primary{--bs-border-opacity:1;border-color:rgba(var(--bs-primary-rgb),var(--bs-border-opacity))!important}.border-secondary{--bs-border-opacity:1;border-color:rgba(var(--bs-secondary-rgb),var(--bs-border-opacity))!important}.border-success{--bs-border-opacity:1;border-color:rgba(var(--bs-success-rgb),var(--bs-border-opacity))!important}.border-info{--bs-border-opacity:1;border-color:rgba(var(--bs-info-rgb),var(--bs-border-opacity))!important}.border-warning{--bs-border-opacity:1;border-color:rgba(var(--bs-warning-rgb),var(--bs-border-opacity))!important}.border-danger{--bs-border-opacity:1;border-color:rgba(var(--bs-danger-rgb),var(--bs-border-opacity))!important}.border-light{--bs-border-opacity:1;border-color:rgba(var(--bs-light-rgb),var(--bs-border-opacity))!important}.border-dark{--bs-border-opacity:1;border-color:rgba(var(--bs-dark-rgb),var(--bs-border-opacity))!important}.border-black{--bs-border-opacity:1;border-color:rgba(var(--bs-black-rgb),var(--bs-border-opacity))!important}.border-white{--bs-border-opacity:1;border-color:rgba(var(--bs-white-rgb),var(--bs-border-opacity))!important}.border-primary-subtle{border-color:var(--bs-primary-border-subtle)!important}.border-secondary-subtle{border-color:var(--bs-secondary-border-subtle)!important}.border-success-subtle{border-color:var(--bs-success-border-subtle)!important}.border-info-subtle{border-color:var(--bs-info-border-subtle)!important}.border-warning-subtle{border-color:var(--bs-warning-border-subtle)!important}.border-danger-subtle{border-color:var(--bs-danger-border-subtle)!important}.border-light-subtle{border-color:var(--bs-light-border-subtle)!important}.border-dark-subtle{border-color:var(--bs-dark-border-subtle)!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.border-opacity-10{--bs-border-opacity:0.1}.border-opacity-25{--bs-border-opacity:0.25}.border-opacity-50{--bs-border-opacity:0.5}.border-opacity-75{--bs-border-opacity:0.75}.border-opacity-100{--bs-border-opacity:1}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-auto{margin:auto!important}.mx-0{margin-right:0!important;margin-left:0!important}.mx-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-3{margin-right:1rem!important;margin-left:1rem!important}.mx-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-5{margin-right:3rem!important;margin-left:3rem!important}.mx-auto{margin-right:auto!important;margin-left:auto!important}.my-0{margin-top:0!important;margin-bottom:0!important}.my-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-auto{margin-left:auto!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.px-0{padding-right:0!important;padding-left:0!important}.px-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-3{padding-right:1rem!important;padding-left:1rem!important}.px-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-5{padding-right:3rem!important;padding-left:3rem!important}.py-0{padding-top:0!important;padding-bottom:0!important}.py-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.row-gap-0{row-gap:0!important}.row-gap-1{row-gap:.25rem!important}.row-gap-2{row-gap:.5rem!important}.row-gap-3{row-gap:1rem!important}.row-gap-4{row-gap:1.5rem!important}.row-gap-5{row-gap:3rem!important}.column-gap-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.325rem + .9vw)!important}.fs-2{font-size:calc(1.3rem + .6vw)!important}.fs-3{font-size:calc(1.275rem + .3vw)!important}.fs-4{font-size:1.25rem!important}.fs-5{font-size:1rem!important}.fs-6{font-size:.75rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-lighter{font-weight:lighter!important}.fw-light{font-weight:200!important}.fw-normal{font-weight:300!important}.fw-medium{font-weight:400!important}.fw-semibold{font-weight:500!important}.fw-bold{font-weight:600!important}.fw-bolder{font-weight:bolder!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-none{text-decoration:none!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-break{word-wrap:break-word!important;word-break:break-word!important}.text-primary{--bs-text-opacity:1;color:rgba(var(--bs-primary-rgb),var(--bs-text-opacity))!important}.text-secondary{--bs-text-opacity:1;color:rgba(var(--bs-secondary-rgb),var(--bs-text-opacity))!important}.text-success{--bs-text-opacity:1;color:rgba(var(--bs-success-rgb),var(--bs-text-opacity))!important}.text-info{--bs-text-opacity:1;color:rgba(var(--bs-info-rgb),var(--bs-text-opacity))!important}.text-warning{--bs-text-opacity:1;color:rgba(var(--bs-warning-rgb),var(--bs-text-opacity))!important}.text-danger{--bs-text-opacity:1;color:rgba(var(--bs-danger-rgb),var(--bs-text-opacity))!important}.text-light{--bs-text-opacity:1;color:rgba(var(--bs-light-rgb),var(--bs-text-opacity))!important}.text-dark{--bs-text-opacity:1;color:rgba(var(--bs-dark-rgb),var(--bs-text-opacity))!important}.text-black{--bs-text-opacity:1;color:rgba(var(--bs-black-rgb),var(--bs-text-opacity))!important}.text-white{--bs-text-opacity:1;color:rgba(var(--bs-white-rgb),var(--bs-text-opacity))!important}.text-body{--bs-text-opacity:1;color:rgba(var(--bs-body-color-rgb),var(--bs-text-opacity))!important}.text-muted{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-black-50{--bs-text-opacity:1;color:rgba(0,0,0,.5)!important}.text-white-50{--bs-text-opacity:1;color:rgba(255,255,255,.5)!important}.text-body-secondary{--bs-text-opacity:1;color:var(--bs-secondary-color)!important}.text-body-tertiary{--bs-text-opacity:1;color:var(--bs-tertiary-color)!important}.text-body-emphasis{--bs-text-opacity:1;color:var(--bs-emphasis-color)!important}.text-reset{--bs-text-opacity:1;color:inherit!important}.text-opacity-25{--bs-text-opacity:0.25}.text-opacity-50{--bs-text-opacity:0.5}.text-opacity-75{--bs-text-opacity:0.75}.text-opacity-100{--bs-text-opacity:1}.text-primary-emphasis{color:var(--bs-primary-text-emphasis)!important}.text-secondary-emphasis{color:var(--bs-secondary-text-emphasis)!important}.text-success-emphasis{color:var(--bs-success-text-emphasis)!important}.text-info-emphasis{color:var(--bs-info-text-emphasis)!important}.text-warning-emphasis{color:var(--bs-warning-text-emphasis)!important}.text-danger-emphasis{color:var(--bs-danger-text-emphasis)!important}.text-light-emphasis{color:var(--bs-light-text-emphasis)!important}.text-dark-emphasis{color:var(--bs-dark-text-emphasis)!important}.link-opacity-10{--bs-link-opacity:0.1}.link-opacity-10-hover:hover{--bs-link-opacity:0.1}.link-opacity-25{--bs-link-opacity:0.25}.link-opacity-25-hover:hover{--bs-link-opacity:0.25}.link-opacity-50{--bs-link-opacity:0.5}.link-opacity-50-hover:hover{--bs-link-opacity:0.5}.link-opacity-75{--bs-link-opacity:0.75}.link-opacity-75-hover:hover{--bs-link-opacity:0.75}.link-opacity-100{--bs-link-opacity:1}.link-opacity-100-hover:hover{--bs-link-opacity:1}.link-offset-1{text-underline-offset:0.125em!important}.link-offset-1-hover:hover{text-underline-offset:0.125em!important}.link-offset-2{text-underline-offset:0.25em!important}.link-offset-2-hover:hover{text-underline-offset:0.25em!important}.link-offset-3{text-underline-offset:0.375em!important}.link-offset-3-hover:hover{text-underline-offset:0.375em!important}.link-underline-primary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-primary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-secondary{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-secondary-rgb),var(--bs-link-underline-opacity))!important}.link-underline-success{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-success-rgb),var(--bs-link-underline-opacity))!important}.link-underline-info{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-info-rgb),var(--bs-link-underline-opacity))!important}.link-underline-warning{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-warning-rgb),var(--bs-link-underline-opacity))!important}.link-underline-danger{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-danger-rgb),var(--bs-link-underline-opacity))!important}.link-underline-light{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-light-rgb),var(--bs-link-underline-opacity))!important}.link-underline-dark{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important;text-decoration-color:rgba(var(--bs-dark-rgb),var(--bs-link-underline-opacity))!important}.link-underline{--bs-link-underline-opacity:1;-webkit-text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important;text-decoration-color:rgba(var(--bs-link-color-rgb),var(--bs-link-underline-opacity,1))!important}.link-underline-opacity-0{--bs-link-underline-opacity:0}.link-underline-opacity-0-hover:hover{--bs-link-underline-opacity:0}.link-underline-opacity-10{--bs-link-underline-opacity:0.1}.link-underline-opacity-10-hover:hover{--bs-link-underline-opacity:0.1}.link-underline-opacity-25{--bs-link-underline-opacity:0.25}.link-underline-opacity-25-hover:hover{--bs-link-underline-opacity:0.25}.link-underline-opacity-50{--bs-link-underline-opacity:0.5}.link-underline-opacity-50-hover:hover{--bs-link-underline-opacity:0.5}.link-underline-opacity-75{--bs-link-underline-opacity:0.75}.link-underline-opacity-75-hover:hover{--bs-link-underline-opacity:0.75}.link-underline-opacity-100{--bs-link-underline-opacity:1}.link-underline-opacity-100-hover:hover{--bs-link-underline-opacity:1}.bg-primary{--bs-bg-opacity:1;background-color:rgba(var(--bs-primary-rgb),var(--bs-bg-opacity))!important}.bg-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-rgb),var(--bs-bg-opacity))!important}.bg-success{--bs-bg-opacity:1;background-color:rgba(var(--bs-success-rgb),var(--bs-bg-opacity))!important}.bg-info{--bs-bg-opacity:1;background-color:rgba(var(--bs-info-rgb),var(--bs-bg-opacity))!important}.bg-warning{--bs-bg-opacity:1;background-color:rgba(var(--bs-warning-rgb),var(--bs-bg-opacity))!important}.bg-danger{--bs-bg-opacity:1;background-color:rgba(var(--bs-danger-rgb),var(--bs-bg-opacity))!important}.bg-light{--bs-bg-opacity:1;background-color:rgba(var(--bs-light-rgb),var(--bs-bg-opacity))!important}.bg-dark{--bs-bg-opacity:1;background-color:rgba(var(--bs-dark-rgb),var(--bs-bg-opacity))!important}.bg-black{--bs-bg-opacity:1;background-color:rgba(var(--bs-black-rgb),var(--bs-bg-opacity))!important}.bg-white{--bs-bg-opacity:1;background-color:rgba(var(--bs-white-rgb),var(--bs-bg-opacity))!important}.bg-body{--bs-bg-opacity:1;background-color:rgba(var(--bs-body-bg-rgb),var(--bs-bg-opacity))!important}.bg-transparent{--bs-bg-opacity:1;background-color:transparent!important}.bg-body-secondary{--bs-bg-opacity:1;background-color:rgba(var(--bs-secondary-bg-rgb),var(--bs-bg-opacity))!important}.bg-body-tertiary{--bs-bg-opacity:1;background-color:rgba(var(--bs-tertiary-bg-rgb),var(--bs-bg-opacity))!important}.bg-opacity-10{--bs-bg-opacity:0.1}.bg-opacity-25{--bs-bg-opacity:0.25}.bg-opacity-50{--bs-bg-opacity:0.5}.bg-opacity-75{--bs-bg-opacity:0.75}.bg-opacity-100{--bs-bg-opacity:1}.bg-primary-subtle{background-color:var(--bs-primary-bg-subtle)!important}.bg-secondary-subtle{background-color:var(--bs-secondary-bg-subtle)!important}.bg-success-subtle{background-color:var(--bs-success-bg-subtle)!important}.bg-info-subtle{background-color:var(--bs-info-bg-subtle)!important}.bg-warning-subtle{background-color:var(--bs-warning-bg-subtle)!important}.bg-danger-subtle{background-color:var(--bs-danger-bg-subtle)!important}.bg-light-subtle{background-color:var(--bs-light-bg-subtle)!important}.bg-dark-subtle{background-color:var(--bs-dark-bg-subtle)!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:var(--bs-border-radius)!important}.rounded-0{border-radius:0!important}.rounded-1{border-radius:var(--bs-border-radius-sm)!important}.rounded-2{border-radius:var(--bs-border-radius)!important}.rounded-3{border-radius:var(--bs-border-radius-lg)!important}.rounded-4{border-radius:var(--bs-border-radius-xl)!important}.rounded-5{border-radius:var(--bs-border-radius-xxl)!important}.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:var(--bs-border-radius-pill)!important}.rounded-top{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-0{border-top-left-radius:0!important;border-top-right-radius:0!important}.rounded-top-1{border-top-left-radius:var(--bs-border-radius-sm)!important;border-top-right-radius:var(--bs-border-radius-sm)!important}.rounded-top-2{border-top-left-radius:var(--bs-border-radius)!important;border-top-right-radius:var(--bs-border-radius)!important}.rounded-top-3{border-top-left-radius:var(--bs-border-radius-lg)!important;border-top-right-radius:var(--bs-border-radius-lg)!important}.rounded-top-4{border-top-left-radius:var(--bs-border-radius-xl)!important;border-top-right-radius:var(--bs-border-radius-xl)!important}.rounded-top-5{border-top-left-radius:var(--bs-border-radius-xxl)!important;border-top-right-radius:var(--bs-border-radius-xxl)!important}.rounded-top-circle{border-top-left-radius:50%!important;border-top-right-radius:50%!important}.rounded-top-pill{border-top-left-radius:var(--bs-border-radius-pill)!important;border-top-right-radius:var(--bs-border-radius-pill)!important}.rounded-end{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-0{border-top-right-radius:0!important;border-bottom-right-radius:0!important}.rounded-end-1{border-top-right-radius:var(--bs-border-radius-sm)!important;border-bottom-right-radius:var(--bs-border-radius-sm)!important}.rounded-end-2{border-top-right-radius:var(--bs-border-radius)!important;border-bottom-right-radius:var(--bs-border-radius)!important}.rounded-end-3{border-top-right-radius:var(--bs-border-radius-lg)!important;border-bottom-right-radius:var(--bs-border-radius-lg)!important}.rounded-end-4{border-top-right-radius:var(--bs-border-radius-xl)!important;border-bottom-right-radius:var(--bs-border-radius-xl)!important}.rounded-end-5{border-top-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-right-radius:var(--bs-border-radius-xxl)!important}.rounded-end-circle{border-top-right-radius:50%!important;border-bottom-right-radius:50%!important}.rounded-end-pill{border-top-right-radius:var(--bs-border-radius-pill)!important;border-bottom-right-radius:var(--bs-border-radius-pill)!important}.rounded-bottom{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-0{border-bottom-right-radius:0!important;border-bottom-left-radius:0!important}.rounded-bottom-1{border-bottom-right-radius:var(--bs-border-radius-sm)!important;border-bottom-left-radius:var(--bs-border-radius-sm)!important}.rounded-bottom-2{border-bottom-right-radius:var(--bs-border-radius)!important;border-bottom-left-radius:var(--bs-border-radius)!important}.rounded-bottom-3{border-bottom-right-radius:var(--bs-border-radius-lg)!important;border-bottom-left-radius:var(--bs-border-radius-lg)!important}.rounded-bottom-4{border-bottom-right-radius:var(--bs-border-radius-xl)!important;border-bottom-left-radius:var(--bs-border-radius-xl)!important}.rounded-bottom-5{border-bottom-right-radius:var(--bs-border-radius-xxl)!important;border-bottom-left-radius:var(--bs-border-radius-xxl)!important}.rounded-bottom-circle{border-bottom-right-radius:50%!important;border-bottom-left-radius:50%!important}.rounded-bottom-pill{border-bottom-right-radius:var(--bs-border-radius-pill)!important;border-bottom-left-radius:var(--bs-border-radius-pill)!important}.rounded-start{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-0{border-bottom-left-radius:0!important;border-top-left-radius:0!important}.rounded-start-1{border-bottom-left-radius:var(--bs-border-radius-sm)!important;border-top-left-radius:var(--bs-border-radius-sm)!important}.rounded-start-2{border-bottom-left-radius:var(--bs-border-radius)!important;border-top-left-radius:var(--bs-border-radius)!important}.rounded-start-3{border-bottom-left-radius:var(--bs-border-radius-lg)!important;border-top-left-radius:var(--bs-border-radius-lg)!important}.rounded-start-4{border-bottom-left-radius:var(--bs-border-radius-xl)!important;border-top-left-radius:var(--bs-border-radius-xl)!important}.rounded-start-5{border-bottom-left-radius:var(--bs-border-radius-xxl)!important;border-top-left-radius:var(--bs-border-radius-xxl)!important}.rounded-start-circle{border-bottom-left-radius:50%!important;border-top-left-radius:50%!important}.rounded-start-pill{border-bottom-left-radius:var(--bs-border-radius-pill)!important;border-top-left-radius:var(--bs-border-radius-pill)!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.z-n1{z-index:-1!important}.z-0{z-index:0!important}.z-1{z-index:1!important}.z-2{z-index:2!important}.z-3{z-index:3!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.object-fit-sm-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-sm-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-sm-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-sm-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-sm-none{-o-object-fit:none!important;object-fit:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-inline-grid{display:inline-grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-right:0!important;margin-left:0!important}.mx-sm-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-sm-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-sm-3{margin-right:1rem!important;margin-left:1rem!important}.mx-sm-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-sm-5{margin-right:3rem!important;margin-left:3rem!important}.mx-sm-auto{margin-right:auto!important;margin-left:auto!important}.my-sm-0{margin-top:0!important;margin-bottom:0!important}.my-sm-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-sm-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-sm-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-sm-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-sm-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-sm-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-auto{margin-left:auto!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.px-sm-0{padding-right:0!important;padding-left:0!important}.px-sm-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-sm-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-sm-3{padding-right:1rem!important;padding-left:1rem!important}.px-sm-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-sm-5{padding-right:3rem!important;padding-left:3rem!important}.py-sm-0{padding-top:0!important;padding-bottom:0!important}.py-sm-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-sm-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-sm-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-sm-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-sm-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.row-gap-sm-0{row-gap:0!important}.row-gap-sm-1{row-gap:.25rem!important}.row-gap-sm-2{row-gap:.5rem!important}.row-gap-sm-3{row-gap:1rem!important}.row-gap-sm-4{row-gap:1.5rem!important}.row-gap-sm-5{row-gap:3rem!important}.column-gap-sm-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-sm-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-sm-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-sm-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-sm-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-sm-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.object-fit-md-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-md-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-md-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-md-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-md-none{-o-object-fit:none!important;object-fit:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-inline-grid{display:inline-grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-right:0!important;margin-left:0!important}.mx-md-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-md-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-md-3{margin-right:1rem!important;margin-left:1rem!important}.mx-md-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-md-5{margin-right:3rem!important;margin-left:3rem!important}.mx-md-auto{margin-right:auto!important;margin-left:auto!important}.my-md-0{margin-top:0!important;margin-bottom:0!important}.my-md-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-md-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-md-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-md-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-md-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-md-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-auto{margin-left:auto!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.px-md-0{padding-right:0!important;padding-left:0!important}.px-md-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-md-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-md-3{padding-right:1rem!important;padding-left:1rem!important}.px-md-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-md-5{padding-right:3rem!important;padding-left:3rem!important}.py-md-0{padding-top:0!important;padding-bottom:0!important}.py-md-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-md-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-md-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-md-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-md-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.row-gap-md-0{row-gap:0!important}.row-gap-md-1{row-gap:.25rem!important}.row-gap-md-2{row-gap:.5rem!important}.row-gap-md-3{row-gap:1rem!important}.row-gap-md-4{row-gap:1.5rem!important}.row-gap-md-5{row-gap:3rem!important}.column-gap-md-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-md-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-md-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-md-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-md-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-md-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.object-fit-lg-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-lg-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-lg-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-lg-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-lg-none{-o-object-fit:none!important;object-fit:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-inline-grid{display:inline-grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-right:0!important;margin-left:0!important}.mx-lg-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-lg-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-lg-3{margin-right:1rem!important;margin-left:1rem!important}.mx-lg-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-lg-5{margin-right:3rem!important;margin-left:3rem!important}.mx-lg-auto{margin-right:auto!important;margin-left:auto!important}.my-lg-0{margin-top:0!important;margin-bottom:0!important}.my-lg-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-lg-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-lg-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-lg-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-lg-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-lg-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-auto{margin-left:auto!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.px-lg-0{padding-right:0!important;padding-left:0!important}.px-lg-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-lg-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-lg-3{padding-right:1rem!important;padding-left:1rem!important}.px-lg-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-lg-5{padding-right:3rem!important;padding-left:3rem!important}.py-lg-0{padding-top:0!important;padding-bottom:0!important}.py-lg-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-lg-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-lg-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-lg-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-lg-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.row-gap-lg-0{row-gap:0!important}.row-gap-lg-1{row-gap:.25rem!important}.row-gap-lg-2{row-gap:.5rem!important}.row-gap-lg-3{row-gap:1rem!important}.row-gap-lg-4{row-gap:1.5rem!important}.row-gap-lg-5{row-gap:3rem!important}.column-gap-lg-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-lg-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-lg-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-lg-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-lg-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-lg-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.object-fit-xl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xl-none{-o-object-fit:none!important;object-fit:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-inline-grid{display:inline-grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-right:0!important;margin-left:0!important}.mx-xl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xl-auto{margin-right:auto!important;margin-left:auto!important}.my-xl-0{margin-top:0!important;margin-bottom:0!important}.my-xl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-auto{margin-left:auto!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.px-xl-0{padding-right:0!important;padding-left:0!important}.px-xl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xl-0{padding-top:0!important;padding-bottom:0!important}.py-xl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.row-gap-xl-0{row-gap:0!important}.row-gap-xl-1{row-gap:.25rem!important}.row-gap-xl-2{row-gap:.5rem!important}.row-gap-xl-3{row-gap:1rem!important}.row-gap-xl-4{row-gap:1.5rem!important}.row-gap-xl-5{row-gap:3rem!important}.column-gap-xl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.object-fit-xxl-contain{-o-object-fit:contain!important;object-fit:contain!important}.object-fit-xxl-cover{-o-object-fit:cover!important;object-fit:cover!important}.object-fit-xxl-fill{-o-object-fit:fill!important;object-fit:fill!important}.object-fit-xxl-scale{-o-object-fit:scale-down!important;object-fit:scale-down!important}.object-fit-xxl-none{-o-object-fit:none!important;object-fit:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-inline-grid{display:inline-grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-right:0!important;margin-left:0!important}.mx-xxl-1{margin-right:.25rem!important;margin-left:.25rem!important}.mx-xxl-2{margin-right:.5rem!important;margin-left:.5rem!important}.mx-xxl-3{margin-right:1rem!important;margin-left:1rem!important}.mx-xxl-4{margin-right:1.5rem!important;margin-left:1.5rem!important}.mx-xxl-5{margin-right:3rem!important;margin-left:3rem!important}.mx-xxl-auto{margin-right:auto!important;margin-left:auto!important}.my-xxl-0{margin-top:0!important;margin-bottom:0!important}.my-xxl-1{margin-top:.25rem!important;margin-bottom:.25rem!important}.my-xxl-2{margin-top:.5rem!important;margin-bottom:.5rem!important}.my-xxl-3{margin-top:1rem!important;margin-bottom:1rem!important}.my-xxl-4{margin-top:1.5rem!important;margin-bottom:1.5rem!important}.my-xxl-5{margin-top:3rem!important;margin-bottom:3rem!important}.my-xxl-auto{margin-top:auto!important;margin-bottom:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-auto{margin-left:auto!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.px-xxl-0{padding-right:0!important;padding-left:0!important}.px-xxl-1{padding-right:.25rem!important;padding-left:.25rem!important}.px-xxl-2{padding-right:.5rem!important;padding-left:.5rem!important}.px-xxl-3{padding-right:1rem!important;padding-left:1rem!important}.px-xxl-4{padding-right:1.5rem!important;padding-left:1.5rem!important}.px-xxl-5{padding-right:3rem!important;padding-left:3rem!important}.py-xxl-0{padding-top:0!important;padding-bottom:0!important}.py-xxl-1{padding-top:.25rem!important;padding-bottom:.25rem!important}.py-xxl-2{padding-top:.5rem!important;padding-bottom:.5rem!important}.py-xxl-3{padding-top:1rem!important;padding-bottom:1rem!important}.py-xxl-4{padding-top:1.5rem!important;padding-bottom:1.5rem!important}.py-xxl-5{padding-top:3rem!important;padding-bottom:3rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.row-gap-xxl-0{row-gap:0!important}.row-gap-xxl-1{row-gap:.25rem!important}.row-gap-xxl-2{row-gap:.5rem!important}.row-gap-xxl-3{row-gap:1rem!important}.row-gap-xxl-4{row-gap:1.5rem!important}.row-gap-xxl-5{row-gap:3rem!important}.column-gap-xxl-0{-moz-column-gap:0!important;column-gap:0!important}.column-gap-xxl-1{-moz-column-gap:0.25rem!important;column-gap:.25rem!important}.column-gap-xxl-2{-moz-column-gap:0.5rem!important;column-gap:.5rem!important}.column-gap-xxl-3{-moz-column-gap:1rem!important;column-gap:1rem!important}.column-gap-xxl-4{-moz-column-gap:1.5rem!important;column-gap:1.5rem!important}.column-gap-xxl-5{-moz-column-gap:3rem!important;column-gap:3rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}}@media (min-width:1200px){.fs-1{font-size:2rem!important}.fs-2{font-size:1.75rem!important}.fs-3{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-inline-grid{display:inline-grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}}.navbar{font-size:.875rem;font-weight:600;text-transform:uppercase}.navbar-nav .nav-link{padding-top:.715rem;padding-bottom:.715rem}.navbar-brand{margin-right:2rem}.bg-light{border:1px solid rgba(0,0,0,.1)}.bg-light.navbar-fixed-top{border-width:0 0 1px}.bg-light.navbar-bottom-top{border-width:1px 0 0}.nav-item{margin-right:2rem}.btn{font-size:.875rem;text-transform:uppercase}.btn-group-sm>.btn,.btn-sm{font-size:10px}.btn-warning,.btn-warning:focus,.btn-warning:hover,.btn-warning:not([disabled]):not(.disabled):active{color:#fff}.btn-outline-secondary{color:#919aa1;border-color:#919aa1}.btn-outline-secondary:not([disabled]):not(.disabled):active,.btn-outline-secondary:not([disabled]):not(.disabled):focus,.btn-outline-secondary:not([disabled]):not(.disabled):hover{color:#fff;background-color:#ced4da;border-color:#ced4da}.btn-outline-secondary:not([disabled]):not(.disabled):focus{box-shadow:0 0 0 .2rem rgba(206,212,218,.5)}[class*=btn-outline-]{border-width:2px}.border-secondary{border:1px solid #ced4da!important}[data-bs-theme=dark] .btn-primary{background-color:#080808}body{letter-spacing:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{text-transform:uppercase;letter-spacing:3px}.text-secondary{color:#55595c!important}th{font-size:.875rem;text-transform:uppercase}.table td,.table th{padding:1.5rem}.table-sm td,.table-sm th{padding:.75rem}[data-bs-theme=dark] .form-control{color:#55595c}[data-bs-theme=dark] .form-control::-moz-placeholder{color:rgba(85,89,92,.75)}[data-bs-theme=dark] .form-control::placeholder{color:rgba(85,89,92,.75)}[data-bs-theme=dark] .form-floating>.form-control:not(:-moz-placeholder-shown)~label{color:rgba(85,89,92,.75)}[data-bs-theme=dark] .form-floating>.form-control-plaintext~label,[data-bs-theme=dark] .form-floating>.form-control:focus~label,[data-bs-theme=dark] .form-floating>.form-control:not(:placeholder-shown)~label,[data-bs-theme=dark] .form-floating>.form-select~label,[data-bs-theme=dark] .form-floating>label{color:rgba(85,89,92,.75)}[data-bs-theme=dark] .form-floating>.form-control-plaintext::-moz-placeholder,[data-bs-theme=dark] .form-floating>.form-control::-moz-placeholder{color:transparent}[data-bs-theme=dark] .form-floating>.form-control-plaintext::placeholder,[data-bs-theme=dark] .form-floating>.form-control::placeholder{color:transparent}[data-bs-theme=dark] .form-check-input:checked{background-color:rgba(85,89,92,.75)}[data-bs-theme=dark] .form-switch .form-check-input{background-image:url("data:image/svg+xml,")}[data-bs-theme=dark] .form-range::-webkit-slider-thumb{background-color:#919aa1}[data-bs-theme=dark] .form-range:disabled::-webkit-slider-thumb{background-color:#343a40}[data-bs-theme=dark] .input-group-text{color:rgba(85,89,92,.75)}.dropdown-menu{font-size:.875rem;text-transform:none}.badge{padding-top:.28rem}.badge-pill{border-radius:10rem}.badge.bg-light,.badge.bg-secondary{color:#343a40}.card .h1,.card .h2,.card .h3,.card .h4,.card .h5,.card .h6,.card h1,.card h2,.card h3,.card h4,.card h5,.card h6,.list-group-item .h1,.list-group-item .h2,.list-group-item .h3,.list-group-item .h4,.list-group-item .h5,.list-group-item .h6,.list-group-item h1,.list-group-item h2,.list-group-item h3,.list-group-item h4,.list-group-item h5,.list-group-item h6{color:inherit} +/*# sourceMappingURL=bootstrap.min.css.map */ \ No newline at end of file