Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5a8fed24bb | ||
|
|
b413fe05de | ||
|
|
38a651f916 | ||
|
|
f98a6979fb | ||
|
|
3e856d0b1c | ||
|
|
8eddc8f771 | ||
|
|
27563a6dc1 | ||
|
|
5e65c4671a | ||
|
|
79b33ab248 | ||
|
|
1fd6264d10 | ||
|
|
2ca9feb49a | ||
|
|
2aed3d104c | ||
|
|
e6f74ca6fe | ||
|
|
0f6c388940 | ||
|
|
d6130584f2 | ||
|
|
56a497985b | ||
|
|
ed8e52f475 | ||
|
|
ef7d17033d | ||
|
|
a71f4f379b | ||
|
|
e21560ed3d | ||
|
|
de866b12b4 | ||
|
|
4f31e68456 | ||
|
|
498d195138 | ||
|
|
84098af7e2 | ||
|
|
630497abdd | ||
|
|
2423c1a75e | ||
|
|
67c935c05b | ||
|
|
e4e2b1a4fb | ||
|
|
3734d7ff2c | ||
|
|
43dfc52bc7 | ||
|
|
f19f212fb4 | ||
|
|
71839d0848 | ||
|
|
65300614b1 | ||
|
|
02a7b87b5b | ||
|
|
bd83a88e70 | ||
|
|
09d4ecda78 | ||
|
|
d27312afdf | ||
|
|
ccb22a497d | ||
|
|
889d8f67c5 | ||
|
|
39c16bd4ea | ||
|
|
b9cb1df473 | ||
|
|
62fa337188 | ||
|
|
c0dadf8b6e | ||
|
|
ab23422a86 | ||
|
|
646e2c0451 | ||
|
|
246cb0f527 | ||
|
|
4c2e9b47e7 | ||
|
|
2d690736e3 | ||
|
|
778c473631 | ||
|
|
7e9cbcf1e9 | ||
|
|
32be67426c | ||
|
|
b957189fd3 | ||
|
|
624c5512a6 | ||
|
|
3493cf8617 | ||
|
|
75080a2c49 | ||
|
|
f3cd7896d9 | ||
|
|
101e7c909c | ||
|
|
429f1e6f96 | ||
|
|
a0c55a811c | ||
|
|
e625216a90 | ||
|
|
8128cede21 | ||
|
|
e5f7cf0176 | ||
|
|
e349d667d4 | ||
|
|
7c1f5c06df | ||
|
|
e8c6ac1c65 | ||
|
|
478f0ff20b | ||
|
|
8274dd46cd | ||
|
|
d7536ea5d0 | ||
|
|
398b147c76 | ||
|
|
15791423ea | ||
|
|
2f5a6b4ce0 | ||
|
|
53bc6d5360 | ||
|
|
f50359b4eb | ||
|
|
9994a1f3fa | ||
|
|
4aa31a2e44 | ||
|
|
dfce3e7b5c | ||
|
|
564a334cdc | ||
|
|
db329c7299 | ||
|
|
0a2ff5c3fb | ||
|
|
9b5198c6db | ||
|
|
94794ff092 | ||
|
|
fe2b3c43b2 | ||
|
|
a7111844b1 | ||
|
|
babc347b18 | ||
|
|
44e45c9b78 | ||
|
|
3f44e9302f | ||
|
|
59501d3b45 | ||
|
|
91a6216f66 | ||
|
|
c444ed54a5 | ||
|
|
ff23199345 | ||
|
|
9545d2a946 | ||
|
|
37608e59b3 | ||
|
|
0d01f6b631 | ||
|
|
b0d2e7a34b | ||
|
|
cedeb06569 | ||
|
|
1114291313 | ||
|
|
9b74c9fd81 | ||
|
|
2668b111f1 | ||
|
|
a19b67eb84 | ||
|
|
c48f5ef215 | ||
|
|
ddbb3fbc19 | ||
|
|
2be5051d12 | ||
|
|
38a271929c | ||
|
|
3be0113f93 | ||
|
|
2b59f11ea5 | ||
|
|
124b1a5177 | ||
|
|
614ab159af | ||
|
|
5952c6619f | ||
|
|
dab208877f | ||
|
|
483fea62ba | ||
|
|
35e144799e | ||
|
|
b14e8c8ea2 | ||
|
|
74a2ddd17f | ||
|
|
32f7c311bc | ||
|
|
4bc7ffd37a | ||
|
|
13f4f79829 | ||
|
|
a76b09af26 | ||
|
|
4fd09204ec | ||
|
|
f554c57d8d | ||
|
|
baa26a6e79 | ||
|
|
b6d06dd3b4 | ||
|
|
6e12da08c0 | ||
|
|
5ebf5bccdb | ||
|
|
f966cf302b | ||
|
|
582432dbb9 | ||
|
|
ece0669f7d | ||
|
|
01b4b44010 | ||
|
|
93b9929f8f | ||
|
|
2858f910c9 | ||
|
|
f185b3273a | ||
|
|
831ea56869 | ||
|
|
215911cf29 | ||
|
|
e5873f73b9 | ||
|
|
582eff8750 | ||
|
|
2cb8321d07 | ||
|
|
194d8d1857 | ||
|
|
22e9c43f78 | ||
|
|
4c04d00323 | ||
|
|
0fd42439e2 | ||
|
|
d970cfbe0c | ||
|
|
91ab109ec5 | ||
|
|
d9fcd9f624 | ||
|
|
092f9b622b | ||
|
|
843686358f | ||
|
|
cfcb901adb | ||
|
|
ba5d9e0e4e | ||
|
|
e8707b36f1 | ||
|
|
d0ba7c0fd6 | ||
|
|
a09817a975 | ||
|
|
37dbb7b374 | ||
|
|
6c7d217463 | ||
|
|
58fb843f3d | ||
|
|
d8a5ccfe80 | ||
|
|
1ae3f7bb83 | ||
|
|
8c76f2d816 | ||
|
|
c46f14f6a6 | ||
|
|
b2b00d321e | ||
|
|
1a11b9ac60 | ||
|
|
a0bc46f522 | ||
|
|
1458d8ce49 | ||
|
|
6ae396e605 | ||
|
|
ed2badfd35 | ||
|
|
1ff57b29f9 | ||
|
|
c50a850ac9 | ||
|
|
15833f3685 | ||
|
|
bf28a678c9 | ||
|
|
14090b96f4 | ||
|
|
8e6b1877cc | ||
|
|
9accb488f2 | ||
|
|
79a6d9a594 | ||
|
|
7d02e70459 | ||
|
|
4c190de479 | ||
|
|
b36d1e02f5 | ||
|
|
53b290ab49 | ||
|
|
b422430994 | ||
|
|
151678f0fe | ||
|
|
cb2c38aaa1 | ||
|
|
00664c66a8 | ||
|
|
0ff5eb7bc9 | ||
|
|
3b8da1d3d6 | ||
|
|
9e139b5704 | ||
|
|
c62a14645a | ||
|
|
3b1b0d0c19 | ||
|
|
c32e64fe74 | ||
|
|
710e88d744 | ||
|
|
517e515ac1 | ||
|
|
e8f0c4383c | ||
|
|
b8cac73e74 | ||
|
|
95ef29fb09 | ||
|
|
86d12884fc | ||
|
|
50d2941e52 | ||
|
|
71506aab2d | ||
|
|
4e1272aba9 | ||
|
|
72ebe6f7e7 | ||
|
|
4b1d4379a0 | ||
|
|
2c376afd91 | ||
|
|
54ba04a7bd | ||
|
|
9b5a70b285 | ||
|
|
4f796dac2e | ||
|
|
db9c3386f1 | ||
|
|
bee5c02a4f | ||
|
|
e8faa77e70 | ||
|
|
551c1bf1fa | ||
|
|
9973f12733 | ||
|
|
278fed52f1 | ||
|
|
f89ac87c51 | ||
|
|
0b8380eff0 | ||
|
|
4ef3a167ea | ||
|
|
c26cefc073 | ||
|
|
e78ef0df49 | ||
|
|
0b6c80e84c | ||
|
|
a52817231e | ||
|
|
f6933b6529 | ||
|
|
e4243e53ac | ||
|
|
0aead45191 | ||
|
|
dacefd321b | ||
|
|
92a9a7358e | ||
|
|
174e6ac0b7 | ||
|
|
c9eaed782a | ||
|
|
567184bcf9 | ||
|
|
541d6ef164 | ||
|
|
3469d02033 | ||
|
|
699aec8ab5 | ||
|
|
7a3a022ecd | ||
|
|
9d8a99df7c | ||
|
|
a47e52e8e7 | ||
|
|
a1fd21de04 | ||
|
|
b3d8586c04 | ||
|
|
0409c5463f | ||
|
|
7a3b69fade | ||
|
|
df275c0108 | ||
|
|
0525453d48 | ||
|
|
4e8b2f34f9 | ||
|
|
bc6a069c90 | ||
|
|
bfa0b0f5c0 | ||
|
|
274b77f705 | ||
|
|
c7ea80bea9 | ||
|
|
1c787fdc4d | ||
|
|
a689cf4fef | ||
|
|
8f92ab06d9 | ||
|
|
b68bec9ebd | ||
|
|
81f65750b7 | ||
|
|
7b7ab2e82e | ||
|
|
a460d2b296 | ||
|
|
33dd6c4c69 | ||
|
|
06c27d6b50 | ||
|
|
7dea44d1e8 | ||
|
|
5f27956035 | ||
|
|
32799f648c | ||
|
|
859b85ab2c | ||
|
|
bd1101c348 | ||
|
|
f29c84d05c | ||
|
|
7dbd6038f3 | ||
|
|
877633f4de | ||
|
|
22d3d18a17 | ||
|
|
d65e61c297 | ||
|
|
467b0e0dd8 | ||
|
|
25a6ef37fa | ||
|
|
34763ace4a | ||
|
|
590a70c623 | ||
|
|
9b58412ca7 | ||
|
|
a6c16e41c2 | ||
|
|
117434a5e3 | ||
|
|
e4582eaac5 | ||
|
|
430d5b8dc7 | ||
|
|
9177c30d6e | ||
|
|
344f8f6d2c | ||
|
|
46971a8d46 | ||
|
|
f330ef3f56 | ||
|
|
85f9988453 | ||
|
|
f3de0bc165 | ||
|
|
421ee9179d | ||
|
|
0a66858d93 | ||
|
|
49428680de | ||
|
|
0c676dc3d6 | ||
|
|
c702b610c5 | ||
|
|
5938c6b3c3 | ||
|
|
8000475c1f | ||
|
|
da772f17cc | ||
|
|
c44b0464a4 | ||
|
|
9d0cf8e313 | ||
|
|
f0009dad88 | ||
|
|
905206f242 | ||
|
|
769fbc1b6a | ||
|
|
8daf57bcee | ||
|
|
33d488946a | ||
|
|
41a5e021c5 | ||
|
|
8f58893553 | ||
|
|
626d3d5564 | ||
|
|
d833cdb733 | ||
|
|
8868914a76 | ||
|
|
70e6f82b10 | ||
|
|
6651613331 | ||
|
|
9ad0f624de | ||
|
|
82c143f847 | ||
|
|
1fdf731b81 | ||
|
|
2d3ccd25b4 | ||
|
|
385ee806d6 | ||
|
|
92aef41031 | ||
|
|
65b29ec4b8 | ||
|
|
9f51d68531 | ||
|
|
5bc4ba6332 | ||
|
|
e9739ac2d5 | ||
|
|
4d3a33dd9b |
@@ -350,3 +350,15 @@ hs_err_pid*
|
|||||||
|
|
||||||
*.idea*
|
*.idea*
|
||||||
**/.DS_store
|
**/.DS_store
|
||||||
|
|
||||||
|
# Fastlane (Play-Store-Upload)
|
||||||
|
android/fastlane/report.xml
|
||||||
|
android/fastlane/Preview.html
|
||||||
|
android/fastlane/play-service-account.json
|
||||||
|
android/fastlane/README.md.bak
|
||||||
|
# lokale Screenshots außerhalb der Fastlane-Metadaten
|
||||||
|
/screenshots/
|
||||||
|
# Fastlane-Bild-PNGs sind generierte Kopien; kanonisch/versioniert liegen die
|
||||||
|
# Screenshots unter materials/screenshots/. Nur die leeren Ordner (.gitkeep)
|
||||||
|
# bleiben eingecheckt, damit supply die Struktur vorfindet.
|
||||||
|
android/fastlane/metadata/android/**/images/**/*.png
|
||||||
|
|||||||
@@ -0,0 +1,89 @@
|
|||||||
|
# MarianumMobile Client
|
||||||
|
|
||||||
|
Flutter-App für die Schul-Community: Stundenplan, Ticker, Newsletter & Co. über das MarianumConnect-Backend, Nextcloud Talk + Files. Zwei Kontoarten: Schul-Konto (Schüler/Lehrer, Benutzername + Passwort) und Eltern-Konto (passwortlos per E-Mail-Code/App-Link, sieht die Stundenpläne der zugeordneten Kinder und erhält Elternbriefe, kein Talk/Files).
|
||||||
|
|
||||||
|
## Stack
|
||||||
|
|
||||||
|
- **Flutter** (Dart >= 3.8)
|
||||||
|
- **State:** `flutter_bloc` + `hydrated_bloc` (persistente BLoCs pro Modul)
|
||||||
|
- **Navigation:** `persistent_bottom_nav_bar_v2` mit zentraler `AppRoutes`-Klasse als Single Entry Point
|
||||||
|
- **HTTP:** `dio`, lokales Caching via `localstore` (Generic `RequestCache<T>`)
|
||||||
|
- **Calendar:** `syncfusion_flutter_calendar`
|
||||||
|
- **Datum/Zeit:** `jiffy` – wird **nur** über die Extensions in `lib/extensions/date_time.dart` verwendet
|
||||||
|
- **Code-Gen:** `freezed`, `json_serializable`
|
||||||
|
|
||||||
|
## Ordnerstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
lib/
|
||||||
|
├── api/ HTTP-Layer pro Backend (marianumconnect/, marianumcloud/, mhsl/ Legacy, demo/)
|
||||||
|
├── session/ Session-Modell (CredentialSession / GuardianSession), SessionManager, SessionLifecycle
|
||||||
|
├── access/ UserRole, AccessRequirement (Gating von Modulen/Settings)
|
||||||
|
├── auth_link/ Eltern-Login: App-Link-Listener, Link-Parser, Geräte-Bindung
|
||||||
|
├── state/app/modules/ BLoC pro Feature-Modul (timetable, chat, chat_list, files, ...)
|
||||||
|
├── state/app/infrastructure LoadableState<T>, DataLoader, geteilte BLoC-Bausteine
|
||||||
|
├── view/ Screens
|
||||||
|
│ ├── login/ Login-Flow
|
||||||
|
│ └── pages/ ein Verzeichnis pro Modul (timetable, files, talk, ...)
|
||||||
|
├── widget/ Geteilte UI-Komponenten (Dialoge, Buttons, Sheets)
|
||||||
|
├── extensions/ DateTime-, Text-, TimeOfDay-Extensions
|
||||||
|
├── routing/ AppRoutes (Single Navigation Entry)
|
||||||
|
├── theming/ Light/Dark Theme
|
||||||
|
├── storage/ Freezed Settings-Modelle (HydratedBloc-persistent)
|
||||||
|
├── notification/ Firebase + flutter_local_notifications
|
||||||
|
└── utils/ Helper (clipboard_helper, debouncer, download_manager, ...)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Konventionen
|
||||||
|
|
||||||
|
**Navigation:** Ausschließlich über `AppRoutes.openX(context, ...)`. Direkte `Navigator.push(...)` für volle Pages sind nicht erlaubt – `Navigator.pop` für Sheets/Dialogs bleibt am Call-Site.
|
||||||
|
|
||||||
|
**Dialoge:**
|
||||||
|
- Info/Fehler: `InfoDialog.show(context, body, copyable: true, title: '...')` aus `lib/widget/info_dialog.dart`.
|
||||||
|
- Bestätigung: `ConfirmDialog(...).asDialog(context)` aus `lib/widget/confirm_dialog.dart`. Async-Bestätigung nutzt `onConfirmAsync` (zeigt Spinner und Inline-Fehler über `AsyncDialogAction`).
|
||||||
|
- **Kein** inline `AlertDialog`/`SimpleDialog` mehr.
|
||||||
|
|
||||||
|
**Bottom-Sheets:** Detail-Sheets gehen über `showDetailsBottomSheet(context, header: ..., children: (ctx) => [...])` aus `lib/widget/details_bottom_sheet.dart`. Header ist optional.
|
||||||
|
|
||||||
|
**Async-Actions:** Statt manuelles Spinner+Try/Catch die `AsyncActionButton`-Familie aus `lib/widget/async_action_button.dart` (`AsyncActionButton`, `AsyncTextButton`, `AsyncIconButton`, `AsyncFab`, `AsyncListTile`, `AsyncDialogAction`, `runWithErrorDialog`). Fehler-Mapping läuft über `errorBuilder` oder zentral über `errorToUserMessage` aus `lib/api/errors/error_mapper.dart`.
|
||||||
|
|
||||||
|
**Clipboard:** Über `copyToClipboard(context, text)` aus `lib/utils/clipboard_helper.dart`. Zeigt automatisch SnackBar.
|
||||||
|
|
||||||
|
**Datum/Zeit-Formatierung:** Über die Extensions in `lib/extensions/date_time.dart`:
|
||||||
|
`dt.formatHm()`, `dt.formatDate()`, `dt.formatDateTime()`, `dt.formatDateShort()`, `dt.formatRelative()`, `start.timeRangeTo(end)`. **Kein** direktes `Jiffy.parseFromDateTime(...).format(pattern: '...')` im View-Code.
|
||||||
|
|
||||||
|
**Settings:** Pro Feature ein Freezed-Modell unter `lib/storage/`, persistiert via HydratedBloc.
|
||||||
|
|
||||||
|
**Session:** Die aktive Sitzung liegt in `SessionManager().current` (`lib/session/`). Nextcloud-Zugriffe nur über `SessionManager().requireNextcloud()` – Eltern-Sessions haben keine Nextcloud-Identität. Abmelden ausschließlich über `SessionLifecycle.signOut()`. Die Keychain-Keys in `SessionKeys` sind eingefroren (Bestandsinstallationen, iOS-NSE).
|
||||||
|
|
||||||
|
**Mehrere Konten:** Die `SessionKeys`-Slots, der MC-Token und die Group-Keychain spiegeln immer das *aktive* Konto; inaktive Konten liegen im Tresor (`accounts_index` + `account_vault_<id>`, `lib/session/account_codec.dart`). Wechseln/Hinzufügen/Entfernen nur über `SessionLifecycle` (`switchTo`, `beginAddAccount`/`finishLogin`/`cancelAddAccount`, `removeInactive`), danach `AccountBloc.activated(id)`. Lokale Daten sind pro Konto getrennt (`AccountStorage`: eigene HydratedBloc-Box; der Request-Cache `CacheStore` folgt dem aktiven Konto mit eigenem Verzeichnis); nur die Settings liegen in der globalen Box. `SessionManager().sessionEpoch` steigt bei jedem Kontowechsel – asynchrone Arbeit prüft damit, ob ihr Ergebnis noch zum aktiven Konto gehört. Was ein Konto außerhalb seines Speichers hinterlässt (Tray, Push-Schlüssel, Downloads), räumt `SessionWipe` auf. Alle Pro-Konto-Blocs gehören in `AccountScope` – er wird per Konto-ID neu aufgebaut (samt `MaterialApp`/Navigator). Push ist nur für das aktive Konto registriert.
|
||||||
|
|
||||||
|
**Rollen & Zuschnitt:** Views verzweigen nie auf Rollen. Module und Settings-Sections deklarieren `AccessRequirement`s (`nextcloud`, `guardian`; `AppModule.requirements`, `Settings._sections`); Views bekommen ein Subjekt + eine Policy, die an genau einer Stelle als pure Funktion aufgelöst wird (Vorbild: `TimetableSubject` + `TimetablePolicy.resolve`, `AbsenceFormPolicy`). `UserRole` nur für Anzeige/Policy-Ableitung.
|
||||||
|
|
||||||
|
**Stundenplan:** Ein `TimetableBloc(subject: …)` für alle Fälle (eigener Plan, Fremdplan, Kind). Den globalen Bloc stellt `PrimaryTimetableScope` bereit und tauscht ihn beim Kindwechsel aus; page-scoped Fremdpläne nutzen `ScopedTimetableBloc`. Die Kinderauswahl (`ChildSelectionCubit`) ist modulübergreifend.
|
||||||
|
|
||||||
|
**Elternbriefe:** Modul `parentLetters` (nur Eltern-Sessions, `AccessRequirement.guardian`): Lehrer-Mitteilungen aus MarianumConnect mit Gelesen-Status, Kenntnisnahme/Auswahl/Unterschrift pro Kind, Thread und Anhängen. Der Posteingang (`ParentLettersBloc`) ist global (Modul-Badge, Push-Refresh), ein Brief ist page-scoped (`ParentLetterBloc`). Ob und wie geantwortet werden darf, entscheidet der Server (`editable`); `ParentLetterFormPolicy.resolve` macht daraus das Formular. Push: Connect-Direct-Push `type: parent-letter`, Tap-Routing allein über `parentLetterId`. Alle Benachrichtigungs-Taps (lokal gerendert wie FCM) werden von `resolvePushTarget` (`lib/push/push_target.dart`) aufgelöst und in `NotificationTasks.openPushTarget` navigiert – neue Push-Ziele nur dort ergänzen.
|
||||||
|
|
||||||
|
## Build / Run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flutter pub get
|
||||||
|
dart run build_runner build --delete-conflicting-outputs # nach Änderungen an Freezed/JSON-Modellen
|
||||||
|
flutter run # Debug auf angeschlossenem Device
|
||||||
|
flutter analyze # statische Analyse, muss 0 Issues melden
|
||||||
|
flutter test # Tests (siehe test/)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Backend-Integrationen
|
||||||
|
|
||||||
|
| Backend | Pfad | Zweck |
|
||||||
|
|---------------------------|-----------------------|----------------------------------------|
|
||||||
|
| MarianumConnect (Bearer) | `lib/api/marianumconnect/` | Auth, Stundenplan (Webuntis-Proxy), Ticker, Newsletter, Ferien, Abwesenheit, Elternbriefe, Capabilities, Push |
|
||||||
|
| Nextcloud (Talk + WebDAV) | `lib/api/marianumcloud/` | Chats, Datei-Verwaltung |
|
||||||
|
| MHSL (Legacy) | `lib/api/mhsl/` | nur noch Einmal-Migration der Custom Events |
|
||||||
|
|
||||||
|
`nextcloud`-Paket ist auf einen Custom-Fork gepinnt (siehe `pubspec.yaml` `dependency_overrides`).
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
`test/` deckt vor allem pure Funktionen ab (DateTime-Extensions, Stundenplan-Logik, Session-Codec, Policies, Eltern-Login-Controller). Beim Hinzufügen neuer pure-function-Helper bitte Test mit dazu.
|
||||||
@@ -1,44 +1,91 @@
|
|||||||
# This file configures the analyzer, which statically analyzes Dart code to
|
# Static analysis configuration for the Flutter project.
|
||||||
# check for errors, warnings, and lints.
|
# https://dart.dev/guides/language/analysis-options
|
||||||
#
|
#
|
||||||
# The issues identified by the analyzer are surfaced in the UI of Dart-enabled
|
# Base ruleset: flutter_lints (recommended Flutter defaults).
|
||||||
# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be
|
# Additional lints below catch real bugs and enforce consistent style.
|
||||||
# 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
|
include: package:flutter_lints/flutter.yaml
|
||||||
|
|
||||||
analyzer:
|
analyzer:
|
||||||
|
language:
|
||||||
|
strict-casts: true
|
||||||
|
strict-raw-types: true
|
||||||
errors:
|
errors:
|
||||||
invalid_annotation_target: ignore
|
invalid_annotation_target: ignore
|
||||||
|
todo: ignore
|
||||||
|
exclude:
|
||||||
|
- "**/*.g.dart"
|
||||||
|
- "**/*.freezed.dart"
|
||||||
|
- "lib/firebase_options.dart"
|
||||||
|
- "build/**"
|
||||||
|
- android/**
|
||||||
|
- ios/**
|
||||||
|
- web/**
|
||||||
|
|
||||||
linter:
|
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-lang.github.io/linter/lints/index.html.
|
|
||||||
#
|
|
||||||
# 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:
|
rules:
|
||||||
# avoid_print: false # Uncomment to disable the `avoid_print` rule
|
# === Project conventions ===
|
||||||
# prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule
|
|
||||||
file_names: false
|
|
||||||
prefer_relative_imports: true
|
prefer_relative_imports: true
|
||||||
unnecessary_lambdas: true
|
|
||||||
prefer_single_quotes: true
|
prefer_single_quotes: true
|
||||||
prefer_if_elements_to_conditional_expressions: true
|
|
||||||
prefer_expression_function_bodies: true
|
|
||||||
omit_local_variable_types: true
|
|
||||||
eol_at_end_of_file: true
|
eol_at_end_of_file: true
|
||||||
cast_nullable_to_non_nullable: true
|
omit_local_variable_types: true
|
||||||
avoid_void_async: true
|
|
||||||
avoid_multiple_declarations_per_line: true
|
avoid_multiple_declarations_per_line: true
|
||||||
|
|
||||||
# Additional information about this file can be found at
|
# === Bug catchers ===
|
||||||
# https://dart.dev/guides/language/analysis-options
|
always_declare_return_types: true
|
||||||
|
avoid_empty_else: true
|
||||||
|
avoid_slow_async_io: true
|
||||||
|
avoid_type_to_string: true
|
||||||
|
avoid_void_async: true
|
||||||
|
await_only_futures: true
|
||||||
|
cancel_subscriptions: true
|
||||||
|
cast_nullable_to_non_nullable: true
|
||||||
|
close_sinks: true
|
||||||
|
empty_catches: true
|
||||||
|
hash_and_equals: true
|
||||||
|
no_adjacent_strings_in_list: true
|
||||||
|
no_duplicate_case_values: true
|
||||||
|
test_types_in_equals: true
|
||||||
|
throw_in_finally: true
|
||||||
|
unawaited_futures: true
|
||||||
|
unnecessary_statements: true
|
||||||
|
unrelated_type_equality_checks: true
|
||||||
|
use_build_context_synchronously: true
|
||||||
|
valid_regexps: true
|
||||||
|
|
||||||
|
# === Flutter widget hygiene ===
|
||||||
|
avoid_unnecessary_containers: true
|
||||||
|
sized_box_for_whitespace: true
|
||||||
|
sort_child_properties_last: true
|
||||||
|
use_colored_box: true
|
||||||
|
use_decorated_box: true
|
||||||
|
use_full_hex_values_for_flutter_colors: true
|
||||||
|
use_key_in_widget_constructors: true
|
||||||
|
|
||||||
|
# === Code clarity ===
|
||||||
|
directives_ordering: true
|
||||||
|
library_prefixes: true
|
||||||
|
no_leading_underscores_for_local_identifiers: true
|
||||||
|
prefer_conditional_assignment: true
|
||||||
|
prefer_if_elements_to_conditional_expressions: true
|
||||||
|
prefer_if_null_operators: true
|
||||||
|
prefer_initializing_formals: true
|
||||||
|
prefer_interpolation_to_compose_strings: true
|
||||||
|
prefer_is_empty: true
|
||||||
|
prefer_is_not_empty: true
|
||||||
|
prefer_is_not_operator: true
|
||||||
|
prefer_iterable_whereType: true
|
||||||
|
prefer_null_aware_operators: true
|
||||||
|
prefer_spread_collections: true
|
||||||
|
prefer_void_to_null: true
|
||||||
|
unnecessary_await_in_return: true
|
||||||
|
unnecessary_brace_in_string_interps: true
|
||||||
|
unnecessary_lambdas: true
|
||||||
|
unnecessary_null_aware_assignments: true
|
||||||
|
unnecessary_null_checks: true
|
||||||
|
unnecessary_parenthesis: true
|
||||||
|
unnecessary_string_interpolations: true
|
||||||
|
use_super_parameters: true
|
||||||
|
|
||||||
|
# === File naming ===
|
||||||
|
file_names: true
|
||||||
|
|||||||
@@ -11,3 +11,4 @@ GeneratedPluginRegistrant.java
|
|||||||
key.properties
|
key.properties
|
||||||
**/*.keystore
|
**/*.keystore
|
||||||
**/*.jks
|
**/*.jks
|
||||||
|
.kotlin/
|
||||||
|
|||||||
@@ -25,15 +25,12 @@ if (flutterVersionName == null) {
|
|||||||
android {
|
android {
|
||||||
namespace "eu.mhsl.marianum.mobile.client"
|
namespace "eu.mhsl.marianum.mobile.client"
|
||||||
compileSdk flutter.compileSdkVersion
|
compileSdk flutter.compileSdkVersion
|
||||||
ndkVersion flutter.ndkVersion
|
ndkVersion "28.2.13676358"
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_17
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
targetCompatibility JavaVersion.VERSION_17
|
||||||
}
|
coreLibraryDesugaringEnabled true
|
||||||
|
|
||||||
kotlinOptions {
|
|
||||||
jvmTarget = '1.8'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@@ -41,15 +38,11 @@ android {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
|
|
||||||
applicationId "eu.mhsl.marianum.mobile.client"
|
applicationId "eu.mhsl.marianum.mobile.client"
|
||||||
// You can update the following values to match your application needs.
|
minSdkVersion 26
|
||||||
// For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration.
|
|
||||||
minSdkVersion 21
|
|
||||||
targetSdkVersion flutter.targetSdkVersion
|
targetSdkVersion flutter.targetSdkVersion
|
||||||
versionCode flutterVersionCode.toInteger()
|
versionCode flutterVersionCode.toInteger()
|
||||||
versionName flutterVersionName
|
versionName flutterVersionName
|
||||||
multiDexEnabled true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
@@ -61,10 +54,20 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
compilerOptions {
|
||||||
|
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_17
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
flutter {
|
flutter {
|
||||||
source '../..'
|
source '../..'
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.android.support:multidex:1.0.3'
|
// Same version as workmanager_android pins — needed to enqueue its
|
||||||
|
// BackgroundWorker from native widget code (the plugin uses
|
||||||
|
// `implementation`, so androidx.work is not exposed transitively).
|
||||||
|
implementation 'androidx.work:work-runtime:2.11.2'
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,4 +4,10 @@
|
|||||||
to allow setting breakpoints, to provide hot reload, etc.
|
to allow setting breakpoints, to provide hot reload, etc.
|
||||||
-->
|
-->
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
<!-- Allow cleartext HTTP in debug builds so developers can point the
|
||||||
|
Marianum-Connect custom endpoint at a local backend (e.g.
|
||||||
|
http://10.0.2.2:8080 from the Android emulator). Release builds
|
||||||
|
keep the default cleartext block. -->
|
||||||
|
<application android:usesCleartextTraffic="true" />
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
<application
|
<application
|
||||||
android:label="Marianum Fulda"
|
android:label="Marianum Fulda"
|
||||||
android:name="${applicationName}"
|
android:name="${applicationName}"
|
||||||
android:icon="@mipmap/ic_launcher">
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:fullBackupContent="@xml/backup_rules"
|
||||||
|
android:dataExtractionRules="@xml/data_extraction_rules">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTask"
|
||||||
android:theme="@style/LaunchTheme"
|
android:theme="@style/LaunchTheme"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
@@ -23,23 +26,148 @@
|
|||||||
<action android:name="android.intent.action.MAIN"/>
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
<category android:name="android.intent.category.LAUNCHER"/>
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
<data android:mimeType="application/*" />
|
||||||
|
<data android:mimeType="text/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.SEND_MULTIPLE" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:mimeType="image/*" />
|
||||||
|
<data android:mimeType="video/*" />
|
||||||
|
<data android:mimeType="application/*" />
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Guardian login mail link (App Link). Verified via
|
||||||
|
/.well-known/assetlinks.json on both hosts. -->
|
||||||
|
<intent-filter android:autoVerify="true">
|
||||||
|
<action android:name="android.intent.action.VIEW" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
<data android:scheme="https" />
|
||||||
|
<data android:host="connect.marianum-fulda.de" />
|
||||||
|
<data android:host="connect-beta.marianum-fulda.de" />
|
||||||
|
<data android:path="/app/guardian-login" />
|
||||||
|
</intent-filter>
|
||||||
|
<!-- The app routes links itself (GuardianLinkListener); Flutter's
|
||||||
|
built-in handling would push the path as a named route onto a
|
||||||
|
MaterialApp that only has `home`. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="flutter_deeplinking_enabled"
|
||||||
|
android:value="false" />
|
||||||
</activity>
|
</activity>
|
||||||
<!-- Don't delete the meta-data below.
|
<!-- Don't delete the meta-data below.
|
||||||
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="flutterEmbedding"
|
android:name="flutterEmbedding"
|
||||||
android:value="2" />
|
android:value="2" />
|
||||||
</application>
|
|
||||||
<!-- Required to query activities that can process text, see:
|
|
||||||
https://developer.android.com/training/package-visibility?hl=en and
|
|
||||||
https://developer.android.com/reference/android/content/Intent#ACTION_PROCESS_TEXT.
|
|
||||||
|
|
||||||
In particular, this is used by the Flutter engine in io.flutter.plugin.text.ProcessTextPlugin. -->
|
<!-- Fallback small icon + accent for anything FCM ever renders itself
|
||||||
|
(e.g. plain notification messages). Launcher mipmaps are unusable
|
||||||
|
as small icons: Android only draws their alpha silhouette, which
|
||||||
|
shows up as a solid circle in the status bar. -->
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.firebase.messaging.default_notification_icon"
|
||||||
|
android:resource="@drawable/ic_stat_notification" />
|
||||||
|
<meta-data
|
||||||
|
android:name="com.google.firebase.messaging.default_notification_color"
|
||||||
|
android:resource="@color/notification_accent" />
|
||||||
|
|
||||||
|
<!-- flutter_local_notifications liefert Notification-Action-Taps (Talk:
|
||||||
|
Antworten / Gelesen) als expliziten Broadcast an diesen Receiver.
|
||||||
|
Das Plugin deklariert ihn NICHT selbst — ohne diesen Eintrag kommt
|
||||||
|
der Tap nirgends an und der Background-Handler startet nie. -->
|
||||||
|
<receiver
|
||||||
|
android:name="com.dexterous.flutterlocalnotifications.ActionBroadcastReceiver"
|
||||||
|
android:exported="false" />
|
||||||
|
|
||||||
|
<!-- background_downloader runs large/long downloads in a foreground
|
||||||
|
service (WorkManager) so they survive the app being backgrounded and
|
||||||
|
beat the default 9-minute WorkManager timeout. On API 34+ the
|
||||||
|
dataSync foreground service type must be declared explicitly here;
|
||||||
|
see the FOREGROUND_SERVICE_DATA_SYNC permission below. -->
|
||||||
|
<service
|
||||||
|
android:name="androidx.work.impl.foreground.SystemForegroundService"
|
||||||
|
android:foregroundServiceType="dataSync"
|
||||||
|
tools:node="merge" />
|
||||||
|
|
||||||
|
<!-- Receiver classes live at the package root (NOT under .widgets) because
|
||||||
|
the home_widget Flutter plugin resolves them as <app-package>.<name>. -->
|
||||||
|
<receiver
|
||||||
|
android:name="eu.mhsl.marianum.mobile.client.TimetableDayWidget"
|
||||||
|
android:enabled="@bool/widget_supported"
|
||||||
|
android:label="@string/widget_day_label"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/timetable_day_widget_info" />
|
||||||
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name="eu.mhsl.marianum.mobile.client.TimetableWeekWidget"
|
||||||
|
android:enabled="@bool/widget_supported"
|
||||||
|
android:label="@string/widget_week_label"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
|
</intent-filter>
|
||||||
|
<meta-data
|
||||||
|
android:name="android.appwidget.provider"
|
||||||
|
android:resource="@xml/timetable_week_widget_info" />
|
||||||
|
</receiver>
|
||||||
|
</application>
|
||||||
|
<!-- Required so url_launcher / can_launch can actually see browsers,
|
||||||
|
mail clients and dialers under Android 11+ package-visibility rules
|
||||||
|
(otherwise UrlLauncher logs "component name for ... is null" and
|
||||||
|
link taps in Talk silently do nothing). The PROCESS_TEXT intent is
|
||||||
|
needed by io.flutter.plugin.text.ProcessTextPlugin (selection
|
||||||
|
menu).
|
||||||
|
See https://developer.android.com/training/package-visibility -->
|
||||||
<queries>
|
<queries>
|
||||||
<intent>
|
<intent>
|
||||||
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
<action android:name="android.intent.action.PROCESS_TEXT"/>
|
||||||
<data android:mimeType="text/plain"/>
|
<data android:mimeType="text/plain"/>
|
||||||
</intent>
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
<data android:scheme="https"/>
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
<data android:scheme="http"/>
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
<data android:scheme="mailto"/>
|
||||||
|
</intent>
|
||||||
|
<intent>
|
||||||
|
<action android:name="android.intent.action.VIEW"/>
|
||||||
|
<data android:scheme="tel"/>
|
||||||
|
</intent>
|
||||||
</queries>
|
</queries>
|
||||||
<uses-permission android:name="android.permission.INTERNET"/>
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<!-- Android 13+ runtime notification permission. Requested at login via
|
||||||
|
FirebaseMessaging.requestPermission(); without this declaration the
|
||||||
|
locally rendered push notifications are silently dropped. -->
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
|
<!-- background_downloader foreground service for large/long downloads that
|
||||||
|
must keep running while the app is backgrounded. DATA_SYNC is the
|
||||||
|
required type declaration on Android 14+ (API 34+). -->
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
|
||||||
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
|
||||||
|
<!-- Workmanager periodic widget refresh needs to reschedule after device
|
||||||
|
reboot, otherwise the widget freezes until the user opens the app. -->
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
|
<!-- Aus open_filex gemergt: die App öffnet nur selbst heruntergeladene Dateien
|
||||||
|
über dessen FileProvider (content://-URIs) und braucht keinen Zugriff auf
|
||||||
|
geteilte Medien. Entfernt wegen Google-Play "Photo and Video Permissions". -->
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" tools:node="remove"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_VIDEO" tools:node="remove"/>
|
||||||
|
<uses-permission android:name="android.permission.READ_MEDIA_AUDIO" tools:node="remove"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,25 +0,0 @@
|
|||||||
// Generated file.
|
|
||||||
//
|
|
||||||
// If you wish to remove Flutter's multidex support, delete this entire file.
|
|
||||||
//
|
|
||||||
// Modifications to this file should be done in a copy under a different name
|
|
||||||
// as this file may be regenerated.
|
|
||||||
|
|
||||||
package io.flutter.app;
|
|
||||||
|
|
||||||
import android.app.Application;
|
|
||||||
import android.content.Context;
|
|
||||||
import androidx.annotation.CallSuper;
|
|
||||||
import androidx.multidex.MultiDex;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of {@link android.app.Application}, adding multidex support.
|
|
||||||
*/
|
|
||||||
public class FlutterMultiDexApplication extends Application {
|
|
||||||
@Override
|
|
||||||
@CallSuper
|
|
||||||
protected void attachBaseContext(Context base) {
|
|
||||||
super.attachBaseContext(base);
|
|
||||||
MultiDex.install(this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,83 @@
|
|||||||
package eu.mhsl.marianum.mobile.client
|
package eu.mhsl.marianum.mobile.client
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Bundle
|
||||||
import io.flutter.embedding.android.FlutterActivity
|
import io.flutter.embedding.android.FlutterActivity
|
||||||
|
import io.flutter.embedding.engine.FlutterEngine
|
||||||
|
import io.flutter.plugin.common.MethodChannel
|
||||||
|
|
||||||
class MainActivity: FlutterActivity()
|
class MainActivity : FlutterActivity() {
|
||||||
|
private val widgetChannel = "eu.mhsl.marianum.widget"
|
||||||
|
private val shareChannel = "eu.mhsl.marianum.share"
|
||||||
|
/// Last seen widget tap target. Cleared by Dart via `consumePendingNavigation`
|
||||||
|
/// so the same intent isn't replayed on every resume.
|
||||||
|
private var pendingTimetableTap: Boolean = false
|
||||||
|
private val shareActions = setOf(Intent.ACTION_SEND, Intent.ACTION_SEND_MULTIPLE)
|
||||||
|
|
||||||
|
/// receive_sharing_intent only emits warm shares to a live Dart listener and
|
||||||
|
/// does not buffer them. After a relaunch into an existing task the share
|
||||||
|
/// arrives via onNewIntent before Dart subscribed, so it is held here until
|
||||||
|
/// Dart reports `listenerReady`.
|
||||||
|
private var shareListenerReady = false
|
||||||
|
private var bufferedShare: Intent? = null
|
||||||
|
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
// Android replays the original launch intent when the activity is
|
||||||
|
// recreated from recents or after process death. A share or widget tap
|
||||||
|
// that was already handled would otherwise run again — for shares with
|
||||||
|
// temp files that are long gone.
|
||||||
|
val replayed = savedInstanceState != null ||
|
||||||
|
(intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0
|
||||||
|
if (replayed && (intent.action in shareActions || isWidgetTap(intent))) {
|
||||||
|
intent = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
|
||||||
|
}
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
|
||||||
|
super.configureFlutterEngine(flutterEngine)
|
||||||
|
MethodChannel(
|
||||||
|
flutterEngine.dartExecutor.binaryMessenger,
|
||||||
|
widgetChannel
|
||||||
|
).setMethodCallHandler { call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
"consumePendingNavigation" -> {
|
||||||
|
val pending = pendingTimetableTap
|
||||||
|
pendingTimetableTap = false
|
||||||
|
result.success(pending)
|
||||||
|
}
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MethodChannel(
|
||||||
|
flutterEngine.dartExecutor.binaryMessenger,
|
||||||
|
shareChannel
|
||||||
|
).setMethodCallHandler { call, result ->
|
||||||
|
when (call.method) {
|
||||||
|
"listenerReady" -> {
|
||||||
|
shareListenerReady = true
|
||||||
|
bufferedShare?.let { flutterEngine.activityControlSurface.onNewIntent(it) }
|
||||||
|
bufferedShare = null
|
||||||
|
result.success(null)
|
||||||
|
}
|
||||||
|
else -> result.notImplemented()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
consumeIntentData(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewIntent(intent: Intent) {
|
||||||
|
super.onNewIntent(intent)
|
||||||
|
if (!shareListenerReady && intent.action in shareActions) {
|
||||||
|
bufferedShare = intent
|
||||||
|
}
|
||||||
|
consumeIntentData(intent)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isWidgetTap(intent: Intent?): Boolean =
|
||||||
|
intent?.getBooleanExtra("widget_open_timetable", false) == true
|
||||||
|
|
||||||
|
private fun consumeIntentData(intent: Intent?) {
|
||||||
|
if (isWidgetTap(intent)) pendingTimetableTap = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package eu.mhsl.marianum.mobile.client
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import eu.mhsl.marianum.mobile.client.widgets.WidgetRefreshRequester
|
||||||
|
import eu.mhsl.marianum.mobile.client.widgets.WidgetRenderer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lives at the package root (not under `widgets/`) because the home_widget
|
||||||
|
* Flutter plugin resolves the receiver class as `<app-package>.<androidName>`.
|
||||||
|
*/
|
||||||
|
class TimetableDayWidget : AppWidgetProvider() {
|
||||||
|
override fun onEnabled(context: Context) {
|
||||||
|
// First widget of this kind placed → fetch fresh data right away.
|
||||||
|
WidgetRefreshRequester.enqueueOneOffRefresh(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdate(
|
||||||
|
context: Context,
|
||||||
|
appWidgetManager: AppWidgetManager,
|
||||||
|
appWidgetIds: IntArray,
|
||||||
|
) {
|
||||||
|
for (id in appWidgetIds) {
|
||||||
|
val options = appWidgetManager.getAppWidgetOptions(id)
|
||||||
|
val views = WidgetRenderer.buildDay(context, context.packageName, options)
|
||||||
|
appWidgetManager.updateAppWidget(id, views)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAppWidgetOptionsChanged(
|
||||||
|
context: Context,
|
||||||
|
appWidgetManager: AppWidgetManager,
|
||||||
|
appWidgetId: Int,
|
||||||
|
newOptions: Bundle,
|
||||||
|
) {
|
||||||
|
// Re-render on resize, otherwise the tiles stay at install-time size
|
||||||
|
// and either clip or leave dead space.
|
||||||
|
val views = WidgetRenderer.buildDay(context, context.packageName, newOptions)
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package eu.mhsl.marianum.mobile.client
|
||||||
|
|
||||||
|
import android.appwidget.AppWidgetManager
|
||||||
|
import android.appwidget.AppWidgetProvider
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
|
import eu.mhsl.marianum.mobile.client.widgets.WidgetRefreshRequester
|
||||||
|
import eu.mhsl.marianum.mobile.client.widgets.WidgetRenderer
|
||||||
|
|
||||||
|
class TimetableWeekWidget : AppWidgetProvider() {
|
||||||
|
override fun onEnabled(context: Context) {
|
||||||
|
// First widget of this kind placed → fetch fresh data right away.
|
||||||
|
WidgetRefreshRequester.enqueueOneOffRefresh(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUpdate(
|
||||||
|
context: Context,
|
||||||
|
appWidgetManager: AppWidgetManager,
|
||||||
|
appWidgetIds: IntArray,
|
||||||
|
) {
|
||||||
|
for (id in appWidgetIds) {
|
||||||
|
val options = appWidgetManager.getAppWidgetOptions(id)
|
||||||
|
val views = WidgetRenderer.buildWeek(context, context.packageName, options)
|
||||||
|
appWidgetManager.updateAppWidget(id, views)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onAppWidgetOptionsChanged(
|
||||||
|
context: Context,
|
||||||
|
appWidgetManager: AppWidgetManager,
|
||||||
|
appWidgetId: Int,
|
||||||
|
newOptions: Bundle,
|
||||||
|
) {
|
||||||
|
val views = WidgetRenderer.buildWeek(context, context.packageName, newOptions)
|
||||||
|
appWidgetManager.updateAppWidget(appWidgetId, views)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,190 @@
|
|||||||
|
package eu.mhsl.marianum.mobile.client.widgets
|
||||||
|
|
||||||
|
import org.json.JSONException
|
||||||
|
import org.json.JSONObject
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Date
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
// Mirror of lib/widget_data/widget_data.dart — JSON keys + enum names
|
||||||
|
// must stay in sync.
|
||||||
|
enum class WidgetLessonStatus {
|
||||||
|
REGULAR, ONGOING, PAST, CANCELLED, IRREGULAR, TEACHER_CHANGED, EVENT, DUTY;
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromWire(raw: String?): WidgetLessonStatus = when (raw) {
|
||||||
|
"regular" -> REGULAR
|
||||||
|
"ongoing" -> ONGOING
|
||||||
|
"past" -> PAST
|
||||||
|
"cancelled" -> CANCELLED
|
||||||
|
"irregular" -> IRREGULAR
|
||||||
|
"teacherChanged" -> TEACHER_CHANGED
|
||||||
|
"event" -> EVENT
|
||||||
|
"duty" -> DUTY
|
||||||
|
else -> REGULAR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class WidgetLesson(
|
||||||
|
val start: Date,
|
||||||
|
val end: Date,
|
||||||
|
val subjectShort: String,
|
||||||
|
val subjectLong: String?,
|
||||||
|
val room: String?,
|
||||||
|
// On teacher accounts this carries the class label ("7a") instead of the
|
||||||
|
// teacher short name (originalTeacher is null then) — mapped in Dart.
|
||||||
|
val teacher: String?,
|
||||||
|
val originalTeacher: String?,
|
||||||
|
val status: WidgetLessonStatus,
|
||||||
|
val customColor: String?,
|
||||||
|
// Tile colour resolved in Dart (subject colours, palettes); null only for
|
||||||
|
// payloads written before the field existed.
|
||||||
|
val color: Int?,
|
||||||
|
val siblingCount: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class WidgetPeriod(
|
||||||
|
val name: String,
|
||||||
|
val startMinutes: Int,
|
||||||
|
val endMinutes: Int,
|
||||||
|
val virtualStartMinutes: Int,
|
||||||
|
val virtualEndMinutes: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class WidgetDayInfo(
|
||||||
|
val date: Date,
|
||||||
|
val isHoliday: Boolean,
|
||||||
|
val holidayName: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class WidgetTimetableData(
|
||||||
|
val fetchedAt: Date,
|
||||||
|
val anchorDate: Date,
|
||||||
|
val lessons: List<WidgetLesson>,
|
||||||
|
val periods: List<WidgetPeriod>,
|
||||||
|
val isHoliday: Boolean,
|
||||||
|
val holidayName: String?,
|
||||||
|
// Week payload only; empty for the day payload.
|
||||||
|
val days: List<WidgetDayInfo>,
|
||||||
|
)
|
||||||
|
|
||||||
|
object WidgetDataParser {
|
||||||
|
private val isoFormat: SimpleDateFormat
|
||||||
|
get() = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS", Locale.ROOT).apply {
|
||||||
|
timeZone = TimeZone.getDefault()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Dart's toIso8601String() ships microseconds (6 digits) when non-zero;
|
||||||
|
/// SimpleDateFormat only parses 3 → strip the extra digits. Local time
|
||||||
|
/// without Z is the default, so removeSuffix("Z") makes the parser
|
||||||
|
/// tolerate both shapes.
|
||||||
|
private fun parseDate(raw: String?): Date? {
|
||||||
|
if (raw.isNullOrEmpty()) return null
|
||||||
|
val cleaned = raw
|
||||||
|
.replace(Regex("([.,]\\d{3})\\d+"), "$1")
|
||||||
|
.removeSuffix("Z")
|
||||||
|
return try {
|
||||||
|
isoFormat.parse(cleaned)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseColor(raw: String?): Int? {
|
||||||
|
if (raw == null || !Regex("#[0-9A-Fa-f]{6}").matches(raw)) return null
|
||||||
|
return 0xFF000000.toInt() or raw.substring(1).toInt(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parse(json: String?): WidgetTimetableData? {
|
||||||
|
if (json.isNullOrEmpty()) return null
|
||||||
|
return try {
|
||||||
|
val root = JSONObject(json)
|
||||||
|
val lessonsArray = root.optJSONArray("lessons")
|
||||||
|
val lessons = mutableListOf<WidgetLesson>()
|
||||||
|
if (lessonsArray != null) {
|
||||||
|
for (i in 0 until lessonsArray.length()) {
|
||||||
|
val obj = lessonsArray.optJSONObject(i) ?: continue
|
||||||
|
val start = parseDate(obj.stringOrNull("start")) ?: continue
|
||||||
|
val end = parseDate(obj.stringOrNull("end")) ?: continue
|
||||||
|
lessons += WidgetLesson(
|
||||||
|
start = start,
|
||||||
|
end = end,
|
||||||
|
subjectShort = obj.stringOrNull("subjectShort") ?: "",
|
||||||
|
subjectLong = obj.stringOrNull("subjectLong"),
|
||||||
|
room = obj.stringOrNull("room"),
|
||||||
|
teacher = obj.stringOrNull("teacher"),
|
||||||
|
originalTeacher = obj.stringOrNull("originalTeacher"),
|
||||||
|
status = WidgetLessonStatus.fromWire(obj.stringOrNull("status")),
|
||||||
|
customColor = obj.stringOrNull("customColor"),
|
||||||
|
color = parseColor(obj.stringOrNull("color")),
|
||||||
|
siblingCount = obj.optInt("siblingCount", 0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val periodsArray = root.optJSONArray("periods")
|
||||||
|
val periods = mutableListOf<WidgetPeriod>()
|
||||||
|
if (periodsArray != null) {
|
||||||
|
for (i in 0 until periodsArray.length()) {
|
||||||
|
val obj = periodsArray.optJSONObject(i) ?: continue
|
||||||
|
periods += WidgetPeriod(
|
||||||
|
name = obj.stringOrNull("name") ?: "",
|
||||||
|
startMinutes = obj.optInt("startMinutes", 0),
|
||||||
|
endMinutes = obj.optInt("endMinutes", 0),
|
||||||
|
virtualStartMinutes = obj.optInt("virtualStartMinutes", 0),
|
||||||
|
virtualEndMinutes = obj.optInt("virtualEndMinutes", 0),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val daysArray = root.optJSONArray("days")
|
||||||
|
val days = mutableListOf<WidgetDayInfo>()
|
||||||
|
if (daysArray != null) {
|
||||||
|
for (i in 0 until daysArray.length()) {
|
||||||
|
val obj = daysArray.optJSONObject(i) ?: continue
|
||||||
|
days += WidgetDayInfo(
|
||||||
|
date = parseDate(obj.stringOrNull("date")) ?: continue,
|
||||||
|
isHoliday = obj.optBoolean("isHoliday", false),
|
||||||
|
holidayName = obj.stringOrNull("holidayName"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
WidgetTimetableData(
|
||||||
|
fetchedAt = parseDate(root.stringOrNull("fetchedAt")) ?: Date(),
|
||||||
|
anchorDate = parseDate(root.stringOrNull("anchorDate")) ?: Date(),
|
||||||
|
lessons = lessons,
|
||||||
|
periods = periods,
|
||||||
|
isHoliday = root.optBoolean("isHoliday", false),
|
||||||
|
holidayName = root.stringOrNull("holidayName"),
|
||||||
|
days = days,
|
||||||
|
)
|
||||||
|
} catch (_: JSONException) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun JSONObject.stringOrNull(key: String): String? {
|
||||||
|
if (!has(key) || isNull(key)) return null
|
||||||
|
val raw = optString(key, "")
|
||||||
|
return if (raw.isEmpty()) null else raw
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object WidgetDateUtils {
|
||||||
|
fun startOfDay(date: Date): Date {
|
||||||
|
val cal = Calendar.getInstance().apply { time = date }
|
||||||
|
cal.set(Calendar.HOUR_OF_DAY, 0)
|
||||||
|
cal.set(Calendar.MINUTE, 0)
|
||||||
|
cal.set(Calendar.SECOND, 0)
|
||||||
|
cal.set(Calendar.MILLISECOND, 0)
|
||||||
|
return cal.time
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSameDay(a: Date, b: Date): Boolean {
|
||||||
|
val ca = Calendar.getInstance().apply { time = a }
|
||||||
|
val cb = Calendar.getInstance().apply { time = b }
|
||||||
|
return ca.get(Calendar.YEAR) == cb.get(Calendar.YEAR) &&
|
||||||
|
ca.get(Calendar.DAY_OF_YEAR) == cb.get(Calendar.DAY_OF_YEAR)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package eu.mhsl.marianum.mobile.client.widgets
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.work.Constraints
|
||||||
|
import androidx.work.Data
|
||||||
|
import androidx.work.NetworkType
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import dev.fluttercommunity.workmanager.BackgroundWorker
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enqueues the app's Dart one-off widget refresh from native code, so a
|
||||||
|
* freshly placed widget populates within seconds instead of waiting for the
|
||||||
|
* next periodic slot.
|
||||||
|
*
|
||||||
|
* DART_TASK_KEY is public plugin API but no semver guarantee — re-verify on
|
||||||
|
* workmanager upgrades. The Dart callback handle comes from SharedPreferences
|
||||||
|
* persisted by Workmanager().initialize(); if the app never ran, the worker
|
||||||
|
* fails gracefully and the widget keeps rendering its cached/empty state.
|
||||||
|
*/
|
||||||
|
object WidgetRefreshRequester {
|
||||||
|
// Mirrors WidgetBackgroundTask.oneOffTaskName on the Dart side.
|
||||||
|
private const val DART_ONE_OFF_TASK = "eu.mhsl.marianum.widget.refresh.once"
|
||||||
|
|
||||||
|
fun enqueueOneOffRefresh(context: Context) {
|
||||||
|
val request = OneTimeWorkRequest.Builder(BackgroundWorker::class.java)
|
||||||
|
.setInputData(
|
||||||
|
Data.Builder()
|
||||||
|
.putString(BackgroundWorker.DART_TASK_KEY, DART_ONE_OFF_TASK)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.setConstraints(
|
||||||
|
Constraints.Builder()
|
||||||
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
WorkManager.getInstance(context).enqueue(request)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 454 B |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 319 B |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 69 B After Width: | Height: | Size: 69 B |
|
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 654 B |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 5.1 KiB After Width: | Height: | Size: 1021 B |
|
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 16 KiB |
@@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Plain rounded rectangle. We deliberately avoid ?attr/appWidgetRadius
|
||||||
|
because RemoteViews inflation does not resolve custom theme attributes
|
||||||
|
reliably across launchers. Hard-coded 20dp matches the system home-screen
|
||||||
|
radius closely on stock Android. -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="20dp" />
|
||||||
|
<solid android:color="@color/widget_background" />
|
||||||
|
</shape>
|
||||||
|
Before Width: | Height: | Size: 69 B After Width: | Height: | Size: 69 B |
@@ -0,0 +1,34 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Status-bar small icon: monochrome Marianum M, ported from
|
||||||
|
marianum_m_watermark.xml (same path + nested transforms). Android renders
|
||||||
|
only the alpha channel of small icons, so the fill is hard white and never
|
||||||
|
tinted at runtime. 24dp with the source's non-square viewport — the system
|
||||||
|
fits it into the icon bounds.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="70.000168"
|
||||||
|
android:viewportHeight="82.227348">
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:scaleX="0.26458333"
|
||||||
|
android:scaleY="0.26458334"
|
||||||
|
android:translateX="107.44411"
|
||||||
|
android:translateY="-80.482198">
|
||||||
|
<group
|
||||||
|
android:translateX="-749.41293"
|
||||||
|
android:translateY="290.52252">
|
||||||
|
<group
|
||||||
|
android:scaleX="0.13333333"
|
||||||
|
android:scaleY="-0.13333333"
|
||||||
|
android:translateX="0"
|
||||||
|
android:translateY="632.14667">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFFFF"
|
||||||
|
android:pathData="M 3499.67,4594.33 c -16.43,-106.19 -29.71,-199.97 -43.79,-293.49 86.83,-19 138.5,-27.61 223.38,-43.82 63.81,-12.18 175.24,-20.4 179.64,-83.23 6.46,-92.69 -124.69,-55.41 -188.38,-43.81 -84.33,15.36 -159.13,28.84 -232.2,43.81 -13.68,-60.72 -26.83,-118.68 -39.43,-179.61 -36.76,-178.32 -73.67,-368.16 -105.11,-551.97 18.09,25.66 30.84,42.72 43.8,65.7 66.7,118.26 140.39,245.04 227.76,354.83 33.49,42.05 76.86,94.81 118.31,113.91 98.42,45.36 166.68,-22.2 170.87,-118.28 3.68,-85.28 -23.09,-181.17 -35.08,-275.99 -12.4,-98.19 -22.89,-194.93 -35.03,-275.98 72.44,102.69 147.93,269.64 240.95,381.12 27.51,33 73.55,80.61 118.27,87.62 218.76,34.33 126.58,-312.17 127.05,-473.13 0.4,-144.9 44.01,-255.37 175.21,-271.59 43.02,-5.31 105.84,11.16 112.7,-26.34 8.67,-47.38 -78.15,-60.52 -125.84,-61.28 -291.34,-4.51 -322.06,262.33 -311.01,573.88 -19.85,-18.57 -35.71,-47.53 -52.57,-74.47 -97.59,-155.88 -203.95,-327.22 -297.92,-503.79 -25.93,-48.79 -53.68,-114.7 -135.8,-83.23 -17.27,6.63 -48.25,44.39 -52.56,56.96 -19.58,57.19 1.55,137.42 8.76,205.89 21.54,203.72 57.81,389.09 78.87,587.01 -26.3,0.51 -43.93,-30.07 -56.96,-48.2 -46.9,-65.27 -86.02,-140.76 -127.04,-214.64 -52.84,-95.15 -108.23,-192.84 -157.71,-293.52 -75.25,-153.09 -188.6,-501.89 -242.12,-678.81 -8.67,-28.67 -17.7,-58.08 -26.3,-87.64 -7.48,-25.72 -10.39,-57.68 -35.05,-74.46 -100.02,18.93 -89.71,104.89 -70.09,205.9 47.35,243.43 170.89,706.45 211.48,946.04 -72.97,-70.97 -153.99,-207.41 -289.14,-236.55 -136.47,-29.44 -217.95,47.68 -271.6,122.66 -17.14,23.96 -41.43,49.54 -26.29,78.84 83.96,35.51 113.37,-65.2 197.15,-74.47 22.65,-2.5 54.56,2.4 74.46,8.78 132.4,42.34 237.57,218.76 297.87,346.07 74.16,156.45 125.32,330.5 148.95,490.64 -65.71,11.4 -142.96,22.15 -219.25,36.52 -109.8,20.72 -158.81,10.75 -201.29,59.86 9.15,41.95 41.41,60.8 70.1,83.24 126.26,-16.84 252.45,-33.77 372.36,-56.97 20.43,89.25 51.98,218.51 74.45,311.05 40.53,26.02 88.88,-8.43 105.17,-35.06 z" />
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
Direct port of /home/elias/Bilder/marianum_m_white.svg.
|
||||||
|
- viewport matches the source SVG (70mm × 82.2mm).
|
||||||
|
- Transforms recreate the SVG's three nested matrices: outer scale+offset,
|
||||||
|
inner translate, and a final scale+y-flip that pulls the path data into
|
||||||
|
the visible coordinate space.
|
||||||
|
- Tinted at runtime via setColorFilter so light/dark themes can share one
|
||||||
|
drawable.
|
||||||
|
-->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="70dp"
|
||||||
|
android:height="82dp"
|
||||||
|
android:viewportWidth="70.000168"
|
||||||
|
android:viewportHeight="82.227348">
|
||||||
|
|
||||||
|
<group
|
||||||
|
android:scaleX="0.26458333"
|
||||||
|
android:scaleY="0.26458334"
|
||||||
|
android:translateX="107.44411"
|
||||||
|
android:translateY="-80.482198">
|
||||||
|
<group
|
||||||
|
android:translateX="-749.41293"
|
||||||
|
android:translateY="290.52252">
|
||||||
|
<group
|
||||||
|
android:scaleX="0.13333333"
|
||||||
|
android:scaleY="-0.13333333"
|
||||||
|
android:translateX="0"
|
||||||
|
android:translateY="632.14667">
|
||||||
|
<path
|
||||||
|
android:fillColor="#FFFFFF"
|
||||||
|
android:pathData="M 3499.67,4594.33 c -16.43,-106.19 -29.71,-199.97 -43.79,-293.49 86.83,-19 138.5,-27.61 223.38,-43.82 63.81,-12.18 175.24,-20.4 179.64,-83.23 6.46,-92.69 -124.69,-55.41 -188.38,-43.81 -84.33,15.36 -159.13,28.84 -232.2,43.81 -13.68,-60.72 -26.83,-118.68 -39.43,-179.61 -36.76,-178.32 -73.67,-368.16 -105.11,-551.97 18.09,25.66 30.84,42.72 43.8,65.7 66.7,118.26 140.39,245.04 227.76,354.83 33.49,42.05 76.86,94.81 118.31,113.91 98.42,45.36 166.68,-22.2 170.87,-118.28 3.68,-85.28 -23.09,-181.17 -35.08,-275.99 -12.4,-98.19 -22.89,-194.93 -35.03,-275.98 72.44,102.69 147.93,269.64 240.95,381.12 27.51,33 73.55,80.61 118.27,87.62 218.76,34.33 126.58,-312.17 127.05,-473.13 0.4,-144.9 44.01,-255.37 175.21,-271.59 43.02,-5.31 105.84,11.16 112.7,-26.34 8.67,-47.38 -78.15,-60.52 -125.84,-61.28 -291.34,-4.51 -322.06,262.33 -311.01,573.88 -19.85,-18.57 -35.71,-47.53 -52.57,-74.47 -97.59,-155.88 -203.95,-327.22 -297.92,-503.79 -25.93,-48.79 -53.68,-114.7 -135.8,-83.23 -17.27,6.63 -48.25,44.39 -52.56,56.96 -19.58,57.19 1.55,137.42 8.76,205.89 21.54,203.72 57.81,389.09 78.87,587.01 -26.3,0.51 -43.93,-30.07 -56.96,-48.2 -46.9,-65.27 -86.02,-140.76 -127.04,-214.64 -52.84,-95.15 -108.23,-192.84 -157.71,-293.52 -75.25,-153.09 -188.6,-501.89 -242.12,-678.81 -8.67,-28.67 -17.7,-58.08 -26.3,-87.64 -7.48,-25.72 -10.39,-57.68 -35.05,-74.46 -100.02,18.93 -89.71,104.89 -70.09,205.9 47.35,243.43 170.89,706.45 211.48,946.04 -72.97,-70.97 -153.99,-207.41 -289.14,-236.55 -136.47,-29.44 -217.95,47.68 -271.6,122.66 -17.14,23.96 -41.43,49.54 -26.29,78.84 83.96,35.51 113.37,-65.2 197.15,-74.47 22.65,-2.5 54.56,2.4 74.46,8.78 132.4,42.34 237.57,218.76 297.87,346.07 74.16,156.45 125.32,330.5 148.95,490.64 -65.71,11.4 -142.96,22.15 -219.25,36.52 -109.8,20.72 -158.81,10.75 -201.29,59.86 9.15,41.95 41.41,60.8 70.1,83.24 126.26,-16.84 252.45,-33.77 372.36,-56.97 20.43,89.25 51.98,218.51 74.45,311.05 40.53,26.02 88.88,-8.43 105.17,-35.06 z" />
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/widget_divider" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Material Icons "coffee_outlined", matches the in-app period ruler. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M18.52 3H6C4.92 3 3.98 3.89 3.98 5.02V10.69C3.98 14.53 6.94 17.91 10.78 18C14.72 18.14 18 14.95 18 11.02V9.98H18.52C20.44 9.98 21.98 8.44 21.98 6.52C21.98 4.55 20.44 3 18.52 3ZM15.98 5.02V8.02H6V5.02H15.98ZM15.98 9.98V11.02C15.98 13.78 13.78 15.98 11.02 15.98C8.25 15.98 6 13.78 6 11.02V9.98ZM18.52 8.02H18V5.02H18.52C19.31 5.02 20.02 5.67 20.02 6.52C20.02 7.31 19.31 8.02 18.52 8.02ZM3.98 18.98H20.02V21H3.98V18.98Z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Material Icons "event_outlined", matches the in-app holiday region. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M18.98 3.98H18V2.02H15.98V3.98H8.02V2.02H6V3.98H5.02C3.89 3.98 3 4.92 3 6V20.02C3 21.09 3.89 21.98 5.02 21.98H18.98C20.11 21.98 21 21.09 21 20.02V6C21 4.92 20.11 3.98 18.98 3.98ZM18.98 20.02H5.02V9.98H18.98V20.02ZM18.98 8.02H5.02V6H18.98V8.02ZM12 12.98H17.02V18H12V12.98Z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Material Icons "restaurant", matches the in-app break region. -->
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M11.02 9H9V2.02H6.98V9H5.02V2.02H3V9C3 11.11 4.64 12.84 6.75 12.98V21.98H9.23V12.98C11.34 12.84 12.98 11.11 12.98 9V2.02H11.02V9ZM15.98 6V14.02H18.52V21.98H21V2.02C18.23 2.02 15.98 4.22 15.98 6Z" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Tinted at runtime with the tile colour resolved in Dart. -->
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:radius="7dp" />
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<item>
|
||||||
|
<shape android:shape="rectangle">
|
||||||
|
<corners android:radius="7dp" />
|
||||||
|
<solid android:color="@android:color/transparent" />
|
||||||
|
<stroke android:width="2dp" android:color="#C8F44336" />
|
||||||
|
</shape>
|
||||||
|
</item>
|
||||||
|
<item
|
||||||
|
android:left="2dp"
|
||||||
|
android:top="2dp"
|
||||||
|
android:right="2dp"
|
||||||
|
android:bottom="2dp"
|
||||||
|
android:drawable="@drawable/widget_lesson_cancelled_x" />
|
||||||
|
</layer-list>
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="100dp"
|
||||||
|
android:height="100dp"
|
||||||
|
android:viewportWidth="100"
|
||||||
|
android:viewportHeight="100">
|
||||||
|
<path
|
||||||
|
android:strokeColor="#C8F44336"
|
||||||
|
android:strokeWidth="2.5"
|
||||||
|
android:pathData="M0,0 L100,100 M100,0 L0,100" />
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="@android:color/white" />
|
||||||
|
</shape>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/widget_break_block_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_marginTop="0dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_break_block_icon"
|
||||||
|
android:layout_width="12dp"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/widget_break_label_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_marginTop="0dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_break_label_icon"
|
||||||
|
android:layout_width="10dp"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/widget_icon_coffee" />
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- FrameLayout root so the Marianum watermark can sit at bottom|end behind
|
||||||
|
the actual widget content without disturbing the LinearLayout flow.
|
||||||
|
Text sizes and chrome heights are dp: WidgetRenderer derives the grid
|
||||||
|
height from them, so they must not follow the system font scale. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/app_widget_background"
|
||||||
|
tools:ignore="SpUsage,SmallSp">
|
||||||
|
|
||||||
|
<!-- Width/height/end+bottom margins are overridden in the renderer so
|
||||||
|
the mark scales with the widget size. -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_watermark"
|
||||||
|
android:layout_width="160dp"
|
||||||
|
android:layout_height="160dp"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:alpha="0.025"
|
||||||
|
android:src="@drawable/marianum_m_watermark" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_day_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="9dp"
|
||||||
|
android:autoSizeMaxTextSize="14dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp"
|
||||||
|
tools:text="Heute · 08.05." />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_day_subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:textSize="10dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="Stand: 14:32" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<!-- Narrow day widgets can't fit title and freshness side by side —
|
||||||
|
the renderer moves the freshness label down here instead. -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_day_subtitle_below"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:textSize="9dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="Stand: 14:32" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_day_time_labels"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_day_grid"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_day_empty"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:textSize="13sp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="12dp"
|
||||||
|
tools:text="Keine Stunden" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Static picker preview of the day widget, laid out like WidgetRenderer's output. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_background"
|
||||||
|
tools:ignore="SpUsage,SmallSp,HardcodedText,UseAppTint">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="160dp"
|
||||||
|
android:layout_height="160dp"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="-28dp"
|
||||||
|
android:layout_marginBottom="-28dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:alpha="0.018"
|
||||||
|
android:src="@drawable/marianum_m_watermark" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:textSize="14dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="Heute · 06.05." />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout android:layout_width="30dp" android:layout_height="match_parent">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="0dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="07:55" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="1" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="08:40" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="36dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="08:40" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="2" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="09:25" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="72dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="09:30" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="3" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="10:15" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp">
|
||||||
|
<ImageView android:layout_width="10dp" android:layout_height="10dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_text_secondary" android:src="@drawable/widget_icon_coffee" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="122dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="10:35" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="4" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="11:20" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="158dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="11:25" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="5" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="12:10" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="194dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="12:15" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="6" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="13:00" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="230dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="13:05" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="7" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="13:50" />
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp" android:background="@color/widget_preview_break">
|
||||||
|
<ImageView android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_preview_accent" android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="0.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#5C6BC0">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="MA-LK" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="B11" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="MUE" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="72.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#993333">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="DE" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A204" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="SCHN" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="122.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#0097A7">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="EN" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="F2.04" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="KRA" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="158.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#000000">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="BIO" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="N103" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="WEB" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/widget_lesson_cancelled_overlay" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="230.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#29639B">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="GE" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A110" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="BER" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/widget_grid_line_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:background="@drawable/widget_grid_line" />
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Mirrors the in-app holiday region: icon and "Schulfrei" on top, the
|
||||||
|
holiday name rotated along the column. The name's width is set by the
|
||||||
|
renderer — after the rotation it is the length along the column. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_holiday_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:ignore="SpUsage,SmallSp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center_horizontal">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_holiday_icon"
|
||||||
|
android:layout_width="14dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:src="@drawable/widget_icon_event" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_holiday_label"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="12dp"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:paddingStart="2dp"
|
||||||
|
android:paddingEnd="2dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@string/widget_school_free"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="6dp"
|
||||||
|
android:autoSizeMaxTextSize="9dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_holiday_name"
|
||||||
|
android:layout_width="120dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:rotation="90"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:letterSpacing="0.1"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="7dp"
|
||||||
|
android:autoSizeMaxTextSize="11dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp"
|
||||||
|
tools:text="Herbstferien" />
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Mirrors AppointmentTile: title on top, room and teacher stacked below,
|
||||||
|
each line shrinking on its own to fit the tile width. Text sizes are dp
|
||||||
|
(not sp) because the line boxes are sized in dp by the renderer. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_lesson_block_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="40dp"
|
||||||
|
android:layout_marginStart="1dp"
|
||||||
|
android:layout_marginEnd="1dp"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
android:background="@drawable/widget_lesson_block"
|
||||||
|
tools:ignore="SpUsage,SmallSp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="4dp"
|
||||||
|
android:paddingEnd="4dp"
|
||||||
|
android:paddingTop="2dp"
|
||||||
|
android:paddingBottom="2dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:id="@+id/widget_lesson_title_row"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:baselineAligned="false">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_lesson_subject"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="14dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="6.5dp"
|
||||||
|
android:autoSizeMaxTextSize="15dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp"
|
||||||
|
tools:text="MA-LK" />
|
||||||
|
|
||||||
|
<!-- Only for tiles too short for a body line below the title. -->
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_lesson_inline"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:layout_marginStart="3dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:textSize="7dp"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="B11" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_lesson_room"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="5.5dp"
|
||||||
|
android:autoSizeMaxTextSize="10dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp"
|
||||||
|
tools:text="A12" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_lesson_teacher"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="10dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="5.5dp"
|
||||||
|
android:autoSizeMaxTextSize="10dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp"
|
||||||
|
tools:text="Müller" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_lesson_cancelled"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/widget_lesson_cancelled_overlay"
|
||||||
|
android:visibility="gone" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_lesson_sibling_badge"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="4dp"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="9dp"
|
||||||
|
android:textColor="@android:color/white"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:text="+1" />
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/app_widget_background">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_watermark"
|
||||||
|
android:layout_width="160dp"
|
||||||
|
android:layout_height="160dp"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:alpha="0.025"
|
||||||
|
android:src="@drawable/marianum_m_watermark" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
android:padding="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_placeholder_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
tools:text="Marianum Vertretungsplan" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_placeholder_message"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="12sp"
|
||||||
|
android:layout_marginTop="6dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
tools:text="Bitte einloggen, um den Stundenplan zu laden" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- One period cell of the ruler, mirroring the in-app _PeriodLabel: number
|
||||||
|
centred, start time above, end time below. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_time_label_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="36dp"
|
||||||
|
android:layout_marginTop="0dp"
|
||||||
|
tools:ignore="SpUsage,SmallSp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_time_label_start"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="top"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:textSize="7dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="07:55" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_time_label_number"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:textSize="11dp"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="1" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_time_label_end"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom"
|
||||||
|
android:layout_marginBottom="2dp"
|
||||||
|
android:gravity="center_horizontal"
|
||||||
|
android:textSize="7dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="08:40" />
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- FrameLayout root so the Marianum watermark can sit at bottom|end behind
|
||||||
|
the actual widget content without disturbing the LinearLayout flow.
|
||||||
|
Text sizes and chrome heights are dp: WidgetRenderer derives the grid
|
||||||
|
height from them, so they must not follow the system font scale. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@drawable/app_widget_background"
|
||||||
|
tools:ignore="SpUsage,SmallSp">
|
||||||
|
|
||||||
|
<!-- Width/height/end+bottom margins are overridden in the renderer so
|
||||||
|
the mark scales with the widget size. -->
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/widget_watermark"
|
||||||
|
android:layout_width="160dp"
|
||||||
|
android:layout_height="160dp"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:alpha="0.025"
|
||||||
|
android:src="@drawable/marianum_m_watermark" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:gravity="center_vertical">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_week_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:autoSizeTextType="uniform"
|
||||||
|
android:autoSizeMinTextSize="9dp"
|
||||||
|
android:autoSizeMaxTextSize="14dp"
|
||||||
|
android:autoSizeStepGranularity="0.5dp"
|
||||||
|
tools:text="KW 19 · 06.05.–10.05." />
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_week_subtitle"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="6dp"
|
||||||
|
android:textSize="10dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="Stand: 14:32" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_header_mon"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_header_tue"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_header_wed"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_header_thu"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_header_fri"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_time_labels"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_col_mon"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_col_tue"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_col_wed"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_col_thu"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_divider" />
|
||||||
|
|
||||||
|
<FrameLayout
|
||||||
|
android:id="@+id/widget_week_col_fri"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_weight="1" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Mirrors the in-app _DayHeaderCell: weekday in caps, day number below,
|
||||||
|
today inside an accent circle. -->
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/widget_week_day_header_root"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:gravity="center"
|
||||||
|
tools:ignore="SpUsage,SmallSp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_week_day_header_weekday"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:fontFamily="sans-serif-medium"
|
||||||
|
android:textSize="9dp"
|
||||||
|
android:textColor="@color/widget_text_secondary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="MO." />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/widget_week_day_header_date"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_marginTop="1dp"
|
||||||
|
android:gravity="center"
|
||||||
|
android:textSize="11dp"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
tools:text="6" />
|
||||||
|
</LinearLayout>
|
||||||
@@ -0,0 +1,336 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Static picker preview of the week widget, laid out like WidgetRenderer's output. -->
|
||||||
|
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="@color/widget_background"
|
||||||
|
tools:ignore="SpUsage,SmallSp,HardcodedText,UseAppTint">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="200dp"
|
||||||
|
android:layout_height="200dp"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_marginEnd="-36dp"
|
||||||
|
android:layout_marginBottom="-36dp"
|
||||||
|
android:scaleType="fitCenter"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:contentDescription="@null"
|
||||||
|
android:alpha="0.018"
|
||||||
|
android:src="@drawable/marianum_m_watermark" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:paddingStart="8dp"
|
||||||
|
android:paddingEnd="8dp"
|
||||||
|
android:paddingTop="10dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:gravity="start|center_vertical"
|
||||||
|
android:includeFontPadding="false"
|
||||||
|
android:textSize="14dp"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textColor="@color/widget_text_primary"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:text="KW 19 · 04.05.–08.05." />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="32dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
<FrameLayout android:layout_width="30dp" android:layout_height="match_parent" />
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="9dp" android:textColor="@color/widget_text_secondary" android:text="MO." />
|
||||||
|
<TextView android:layout_width="18dp" android:layout_height="18dp" android:layout_marginTop="1dp" android:gravity="center" android:includeFontPadding="false" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="4" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="9dp" android:textColor="@color/widget_text_secondary" android:text="DI." />
|
||||||
|
<TextView android:layout_width="18dp" android:layout_height="18dp" android:layout_marginTop="1dp" android:gravity="center" android:includeFontPadding="false" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="5" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="9dp" android:textColor="@color/widget_text_secondary" android:text="MI." />
|
||||||
|
<TextView android:layout_width="18dp" android:layout_height="18dp" android:layout_marginTop="1dp" android:gravity="center" android:includeFontPadding="false" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="6" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="9dp" android:textColor="@color/widget_text_secondary" android:text="DO." />
|
||||||
|
<TextView android:layout_width="18dp" android:layout_height="18dp" android:layout_marginTop="1dp" android:gravity="center" android:includeFontPadding="false" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="7" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<LinearLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="9dp" android:textColor="@color/widget_text_secondary" android:text="FR." />
|
||||||
|
<TextView android:layout_width="18dp" android:layout_height="18dp" android:layout_marginTop="1dp" android:gravity="center" android:includeFontPadding="false" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="8" />
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
android:layout_marginTop="2dp"
|
||||||
|
android:orientation="horizontal">
|
||||||
|
|
||||||
|
<FrameLayout android:layout_width="30dp" android:layout_height="match_parent">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="0dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="07:55" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="1" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="08:40" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="36dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="08:40" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="2" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="09:25" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="72dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="09:30" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="3" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="10:15" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp">
|
||||||
|
<ImageView android:layout_width="10dp" android:layout_height="10dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_text_secondary" android:src="@drawable/widget_icon_coffee" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="122dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="10:35" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="4" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="11:20" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="158dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="11:25" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="5" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="12:10" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="194dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="12:15" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="6" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="13:00" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="36dp" android:layout_marginTop="230dp">
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="top" android:layout_marginTop="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="13:05" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:gravity="center_horizontal" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:textSize="11dp" android:textColor="@color/widget_text_primary" android:text="7" />
|
||||||
|
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_marginBottom="2dp" android:gravity="center_horizontal" android:includeFontPadding="false" android:textSize="7dp" android:textColor="@color/widget_text_secondary" android:text="13:50" />
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp" android:background="@color/widget_preview_break">
|
||||||
|
<ImageView android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_preview_accent" android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="0.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#5C6BC0">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="MA-LK" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="B11" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="MUE" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="72.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#993333">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="DE" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A204" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="SCHN" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="122.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#0097A7">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="EN" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="F2.04" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="KRA" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="158.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#000000">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="BIO" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="N103" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="WEB" />
|
||||||
|
</LinearLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/widget_lesson_cancelled_overlay" />
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp" android:background="@color/widget_preview_break">
|
||||||
|
<ImageView android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_preview_accent" android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="0.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#26A69A">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="SPO" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="TH1" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="BAU" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="36.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#8F19B3">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="PoWi" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A105" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="HOF" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="84.5dp" android:layout_marginTop="72.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#29639B">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="PH" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="N201" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="LEH" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="158.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#9E9D24">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="GE" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A110" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="BER" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp" android:background="@color/widget_preview_break">
|
||||||
|
<ImageView android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_preview_accent" android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="0.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#E91E63">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="CH" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="N305" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="MEI" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="72.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#5C6BC0">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="MA-LK" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="B11" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="MUE" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="122.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#993333">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="DE" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A204" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="SCHN" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="194.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#0097A7">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="EN" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="F2.04" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="KRA" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp" android:background="@color/widget_preview_break">
|
||||||
|
<ImageView android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_preview_accent" android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="0.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#78909C">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="EK" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A301" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="LAN" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="36.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#993333">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="BIO" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="N103" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="WEB" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="122.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#7E57C2">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="MU" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="M1" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="SIN" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="158.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#F4511E">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="KU" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="K2" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="MAL" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="0dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="36dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="72dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="108dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="108dp" android:background="@color/widget_preview_break">
|
||||||
|
<ImageView android:layout_width="12dp" android:layout_height="12dp" android:layout_gravity="center" android:importantForAccessibility="no" android:contentDescription="@null" android:tint="@color/widget_preview_accent" android:src="@drawable/widget_icon_restaurant" />
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="122dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="158dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="194dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="230dp" android:background="@color/widget_divider" />
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="70.5dp" android:layout_marginTop="0.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#993333">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="PH" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="N201" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="LEH" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="72.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#FFA000">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="LA" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A108" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="CIC" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
<FrameLayout android:layout_width="match_parent" android:layout_height="34.5dp" android:layout_marginTop="122.8dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:background="@drawable/widget_lesson_block" android:backgroundTint="#9E9D24">
|
||||||
|
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingStart="4dp" android:paddingEnd="4dp" android:paddingTop="2dp" android:paddingBottom="2dp">
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:fontFamily="sans-serif-medium" android:maxLines="1" android:textSize="11dp" android:textColor="@android:color/white" android:text="GE" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="A110" />
|
||||||
|
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:includeFontPadding="false" android:textSize="8dp" android:textColor="@android:color/white" android:text="BER" />
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</FrameLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</LinearLayout>
|
||||||
|
</FrameLayout>
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<background android:drawable="@drawable/ic_launcher_background"/>
|
<background android:drawable="@drawable/ic_launcher_background"/>
|
||||||
<foreground android:drawable="@drawable/ic_launcher_foreground"/>
|
<foreground>
|
||||||
|
<inset
|
||||||
|
android:drawable="@drawable/ic_launcher_foreground"
|
||||||
|
android:inset="16%" />
|
||||||
|
</foreground>
|
||||||
</adaptive-icon>
|
</adaptive-icon>
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 4.9 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 11 KiB |
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="widget_background">#FF1F1716</color>
|
||||||
|
<color name="widget_text_primary">#FFF1F1F1</color>
|
||||||
|
<color name="widget_text_secondary">#FFB0B0B0</color>
|
||||||
|
<color name="widget_divider">#33FFFFFF</color>
|
||||||
|
<color name="widget_preview_accent">#FFFFB3AF</color>
|
||||||
|
<color name="widget_preview_break">#32FFB3AF</color>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<bool name="widget_supported">true</bool>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- Brand accent for notifications; mirrors LightAppTheme.marianumRed
|
||||||
|
(Color.fromARGB(255, 153, 51, 51)). Used as the FCM default
|
||||||
|
notification color and must stay in sync with the Dart constant. -->
|
||||||
|
<color name="notification_accent">#993333</color>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="widget_day_label">Marianum · Heute</string>
|
||||||
|
<string name="widget_week_label">Marianum · Woche</string>
|
||||||
|
<string name="widget_day_description">Stundenplan und Vertretungen für den anstehenden Schultag.</string>
|
||||||
|
<string name="widget_week_description">Stundenplan und Vertretungen für die ganze Schulwoche.</string>
|
||||||
|
<string name="widget_no_lessons">Keine Stunden</string>
|
||||||
|
<string name="widget_holiday">Ferien</string>
|
||||||
|
<string name="widget_school_free">Schulfrei</string>
|
||||||
|
<string name="widget_login_required">Bitte einloggen, um den Stundenplan zu laden</string>
|
||||||
|
<string name="widget_loading">Lade…</string>
|
||||||
|
<string name="widget_status_label">Stand: %1$s</string>
|
||||||
|
<string name="widget_today">Heute</string>
|
||||||
|
<string name="widget_tomorrow">Morgen</string>
|
||||||
|
<string name="widget_placeholder_title">Marianum Stundenplan</string>
|
||||||
|
<string name="widget_calendar_week_prefix">KW</string>
|
||||||
|
<string name="widget_yesterday_prefix">gestern</string>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<color name="widget_background">#FFFCF7F5</color>
|
||||||
|
<color name="widget_text_primary">#FF111111</color>
|
||||||
|
<color name="widget_text_secondary">#FF555555</color>
|
||||||
|
<color name="widget_divider">#22000000</color>
|
||||||
|
<color name="widget_preview_accent">#FF904A47</color>
|
||||||
|
<color name="widget_preview_break">#32904A47</color>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<!-- WidgetRenderer positions every tile with RemoteViews calls that only
|
||||||
|
exist from Android 12 (API 31). Below that the widgets are not
|
||||||
|
offered at all rather than showing up empty. -->
|
||||||
|
<bool name="widget_supported">false</bool>
|
||||||
|
</resources>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Auto-Backup rules for Android 11 and below.
|
||||||
|
Excludes the home_widget plugin's SharedPreferences file
|
||||||
|
(HomeWidgetPreferences) so the cached timetable — which contains
|
||||||
|
teacher names, room numbers and personal custom events — is not
|
||||||
|
uploaded to the user's Google Drive. -->
|
||||||
|
<full-backup-content>
|
||||||
|
<exclude domain="sharedpref" path="HomeWidgetPreferences.xml"/>
|
||||||
|
</full-backup-content>
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Backup + device-transfer rules for Android 12+.
|
||||||
|
Excludes the home_widget plugin's SharedPreferences file
|
||||||
|
(HomeWidgetPreferences) so the cached timetable — which contains
|
||||||
|
teacher names, room numbers and personal custom events — is not
|
||||||
|
uploaded to the user's Google Drive or transferred to a new device.
|
||||||
|
The widget repopulates from a fresh Webuntis fetch after sign-in. -->
|
||||||
|
<data-extraction-rules>
|
||||||
|
<cloud-backup>
|
||||||
|
<exclude domain="sharedpref" path="HomeWidgetPreferences.xml"/>
|
||||||
|
</cloud-backup>
|
||||||
|
<device-transfer>
|
||||||
|
<exclude domain="sharedpref" path="HomeWidgetPreferences.xml"/>
|
||||||
|
</device-transfer>
|
||||||
|
</data-extraction-rules>
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:initialLayout="@layout/widget_placeholder"
|
||||||
|
android:minWidth="110dp"
|
||||||
|
android:minHeight="180dp"
|
||||||
|
android:targetCellWidth="2"
|
||||||
|
android:targetCellHeight="5"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:widgetCategory="home_screen"
|
||||||
|
android:updatePeriodMillis="0"
|
||||||
|
android:description="@string/widget_day_description"
|
||||||
|
android:previewLayout="@layout/widget_day_preview" />
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:initialLayout="@layout/widget_placeholder"
|
||||||
|
android:minWidth="320dp"
|
||||||
|
android:minHeight="240dp"
|
||||||
|
android:targetCellWidth="5"
|
||||||
|
android:targetCellHeight="5"
|
||||||
|
android:resizeMode="horizontal|vertical"
|
||||||
|
android:widgetCategory="home_screen"
|
||||||
|
android:updatePeriodMillis="0"
|
||||||
|
android:description="@string/widget_week_description"
|
||||||
|
android:previewLayout="@layout/widget_week_preview" />
|
||||||
@@ -5,14 +5,57 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.buildDir = '../build'
|
rootProject.layout.buildDirectory = file('../build')
|
||||||
subprojects {
|
subprojects {
|
||||||
project.buildDir = "${rootProject.buildDir}/${project.name}"
|
project.layout.buildDirectory = rootProject.layout.buildDirectory.dir(project.name)
|
||||||
}
|
}
|
||||||
|
// AGP 9 enables built-in Kotlin, but Flutter's migrator pins
|
||||||
|
// android.builtInKotlin=false while the plugin ecosystem catches up. Most
|
||||||
|
// plugins honour that flag and fall back to KGP themselves; file_picker and
|
||||||
|
// background_downloader only check the AGP major version and silently skip
|
||||||
|
// applying KGP, which leaves their Kotlin sources uncompiled (missing
|
||||||
|
// FilePickerPlugin/BackgroundDownloaderPlugin at link time). Apply KGP for
|
||||||
|
// them as soon as AGP is on the project, i.e. before their android {} block
|
||||||
|
// runs. Drop this once both plugins ship a builtInKotlin-aware build script.
|
||||||
|
gradle.beforeProject { sub ->
|
||||||
|
if (!(sub.name in ['file_picker', 'background_downloader'])) return
|
||||||
|
sub.plugins.withId('com.android.library') {
|
||||||
|
sub.pluginManager.apply('org.jetbrains.kotlin.android')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pin every Android subproject to JVM 17 so plugins that ship Kotlin sources
|
||||||
|
// compiled with a higher target (e.g. receive_sharing_intent at 21) or stale
|
||||||
|
// Java compatibility (e.g. home_widget at 1.8) don't break the build under
|
||||||
|
// newer Gradle/Kotlin tooling. Registered before evaluationDependsOn so the
|
||||||
|
// afterEvaluate fires at the right point in the lifecycle.
|
||||||
|
subprojects { sub ->
|
||||||
|
sub.afterEvaluate {
|
||||||
|
if (sub.hasProperty('android')) {
|
||||||
|
sub.android {
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_17
|
||||||
|
targetCompatibility = JavaVersion.VERSION_17
|
||||||
|
}
|
||||||
|
// Some plugins (e.g. app_settings) hard-pin an older compileSdk
|
||||||
|
// than their transitive AndroidX deps require, which fails the
|
||||||
|
// AAR metadata check. Align every plugin with the app's
|
||||||
|
// compileSdk (flutter.compileSdkVersion) so the build passes.
|
||||||
|
compileSdkVersion 36
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sub.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = '17'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
project.evaluationDependsOn(':app')
|
project.evaluationDependsOn(':app')
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register("clean", Delete) {
|
tasks.register("clean", Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.layout.buildDirectory
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package_name("eu.mhsl.marianum.mobile.client")
|
||||||
|
|
||||||
|
# Service-Account-JSON für die Google Play Developer API. Pfad über die
|
||||||
|
# Umgebungsvariable SUPPLY_JSON_KEY setzen (die Datei selbst wird per
|
||||||
|
# .gitignore nicht eingecheckt).
|
||||||
|
json_key_file(ENV["SUPPLY_JSON_KEY"] || "fastlane/play-service-account.json")
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
default_platform(:android)
|
||||||
|
|
||||||
|
# Play-Store-Auslieferung über fastlane supply. Die Screenshots erzeugt
|
||||||
|
# ../tool/screenshots.sh (Demo-Login + integration_test) direkt in
|
||||||
|
# metadata/android/<locale>/images/. Texte/Changelogs liegen daneben in
|
||||||
|
# metadata/android/<locale>/.
|
||||||
|
platform :android do
|
||||||
|
desc "Nur Screenshots hochladen (verändert keine Texte/Binaries)"
|
||||||
|
lane :upload_screenshots do
|
||||||
|
upload_to_play_store(
|
||||||
|
skip_upload_apk: true,
|
||||||
|
skip_upload_aab: true,
|
||||||
|
skip_upload_metadata: true,
|
||||||
|
skip_upload_changelogs: true,
|
||||||
|
skip_upload_images: false,
|
||||||
|
skip_upload_screenshots: false,
|
||||||
|
metadata_path: "./fastlane/metadata/android",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
desc "Store-Texte, Changelogs und Screenshots hochladen (keine Binaries)"
|
||||||
|
lane :upload_metadata do
|
||||||
|
upload_to_play_store(
|
||||||
|
skip_upload_apk: true,
|
||||||
|
skip_upload_aab: true,
|
||||||
|
metadata_path: "./fastlane/metadata/android",
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# fastlane-Plugins (aktuell keine). Datei vorhanden, damit `fastlane` das
|
||||||
|
# Plugin-Handling initialisiert.
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# Fastlane – Play-Store-Screenshots & Upload
|
||||||
|
|
||||||
|
Schritt 2 der Play-Store-Automatisierung. Die App muss dafür **nicht** neu
|
||||||
|
gebaut werden – der Demo-Modus (`demo@`-Login) liefert die kompletten Inhalte
|
||||||
|
aus Fixtures.
|
||||||
|
|
||||||
|
## 1. Screenshots aufnehmen
|
||||||
|
|
||||||
|
Ein Gerät/Emulator (≥ Android 8) per `adb devices` sichtbar, dann aus dem
|
||||||
|
**Client**-Wurzelverzeichnis:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tool/screenshots.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Fährt Phone (1080×1920), 7″ (1200×1920) und 10″ (1600×2560) nacheinander durch
|
||||||
|
(setzt die Displaygröße per `adb shell wm size/density`) und legt die PNGs in
|
||||||
|
`metadata/android/de-DE/images/{phone,sevenInch,tenInch}Screenshots/` ab.
|
||||||
|
|
||||||
|
- Nur eine Größe: `PROFILES="phone" tool/screenshots.sh`
|
||||||
|
- Profile-Build (flüssigere Frames): `BUILD_MODE=profile tool/screenshots.sh`
|
||||||
|
|
||||||
|
## 2. Hochladen
|
||||||
|
|
||||||
|
Service-Account-JSON der Google Play Developer API besorgen und referenzieren:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export SUPPLY_JSON_KEY=/pfad/zu/play-service-account.json
|
||||||
|
cd android
|
||||||
|
fastlane upload_screenshots # nur Bilder
|
||||||
|
# oder
|
||||||
|
fastlane upload_metadata # Bilder + Texte/Changelogs, keine Binaries
|
||||||
|
```
|
||||||
|
|
||||||
|
Der Service-Account-Key wird **nicht** eingecheckt (siehe `.gitignore`).
|
||||||
@@ -1,3 +1,6 @@
|
|||||||
org.gradle.jvmargs=-Xmx4G
|
org.gradle.jvmargs=-Xmx4G
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
android.enableJetifier=true
|
# This newDsl flag was added automatically by Flutter migrator
|
||||||
|
android.newDsl=false
|
||||||
|
# This builtInKotlin flag was added automatically by Flutter migrator
|
||||||
|
android.builtInKotlin=false
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
#This file is generated by updateDaemonJvm
|
||||||
|
toolchainVersion=21
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.3.1-all.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
id "dev.flutter.flutter-plugin-loader" version "1.0.0"
|
||||||
id "com.android.application" version "7.3.0" apply false
|
id "com.android.application" version '9.1.0' apply false
|
||||||
id "org.jetbrains.kotlin.android" version "1.8.10" apply false
|
id "com.android.library" version '9.1.0' apply false
|
||||||
|
id "org.jetbrains.kotlin.android" version "2.4.0" apply false
|
||||||
|
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
include ":app"
|
include ":app"
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 68 KiB After Width: | Height: | Size: 12 KiB |
@@ -0,0 +1,29 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFBTCCAu2gAwIBAgIQWgDyEtjUtIDzkkFX6imDBTANBgkqhkiG9w0BAQsFADBP
|
||||||
|
MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy
|
||||||
|
Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa
|
||||||
|
Fw0yNzAzMTIyMzU5NTlaMDMxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF
|
||||||
|
bmNyeXB0MQwwCgYDVQQDEwNSMTMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||||
|
AoIBAQClZ3CN0FaBZBUXYc25BtStGZCMJlA3mBZjklTb2cyEBZPs0+wIG6BgUUNI
|
||||||
|
fSvHSJaetC3ancgnO1ehn6vw1g7UDjDKb5ux0daknTI+WE41b0VYaHEX/D7YXYKg
|
||||||
|
L7JRbLAaXbhZzjVlyIuhrxA3/+OcXcJJFzT/jCuLjfC8cSyTDB0FxLrHzarJXnzR
|
||||||
|
yQH3nAP2/Apd9Np75tt2QnDr9E0i2gB3b9bJXxf92nUupVcM9upctuBzpWjPoXTi
|
||||||
|
dYJ+EJ/B9aLrAek4sQpEzNPCifVJNYIKNLMc6YjCR06CDgo28EdPivEpBHXazeGa
|
||||||
|
XP9enZiVuppD0EqiFwUBBDDTMrOPAgMBAAGjgfgwgfUwDgYDVR0PAQH/BAQDAgGG
|
||||||
|
MB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATASBgNVHRMBAf8ECDAGAQH/
|
||||||
|
AgEAMB0GA1UdDgQWBBTnq58PLDOgU9NeT3jIsoQOO9aSMzAfBgNVHSMEGDAWgBR5
|
||||||
|
tFnme7bl5AFzgAiIyBpY9umbbjAyBggrBgEFBQcBAQQmMCQwIgYIKwYBBQUHMAKG
|
||||||
|
Fmh0dHA6Ly94MS5pLmxlbmNyLm9yZy8wEwYDVR0gBAwwCjAIBgZngQwBAgEwJwYD
|
||||||
|
VR0fBCAwHjAcoBqgGIYWaHR0cDovL3gxLmMubGVuY3Iub3JnLzANBgkqhkiG9w0B
|
||||||
|
AQsFAAOCAgEAUTdYUqEimzW7TbrOypLqCfL7VOwYf/Q79OH5cHLCZeggfQhDconl
|
||||||
|
k7Kgh8b0vi+/XuWu7CN8n/UPeg1vo3G+taXirrytthQinAHGwc/UdbOygJa9zuBc
|
||||||
|
VyqoH3CXTXDInT+8a+c3aEVMJ2St+pSn4ed+WkDp8ijsijvEyFwE47hulW0Ltzjg
|
||||||
|
9fOV5Pmrg/zxWbRuL+k0DBDHEJennCsAen7c35Pmx7jpmJ/HtgRhcnz0yjSBvyIw
|
||||||
|
6L1QIupkCv2SBODT/xDD3gfQQyKv6roV4G2EhfEyAsWpmojxjCUCGiyg97FvDtm/
|
||||||
|
NK2LSc9lybKxB73I2+P2G3CaWpvvpAiHCVu30jW8GCxKdfhsXtnIy2imskQqVZ2m
|
||||||
|
0Pmxobb28Tucr7xBK7CtwvPrb79os7u2XP3O5f9b/H66GNyRrglRXlrYjI1oGYL/
|
||||||
|
f4I1n/Sgusda6WvA6C190kxjU15Y12mHU4+BxyR9cx2hhGS9fAjMZKJss28qxvz6
|
||||||
|
Axu4CaDmRNZpK/pQrXF17yXCXkmEWgvSOEZy6Z9pcbLIVEGckV/iVeq0AOo2pkg9
|
||||||
|
p4QRIy0tK2diRENLSF2KysFwbY6B26BFeFs3v1sYVRhFW9nLkOrQVporCS0KyZmf
|
||||||
|
wVD89qSTlnctLcZnIavjKsKUu1nA1iU0yYMdYepKR7lWbnwhdx3ewok=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="69.999985mm"
|
||||||
|
height="82.227501mm"
|
||||||
|
viewBox="0 0 69.999985 82.227501"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="g1"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458334,120.1078,-90.601937)"><g
|
||||||
|
id="group-R5"
|
||||||
|
transform="translate(-749.41293,290.52252)"><path
|
||||||
|
id="path2"
|
||||||
|
d="m 418.75901,57.817748 c -2.19013,14.15999 -3.96053,26.66133 -5.83906,39.13333 11.5776,2.532 18.4688,3.680002 29.7848,5.841332 8.50666,1.62133 23.36533,2.71733 23.952,11.096 0.86133,12.35866 -16.62534,7.388 -25.11734,5.84133 -11.244,-2.04667 -21.21693,-3.844 -30.9596,-5.84133 -1.82346,8.09866 -3.57813,15.82533 -5.25733,23.948 -4.90253,23.77866 -9.824,49.08933 -14.01666,73.59866 2.4136,-3.42133 4.11413,-5.69733 5.84226,-8.76267 8.89267,-15.76799 18.71867,-32.67066 30.37027,-47.31066 4.46106,-5.60667 10.24506,-12.64133 15.77306,-15.188 13.12267,-6.048 22.224,2.96133 22.78,15.77067 0.49334,11.372 -3.07733,24.15733 -4.676,36.80133 -1.65333,13.08933 -3.05066,25.98933 -4.66933,36.796 9.65733,-13.69067 19.72267,-35.95334 32.12533,-50.81733 3.668,-4.4 9.80667,-10.748 15.76934,-11.68134 29.16799,-4.57866 16.87733,41.62267 16.94133,63.084 0.0547,19.32001 5.86667,34.04934 23.36133,36.21068 5.73333,0.70933 14.10933,-1.48667 15.02533,3.51466 1.15467,6.31467 -10.42133,8.068 -16.77866,8.168 -38.84667,0.60267 -42.94133,-34.97734 -41.46933,-76.51601 -2.64534,2.476 -4.76134,6.336 -7.00934,9.93067 -13.00933,20.78267 -27.192,43.62801 -39.72133,67.17068 -3.45467,6.504 -7.15867,15.29333 -18.10667,11.09733 -2.30133,-0.88267 -6.43466,-5.92 -7.008,-7.59467 -2.60786,-7.62666 0.20667,-18.32533 1.168,-27.45333 2.87334,-27.16134 7.70934,-51.87868 10.516,-78.26534 -3.50533,-0.0707 -5.85733,4.008 -7.59333,6.42667 -6.2548,8.70266 -11.47147,18.76666 -16.94133,28.61866 -7.04214,12.684 -14.42814,25.71067 -21.02867,39.13201 -10.03173,20.41333 -25.14373,66.92133 -32.28013,90.50933 -1.15573,3.82133 -2.35933,7.744 -3.5052,11.68667 -0.998,3.428 -1.38693,7.69066 -4.67347,9.928 -13.33853,-2.52534 -11.962,-13.98534 -9.3464,-27.45467 6.31414,-32.45733 22.78547,-94.19334 28.19587,-126.13867 -9.72813,9.464 -20.53067,27.65466 -38.552,31.54133 -18.1928,3.92667 -29.05788,-6.35733 -36.2136,-16.35333 -2.28489,-3.19467 -5.52188,-6.60534 -3.50417,-10.51467 11.19375,-4.73333 15.11457,8.69467 26.28537,9.93067 3.0204,0.33199 7.2756,-0.32001 9.93027,-1.17067 17.65253,-5.64667 31.67346,-29.168 39.71506,-46.14133 9.88747,-20.86267 16.70987,-44.06667 19.86094,-65.42133 -8.76254,-1.51867 -19.064,-2.95467 -29.2344,-4.86933 -14.64054,-2.76134 -21.17334,-1.432 -26.83947,-7.980002 1.2228,-5.592 5.5228,-8.108 9.34627,-11.09867 16.83653,2.24533 33.6584,4.504 49.64946,7.59333 2.72454,-11.9 6.92973,-29.13199 9.92813,-41.47199 5.40267,-3.468 11.84947,1.12533 14.0204,4.676"
|
||||||
|
style="fill:#941a1f;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.133333" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 3.0 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="70.000168mm"
|
||||||
|
height="82.227348mm"
|
||||||
|
viewBox="0 0 70.000168 82.227348"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
xml:space="preserve"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||||
|
id="defs1" /><g
|
||||||
|
id="g1"
|
||||||
|
transform="matrix(0.26458333,0,0,0.26458334,107.44411,-80.482198)"><g
|
||||||
|
id="group-R5"
|
||||||
|
transform="translate(-749.41293,290.52252)"><path
|
||||||
|
id="path3"
|
||||||
|
d="m 3499.67,4594.33 c -16.43,-106.19 -29.71,-199.97 -43.79,-293.49 86.83,-19 138.5,-27.61 223.38,-43.82 63.81,-12.18 175.24,-20.4 179.64,-83.23 6.46,-92.69 -124.69,-55.41 -188.38,-43.81 -84.33,15.36 -159.13,28.84 -232.2,43.81 -13.68,-60.72 -26.83,-118.68 -39.43,-179.61 -36.76,-178.32 -73.67,-368.16 -105.11,-551.97 18.09,25.66 30.84,42.72 43.8,65.7 66.7,118.26 140.39,245.04 227.76,354.83 33.49,42.05 76.86,94.81 118.31,113.91 98.42,45.36 166.68,-22.2 170.87,-118.28 3.68,-85.28 -23.09,-181.17 -35.08,-275.99 -12.4,-98.19 -22.89,-194.93 -35.03,-275.98 72.44,102.69 147.93,269.64 240.95,381.12 27.51,33 73.55,80.61 118.27,87.62 218.76,34.33 126.58,-312.17 127.05,-473.13 0.4,-144.9 44.01,-255.37 175.21,-271.59 43.02,-5.31 105.84,11.16 112.7,-26.34 8.67,-47.38 -78.15,-60.52 -125.84,-61.28 -291.34,-4.51 -322.06,262.33 -311.01,573.88 -19.85,-18.57 -35.71,-47.53 -52.57,-74.47 -97.59,-155.88 -203.95,-327.22 -297.92,-503.79 -25.93,-48.79 -53.68,-114.7 -135.8,-83.23 -17.27,6.63 -48.25,44.39 -52.56,56.96 -19.58,57.19 1.55,137.42 8.76,205.89 21.54,203.72 57.81,389.09 78.87,587.01 -26.3,0.51 -43.93,-30.07 -56.96,-48.2 -46.9,-65.27 -86.02,-140.76 -127.04,-214.64 -52.84,-95.15 -108.23,-192.84 -157.71,-293.52 -75.25,-153.09 -188.6,-501.89 -242.12,-678.81 -8.67,-28.67 -17.7,-58.08 -26.3,-87.64 -7.48,-25.72 -10.39,-57.68 -35.05,-74.46 -100.02,18.93 -89.71,104.89 -70.09,205.9 47.35,243.43 170.89,706.45 211.48,946.04 -72.97,-70.97 -153.99,-207.41 -289.14,-236.55 -136.47,-29.44 -217.95,47.68 -271.6,122.66 -17.14,23.96 -41.43,49.54 -26.29,78.84 83.96,35.51 113.37,-65.2 197.15,-74.47 22.65,-2.5 54.56,2.4 74.46,8.78 132.4,42.34 237.57,218.76 297.87,346.07 74.16,156.45 125.32,330.5 148.95,490.64 -65.71,11.4 -142.96,22.15 -219.25,36.52 -109.8,20.72 -158.81,10.75 -201.29,59.86 9.15,41.95 41.41,60.8 70.1,83.24 126.26,-16.84 252.45,-33.77 372.36,-56.97 20.43,89.25 51.98,218.51 74.45,311.05 40.53,26.02 88.88,-8.43 105.17,-35.06"
|
||||||
|
style="fill:#d3d2d2;fill-opacity:1;fill-rule:evenodd;stroke:none"
|
||||||
|
transform="matrix(0.13333333,0,0,-0.13333333,0,632.14667)" /></g></g></svg>
|
||||||
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 108 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 58 KiB |