diff --git a/.env.example b/.env.example
index e66bfee..f301e49 100644
--- a/.env.example
+++ b/.env.example
@@ -1 +1 @@
-MI_UTEM_API_DEBUG=https://api-mi-utem.herokuapp.com/
\ No newline at end of file
+MI_UTEM_API_DEBUG=https://api.exdev.cl
\ No newline at end of file
diff --git a/.fvmrc b/.fvmrc
new file mode 100644
index 0000000..2b19323
--- /dev/null
+++ b/.fvmrc
@@ -0,0 +1,4 @@
+{
+ "flutter": "3.7.12",
+ "flavors": {}
+}
\ No newline at end of file
diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml
new file mode 100644
index 0000000..9cbb387
--- /dev/null
+++ b/.github/workflows/dev.yml
@@ -0,0 +1,103 @@
+name: Publicar Aplicación Beta
+on:
+ pull_request:
+ types: [opened, reopened, synchronize, closed]
+
+jobs:
+ build:
+ # Formato de comentario: /deploy-beta
+ if: |
+ github.event.pull_request.author_association == 'MEMBER' &&
+ (github.event.pull_request.state == 'open' && !github.event.pull_request.draft) &&
+ (!github.event.pull_request.locked && !github.event.pull_request.active_lock_reason) &&
+ (!github.event.pull_request.merged_at)
+ runs-on: macos-latest
+ environment: development
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event.pull_request.head.ref }}
+ - name: Instalar Ruby
+ uses: ruby/setup-ruby@v1
+ with:
+ ruby-version: '3.3.0'
+ bundler-cache: true
+ - name: Instalar Java
+ uses: actions/setup-java@v4
+ with:
+ distribution: 'zulu'
+ java-version: '17'
+ cache: 'gradle'
+ - name: Instalar Flutter
+ uses: flutter-actions/setup-flutter@v3
+ with:
+ channel: stable
+ version: 3.7.12
+ cache: true
+ cache-sdk: true
+ cache-key: mi-utem
+ - name: Instalar Dependencias
+ run: flutter pub get
+ - name: Copiar .env
+ run: cp .env.example .env
+ - name: Generar Archivos
+ env:
+ GOOGLE_SERVICES: ${{ secrets.GOOGLE_SERVICES }}
+ API_PLAY_STORE: ${{ secrets.API_PLAY_STORE }}
+ KEYSTORE_PROPERTIES: ${{ secrets.KEYSTORE_PROPERTIES }}
+ KEYSTORE_FILE: ${{ secrets.KEYSTORE_FILE }}
+ APP_STORE_CONNECT_AUTHKEY: ${{ secrets.APP_STORE_CONNECT_AUTHKEY }}
+ GOOGLE_SERVICE_INFO_PLIST: ${{ secrets.GOOGLE_SERVICE_INFO_PLIST }}
+ run: |
+ echo $GOOGLE_SERVICES | base64 --decode > android/app/google-services.json
+ echo $API_PLAY_STORE | base64 --decode > android/api-playstore.json
+
+ mkdir -p android/keystores
+ chmod 755 android/keystores
+
+ echo $KEYSTORE_PROPERTIES | base64 --decode > android/keystores/key.properties
+ echo $KEYSTORE_FILE | base64 --decode > android/keystores/keystore.jks
+
+ chmod 644 android/keystores/key*
+
+ echo $APP_STORE_CONNECT_AUTHKEY | base64 --decode > ios/fastlane/AuthKey.p8
+ echo $GOOGLE_SERVICE_INFO_PLIST > ios/Runner/GoogleService-Info.plist
+ - name: Publicar Beta
+ uses: maierj/fastlane-action@v3.1.0
+ env:
+ APP_IDENTIFIER_IOS: ${{ secrets.APP_IDENTIFIER_IOS }}
+ APP_IDENTIFIER_ANDROID: ${{ secrets.APP_IDENTIFIER_ANDROID }}
+
+ SLACK_URL: ${{ secrets.SLACK_URL }}
+ APPLE_ID: ${{ secrets.APPLE_ID }}
+
+ FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
+ FASTLANE_PASSWORD: ${{ secrets.FASTLANE_PASSWORD }}
+ FASTLANE_ITC_TEAM_ID: ${{ secrets.FASTLANE_ITC_TEAM_ID }}
+ FASTLANE_TEAM_ID: ${{ secrets.FASTLANE_TEAM_ID }}
+ FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD: ${{ secrets.FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD }}
+
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+ MATCH_REPO_GIT_URL: ${{ secrets.MATCH_REPO_GIT_URL }}
+ MATCH_GIT_BASIC_AUTHORIZATION: ${{ secrets.MATCH_GIT_BASIC_AUTHORIZATION }}
+ MATCH_KEYCHAIN_PASSWORD: ${{ secrets.MATCH_KEYCHAIN_PASSWORD }}
+ MATCH_PASSWORD: ${{ secrets.MATCH_PASSWORD }}
+
+ KEYCHAIN_NAME: ${{ secrets.KEYCHAIN_NAME }}
+ KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
+
+ FASTLANE_SESSION: ${{ secrets.FASTLANE_SESSION }}
+
+ APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
+ APP_STORE_CONNECT_ISSUER_ID: ${{ secrets.APP_STORE_CONNECT_ISSUER_ID }}
+ with:
+ lane: 'upload'
+ options: '{ "type": "beta", "skip_git_push": "true", "skip_slack": "true", "is_ci": "true" }'
+ - name: Publicar Version en Git
+ run: |
+ git config user.name "github-actions[bot]"
+ git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
+ git add pubspec.yaml
+ git commit -m "ci(bump-version): github action bump version"
+ git push
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 4421ce2..11b0d65 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1060,7 +1060,6 @@ FodyWeavers.xsd
# Custom ignores
*.pem
-*.code-workspace
**/prod/google-services.json
android/app/google-services.json
api-playstore.json
@@ -1068,4 +1067,6 @@ GoogleService-Info*.plist
!GoogleService-Info-dev.plist
android/keystores/*
*/fastlane/report.xml
-.flutter-plugins-dependencies
\ No newline at end of file
+
+# Llave de API de App Store Connect
+**/ios/**/*.p8
\ No newline at end of file
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..7100e0a
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "dart.flutterSdkPath": ".fvm/versions/3.7.12"
+}
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index ba86ae6..a6b6f12 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,9 +28,33 @@ Tipos de cambios
## [Unreleased]
+### Added
+- Apodo para personalizar la aplicación.
+- Se agrega onboarding (con configuración de apodo, solicitud de permiso de notificaciones y bienvenida a la app).
+- Lista de estudiantes al resumen de asignatura.
+- Vista previa de estudiantes y profesores.
+- Vista previa de los datos del profesor.
+- Se agrega ventana de vista previa de la asignatura desde horario (al mantener presionado un bloque).
+- Se agrega navegación hacia la asignatura desde el horario al presionar un bloque.
+- Botón para limpiar las notas en la calculadora.
+- Sección de `Acerca de la App` en modo depuración.
+- Se agrega métricas y toma de errores de Sentry (esta vez están bien configurados).
+- Se agrega modo fuera de línea para permitir el uso de la app sin conexión.
+- Se permite cualquier orientación de pantalla (horizontal y vertical).
+
### Changed
+- Se actualizaron algunas dependencias.
+- Se ordenan las clases y widgets de la app.
+- Se optimiza el código y la aplicación en general.
+- Se separan clases en formato de repositorios, servicios y controladores.
+- Se mejora la documentación de algunos archivos y métodos.
+- Ahora se cargan las noticias de la página [noticias.utem.cl](https://noticias.utem.cl).
+- Se utiliza navegación de flutter nativa (Usando [`Navigator`](https://docs.flutter.dev/cookbook/navigation/navigation-basics) en lugar de rutas nombradas).
-- Se actualizan dependecias de Flutter
+### Removed
+- Se elimina pestaña de estudiantes del detalle de asignatura (a favor del botón de lista de estudiantes en el resumen).
+- Modal de Permitir Notificaciones a favor de modal nativa del sistema. Solo se editará el mensaje de notificaciones, ya que es redundante el botón de permitir y cancelar.
+- Vistas sin uso en la aplicación.
## [2.11.9] - 2023-10-11Z
@@ -135,8 +159,3 @@ Esta versión del changelog contiene cambios hechos en 2.10, debido a que no se
- Lista de estudiantes en la pantalla de asignatura
- Perfil de profesores
-- Perfil de profesores
-- Perfil de profesores
-- Perfil de profesores
-- Perfil de profesores
-- Perfil de profesores
diff --git a/Gemfile b/Gemfile
index e4b5be5..4812693 100644
--- a/Gemfile
+++ b/Gemfile
@@ -6,6 +6,7 @@ source "https://rubygems.org"
gem 'fastlane'
gem 'cocoapods'
+gem 'abbrev'
plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
diff --git a/Gemfile.lock b/Gemfile.lock
index 9b45670..4957f90 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1,48 +1,57 @@
GEM
remote: https://rubygems.org/
specs:
- CFPropertyList (3.0.5)
+ CFPropertyList (3.0.7)
+ base64
+ nkf
rexml
- activesupport (6.1.6)
+ abbrev (0.1.2)
+ activesupport (7.1.3.2)
+ base64
+ bigdecimal
concurrent-ruby (~> 1.0, >= 1.0.2)
+ connection_pool (>= 2.2.5)
+ drb
i18n (>= 1.6, < 2)
minitest (>= 5.1)
+ mutex_m
tzinfo (~> 2.0)
- zeitwerk (~> 2.3)
- addressable (2.8.0)
- public_suffix (>= 2.0.2, < 5.0)
+ addressable (2.8.6)
+ public_suffix (>= 2.0.2, < 6.0)
algoliasearch (1.27.5)
httpclient (~> 2.8, >= 2.8.3)
json (>= 1.5.1)
- artifactory (3.0.15)
+ artifactory (3.0.17)
atomos (0.1.3)
- aws-eventstream (1.2.0)
- aws-partitions (1.570.0)
- aws-sdk-core (3.130.0)
- aws-eventstream (~> 1, >= 1.0.2)
- aws-partitions (~> 1, >= 1.525.0)
- aws-sigv4 (~> 1.1)
- jmespath (~> 1.0)
- aws-sdk-kms (1.55.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-eventstream (1.3.0)
+ aws-partitions (1.907.0)
+ aws-sdk-core (3.191.6)
+ aws-eventstream (~> 1, >= 1.3.0)
+ aws-partitions (~> 1, >= 1.651.0)
+ aws-sigv4 (~> 1.8)
+ jmespath (~> 1, >= 1.6.1)
+ aws-sdk-kms (1.78.0)
+ aws-sdk-core (~> 3, >= 3.191.0)
aws-sigv4 (~> 1.1)
- aws-sdk-s3 (1.113.0)
- aws-sdk-core (~> 3, >= 3.127.0)
+ aws-sdk-s3 (1.146.1)
+ aws-sdk-core (~> 3, >= 3.191.0)
aws-sdk-kms (~> 1)
- aws-sigv4 (~> 1.4)
- aws-sigv4 (1.4.0)
+ aws-sigv4 (~> 1.8)
+ aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
+ base64 (0.2.0)
+ bigdecimal (3.1.7)
claide (1.1.0)
- cocoapods (1.11.3)
+ cocoapods (1.15.2)
addressable (~> 2.8)
claide (>= 1.0.2, < 2.0)
- cocoapods-core (= 1.11.3)
+ cocoapods-core (= 1.15.2)
cocoapods-deintegrate (>= 1.0.3, < 2.0)
- cocoapods-downloader (>= 1.4.0, < 2.0)
+ cocoapods-downloader (>= 2.1, < 3.0)
cocoapods-plugins (>= 1.0.0, < 2.0)
cocoapods-search (>= 1.0.0, < 2.0)
- cocoapods-trunk (>= 1.4.0, < 2.0)
+ cocoapods-trunk (>= 1.6.0, < 2.0)
cocoapods-try (>= 1.1.0, < 2.0)
colored2 (~> 3.1)
escape (~> 0.0.4)
@@ -50,10 +59,10 @@ GEM
gh_inspector (~> 1.0)
molinillo (~> 0.8.0)
nap (~> 1.0)
- ruby-macho (>= 1.0, < 3.0)
- xcodeproj (>= 1.21.0, < 2.0)
- cocoapods-core (1.11.3)
- activesupport (>= 5.0, < 7)
+ ruby-macho (>= 2.3.0, < 3.0)
+ xcodeproj (>= 1.23.0, < 2.0)
+ cocoapods-core (1.15.2)
+ activesupport (>= 5.0, < 8)
addressable (~> 2.8)
algoliasearch (~> 1.0)
concurrent-ruby (~> 1.1)
@@ -63,7 +72,7 @@ GEM
public_suffix (~> 4.0)
typhoeus (~> 1.0)
cocoapods-deintegrate (1.0.5)
- cocoapods-downloader (1.6.3)
+ cocoapods-downloader (2.1)
cocoapods-plugins (1.0.0)
nap
cocoapods-search (1.0.1)
@@ -75,19 +84,20 @@ GEM
colored2 (3.1.2)
commander (4.6.0)
highline (~> 2.0.0)
- concurrent-ruby (1.1.10)
+ concurrent-ruby (1.2.3)
+ connection_pool (2.4.1)
declarative (0.0.20)
- digest-crc (0.6.4)
+ digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
- domain_name (0.5.20190701)
- unf (>= 0.0.5, < 1.0.0)
- dotenv (2.7.6)
+ domain_name (0.6.20240107)
+ dotenv (2.8.1)
+ drb (2.2.1)
emoji_regex (3.2.3)
escape (0.0.4)
- ethon (0.15.0)
+ ethon (0.16.0)
ffi (>= 1.15.0)
- excon (0.92.1)
- faraday (1.10.0)
+ excon (0.110.0)
+ faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
faraday-excon (~> 1.1)
@@ -106,8 +116,8 @@ GEM
faraday-em_synchrony (1.0.0)
faraday-excon (1.1.0)
faraday-httpclient (1.0.1)
- faraday-multipart (1.0.3)
- multipart-post (>= 1.2, < 3)
+ faraday-multipart (1.0.4)
+ multipart-post (~> 2)
faraday-net_http (1.0.1)
faraday-net_http_persistent (1.2.0)
faraday-patron (1.0.0)
@@ -115,15 +125,15 @@ GEM
faraday-retry (1.0.3)
faraday_middleware (1.2.0)
faraday (~> 1.0)
- fastimage (2.2.6)
- fastlane (2.205.1)
+ fastimage (2.3.1)
+ fastlane (2.220.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
aws-sdk-s3 (~> 1.0)
babosa (>= 1.0.3, < 2.0.0)
bundler (>= 1.12.0, < 3.0.0)
- colored
+ colored (~> 1.2)
commander (~> 4.6)
dotenv (>= 2.1.1, < 3.0.0)
emoji_regex (>= 0.1, < 4.0)
@@ -135,34 +145,36 @@ GEM
gh_inspector (>= 1.1.2, < 2.0.0)
google-apis-androidpublisher_v3 (~> 0.3)
google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-env (>= 1.6.0, < 2.0.0)
google-cloud-storage (~> 1.31)
highline (~> 2.0)
+ http-cookie (~> 1.0.5)
json (< 3.0.0)
jwt (>= 2.1.0, < 3)
mini_magick (>= 4.9.4, < 5.0.0)
- multipart-post (~> 2.0.0)
+ multipart-post (>= 2.0.0, < 3.0.0)
naturally (~> 2.2)
- optparse (~> 0.1.1)
+ optparse (>= 0.1.1, < 1.0.0)
plist (>= 3.1.0, < 4.0.0)
rubyzip (>= 2.0.0, < 3.0.0)
- security (= 0.1.3)
+ security (= 0.1.5)
simctl (~> 1.6.3)
terminal-notifier (>= 2.0.0, < 3.0.0)
- terminal-table (>= 1.4.5, < 2.0.0)
+ terminal-table (~> 3)
tty-screen (>= 0.6.3, < 1.0.0)
tty-spinner (>= 0.8.0, < 1.0.0)
word_wrap (~> 1.0.0)
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
- xcpretty-travis-formatter (>= 0.0.3)
+ xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
fastlane-plugin-changelog (0.16.0)
- ffi (1.15.5)
+ ffi (1.16.3)
fourflusher (2.3.1)
fuzzy_match (2.0.4)
gh_inspector (1.1.3)
- google-apis-androidpublisher_v3 (0.16.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-core (0.4.2)
+ google-apis-androidpublisher_v3 (0.54.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-core (0.11.3)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
@@ -170,98 +182,94 @@ GEM
representable (~> 3.0)
retriable (>= 2.0, < 4.a)
rexml
- webrick
- google-apis-iamcredentials_v1 (0.10.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-playcustomapp_v1 (0.7.0)
- google-apis-core (>= 0.4, < 2.a)
- google-apis-storage_v1 (0.11.0)
- google-apis-core (>= 0.4, < 2.a)
- google-cloud-core (1.6.0)
- google-cloud-env (~> 1.0)
+ google-apis-iamcredentials_v1 (0.17.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-playcustomapp_v1 (0.13.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-apis-storage_v1 (0.31.0)
+ google-apis-core (>= 0.11.0, < 2.a)
+ google-cloud-core (1.7.0)
+ google-cloud-env (>= 1.0, < 3.a)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
- google-cloud-errors (1.2.0)
- google-cloud-storage (1.36.1)
+ google-cloud-errors (1.4.0)
+ google-cloud-storage (1.47.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
- google-apis-storage_v1 (~> 0.1)
+ google-apis-storage_v1 (~> 0.31.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
- googleauth (1.1.2)
+ googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
- memoist (~> 0.16)
multi_json (~> 1.11)
os (>= 0.9, < 2.0)
signet (>= 0.16, < 2.a)
highline (2.0.3)
- http-cookie (1.0.4)
+ http-cookie (1.0.5)
domain_name (~> 0.5)
httpclient (2.8.3)
- i18n (1.10.0)
+ i18n (1.14.4)
concurrent-ruby (~> 1.0)
- jmespath (1.6.1)
- json (2.6.1)
- jwt (2.3.0)
- memoist (0.16.2)
- mini_magick (4.11.0)
- mini_mime (1.1.2)
- minitest (5.15.0)
+ jmespath (1.6.2)
+ json (2.7.2)
+ jwt (2.8.1)
+ base64
+ mini_magick (4.12.0)
+ mini_mime (1.1.5)
+ minitest (5.22.3)
molinillo (0.8.0)
multi_json (1.15.0)
- multipart-post (2.0.0)
+ multipart-post (2.4.0)
+ mutex_m (0.2.0)
nanaimo (0.3.0)
nap (1.1.0)
naturally (2.2.1)
netrc (0.11.0)
- optparse (0.1.1)
+ nkf (0.2.0)
+ optparse (0.4.0)
os (1.1.4)
- plist (3.6.0)
- public_suffix (4.0.6)
- rake (13.0.6)
- representable (3.1.1)
+ plist (3.7.1)
+ public_suffix (4.0.7)
+ rake (13.2.0)
+ representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
uber (< 0.2.0)
retriable (3.1.2)
- rexml (3.2.5)
+ rexml (3.2.6)
rouge (2.0.7)
ruby-macho (2.5.1)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
- security (0.1.3)
- signet (0.16.1)
+ security (0.1.5)
+ signet (0.19.0)
addressable (~> 2.8)
- faraday (>= 0.17.5, < 3.0)
+ faraday (>= 0.17.5, < 3.a)
jwt (>= 1.5, < 3.0)
multi_json (~> 1.10)
- simctl (1.6.8)
+ simctl (1.6.10)
CFPropertyList
naturally
terminal-notifier (2.0.0)
- terminal-table (1.8.0)
- unicode-display_width (~> 1.1, >= 1.1.1)
+ terminal-table (3.0.2)
+ unicode-display_width (>= 1.1.1, < 3)
trailblazer-option (0.1.2)
tty-cursor (0.7.1)
- tty-screen (0.8.1)
+ tty-screen (0.8.2)
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
- typhoeus (1.4.0)
+ typhoeus (1.4.1)
ethon (>= 0.9.0)
- tzinfo (2.0.4)
+ tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uber (0.1.0)
- unf (0.1.4)
- unf_ext
- unf_ext (0.0.8.1)
- unicode-display_width (1.8.0)
- webrick (1.7.0)
+ unicode-display_width (2.5.0)
word_wrap (1.0.0)
- xcodeproj (1.21.0)
+ xcodeproj (1.24.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
@@ -272,17 +280,18 @@ GEM
rouge (~> 2.0.7)
xcpretty-travis-formatter (1.0.1)
xcpretty (~> 0.2, >= 0.0.7)
- zeitwerk (2.5.4)
PLATFORMS
+ arm64-darwin-22
x86_64-darwin-19
x86_64-darwin-20
x86_64-darwin-21
DEPENDENCIES
+ abbrev
cocoapods
fastlane
fastlane-plugin-changelog
BUNDLED WITH
- 2.3.7
+ 2.5.7
diff --git a/README.md b/README.md
index 71eeefb..66b9cb1 100644
--- a/README.md
+++ b/README.md
@@ -2,11 +2,71 @@
Aplicación multiplataforma hecha por estudiantes de la [Universidad Tecnológica Metropolitana de Chile](https://www.utem.cl/) enfocada en adaptar la [plataforma académica Mi.UTEM](https://mi.utem.cl/) de la institución a dispositivos móviles.
## Requisitos técnicos
-- Flutter 3.13.6
+- Flutter 3.7.12 (te recomendamos utilizar [fvm](https://fvm.app) para facilitar la administración de versiones)
+- macOS + XCode (para compilar en iOS)
+- Android Studio (para compilar en Android)
+- ruby 3.3.0 (para compilar y subir app a App Store y Google Play)
+
+## Organización de carpetas
+```
+|-- lib
+| |-- config (Configuración de la aplicación)
+| |-- controllers (Controladores de la aplicación, para procesar datos de una vista especifica)
+| |-- models (Modelos de datos)
+| |-- repositories (Repositorios de datos, para obtener datos desde la API)
+| |-- screens (Pantallas de la aplicación)
+| |-- services (Servicios de la aplicación, maneja y procesa los datos de repositorios)
+| |-- themes (Temas de la aplicación)
+| |-- utils (Utilidades de la aplicación)
+| |-- widgets (Widgets de la aplicación)
+|-- main.dart (Punto de entrada de la aplicación)
+|-- service_manager.dart (Registra los servicios de la aplicación)
+```
+
+### Construcción de la app
+
+Para construir la app utilizamos fastlane.
+Comienza revisando la documentación de Fastlane para [iOS](https://docs.fastlane.tools/getting-started/ios/setup/) y [Android](https://docs.fastlane.tools/getting-started/android/setup/).
+Utilizaremos la instalación de bundler para instalar las dependencias y ejecutar fastlane.
+
+
+Instalación de Bundler
+
+(Se asume que tienes instalado Ruby 3.3.0 o superior)
+```bash
+gem install bundler
+```
+
+
+
+Instalación de las Dependencias
+
+Una vez instalado ejecutarás este comando para instalar las dependencias:
+```bash
+bundle install
+```
+
+
+
+Subiendo una nueva Actualización
+
+Para construir la app ejecuta este comando:
+```bash
+bundle exec fastlane upload type:"beta" skip_ios:false skip_android:false skip_clean:true skip_cocoapods:true skip_git_push:true skip_slack:true is_ci:true
+```
+Este comando subirá el archivo binario a AppStore y Google Play. Esto hacen las variables:
+- `skip_ios`: Si es `true` no subirá la app a AppStore, si es `false` subirá la app a AppStore.
+- `skip_android`: Si es `true` no subirá la app a Google Play, si es `false` subirá la app a Google Play.
+- `skip_clean`: Si es `true` no limpiará los archivos temporales, si es `false` limpiará los archivos temporales (se recomienda utilizar para construcciones en producción y evitar problemas con archivos guardados en caché).
+- `skip_cocoapods`: Si es `true` no instalará las dependencias de CocoaPods, si es `false` instalará las dependencias de CocoaPods (se recomienda utilizar para construcciones en producción y evitar problemas con dependencias de CocoaPods).
+- `skip_git_push`: Si es `true` no creará una nueva etiqueta, si es `false` creará una nueva etiqueta con la lista de cambios formateada.
+- `skip_slack`: Si es `true` no enviará un mensaje a Slack, si es `false` enviará un mensaje a Slack.
+- `is_ci`: Si es `true` se ejecutará en modo de integración continua, es decir, no esperará a ver si la versión aparece en AppStore o Google Play, si es `false` esperará a ver si la versión aparece en AppStore o Google Play. Además, al ser `true` también evitará editar el repositorio de Match (el cual contiene los certificados de distribución de la app).
+
## Créditos
Este proyecto fue creado por el Club de Desarrollo Experimental (ExDev) de la Universidad Tecnológica Metropolitana y es mantenido por los propios estudiantes con el apoyo del equipo de SISEI. Mira los perfiles que han contribuido a este proyecto:
-
+
\ No newline at end of file
diff --git a/android/app/build.gradle b/android/app/build.gradle
index fe0da47..77e7f4e 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -37,7 +37,6 @@ android {
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
- // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "cl.inndev.miutem"
minSdkVersion 23
multiDexEnabled true
diff --git a/android/build.gradle b/android/build.gradle
index 74e4842..ca02cfb 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,8 +1,8 @@
buildscript {
ext.kotlin_version = '1.7.21'
ext {
- compileSdkVersion = 33 // or latest
- targetSdkVersion = 33 // or latest
+ compileSdkVersion = 34 // or latest
+ targetSdkVersion = 34 // or latest
appCompatVersion = "1.4.2" // or latest
}
repositories {
diff --git a/fastlane/.env.example b/fastlane/.env.example
index f06b1b3..96dddc9 100644
--- a/fastlane/.env.example
+++ b/fastlane/.env.example
@@ -1,15 +1,20 @@
-SLACK_URL=https://hooks.slack.com/services/ASDFG...
+APP_IDENTIFIER_IOS=cl.utem.miutem
+APP_IDENTIFIER_ANDROID=cl.inndev.miutem
+
+SLACK_URL=https://hooks.slack.com/services/...
APPLE_ID=exdev@utem.cl
+
FASTLANE_USER=exdev@utem.cl
-FASTLANE_PASSWORD=apple_id_password
+FASTLANE_PASSWORD=
FASTLANE_ITC_TEAM_ID=122942314
FASTLANE_TEAM_ID=DS265QHA5J
-FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD=app_specific_password
-MATCH_PASSWORD=match_password
-GITHUB_TOKEN=github_token
-APP_IDENTIFIER_IOS=com.app.identifier_ios
-APP_IDENTIFIER_ANDROID=com.app.identifier_android
-MATCH_REPO_GIT_URL=git@github.com:certificates-repo
-
-KEYCHAIN_PASSWORD=tempKeychainPassword
-KEYCHAIN_NAME=tempKeychainName
\ No newline at end of file
+FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD=
+
+GITHUB_TOKEN=
+
+MATCH_REPO_GIT_URL=git@github.com:example/examplerepo.git
+MATCH_GIT_BASIC_AUTHORIZATION=
+MATCH_KEYCHAIN_PASSWORD=
+
+KEYCHAIN_NAME=login.keychain
+KEYCHAIN_PASSWORD=
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
index fa0e814..fa0ccea 100644
--- a/fastlane/Fastfile
+++ b/fastlane/Fastfile
@@ -42,40 +42,92 @@ platform :mobile do
changelog
end
- lane :test do
- puts("Testing Fastlane for mobile")
+ lane :test do |options|
+ skip_slack = false
+ skip_android_test = false
+ skip_ios_test = false
+
+ if options[:skip_slack]
+ skip_slack = options[:skip_slack]
+ end
+
+ if options[:skip_android_test]
+ skip_android_test = options[:skip_android_test]
+ end
+
+ if options[:skip_ios_test]
+ skip_ios_test = options[:skip_ios_test]
+ end
+
+ puts "Testing Fastlane for mobile"
changelog = read_changelog
emojified_changelog = emojify_changelog
-
+
changelog = translate_changelog(changelog: changelog)
emojified_changelog = translate_changelog(changelog: emojified_changelog)
puts "Changelog: #{changelog}"
puts "Emojified Changelog: #{emojified_changelog}"
- android_test
- ios_test
+ unless skip_android_test
+ android_test
+ end
- slack(
- message: "Este es un mensaje de prueba desde Fastlane",
- slack_url: ENV["SLACK_URL"],
- channel: "#proy-mi-utem-bots",
- default_payloads: [],
- attachment_properties: {
- fields: [
- {
- title: "Campo",
- value: "Prueba"
+ unless skip_ios_test
+ ios_test
+ end
+
+ unless skip_slack
+ slack(
+ message: "Este es un mensaje de prueba desde Fastlane",
+ channel: "proy-mi-utem-bots",
+ default_payloads: [],
+ attachment_properties: {
+ fields: [
+ {
+ title: "Campo",
+ value: "Prueba"
+ },
+ ]
},
- ]
- },
- )
+ )
+ end
+ end
+
+ desc "Lee el archivo ../pubspec.yaml, obtiene la version y su numero de compilación"
+ lane :get_pubspec_version do
+ pubspec = File.read("../pubspec.yaml")
+ version = pubspec.match(/version: (.+)/)[1]
+ build_name = version.match(/(\d+\.\d+\.\d+)/)[1]
+ build_number = ((version.match(/(\d+)$/)[1]).to_i + 1).to_s
+
+ {
+ "build_name" => build_name,
+ "build_number" => build_number
+ }
+ end
+
+ desc "Incrementa el numero de compilación en el archivo ../pubspec.yaml"
+ lane :increment_pubspec_build_number do
+ version = get_pubspec_version()
+ build_number = version["build_number"]
+ build_name = version["build_name"]
+
+ puts "Incrementando el numero de compilación en el archivo ../pubspec.yaml"
+ new_version = "version: #{build_name}+#{build_number}"
+
+ pubspec = File.read("../pubspec.yaml")
+ pubspec = pubspec.gsub(/version: (.+)/, new_version)
+ File.write("../pubspec.yaml", pubspec)
+
+ puts "Numero de compilación incrementado en el archivo ../pubspec.yaml"
end
lane :upload do |options|
- build_number = options[:build_number]
- build_name = options[:build_name]
+ version = get_pubspec_version()
+ build_number = version["build_number"] # Obtiene la version del pubspec.yaml
+ build_name = version["build_name"] # Obtiene el numero de compilación del pubspec.yaml
changelog = read_changelog
emojified_changelog = emojify_changelog
changelog = translate_changelog(changelog: changelog)
@@ -89,6 +141,17 @@ platform :mobile do
skip_git_push = false
skip_slack = false
is_ci = false
+ increment_build_number = false
+
+ puts "Construyendo app con version #{build_name} (#{build_number})"
+
+ if options[:build_number]
+ build_number = options[:build_number]
+ end
+
+ if options[:build_name]
+ build_name = options[:build_name]
+ end
if options[:type] == "release" || options[:type] == "beta"
type = options[:type]
@@ -126,6 +189,10 @@ platform :mobile do
is_ci = options[:is_ci]
end
+ if options[:increment_build_number]
+ increment_build_number = options[:increment_build_number]
+ end
+
if build_name
build_name = build_name.tr('v', '')
end
@@ -154,33 +221,34 @@ platform :mobile do
)
end
- stamp_changelog(
- section_identifier: build_name,
- git_tag: build_name,
- )
-
- unless skip_git_push
- push_to_git_remote
- git_add
- git_commit(path: "*", message: "Stamp changelog for #{build_name} (#{build_number})")
- push_to_git_remote
-
- github_release = set_github_release(
- repository_name: "exdevutem/mi-utem",
- api_token: ENV["GITHUB_TOKEN"],
- name: "v#{build_name}",
- tag_name: "v#{build_name}",
- description: emojified_changelog,
- commitish: "dev",
- upload_assets: ["./build/app/outputs/bundle/release/app-release.aab", "./build/app/outputs/apk/release/app-release.apk"]
+ if options[:type] == "release"
+ stamp_changelog(
+ section_identifier: build_name,
+ git_tag: build_name,
)
+
+ unless skip_git_push
+ push_to_git_remote
+ git_add
+ git_commit(path: "*", message: "Stamp changelog for #{build_name} (#{build_number})")
+ push_to_git_remote
+
+ github_release = set_github_release(
+ repository_name: "exdevutem/mi-utem",
+ api_token: ENV["GITHUB_TOKEN"],
+ name: "v#{build_name}+#{build_number}",
+ tag_name: "v#{build_name}+#{build_number}",
+ description: emojified_changelog,
+ commitish: "dev",
+ upload_assets: ["./build/app/outputs/bundle/release/app-release.aab", "./build/app/outputs/apk/release/app-release.apk"]
+ )
+ end
end
unless skip_slack
slack(
message: "🚀 Se ha publicado la nueva versión #{build_name} (#{build_number})",
- slack_url: ENV["SLACK_URL"],
- channel: "#proy-mi-utem",
+ channel: "proy-mi-utem",
default_payloads: [],
attachment_properties: {
fields: [
@@ -196,5 +264,10 @@ platform :mobile do
},
)
end
+
+ puts "App construida y publicada con éxito"
+ unless increment_build_number
+ increment_pubspec_build_number()
+ end
end
end
\ No newline at end of file
diff --git a/ios/Podfile b/ios/Podfile
index 16c1ff0..1cdce05 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -34,6 +34,7 @@ target 'Runner' do
use_modular_headers!
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
+ pod 'GoogleUtilities', :git => 'https://github.com/google/GoogleUtilities.git'
end
post_install do |installer|
@@ -112,6 +113,7 @@ target 'MiUtemNotificationServiceExtension' do
use_modular_headers!
install_awesome_fcm_ios_pod_target File.dirname(File.realpath(__FILE__))
+ pod 'GoogleUtilities', :git => 'https://github.com/google/GoogleUtilities.git'
end
update_awesome_fcm_service_target('MiUtemNotificationServiceExtension', File.dirname(File.realpath(__FILE__)), flutter_root)
################ Awesome Notifications FCM pod mod ###################
\ No newline at end of file
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index 1a54867..c21e7ce 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -596,18 +596,18 @@ PODS:
- abseil/base/base_internal
- abseil/base/config
- abseil/meta/type_traits
- - awesome_notifications (0.0.5):
+ - awesome_notifications (0.8.1):
- Flutter
- - IosAwnCore (= 0.7.3)
+ - IosAwnCore (~> 0.8.0)
- awesome_notifications_core (0.0.1):
- Flutter
- - awesome_notifications_fcm (0.7.3):
+ - awesome_notifications_fcm (0.8.1):
- awesome_notifications
- - Firebase
- Firebase/Messaging
+ - FirebaseCore
- Flutter
- - IosAwnCore (= 0.7.3)
- - IosAwnFcmDist (= 0.7.5)
+ - IosAwnCore (~> 0.8.0)
+ - IosAwnFcmDist (~> 0.8.0)
- background_fetch (1.2.1):
- Flutter
- BoringSSL-GRPC (0.0.24):
@@ -621,8 +621,6 @@ PODS:
- firebase_core
- Flutter
- nanopb (< 2.30910.0, >= 2.30908.0)
- - Firebase (10.7.0):
- - Firebase/Core (= 10.7.0)
- Firebase/Analytics (10.7.0):
- Firebase/Core
- Firebase/Core (10.7.0):
@@ -630,6 +628,9 @@ PODS:
- FirebaseAnalytics (~> 10.7.0)
- Firebase/CoreOnly (10.7.0):
- FirebaseCore (= 10.7.0)
+ - Firebase/Crashlytics (10.7.0):
+ - Firebase/CoreOnly
+ - FirebaseCrashlytics (~> 10.7.0)
- Firebase/Firestore (10.7.0):
- Firebase/CoreOnly
- FirebaseFirestore (~> 10.7.0)
@@ -646,9 +647,13 @@ PODS:
- Firebase/Analytics (= 10.7.0)
- firebase_core
- Flutter
- - firebase_core (2.11.0):
+ - firebase_core (2.16.0):
- Firebase/CoreOnly (= 10.7.0)
- Flutter
+ - firebase_crashlytics (3.3.6):
+ - Firebase/Crashlytics (= 10.7.0)
+ - firebase_core
+ - Flutter
- firebase_in_app_messaging (0.7.0-15):
- Firebase/InAppMessaging (= 10.7.0)
- firebase_core
@@ -657,7 +662,7 @@ PODS:
- Firebase/RemoteConfig (= 10.7.0)
- firebase_core
- Flutter
- - FirebaseABTesting (10.16.0):
+ - FirebaseABTesting (10.23.0):
- FirebaseCore (~> 10.0)
- FirebaseAnalytics (10.7.0):
- FirebaseAnalytics/AdIdSupport (= 10.7.0)
@@ -681,8 +686,18 @@ PODS:
- FirebaseCoreInternal (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/Logger (~> 7.8)
+ - FirebaseCoreExtension (10.23.0):
+ - FirebaseCore (~> 10.0)
- FirebaseCoreInternal (10.16.0):
- "GoogleUtilities/NSData+zlib (~> 7.8)"
+ - FirebaseCrashlytics (10.7.0):
+ - FirebaseCore (~> 10.5)
+ - FirebaseInstallations (~> 10.0)
+ - FirebaseSessions (~> 10.5)
+ - GoogleDataTransport (~> 9.2)
+ - GoogleUtilities/Environment (~> 7.8)
+ - nanopb (< 2.30910.0, >= 2.30908.0)
+ - PromisesObjC (~> 2.1)
- FirebaseFirestore (10.7.0):
- abseil/algorithm (~> 1.20211102.0)
- abseil/base (~> 1.20211102.0)
@@ -702,7 +717,7 @@ PODS:
- FirebaseInstallations (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- nanopb (< 2.30910.0, >= 2.30908.0)
- - FirebaseInstallations (10.16.0):
+ - FirebaseInstallations (10.23.0):
- FirebaseCore (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- GoogleUtilities/UserDefaults (~> 7.8)
@@ -722,9 +737,15 @@ PODS:
- FirebaseInstallations (~> 10.0)
- GoogleUtilities/Environment (~> 7.8)
- "GoogleUtilities/NSData+zlib (~> 7.8)"
+ - FirebaseSessions (10.23.0):
+ - FirebaseCore (~> 10.5)
+ - FirebaseCoreExtension (~> 10.0)
+ - FirebaseInstallations (~> 10.0)
+ - GoogleDataTransport (~> 9.2)
+ - GoogleUtilities/Environment (~> 7.10)
+ - nanopb (< 2.30911.0, >= 2.30908.0)
+ - PromisesSwift (~> 2.1)
- Flutter (1.0.0)
- - flutter_keyboard_visibility (0.0.1):
- - Flutter
- flutter_secure_storage (6.0.0):
- Flutter
- flutter_uxcam (2.4.5):
@@ -753,29 +774,54 @@ PODS:
- GoogleUtilities/Network (~> 7.8)
- "GoogleUtilities/NSData+zlib (~> 7.8)"
- nanopb (< 2.30910.0, >= 2.30908.0)
- - GoogleDataTransport (9.2.5):
+ - GoogleDataTransport (9.4.1):
- GoogleUtilities/Environment (~> 7.7)
- - nanopb (< 2.30910.0, >= 2.30908.0)
+ - nanopb (< 2.30911.0, >= 2.30908.0)
- PromisesObjC (< 3.0, >= 1.2)
- - GoogleUtilities/AppDelegateSwizzler (7.11.5):
+ - GoogleUtilities (7.13.0):
+ - GoogleUtilities/AppDelegateSwizzler (= 7.13.0)
+ - GoogleUtilities/Environment (= 7.13.0)
+ - GoogleUtilities/ISASwizzler (= 7.13.0)
+ - GoogleUtilities/Logger (= 7.13.0)
+ - GoogleUtilities/MethodSwizzler (= 7.13.0)
+ - GoogleUtilities/Network (= 7.13.0)
+ - "GoogleUtilities/NSData+zlib (= 7.13.0)"
+ - GoogleUtilities/Privacy (= 7.13.0)
+ - GoogleUtilities/Reachability (= 7.13.0)
+ - GoogleUtilities/SwizzlerTestHelpers (= 7.13.0)
+ - GoogleUtilities/UserDefaults (= 7.13.0)
+ - GoogleUtilities/AppDelegateSwizzler (7.13.0):
- GoogleUtilities/Environment
- GoogleUtilities/Logger
- GoogleUtilities/Network
- - GoogleUtilities/Environment (7.11.5):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Environment (7.13.0):
+ - GoogleUtilities/Privacy
- PromisesObjC (< 3.0, >= 1.2)
- - GoogleUtilities/Logger (7.11.5):
+ - GoogleUtilities/ISASwizzler (7.13.0):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Logger (7.13.0):
- GoogleUtilities/Environment
- - GoogleUtilities/MethodSwizzler (7.11.5):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/MethodSwizzler (7.13.0):
- GoogleUtilities/Logger
- - GoogleUtilities/Network (7.11.5):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Network (7.13.0):
- GoogleUtilities/Logger
- "GoogleUtilities/NSData+zlib"
+ - GoogleUtilities/Privacy
- GoogleUtilities/Reachability
- - "GoogleUtilities/NSData+zlib (7.11.5)"
- - GoogleUtilities/Reachability (7.11.5):
+ - "GoogleUtilities/NSData+zlib (7.13.0)":
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/Privacy (7.13.0)
+ - GoogleUtilities/Reachability (7.13.0):
- GoogleUtilities/Logger
- - GoogleUtilities/UserDefaults (7.11.5):
+ - GoogleUtilities/Privacy
+ - GoogleUtilities/SwizzlerTestHelpers (7.13.0):
+ - GoogleUtilities/MethodSwizzler
+ - GoogleUtilities/UserDefaults (7.13.0):
- GoogleUtilities/Logger
+ - GoogleUtilities/Privacy
- "gRPC-C++ (1.44.0)":
- "gRPC-C++/Implementation (= 1.44.0)"
- "gRPC-C++/Interface (= 1.44.0)"
@@ -833,10 +879,12 @@ PODS:
- Flutter
- in_app_review (0.2.0):
- Flutter
- - IosAwnCore (0.7.3)
- - IosAwnFcmDist (0.7.5):
- - IosAwnCore (= 0.7.3)
- - leveldb-library (1.22.2)
+ - IosAwnCore (0.8.0)
+ - IosAwnFcmDist (0.8.0):
+ - FirebaseCore
+ - FirebaseMessaging
+ - IosAwnCore (~> 0.8.0)
+ - leveldb-library (1.22.4)
- Libuv-gRPC (0.0.10):
- Libuv-gRPC/Implementation (= 0.0.10)
- Libuv-gRPC/Interface (= 0.0.10)
@@ -855,14 +903,18 @@ PODS:
- FlutterMacOS
- permission_handler_apple (9.1.1):
- Flutter
- - PromisesObjC (2.3.1)
- - Sentry/HybridSDK (8.11.0):
- - SentryPrivate (= 8.11.0)
- - sentry_flutter (0.0.1):
+ - PromisesObjC (2.4.0)
+ - PromisesSwift (2.4.0):
+ - PromisesObjC (= 2.4.0)
+ - screen_protector (1.2.1):
+ - Flutter
+ - ScreenProtectorKit (~> 1.3.1)
+ - ScreenProtectorKit (1.3.1)
+ - Sentry/HybridSDK (8.25.2)
+ - sentry_flutter (8.2.0):
- Flutter
- FlutterMacOS
- - Sentry/HybridSDK (= 8.11.0)
- - SentryPrivate (8.11.0)
+ - Sentry/HybridSDK (= 8.25.2)
- share_plus (0.0.1):
- Flutter
- shared_preferences_foundation (0.0.1):
@@ -873,7 +925,7 @@ PODS:
- FMDB (>= 2.7.5)
- url_launcher_ios (0.0.1):
- Flutter
- - UXCam (3.6.6)
+ - UXCam (3.6.11)
- video_player_avfoundation (0.0.1):
- Flutter
@@ -885,21 +937,23 @@ DEPENDENCIES:
- cloud_firestore (from `.symlinks/plugins/cloud_firestore/ios`)
- firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`)
+ - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`)
- firebase_in_app_messaging (from `.symlinks/plugins/firebase_in_app_messaging/ios`)
- firebase_remote_config (from `.symlinks/plugins/firebase_remote_config/ios`)
- Flutter (from `Flutter`)
- - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`)
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
- flutter_uxcam (from `.symlinks/plugins/flutter_uxcam/ios`)
+ - GoogleUtilities (from `https://github.com/google/GoogleUtilities.git`)
- image_editor_common (from `.symlinks/plugins/image_editor_common/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_review (from `.symlinks/plugins/in_app_review/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
+ - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
+ - screen_protector (from `.symlinks/plugins/screen_protector/ios`)
- sentry_flutter (from `.symlinks/plugins/sentry_flutter/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`)
- - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
+ - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
- sqflite (from `.symlinks/plugins/sqflite/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/ios`)
@@ -912,16 +966,18 @@ SPEC REPOS:
- FirebaseABTesting
- FirebaseAnalytics
- FirebaseCore
+ - FirebaseCoreExtension
- FirebaseCoreInternal
+ - FirebaseCrashlytics
- FirebaseFirestore
- FirebaseInAppMessaging
- FirebaseInstallations
- FirebaseMessaging
- FirebaseRemoteConfig
+ - FirebaseSessions
- FMDB
- GoogleAppMeasurement
- GoogleDataTransport
- - GoogleUtilities
- "gRPC-C++"
- gRPC-Core
- IosAwnCore
@@ -930,8 +986,9 @@ SPEC REPOS:
- Libuv-gRPC
- nanopb
- PromisesObjC
+ - PromisesSwift
+ - ScreenProtectorKit
- Sentry
- - SentryPrivate
- UXCam
EXTERNAL SOURCES:
@@ -949,18 +1006,20 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/firebase_analytics/ios"
firebase_core:
:path: ".symlinks/plugins/firebase_core/ios"
+ firebase_crashlytics:
+ :path: ".symlinks/plugins/firebase_crashlytics/ios"
firebase_in_app_messaging:
:path: ".symlinks/plugins/firebase_in_app_messaging/ios"
firebase_remote_config:
:path: ".symlinks/plugins/firebase_remote_config/ios"
Flutter:
:path: Flutter
- flutter_keyboard_visibility:
- :path: ".symlinks/plugins/flutter_keyboard_visibility/ios"
flutter_secure_storage:
:path: ".symlinks/plugins/flutter_secure_storage/ios"
flutter_uxcam:
:path: ".symlinks/plugins/flutter_uxcam/ios"
+ GoogleUtilities:
+ :git: https://github.com/google/GoogleUtilities.git
image_editor_common:
:path: ".symlinks/plugins/image_editor_common/ios"
image_picker_ios:
@@ -970,15 +1029,17 @@ EXTERNAL SOURCES:
package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation:
- :path: ".symlinks/plugins/path_provider_foundation/darwin"
+ :path: ".symlinks/plugins/path_provider_foundation/ios"
permission_handler_apple:
:path: ".symlinks/plugins/permission_handler_apple/ios"
+ screen_protector:
+ :path: ".symlinks/plugins/screen_protector/ios"
sentry_flutter:
:path: ".symlinks/plugins/sentry_flutter/ios"
share_plus:
:path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation:
- :path: ".symlinks/plugins/shared_preferences_foundation/darwin"
+ :path: ".symlinks/plugins/shared_preferences_foundation/ios"
sqflite:
:path: ".symlinks/plugins/sqflite/ios"
url_launcher_ios:
@@ -986,60 +1047,70 @@ EXTERNAL SOURCES:
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/ios"
+CHECKOUT OPTIONS:
+ GoogleUtilities:
+ :commit: 26c898aed8bed13b8a63057ee26500abbbcb8d55
+ :git: https://github.com/google/GoogleUtilities.git
+
SPEC CHECKSUMS:
abseil: ebe5b5529fb05d93a8bdb7951607be08b7fa71bc
- awesome_notifications: d63d9a25f126860f9a600850d99772237895b3ba
+ awesome_notifications: db394d2e061e4583ba0f738ddea611e3986cc3fb
awesome_notifications_core: d02eed89738fa362d56cbd372850e9adcd2c6bef
- awesome_notifications_fcm: 7e2d7ab4ca1826fe3a9a5ca96771ace73e05db48
+ awesome_notifications_fcm: 554a9088f81a91dbe8a318abee6b48f43e4a9417
background_fetch: 896944864b038d2837fc750d470e9841e1e6a363
BoringSSL-GRPC: 3175b25143e648463a56daeaaa499c6cb86dad33
cloud_firestore: e0da2eedba479416c908433ac8879fdd81f61157
Firebase: 0219acf760880eeec8ce479895bd7767466d9f81
firebase_analytics: e8e294333de66e5429d4aac365966281b4dbfb7d
- firebase_core: dee76ded6c693fdb38b8ea39aef7129e32e587a3
+ firebase_core: 27bc73423698d0960be189ccf29bdc2d373f2746
+ firebase_crashlytics: 1b3768f2e118b0281ad30f2931369e0d1921789c
firebase_in_app_messaging: 2b36a1746f4fefbd6f578a2f6659358a0d3f2c94
firebase_remote_config: e5f1ed5b29191424280b7b249228f0ed64bc90ee
- FirebaseABTesting: 03f0a8b88cf618350527f2c6a2234e29b9c65064
+ FirebaseABTesting: aec61ed9a34d85a95e2013a3fdf051426a2419df
FirebaseAnalytics: f8133442ee6f8512e28ff19e62ce15398bfaeace
FirebaseCore: e317665b9d744727a97e623edbbed009320afdd7
+ FirebaseCoreExtension: cb88851781a24e031d1b58e0bd01eb1f46b044b5
FirebaseCoreInternal: 26233f705cc4531236818a07ac84d20c333e505a
+ FirebaseCrashlytics: 35fdd1a433b31e28adcf5c8933f4c526691a1e0b
FirebaseFirestore: 3963a6edd1c84b4748dab3e2c62624a29d03eca1
FirebaseInAppMessaging: d04732fe9c37c3d026d66435abba60120087a7f5
- FirebaseInstallations: b822f91a61f7d1ba763e5ccc9d4f2e6f2ed3b3ee
+ FirebaseInstallations: 42d6ead4605d6eafb3b6683674e80e18eb6f2c35
FirebaseMessaging: ac9062bcc35ed56e15a0241d8fd317022499baf8
FirebaseRemoteConfig: d5de62211e2eaa2152d8ee85a23c301b70887a74
+ FirebaseSessions: f06853e30f99fe42aa511014d7ee6c8c319f08a3
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
- flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069
flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be
flutter_uxcam: 49ca783e481233911475724eb1366064183fffc1
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
GoogleAppMeasurement: fe17c92a32207dd5cdd4e8d742767f2da74857f6
- GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2
- GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084
+ GoogleDataTransport: 6c09b596d841063d76d4288cc2d2f42cc36e1e2a
+ GoogleUtilities: d053d902a8edaa9904e1bd00c37535385b8ed152
"gRPC-C++": 9675f953ace2b3de7c506039d77be1f2e77a8db2
gRPC-Core: 943e491cb0d45598b0b0eb9e910c88080369290b
image_editor_common: d6f6644ae4a6de80481e89fe6d0a8c49e30b4b43
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
in_app_review: 318597b3a06c22bb46dc454d56828c85f444f99d
- IosAwnCore: 6494e0e174d49f04f513e8a002187be226889a37
- IosAwnFcmDist: 47578dd46472304b20f1965ad12cc893c877e57c
- leveldb-library: f03246171cce0484482ec291f88b6d563699ee06
+ IosAwnCore: ed1b2b6d84962a758354dbacd9ce525c72ce28a9
+ IosAwnFcmDist: 0ac4da8f9ef8f2db9e5ec5d0c10c8db793ce447d
+ leveldb-library: 06a69cc7582d64b29424a63e085e683cc188230a
Libuv-gRPC: 55e51798e14ef436ad9bc45d12d43b77b49df378
nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431
package_info_plus: 115f4ad11e0698c8c1c5d8a689390df880f47e85
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
- PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4
- Sentry: 39d57e691e311bdb73bc1ab5bbebbd6bc890050d
- sentry_flutter: b2feefdad5b0f06602347172bc7257e8e9da5562
- SentryPrivate: 48712023cdfd523735c2edb6b06bedf26c4730a3
+ PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
+ PromisesSwift: 9d77319bbe72ebf6d872900551f7eeba9bce2851
+ screen_protector: 6f92086bd2f2f4b54f54913289b9d1310610140b
+ ScreenProtectorKit: 83a6281b02c7a5902ee6eac4f5045f674e902ae4
+ Sentry: 51b056d96914a741f63eca774d118678b1eb05a1
+ sentry_flutter: e8397d13e297a5d4b6be8a752e33140b21c5cc97
share_plus: c3fef564749587fc939ef86ffb283ceac0baf9f5
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
- UXCam: 7f200dd8f0829ae92a2ef82cadbb35dadff6108d
+ UXCam: 73a2718c84c547012c5bd47959179d900b1948c2
video_player_avfoundation: 81e49bb3d9fb63dccf9fa0f6d877dc3ddbeac126
-PODFILE CHECKSUM: 816280d49dfc997733647f095bf1e4c52c291937
+PODFILE CHECKSUM: 4d4f03dca85c6d30067635d550a818b62d393f0e
-COCOAPODS: 1.13.0
+COCOAPODS: 1.15.2
diff --git a/ios/PrivacyInfo.xcprivacy b/ios/PrivacyInfo.xcprivacy
new file mode 100644
index 0000000..e17b525
--- /dev/null
+++ b/ios/PrivacyInfo.xcprivacy
@@ -0,0 +1,33 @@
+
+
+
+
+ NSPrivacyAccessedAPITypes
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryUserDefaults
+ NSPrivacyAccessedAPITypeReasons
+
+ CA92.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryDiskSpace
+ NSPrivacyAccessedAPITypeReasons
+
+ 7D9E.1
+
+
+
+ NSPrivacyAccessedAPIType
+ NSPrivacyAccessedAPICategoryFileTimestamp
+ NSPrivacyAccessedAPITypeReasons
+
+ C617.1
+
+
+
+
+
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index fc3827b..bb1e76d 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -10,6 +10,8 @@
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
+ 79C1453E2BBDF10B0064A7E0 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 79FBEAF12BBDC94D0075EACE /* PrivacyInfo.xcprivacy */; };
+ 79FBEAF22BBDC94D0075EACE /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 79FBEAF12BBDC94D0075EACE /* PrivacyInfo.xcprivacy */; };
8F4ED3CFA3A6AA57DAA4905A /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6121D4E2A474C9DE828CDCAE /* Pods_Runner.framework */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
@@ -72,6 +74,7 @@
6DE503BB399A91B6C5520D76 /* Pods-Runner.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-dev.xcconfig"; 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 = ""; };
+ 79FBEAF12BBDC94D0075EACE /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; };
7FE2002C76C7F77E5A50737A /* Pods-MiUtemNotificationServiceExtension.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MiUtemNotificationServiceExtension.debug-dev.xcconfig"; path = "Target Support Files/Pods-MiUtemNotificationServiceExtension/Pods-MiUtemNotificationServiceExtension.debug-dev.xcconfig"; sourceTree = ""; };
9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; };
@@ -159,6 +162,7 @@
97C146E51CF9000F007C117D = {
isa = PBXGroup;
children = (
+ 79FBEAF12BBDC94D0075EACE /* PrivacyInfo.xcprivacy */,
9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */,
EBE5B6BC29D4D890005924AB /* MiUtemNotificationServiceExtension */,
@@ -256,7 +260,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1420;
- LastUpgradeCheck = 1430;
+ LastUpgradeCheck = 1300;
ORGANIZATIONNAME = "";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
@@ -298,6 +302,7 @@
EBCDF3152A08916400C04BA3 /* prod.xcconfig in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
+ 79FBEAF22BBDC94D0075EACE /* PrivacyInfo.xcprivacy in Resources */,
EBBC93162A9CF30F00452092 /* GoogleService-Info.plist in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -306,6 +311,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 79C1453E2BBDF10B0064A7E0 /* PrivacyInfo.xcprivacy in Resources */,
EBCDF3192A0891B800C04BA3 /* dev.xcconfig in Resources */,
EBCDF3162A08916400C04BA3 /* prod.xcconfig in Resources */,
);
@@ -848,7 +854,7 @@
INFOPLIST_FILE = MiUtemNotificationServiceExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MiUtemNotificationServiceExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 16.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -980,7 +986,7 @@
INFOPLIST_FILE = MiUtemNotificationServiceExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MiUtemNotificationServiceExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 16.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1104,7 +1110,7 @@
INFOPLIST_FILE = MiUtemNotificationServiceExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MiUtemNotificationServiceExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 16.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1142,7 +1148,7 @@
INFOPLIST_FILE = MiUtemNotificationServiceExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MiUtemNotificationServiceExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 16.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1185,7 +1191,7 @@
INFOPLIST_FILE = MiUtemNotificationServiceExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MiUtemNotificationServiceExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 16.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -1225,7 +1231,7 @@
INFOPLIST_FILE = MiUtemNotificationServiceExtension/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = MiUtemNotificationServiceExtension;
INFOPLIST_KEY_NSHumanReadableCopyright = "";
- IPHONEOS_DEPLOYMENT_TARGET = 16.2;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme
index 77d0e8a..70cb7d0 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme
@@ -50,6 +50,13 @@
ReferencedContainer = "container:Runner.xcodeproj">
+
+
+
+
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ ITSAppUsesNonExemptEncryption
+
LSRequiresIPhoneOS
NSAppTransportSecurity
@@ -37,6 +39,8 @@
Mi UTEM quiere acceder a tu cámara para que puedas subir contenido
NSPhotoLibraryUsageDescription
Mi UTEM quiere acceder a tus fotos para que puedas subir contenido
+ NSUserNotificationsUsageDescription
+ Queremos avisarte cuando existan cambios en tus notas, o sobre otras novedades.
UIBackgroundModes
fetch
diff --git a/ios/Runner/Info-prod.plist b/ios/Runner/Info-prod.plist
index 37909b4..9ee5183 100644
--- a/ios/Runner/Info-prod.plist
+++ b/ios/Runner/Info-prod.plist
@@ -26,6 +26,8 @@
????
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ ITSAppUsesNonExemptEncryption
+
LSRequiresIPhoneOS
NSAppTransportSecurity
@@ -37,6 +39,8 @@
Mi UTEM quiere acceder a tu cámara para que puedas subir contenido
NSPhotoLibraryUsageDescription
Mi UTEM quiere acceder a tus fotos para que puedas subir contenido
+ NSUserNotificationsUsageDescription
+ Queremos avisarte cuando existan cambios en tus notas, o sobre otras novedades.
UIBackgroundModes
fetch
diff --git a/ios/Runner/Runner.entitlements b/ios/Runner/Runner.entitlements
index 903def2..a8b7773 100644
--- a/ios/Runner/Runner.entitlements
+++ b/ios/Runner/Runner.entitlements
@@ -4,5 +4,9 @@
aps-environment
development
+ com.apple.developer.associated-domains
+
+ webcredentials:mi.utem.cl
+
diff --git a/ios/fastlane/Fastfile b/ios/fastlane/Fastfile
index add9d1b..2e19a34 100644
--- a/ios/fastlane/Fastfile
+++ b/ios/fastlane/Fastfile
@@ -62,6 +62,7 @@ lane :ios_build_and_upload do |options|
app_identifier: [ENV["APP_IDENTIFIER_IOS"], ENV["APP_IDENTIFIER_IOS"] + ".MiUtemNotificationServiceExtension"],
type: "appstore",
git_url: ENV["MATCH_REPO_GIT_URL"],
+ git_basic_authorization: ENV["MATCH_GIT_BASIC_AUTHORIZATION"],
readonly: is_ci,
keychain_name: ENV["KEYCHAIN_NAME"],
keychain_password: ENV["KEYCHAIN_PASSWORD"],
@@ -83,19 +84,34 @@ lane :ios_build_and_upload do |options|
end
lane :ios_beta_upload do |options|
+ api_key = app_store_connect_api_key(
+ key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"],
+ issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"],
+ key_filepath: "./ios/fastlane/AuthKey.p8",
+ in_house: true, # Esto debe ser true porque estamos usando match
+ )
+
changelog = options[:changelog]
is_ci = options[:is_ci]
upload_to_testflight(
+ api_key: api_key,
changelog: changelog,
skip_waiting_for_build_processing: is_ci
)
end
lane :ios_release_upload do |options|
+ api_key = app_store_connect_api_key(
+ key_id: ENV["APP_STORE_CONNECT_API_KEY_ID"],
+ issuer_id: ENV["APP_STORE_CONNECT_ISSUER_ID"],
+ key_filepath: "./ios/fastlane/AuthKey.p8",
+ in_house: true, # Esto debe ser true porque estamos usando match
+ )
changelog = options[:changelog]
upload_to_app_store(
+ api_key: api_key,
release_notes: changelog
)
end
diff --git a/lib/config/constants.dart b/lib/config/constants.dart
index 08a447a..9d4204a 100644
--- a/lib/config/constants.dart
+++ b/lib/config/constants.dart
@@ -1,6 +1,6 @@
-class Constants {
- static const String sentryDsn =
- 'https://0af59b2ad2b44f4e8c9cad4ea8d5f32e@o507661.ingest.sentry.io/5599080';
- static const String uxCamDevKey = '0y6p88obpgiug1g';
- static const String uxCamProdKey = 'fxkjj5ulr7vb4yf';
-}
+import 'package:flutter_dotenv/flutter_dotenv.dart';
+
+final apiUrl = bool.fromEnvironment('dart.vm.product') ? 'https://api.exdev.cl' : (dotenv.env['MI_UTEM_API_DEBUG'] ?? 'https://api.exdev.cl');
+const String sentryDsn = 'https://c03edae5839c62f95de91c1cbabb65d7@o4506938204553216.ingest.us.sentry.io/4506938205470720';
+const String uxCamDevKey = '0y6p88obpgiug1g';
+const String uxCamProdKey = 'fxkjj5ulr7vb4yf';
diff --git a/lib/config/logger.dart b/lib/config/logger.dart
index 55058ea..13ad4a3 100644
--- a/lib/config/logger.dart
+++ b/lib/config/logger.dart
@@ -1,3 +1,5 @@
import 'package:logger/logger.dart';
-final logger = Logger();
+final logger = Logger(
+ printer: PrettyPrinter(),
+);
diff --git a/lib/config/router.dart b/lib/config/router.dart
deleted file mode 100644
index 2826c2b..0000000
--- a/lib/config/router.dart
+++ /dev/null
@@ -1,106 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:get/route_manager.dart';
-import 'package:mi_utem/config/routes.dart';
-import 'package:mi_utem/screens/asignatura_detalle_screen.dart';
-import 'package:mi_utem/screens/asignaturas_lista_screen.dart';
-import 'package:mi_utem/controllers/asignaturas_controller.dart';
-import 'package:mi_utem/controllers/qr_passes_controller.dart';
-import 'package:mi_utem/screens/calculadora_notas_screen.dart';
-import 'package:mi_utem/screens/credencial_screen.dart';
-import 'package:mi_utem/screens/horario/horario_screen.dart';
-import 'package:mi_utem/screens/login_screen/login_screen.dart';
-import 'package:mi_utem/screens/main_screen.dart';
-import 'package:mi_utem/screens/permiso_covid_screen.dart';
-import 'package:mi_utem/screens/splash_screen.dart';
-import 'package:mi_utem/screens/usuario_screen.dart';
-import 'package:mi_utem/services/auth_service.dart';
-import 'package:mi_utem/services/perfil_service.dart';
-import 'package:mi_utem/widgets/acerca_screen.dart';
-
-final _loginPage = GetPage(
- name: Routes.login,
- page: () => LoginScreen(),
- middlewares: [OnlyNoAuthMiddleware()],
-);
-
-final _homePage = GetPage(
- name: Routes.home,
- bindings: [QrPassesBinding()],
- page: () {
- final usuario = PerfilService.getLocalUsuario();
-
- return MainScreen(usuario: usuario);
- },
- middlewares: [OnlyAuthMiddleware()],
-);
-
-final pages = [
- GetPage(
- name: Routes.splash,
- page: () => SplashScreen(),
- ),
- GetPage(
- name: Routes.about,
- page: () => AcercaScreen(),
- ),
- _loginPage,
- _homePage,
- GetPage(
- name: Routes.perfil,
- page: () => UsuarioScreen(),
- middlewares: [OnlyAuthMiddleware()],
- ),
- GetPage(
- name: Routes.credencial,
- page: () => CredencialScreen(),
- middlewares: [OnlyAuthMiddleware()],
- ),
- GetPage(
- name: Routes.calculadoraNotas,
- page: () => CalculadoraNotasScreen(),
- middlewares: [OnlyAuthMiddleware()],
- ),
- GetPage(
- name: Routes.horario,
- page: () => HorarioScreen(),
- binding: HorarioBinding(),
- middlewares: [OnlyAuthMiddleware()],
- ),
- GetPage(
- name: Routes.asignaturas,
- page: () => AsignaturasListaScreen(),
- middlewares: [OnlyAuthMiddleware()],
- binding: AsignaturasBinding(),
- ),
- GetPage(
- name: '${Routes.asignatura}/:asignaturaId',
- page: () => AsignaturaDetalleScreen(),
- ),
- GetPage(
- name: Routes.pass,
- page: () => PermisoCovidScreen(),
- middlewares: [OnlyAuthMiddleware()],
- ),
-];
-
-class OnlyAuthMiddleware extends GetMiddleware {
- @override
- RouteSettings? redirect(String? page) {
- final isLoggedIn = AuthService.isLoggedIn();
- if (!isLoggedIn) {
- return const RouteSettings(name: Routes.login);
- }
- return null;
- }
-}
-
-class OnlyNoAuthMiddleware extends GetMiddleware {
- @override
- RouteSettings? redirect(String? page) {
- final isLoggedIn = AuthService.isLoggedIn();
- if (isLoggedIn) {
- return const RouteSettings(name: Routes.home);
- }
- return null;
- }
-}
diff --git a/lib/config/routes.dart b/lib/config/routes.dart
deleted file mode 100644
index 1884123..0000000
--- a/lib/config/routes.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-class Routes {
- static const splash = '/splash';
- static const login = '/login';
- static const home = '/';
- static const about = '/about';
- static const horario = '/horario';
- static const asignaturas = '/asignaturas';
- static const perfil = '/perfil';
- static const credencial = '/credencial';
- static const calculadoraNotas = '/calculadora-notas';
- static const imageView = '/image-view';
- static const asignatura = '/asignatura';
-
- static const passBase = '/pass';
- static const passParameter = 'passId';
- static const pass = '$passBase/:$passParameter';
-}
diff --git a/lib/config/secure_storage.dart b/lib/config/secure_storage.dart
new file mode 100644
index 0000000..5366ad9
--- /dev/null
+++ b/lib/config/secure_storage.dart
@@ -0,0 +1,3 @@
+import 'package:flutter_secure_storage/flutter_secure_storage.dart';
+
+final secureStorage = FlutterSecureStorage();
\ No newline at end of file
diff --git a/lib/controllers/asignatura_controller.dart b/lib/controllers/asignatura_controller.dart
deleted file mode 100644
index 544e732..0000000
--- a/lib/controllers/asignatura_controller.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-import 'package:get/get.dart';
-import 'package:mi_utem/controllers/carreras_controller.dart';
-import 'package:mi_utem/models/asignatura.dart';
-import 'package:mi_utem/models/carrera.dart';
-import 'package:mi_utem/models/grades.dart';
-import 'package:mi_utem/services/grades_service.dart';
-
-class AsignaturaController extends GetxController with StateMixin {
- late final String asignaturaId;
- late final Asignatura? _initialAsignatura;
-
- Carrera? _selectedCarrera;
-
- AsignaturaController(this.asignaturaId, {Asignatura? asignatura}) {
- if (asignatura != null) {
- _initialAsignatura = asignatura;
- }
- }
-
- @override
- void onInit() {
- _selectedCarrera = Get.find().selectedCarrera.value;
- if (_selectedCarrera != null) {
- getAsignaturaDetail(Get.find().selectedCarrera.value);
- }
-
- ever(
- Get.find().selectedCarrera,
- (carrera) {
- _selectedCarrera = carrera;
- getAsignaturaDetail(carrera, forceRefresh: true);
- },
- );
- super.onInit();
- }
-
- Future refreshData() async {
- await getAsignaturaDetail(_selectedCarrera, forceRefresh: true);
- }
-
- Future getAsignaturaDetail(Carrera? carrera,
- {bool forceRefresh = false}) async {
- final carreraId = carrera?.id;
- if (carreraId != null) {
- change(null, status: RxStatus.loading());
- try {
- Grades grades = await GradesService.getGrades(
- carreraId,
- asignaturaId,
- forceRefresh: forceRefresh,
- );
-
- Asignatura asignatura = _initialAsignatura!;
- asignatura.grades = grades;
-
- change(asignatura, status: RxStatus.success());
- } catch (e) {
- change(null, status: RxStatus.error(e.toString()));
- }
- }
- }
-}
diff --git a/lib/controllers/asignaturas_controller.dart b/lib/controllers/asignaturas_controller.dart
deleted file mode 100644
index a8090d1..0000000
--- a/lib/controllers/asignaturas_controller.dart
+++ /dev/null
@@ -1,67 +0,0 @@
-import 'package:get/get.dart';
-import 'package:mi_utem/controllers/asignatura_controller.dart';
-import 'package:mi_utem/controllers/carreras_controller.dart';
-import 'package:mi_utem/models/asignatura.dart';
-import 'package:mi_utem/models/carrera.dart';
-import 'package:mi_utem/services/asignaturas_service.dart';
-
-class AsignaturasController extends GetxController
- with StateMixin> {
- @override
- void onInit() {
- change(null, status: RxStatus.loading());
-
- if (Get.find().selectedCarrera.value != null) {
- getAsignaturas(Get.find().selectedCarrera.value);
- }
-
- ever(
- Get.find().selectedCarrera,
- (carrera) => getAsignaturas(carrera, forceRefresh: true),
- );
- super.onInit();
- }
-
- void getAsignaturas(
- Carrera? carrera, {
- bool forceRefresh = false,
- }) async {
- change(null, status: RxStatus.loading());
-
- final carreraId = carrera?.id;
-
- if (carreraId == null) {
- change(null, status: RxStatus.error("No hay carrera seleccionada"));
- return;
- }
-
- List response = await AsignaturasService.getAsignaturas(
- carreraId,
- forceRefresh: forceRefresh,
- );
-
- change(response, status: RxStatus.success());
-
- for (var asignatura in response) {
- if (asignatura.id != null) {
- Get.put(
- AsignaturaController(asignatura.id!, asignatura: asignatura),
- tag: asignatura.id,
- permanent: true,
- );
- }
- }
- }
-
- void refreshAsignaturas() {
- final carrera = Get.find().selectedCarrera.value;
- getAsignaturas(carrera, forceRefresh: true);
- }
-}
-
-class AsignaturasBinding extends Bindings {
- @override
- void dependencies() {
- Get.put(AsignaturasController(), permanent: true);
- }
-}
diff --git a/lib/controllers/calculator_controller.dart b/lib/controllers/calculator_controller.dart
index c042466..a415542 100644
--- a/lib/controllers/calculator_controller.dart
+++ b/lib/controllers/calculator_controller.dart
@@ -1,9 +1,9 @@
-import 'package:flutter_masked_text/flutter_masked_text.dart';
+import 'package:extended_masked_text/extended_masked_text.dart';
import 'package:get/get.dart';
-import 'package:mi_utem/models/evaluacion.dart';
-import 'package:mi_utem/models/grades.dart';
+import 'package:mi_utem/models/evaluacion/evaluacion.dart';
+import 'package:mi_utem/models/evaluacion/grades.dart';
-class CalculatorController extends GetxController {
+class CalculatorController {
static const maxPercentage = 100;
static const maxGrade = 7;
static const minimumGradeForExam = 2.95;
@@ -18,8 +18,6 @@ class CalculatorController extends GetxController {
final examGradeTextFieldController = MaskedTextController(mask: "0.0");
final freeEditable = false.obs;
- static CalculatorController get to => Get.find();
-
double? get calculatedFinalGrade {
if (calculatedPresentationGrade != null) {
if (examGrade.value != null) {
@@ -127,45 +125,51 @@ class CalculatorController extends GetxController {
double? get suggestedGrade {
if (hasMissingPartialGrade && percentageWithoutGrade > 0) {
final weightOfMissingGrades = percentageWithoutGrade / maxPercentage;
- final requiredGradeValue =
- passingGrade - (suggestedPresentationGrade ?? 0);
- final missingGradesValue = requiredGradeValue / weightOfMissingGrades;
- return missingGradesValue;
+ final requiredGradeValue = passingGrade - (suggestedPresentationGrade ?? 0);
+ return requiredGradeValue / weightOfMissingGrades;
}
return null;
}
- void makeEditable() {
- freeEditable.value = true;
- }
+ bool get hasGrades => partialGrades.isNotEmpty;
+
+ void makeEditable() => freeEditable.value = true;
+
+ void makeNonEditable() => freeEditable.value = false;
- void makeNonEditable() {
- freeEditable.value = false;
+ void clearGrades() {
+ partialGrades.clear();
+ percentageTextFieldControllers.clear();
+ gradeTextFieldControllers.clear();
+ clearExamGrade();
}
- void loadGrades(Grades grades) {
+ void updateWithGrades(Grades? grades) {
partialGrades.clear();
percentageTextFieldControllers.clear();
gradeTextFieldControllers.clear();
- for (var evaluacion in grades.notasParciales) {
- final partialGrade = IEvaluacion.fromRemote(evaluacion);
- addGrade(partialGrade);
+ if(grades == null) {
+ return;
+ }
+
+ for(final grade in grades.notasParciales) {
+ addGrade(IEvaluacion.fromRemote(grade));
}
setExamGrade(grades.notaExamen);
}
- void changeGradeAt(int index, IEvaluacion changedGrade) {
+ void updateGradeAt(int index, IEvaluacion updatedGrade) {
final grade = partialGrades[index];
- if (grade.editable || freeEditable.value) {
- partialGrades[index] = changedGrade;
+ if(!(grade.editable || freeEditable.value)) {
+ return;
+ }
- if (hasMissingPartialGrade) {
- clearExamGrade();
- }
- } else {
- throw Exception("No se puede editar una nota que está asignada");
+ partialGrades[index] = updatedGrade;
+
+ if (hasMissingPartialGrade) {
+ clearExamGrade();
}
}
@@ -174,26 +178,17 @@ class CalculatorController extends GetxController {
examGradeTextFieldController.text = "";
}
- void setExamGrade(num? grade) {
+ void setExamGrade(num? grade, { bool updateTextController = true }) {
examGrade.value = grade?.toDouble();
- examGradeTextFieldController.text =
- grade?.toDouble().toStringAsFixed(1) ?? "";
+ if(updateTextController) {
+ examGradeTextFieldController.updateText(grade?.toDouble().toStringAsFixed(1) ?? "");
+ }
}
void addGrade(IEvaluacion grade) {
partialGrades.add(grade);
- percentageTextFieldControllers.add(
- MaskedTextController(
- mask: "000",
- text: grade.porcentaje?.toDouble().toStringAsFixed(0) ?? "",
- ),
- );
- gradeTextFieldControllers.add(
- MaskedTextController(
- mask: "0.0",
- text: grade.nota?.toDouble().toStringAsFixed(1) ?? "",
- ),
- );
+ percentageTextFieldControllers.add(MaskedTextController(mask: "000", text: grade.porcentaje?.toStringAsFixed(0) ?? ""));
+ gradeTextFieldControllers.add(MaskedTextController(mask: "0.0", text: grade.nota?.toStringAsFixed(1) ?? ""));
}
void removeGradeAt(int index) {
@@ -206,4 +201,4 @@ class CalculatorController extends GetxController {
throw Exception("No se puede eliminar una nota que está asignada");
}
}
-}
+}
\ No newline at end of file
diff --git a/lib/controllers/carreras_controller.dart b/lib/controllers/carreras_controller.dart
deleted file mode 100644
index 20eb963..0000000
--- a/lib/controllers/carreras_controller.dart
+++ /dev/null
@@ -1,48 +0,0 @@
-import 'package:get/get.dart';
-import 'package:mi_utem/models/carrera.dart';
-import 'package:mi_utem/services/analytics_service.dart';
-import 'package:mi_utem/services/carreras_service.dart';
-
-class CarrerasController extends GetxController {
- final carreras = [].obs;
- final selectedCarrera = Rxn();
-
- static CarrerasController get to => Get.find();
-
- @override
- void onInit() {
- getCarreras();
-
- super.onInit();
- }
-
- void getCarreras() async {
- final carreras = await CarreraService.getCarreras(forceRefresh: true);
-
- this.carreras.value = carreras;
- _autoSelectCarreraActiva(carreras);
- }
-
- void _autoSelectCarreraActiva(List carreras) {
- final estados = ["Regular", "Causal de Eliminacion"]
- .reversed
- .map((e) => e.toLowerCase())
- .toList();
-
- carreras.sort(
- (a, b) => estados.indexOf(b.estado!.toLowerCase()).compareTo(
- estados.indexOf(a.estado!.toLowerCase()),
- ),
- );
-
- Carrera activa = carreras.first;
-
- AnalyticsService.setCarreraToUser(activa);
-
- changeSelectedCarrera(activa);
- }
-
- void changeSelectedCarrera(Carrera carrera) {
- selectedCarrera.value = carrera;
- }
-}
diff --git a/lib/controllers/grades_changes_controller.dart b/lib/controllers/grades_changes_controller.dart
deleted file mode 100644
index 0be8fb7..0000000
--- a/lib/controllers/grades_changes_controller.dart
+++ /dev/null
@@ -1,249 +0,0 @@
-import 'dart:developer';
-
-import 'package:get_storage/get_storage.dart';
-import 'package:mi_utem/controllers/carreras_controller.dart';
-import 'package:mi_utem/models/asignatura.dart';
-import 'package:mi_utem/models/grades.dart';
-import 'package:mi_utem/services/asignaturas_service.dart';
-import 'package:mi_utem/services/auth_service.dart';
-import 'package:mi_utem/services/grades_service.dart';
-import 'package:mi_utem/services/notification_service.dart';
-import 'package:sentry_flutter/sentry_flutter.dart';
-
-class GradesChangesController {
- static const savedGradesPrefix = 'savedGrades_';
- static const suscribedAsignaturasPrefix = 'suscribedAsignaturas_';
-
- static final GetStorage box = GetStorage();
-
- static Future saveGrades(String asignaturaId, Grades grades) async {
- final jsonGrades = grades.toJson();
- jsonGrades['lastUpdate'] = DateTime.now().toIso8601String();
-
- log('Saving grades for $asignaturaId: $jsonGrades');
-
- return box.write('$savedGradesPrefix$asignaturaId', jsonGrades);
- }
-
- static GradeChangeType _getGradeValueChangeType(
- Grades oldGrades,
- Grades updatedGrades,
- ) {
- final oldGradesLength = oldGrades.notasParciales.length;
- final updatedGradesLength = updatedGrades.notasParciales.length;
-
- if (oldGradesLength == updatedGradesLength) {
- GradeChangeType? currentChange;
-
- for (int i = 0; i < oldGradesLength; i++) {
- final oldValue = oldGrades.notasParciales[i];
- final updatedValue = updatedGrades.notasParciales[i];
-
- if (oldValue.nota != updatedValue.nota) {
- if (oldValue.nota == null && updatedValue.nota != null) {
- Sentry.configureScope(
- (scope) => scope.setExtra('newGrade', updatedValue.nota),
- );
- currentChange = GradeChangeType.gradeSetted;
- } else if (oldValue.nota != null && updatedValue.nota == null) {
- currentChange = currentChange ?? GradeChangeType.gradeDeleted;
- } else {
- currentChange = currentChange ?? GradeChangeType.gradeUpdated;
- }
- }
- }
-
- if (currentChange != null) {
- return currentChange;
- }
- } else {
- Sentry.captureMessage(
- 'Asignatura $oldGrades.id has a different number of weighters in _getGradeValueChangeType function',
- level: SentryLevel.warning,
- );
- }
- return GradeChangeType.noChange;
- }
-
- static bool _hasAWeighterDiferrence(
- Grades oldGrades,
- Grades updatedGrades,
- ) {
- final oldGradesLength = oldGrades.notasParciales.length;
- final updatedGradesLength = updatedGrades.notasParciales.length;
-
- if (oldGradesLength == updatedGradesLength) {
- for (int i = 0; i < oldGradesLength; i++) {
- final oldWeighter = oldGrades.notasParciales[i];
- final updatedWeighter = updatedGrades.notasParciales[i];
-
- if (oldWeighter.porcentaje != updatedWeighter.porcentaje) {
- return true;
- }
- }
- } else {
- Sentry.captureMessage(
- 'Asignatura $oldGrades.id has a different number of weighters in _hasAWeighterDiferrence function',
- level: SentryLevel.warning,
- );
- }
- return false;
- }
-
- static bool _hasAGradeWithValue(Grades asignatura) {
- return asignatura.notasParciales.any((element) => element.nota != null);
- }
-
- static GradeChangeType compareGrades(
- String asignaturaId,
- Grades updatedGrades,
- ) {
- final oldGradesJson = box.read('$savedGradesPrefix$asignaturaId');
-
- if (oldGradesJson != null) {
- final oldGrades = Grades.fromJson(oldGradesJson);
-
- log(oldGrades.toString());
-
- final oldGradesLength = oldGrades.notasParciales.length;
- final updatedGradesLength = updatedGrades.notasParciales.length;
-
- if (oldGradesLength == 0) {
- if (updatedGradesLength == 0) {
- return GradeChangeType.noChange;
- } else {
- if (_hasAGradeWithValue(updatedGrades)) {
- return GradeChangeType.gradeSetted;
- } else {
- return GradeChangeType.weightersSetted;
- }
- }
- } else {
- if (updatedGradesLength == 0) {
- return GradeChangeType.weightersDeleted;
- } else {
- if (oldGradesLength != updatedGradesLength) {
- return GradeChangeType.weightersUpdated;
- } else {
- if (_hasAWeighterDiferrence(oldGrades, updatedGrades)) {
- return GradeChangeType.weightersUpdated;
- } else {
- return _getGradeValueChangeType(oldGrades, updatedGrades);
- }
- }
- }
- }
- } else {
- log('compareGrades oldGradesJson was null');
- }
-
- return GradeChangeType.noChange;
- }
-
- static Future