87 Commits

Author SHA1 Message Date
Marianum d8a5ccfe80 iOS widget enhancements 2026-05-12 16:46:56 +02:00
Marianum 1ae3f7bb83 finalized iOS setup 2026-05-12 15:47:32 +02:00
MineTec 8c76f2d816 removed now indicator from android and ios widgets 2026-05-11 13:55:16 +02:00
MineTec c46f14f6a6 updated kotlin gradle plugin version to 2.2.20 2026-05-10 20:27:50 +02:00
MineTec b2b00d321e Merge pull request 'implemented chat long-polling and optimistic updates, centralized notification management, optimized avatar caching, cleanup and bugfixes' (#99) from develop-notifications into develop
Reviewed-on: #99
2026-05-10 15:02:12 +00:00
MineTec 1a11b9ac60 refactored internal documentation and simplified comments across chat BLoCs, file viewer, and navigation components 2026-05-10 17:01:50 +02:00
MineTec a0bc46f522 optimized avatar and linkify performance, refined navigation to preserve popups, implemented read marker caching, and added file size limits for saving, minor timetable details changes 2026-05-10 16:40:39 +02:00
MineTec 1458d8ce49 implemented chat long-polling and optimistic updates, centralized notification management, optimized avatar caching 2026-05-10 15:47:55 +02:00
MineTec 6ae396e605 Merge pull request 'general search, talk enhancements, overhauled fileviewer' (#98) from develop-search into develop
Reviewed-on: #98
2026-05-09 22:55:11 +00:00
MineTec ed2badfd35 fixed chat bubble link styling and gesture handling, and added android package visibility for common schemes 2026-05-10 00:54:13 +02:00
MineTec 1ff57b29f9 overhauled file viewer with video, audio, text, and SVG support, added media player and line-numbered text views, and fixed search controller recursion 2026-05-10 00:33:09 +02:00
MineTec c50a850ac9 reordered files app bar actions by moving search icon 2026-05-09 23:43:29 +02:00
MineTec 15833f3685 implemented disposal guard in files search controller to safely handle async listener notifications 2026-05-09 23:40:04 +02:00
MineTec bf28a678c9 implemented background prefetching for files root, added 24-hour caching for root directory listing, and enabled cache renewal for manual refreshes 2026-05-09 23:39:06 +02:00
MineTec 14090b96f4 implemented file search with local cache and server-side support, added result highlighting, and integrated search delegate into files page 2026-05-09 23:20:11 +02:00
MineTec 8e6b1877cc implemented search for marianum messages with name and date filtering 2026-05-09 22:35:20 +02:00
MineTec 9accb488f2 added delete confirmation dialog for chat messages and refined deletion logic flow 2026-05-09 22:32:45 +02:00
MineTec 79a6d9a594 filtered deleted messages from search and chat view, refactored chat bubble styling for deleted comments, and updated tests 2026-05-09 22:28:26 +02:00
MineTec 7d02e70459 implemented short relative date formatting for chat and added unit tests 2026-05-09 22:23:25 +02:00
MineTec 4c190de479 implemented in-chat search with text highlighting, added search navigation UI, and integrated scrollable list for message jumping 2026-05-09 22:21:36 +02:00
MineTec b36d1e02f5 Merge pull request 'added native features like homescreen-widgets and share intents' (#97) from develop-native into develop
Reviewed-on: #97
2026-05-09 19:35:32 +00:00
MineTec 53b290ab49 ensured timetable visibility on widget navigation by resetting root navigator 2026-05-09 21:31:39 +02:00
MineTec b422430994 implemented message forwarding and direct chat creation from group members, and added specialized share picker for forwarded content 2026-05-09 20:39:19 +02:00
MineTec 151678f0fe implemented internal file sharing and saving, added server-side file references, refactored share pickers for unified flows, and updated UI branding labels 2026-05-09 20:18:52 +02:00
MineTec cb2c38aaa1 implemented native share intent support for android and ios with chat and folder pickers 2026-05-09 19:42:51 +02:00
MineTec 00664c66a8 added base homescreen-widget setup, working on Android, iOS in progress 2026-05-09 18:01:05 +02:00
MineTec 0ff5eb7bc9 Merge pull request 'claude refactor' (#95) from develop-refactor into develop
Reviewed-on: #95
2026-05-08 19:49:43 +00:00
MineTec 3b8da1d3d6 dart format 2026-05-08 20:12:40 +02:00
MineTec 9e139b5704 refactored data providers with centralized cache resolution, unified UI using custom dialogs and bottom sheets, and enhanced network error handling for Dio and TLS errors 2026-05-08 20:01:45 +02:00
MineTec c62a14645a refactored broad range of the application, split files, modularized calendar and file views, centralized bottom sheets and clipboard handling, and implemented unit test coverage 2026-05-08 19:05:16 +02:00
MineTec 3b1b0d0c19 fixed lesson merging mutation, improved overlap detection, and implemented priority-based lane assignment with tablet support 2026-05-07 13:27:40 +02:00
MineTec c32e64fe74 improved yOfDateTime precision and period-based calculation in workweek calendar 2026-05-07 09:51:13 +02:00
MineTec 710e88d744 refactored chat data fetching to support separate cache and network callbacks 2026-05-07 09:46:30 +02:00
MineTec 517e515ac1 centered login view and updated layout constraints 2026-05-07 09:11:09 +02:00
MineTec e8f0c4383c added camera support and enabled gallery selection on ios 2026-05-06 23:09:44 +02:00
MineTec b8cac73e74 updated timetable UI with event status and enhanced appointment tile rendering 2026-05-06 22:53:24 +02:00
MineTec 95ef29fb09 implemented dynamic module settings and configurable bottom bar, added all-day event support to timetable, and overhauled marianum dates UI with month grouping and search 2026-05-06 22:37:41 +02:00
MineTec 86d12884fc custom login implementation, period-based timetable layout with overlap handling, enhanced error dialogs, and unified bottom sheets 2026-05-06 20:42:09 +02:00
MineTec 50d2941e52 refactored lesson details, centralized logout logic, and added resume re-fetch 2026-05-06 16:27:45 +02:00
MineTec 71506aab2d Merge remote-tracking branch 'origin/develop-refactor' into develop-refactor 2026-05-06 11:59:17 +02:00
MineTec 4e1272aba9 claude refactorings, flutter best practices, platform dependent changes, general cleanup 2026-05-06 11:59:01 +02:00
MineTec 72ebe6f7e7 claude refactorings, flutter best practices, platform dependent changes, general cleanup 2026-05-06 11:58:50 +02:00
MineTec 4b1d4379a0 loading state and error handling refactor 2026-05-06 10:11:45 +02:00
MineTec 2c376afd91 removed stray character in settings.gradle 2026-05-05 22:38:07 +02:00
MineTec 54ba04a7bd wait for account data population and set initial AccountBloc status 2026-05-05 22:08:10 +02:00
MineTec 9b5a70b285 api and storage restructure 2026-05-05 22:00:07 +02:00
MineTec 4f796dac2e folder restructuring 2026-05-05 21:44:23 +02:00
MineTec db9c3386f1 better loading indicators for timetables, talk and files 2026-05-05 21:07:48 +02:00
MineTec bee5c02a4f marianum appointments 2026-05-05 16:05:07 +02:00
MineTec e8faa77e70 refactored timetable 2026-05-05 13:49:45 +02:00
MineTec 551c1bf1fa claude refactor 2026-05-04 13:54:39 +02:00
MineTec 9973f12733 Merge pull request 'added opacity to past custom events' (#94) from develop-customEventOpacity into develop
Reviewed-on: #94
2026-05-04 10:20:05 +00:00
MineTec 278fed52f1 fixed indention 2026-05-04 12:19:43 +02:00
Pupsi f89ac87c51 added opacity to past custom events 2026-05-04 09:45:24 +02:00
MineTec 0b8380eff0 removed toolchain vendor restriction 2026-05-04 09:04:54 +02:00
Pupsi 4ef3a167ea fixed dart errors in notificationService 2026-05-04 08:51:16 +02:00
MineTec c26cefc073 moved native splash dependency to runtime dependencies 2026-04-04 00:38:25 +02:00
MineTec e78ef0df49 toolchain migration, agp upgrade, flutter upgrade, dependency upgrades 2026-04-04 00:30:24 +02:00
MineTec 0b6c80e84c fixed hanging chat when it contains any 'call' 2026-04-04 00:11:44 +02:00
Pupsi a52817231e fixed list view breaking layout 2026-02-01 17:16:42 +01:00
Pupsi f6933b6529 Merge pull request 'develop-polls' (#93) from develop-polls into develop
Reviewed-on: #93
Reviewed-by: Elias Müller <elias@elias-mueller.com>
2026-02-01 14:56:23 +00:00
Pupsi e4243e53ac resolved pr issues 2026-02-01 15:55:43 +01:00
Pupsi 0aead45191 Merge remote-tracking branch 'origin/develop' into develop-polls
# Conflicts:
#	devtools_options.yaml
2026-02-01 15:37:26 +01:00
Pupsi dacefd321b updated poll list design 2026-02-01 15:35:40 +01:00
Pupsi 92a9a7358e changed link to directly open the chat 2026-02-01 15:20:01 +01:00
Pupsi 174e6ac0b7 fixed finished polls causing errors, made poll list dense 2026-02-01 15:07:48 +01:00
MineTec c9eaed782a update grade averages UI and enable devtools extensions 2026-02-01 15:06:49 +01:00
Pupsi 567184bcf9 filtered system messages for poll votes 2026-02-01 13:56:39 +01:00
Pupsi 541d6ef164 fixed issues with null values in votes map 2026-02-01 13:32:18 +01:00
Pupsi 3469d02033 changed poll dialog to only show results 2026-02-01 03:23:36 +01:00
Pupsi 699aec8ab5 Merge branch 'develop' into develop-polls 2026-02-01 00:06:51 +01:00
Pupsi 7a3a022ecd Merge remote-tracking branch 'origin/develop' into develop 2026-01-31 23:41:05 +01:00
Pupsi 9d8a99df7c added screen_brightness 2026-01-31 23:33:31 +01:00
Pupsi a47e52e8e7 added screen_brightness 2026-01-31 23:31:53 +01:00
MineTec a1fd21de04 Merge pull request 'develop-fileDownload' (#92) from develop-fileDownload into develop
Reviewed-on: #92
Reviewed-by: Elias Müller <elias@elias-mueller.com>
2026-01-31 22:15:50 +00:00
Pupsi b3d8586c04 Merge remote-tracking branch 'origin/develop' into develop-fileDownload
# Conflicts:
#	pubspec.yaml
2026-01-31 22:59:46 +01:00
Pupsi 0409c5463f combined actions to popup menu 2026-01-31 22:55:49 +01:00
MineTec 7a3b69fade update dependencies and bump version to 0.1.7+45
- Bump version to `0.1.7+45` and update SDK constraint to `>=3.8.0 <4.0.0`.
- Update numerous dependencies
2026-01-31 22:40:50 +01:00
Pupsi df275c0108 added file saver 2026-01-31 22:17:31 +01:00
MineTec 0525453d48 migrate launcher icons configuration to standalone file 2026-01-31 21:09:56 +01:00
MineTec 4e8b2f34f9 bumped version 2026-01-26 17:13:58 +01:00
MineTec bc6a069c90 fixed voice-message preventing chat loading 2026-01-26 16:44:39 +01:00
MineTec bfa0b0f5c0 feat: add devtools extensions and fix poll dialog UI/UX
- Enabled `provider` and `shared_preferences` extensions in `devtools_options.yaml`.
- Added logging for message object data on chat bubble tap.
- Fixed layout issues in poll dialog by wrapping `LoadingSpinner` in a `Column` and changing `ListView` to a `Column` in `pollOptionsList.dart`.
- Updated poll submission button to wait for the poll state to load before allowing interaction.
2026-01-18 10:28:17 +01:00
MineTec 274b77f705 Merge branch 'develop' into develop-polls 2026-01-17 23:22:52 +01:00
Marianum c7ea80bea9 updated xCode settings 2025-12-10 14:37:36 +01:00
Pupsi b68bec9ebd WIP: add option to vote on polls 2025-10-10 11:39:57 +02:00
Pupsi 81f65750b7 added functionality to show own votes in polls 2025-10-10 02:01:43 +02:00
691 changed files with 36351 additions and 12889 deletions
+77
View File
@@ -0,0 +1,77 @@
# MarianumMobile Client
Flutter-App für die Schul-Community: Webuntis-Stundenplan, Nextcloud Talk + Files, Custom MHSL-Backend (Breaker, Custom Events, Push).
## 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 (mhsl/, marianumcloud/, webuntis/, holidays/)
├── 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.
## 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 |
|---------------------------|-----------------------|----------------------------------------|
| Webuntis | `lib/api/webuntis/` | Stundenplan, Klassen, Räume, Lehrer |
| Nextcloud (Talk + WebDAV) | `lib/api/marianumcloud/` | Chats, Datei-Verwaltung |
| Custom MHSL-Server | `lib/api/mhsl/` | Breaker, Custom Events, Notify, Noten |
| Holiday-Calendar | `lib/api/holidays/` | Ferien |
`nextcloud`-Paket ist auf einen Custom-Fork gepinnt (siehe `pubspec.yaml` `dependency_overrides`).
## Tests
`test/` deckt aktuell nur Kern-Funktionen ab (DateTime-Extensions, AsyncActionController, LessonResolver). Beim Hinzufügen neuer pure-function-Helper bitte Test mit dazu.
+73 -29
View File
@@ -1,44 +1,88 @@
# 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/**"
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
+1 -4
View File
@@ -25,7 +25,7 @@ if (flutterVersionName == null) {
android { android {
namespace "eu.mhsl.marianum.mobile.client" namespace "eu.mhsl.marianum.mobile.client"
compileSdk flutter.compileSdkVersion compileSdk flutter.compileSdkVersion
ndkVersion "27.0.12077973" ndkVersion "28.2.13676358"
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_17
@@ -57,9 +57,6 @@ android {
signingConfig signingConfigs.debug signingConfig signingConfigs.debug
} }
} }
buildFeatures {
viewBinding true
}
} }
flutter { flutter {
+90 -54
View File
@@ -1,73 +1,109 @@
<?xml version="1.0" encoding="utf-8"?> <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"
>
<!--
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.
-->
<queries>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT" />
<data android:mimeType="text/plain" />
</intent>
</queries>
<uses-permission android:name="android.permission.INTERNET" />
<application <application
tools:replace="android:label" android:label="Marianum Fulda"
android:name="${applicationName}" android:name="${applicationName}"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="Marianum Fulda"> android:fullBackupContent="@xml/backup_rules"
<receiver android:dataExtractionRules="@xml/data_extraction_rules">
android:name=".TimetableWidget"
android:exported="false">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/timetable_widget_info" />
</receiver>
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:exported="true" android:exported="true"
android:hardwareAccelerated="true"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/LaunchTheme" android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
<!--
Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. to determine the Window background behind the Flutter UI. -->
-->
<meta-data <meta-data
android:name="io.flutter.embedding.android.NormalTheme" android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme" /> android:resource="@style/NormalTheme"
/>
<intent-filter> <intent-filter>
<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>
<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> </intent-filter>
</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" />
<!-- 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: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: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> </application>
</manifest> <!-- 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>
<intent>
<action android:name="android.intent.action.PROCESS_TEXT"/>
<data android:mimeType="text/plain"/>
</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>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- 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"/>
</manifest>
@@ -1,39 +0,0 @@
package eu.mhsl.marianum.mobile.client
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.widget.RemoteViews
import es.antonborri.home_widget.HomeWidgetPlugin
import android.util.Base64
/**
* Implementation of App Widget functionality.
*/
class TimetableWidget : AppWidgetProvider() {
override fun onUpdate(
context: Context,
appWidgetManager: AppWidgetManager,
appWidgetIds: IntArray,
) {
for (appWidgetId in appWidgetIds) {
val widgetData = HomeWidgetPlugin.getData(context)
val views = RemoteViews(context.packageName, R.layout.timetable_widget).apply {
val imageBase64 = widgetData.getString("screen", null) ?: return@apply
val imageBytes = Base64.decode(imageBase64, Base64.DEFAULT);
val imageBitmap: Bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
setImageViewBitmap(R.id.widget_image, imageBitmap)
}
val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)
val pendingIntent = PendingIntent.getActivity(context, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE)
views.setOnClickPendingIntent(R.id.background, pendingIntent)
appWidgetManager.updateAppWidget(appWidgetId, views)
}
}
}
@@ -1,5 +1,42 @@
package eu.mhsl.marianum.mobile.client package eu.mhsl.marianum.mobile.client
import android.content.Intent
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"
/// 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
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()
}
}
consumeIntentData(intent)
}
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
consumeIntentData(intent)
}
private fun consumeIntentData(intent: Intent?) {
if (intent?.getBooleanExtra("widget_open_timetable", false) == true) {
pendingTimetableTap = true
}
}
}
@@ -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.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 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,31 @@
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.WidgetRenderer
class TimetableWeekWidget : AppWidgetProvider() {
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,157 @@
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;
companion object {
fun fromWire(raw: String?): WidgetLessonStatus = when (raw) {
"regular" -> REGULAR
"ongoing" -> ONGOING
"past" -> PAST
"cancelled" -> CANCELLED
"irregular" -> IRREGULAR
"teacherChanged" -> TEACHER_CHANGED
"event" -> EVENT
else -> REGULAR
}
}
}
data class WidgetLesson(
val start: Date,
val end: Date,
val subjectShort: String,
val subjectLong: String?,
val room: String?,
val teacher: String?,
val originalTeacher: String?,
val status: WidgetLessonStatus,
val customColor: String?,
val siblingCount: Int,
)
data class WidgetPeriod(
val name: String,
val startMinutes: Int,
val endMinutes: Int,
val virtualStartMinutes: Int,
val virtualEndMinutes: Int,
)
data class WidgetTimetableData(
val fetchedAt: Date,
val anchorDate: Date,
val lessons: List<WidgetLesson>,
val periods: List<WidgetPeriod>,
val isHoliday: Boolean,
val holidayName: String?,
)
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
}
}
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"),
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),
)
}
}
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"),
)
} 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,740 @@
package eu.mhsl.marianum.mobile.client.widgets
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.Configuration
import android.os.Bundle
import android.util.TypedValue
import android.view.View
import android.widget.RemoteViews
import eu.mhsl.marianum.mobile.client.MainActivity
import eu.mhsl.marianum.mobile.client.R
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
import kotlin.math.max
/**
* Renders the day and week widgets as a time-grid: lesson blocks absolutely
* positioned on a vertical axis, mirroring the in-app Syncfusion calendar.
* Per-hour dp is computed from the widget bundle so the grid scales with
* resize, clamped to [MIN_HOUR_HEIGHT_DP, MAX_HOUR_HEIGHT_DP].
*/
object WidgetRenderer {
private const val FALLBACK_VIRTUAL_MINUTES = 11 * 60
private const val DAY_CHROME_DP = 40
private const val WEEK_CHROME_DP = 64
private const val MIN_HOUR_HEIGHT_DP = 18
private const val MAX_HOUR_HEIGHT_DP = 72
private const val MIN_BLOCK_HEIGHT_DP = 16
private const val LESSON_GAP_DP = 1.5f
// Below SHOW_ROOM_MIN: subject only. Below SHOW_TEACHER_SEPARATE_MIN:
// subject + room. Above: subject + room + teacher stacked.
private const val BLOCK_SHOW_ROOM_MIN_DP = 18
private const val BLOCK_SHOW_TEACHER_SEPARATE_MIN_DP = 30
/// Below this column width autoSize can't fit subject + room — drop
/// room/teacher entirely on the week-widget.
private const val WEEK_COLUMN_TIGHT_DP = 45
private val timeFormat = SimpleDateFormat("HH:mm", Locale.GERMAN)
private val dateShort = SimpleDateFormat("dd.MM.", Locale.GERMAN)
private val weekdayShort = SimpleDateFormat("EE", Locale.GERMAN)
private val dateTimeShort = SimpleDateFormat("dd.MM. HH:mm", Locale.GERMAN)
/// Hex values mirror LightAppTheme / DarkAppTheme tokens so the widget
/// matches the app's branding rather than the generic system look.
private data class WidgetPalette(
val background: Int,
val textPrimary: Int,
val textSecondary: Int,
val divider: Int,
val breakBlock: Int,
val watermarkAlpha: Float,
)
private val lightPalette = WidgetPalette(
background = 0xFFFCF7F5.toInt(),
textPrimary = 0xFF1A1A1A.toInt(),
textSecondary = 0xFF555555.toInt(),
divider = 0x22000000,
breakBlock = 0x0C000000,
watermarkAlpha = 0.014f,
)
private val darkPalette = WidgetPalette(
background = 0xFF1F1716.toInt(),
textPrimary = 0xFFF1F1F1.toInt(),
textSecondary = 0xFFB0B0B0.toInt(),
divider = 0x33FFFFFF,
breakBlock = 0x14FFFFFF,
watermarkAlpha = 0.025f,
)
private fun resolvePalette(context: Context, themeMode: String?): WidgetPalette {
val isDark = when (themeMode) {
"light" -> false
"dark" -> true
else -> {
val uiMode = context.resources.configuration.uiMode and
Configuration.UI_MODE_NIGHT_MASK
uiMode == Configuration.UI_MODE_NIGHT_YES
}
}
return if (isDark) darkPalette else lightPalette
}
fun buildDay(
context: Context,
packageName: String,
options: Bundle? = null,
): RemoteViews {
val prefs = sharedPrefs(context)
val palette = resolvePalette(context, prefs.getString(KEY_THEME_MODE, "system"))
if (!prefs.getBoolean(KEY_LOGGED_IN, false)) {
return buildPlaceholder(
context,
packageName,
context.getString(R.string.widget_login_required),
palette,
)
}
val data = WidgetDataParser.parse(prefs.getString(KEY_DAY_DATA, null))
?: return buildPlaceholder(
context,
packageName,
context.getString(R.string.widget_loading),
palette,
)
val totalVirtualMin = data.periods.lastOrNull()?.virtualEndMinutes
?: FALLBACK_VIRTUAL_MINUTES
val hourHeightDp = resolveHourHeight(options, DAY_CHROME_DP, totalVirtualMin)
val views = RemoteViews(packageName, R.layout.widget_day)
applyChrome(views, palette, options)
views.setTextColor(R.id.widget_day_title, palette.textPrimary)
views.setTextColor(R.id.widget_day_subtitle, palette.textSecondary)
views.setTextColor(R.id.widget_day_empty, palette.textSecondary)
views.setTextViewText(
R.id.widget_day_title,
"${dayLabel(context, data.anchorDate)} · ${dateShort.format(data.anchorDate)}",
)
views.setTextViewText(
R.id.widget_day_subtitle,
context.getString(R.string.widget_status_label, freshnessLabel(context, data.fetchedAt)),
)
views.removeAllViews(R.id.widget_day_time_labels)
views.removeAllViews(R.id.widget_day_grid)
if (data.isHoliday) {
views.setViewVisibility(R.id.widget_day_empty, View.VISIBLE)
views.setTextViewText(
R.id.widget_day_empty,
data.holidayName ?: context.getString(R.string.widget_holiday),
)
} else if (data.lessons.isEmpty()) {
views.setViewVisibility(R.id.widget_day_empty, View.VISIBLE)
views.setTextViewText(
R.id.widget_day_empty,
context.getString(R.string.widget_no_lessons),
)
} else {
views.setViewVisibility(R.id.widget_day_empty, View.GONE)
populateGridLines(packageName, views, R.id.widget_day_time_labels, hourHeightDp, palette, data.periods)
populateTimeLabels(packageName, views, R.id.widget_day_time_labels, hourHeightDp, palette, data.periods)
populateGridLines(packageName, views, R.id.widget_day_grid, hourHeightDp, palette, data.periods)
populateBreakBlocks(packageName, views, R.id.widget_day_grid, hourHeightDp, palette, data.periods)
for (lesson in data.lessons) {
addLessonBlock(
context = context,
packageName = packageName,
parent = views,
containerId = R.id.widget_day_grid,
lesson = lesson,
hourHeightDp = hourHeightDp,
periods = data.periods,
subjectOnly = false,
horizontalPaddingDp = 7,
)
}
}
views.setOnClickPendingIntent(R.id.widget_root, openAppIntent(context))
return views
}
fun buildWeek(
context: Context,
packageName: String,
options: Bundle? = null,
): RemoteViews {
val prefs = sharedPrefs(context)
val palette = resolvePalette(context, prefs.getString(KEY_THEME_MODE, "system"))
if (!prefs.getBoolean(KEY_LOGGED_IN, false)) {
return buildPlaceholder(
context,
packageName,
context.getString(R.string.widget_login_required),
palette,
)
}
val data = WidgetDataParser.parse(prefs.getString(KEY_WEEK_DATA, null))
?: return buildPlaceholder(
context,
packageName,
context.getString(R.string.widget_loading),
palette,
)
val totalVirtualMin = data.periods.lastOrNull()?.virtualEndMinutes
?: FALLBACK_VIRTUAL_MINUTES
val hourHeightDp = resolveHourHeight(options, WEEK_CHROME_DP, totalVirtualMin)
val views = RemoteViews(packageName, R.layout.widget_week)
applyChrome(views, palette, options)
views.setTextColor(R.id.widget_week_title, palette.textPrimary)
views.setTextColor(R.id.widget_week_subtitle, palette.textSecondary)
val cal = Calendar.getInstance().apply { time = data.anchorDate }
val weekNumber = cal.get(Calendar.WEEK_OF_YEAR)
val end = Calendar.getInstance().apply {
time = data.anchorDate
add(Calendar.DAY_OF_YEAR, 4)
}.time
val kwPrefix = context.getString(R.string.widget_calendar_week_prefix)
views.setTextViewText(
R.id.widget_week_title,
"$kwPrefix $weekNumber · ${dateShort.format(data.anchorDate)}${dateShort.format(end)}",
)
views.setTextViewText(
R.id.widget_week_subtitle,
context.getString(R.string.widget_status_label, freshnessLabel(context, data.fetchedAt)),
)
val headerIds = listOf(
R.id.widget_week_header_mon,
R.id.widget_week_header_tue,
R.id.widget_week_header_wed,
R.id.widget_week_header_thu,
R.id.widget_week_header_fri,
)
val columnIds = listOf(
R.id.widget_week_col_mon,
R.id.widget_week_col_tue,
R.id.widget_week_col_wed,
R.id.widget_week_col_thu,
R.id.widget_week_col_fri,
)
views.removeAllViews(R.id.widget_week_time_labels)
populateGridLines(packageName, views, R.id.widget_week_time_labels, hourHeightDp, palette, data.periods)
populateTimeLabels(packageName, views, R.id.widget_week_time_labels, hourHeightDp, palette, data.periods)
val (weekWidthDp, _) = widgetSizeDp(options)
// Time-label column is 28dp wide; the rest is split across 5 days
// plus thin dividers (negligible). Drop room/teacher only on the
// very narrowest week widgets — autoSize handles the in-between
// sizes.
val dayColumnWidthDp = (weekWidthDp - 28f - 20f) / 5f
val subjectOnly = dayColumnWidthDp < WEEK_COLUMN_TIGHT_DP
for ((index, columnId) in columnIds.withIndex()) {
views.removeAllViews(headerIds[index])
views.removeAllViews(columnId)
val day = Calendar.getInstance().apply {
time = data.anchorDate
add(Calendar.DAY_OF_YEAR, index)
}.time
val header = RemoteViews(packageName, R.layout.widget_week_day_header)
header.setTextColor(R.id.widget_week_day_header_weekday, palette.textPrimary)
header.setTextColor(R.id.widget_week_day_header_date, palette.textSecondary)
header.setTextViewText(R.id.widget_week_day_header_weekday, weekdayShort.format(day))
header.setTextViewText(R.id.widget_week_day_header_date, dateShort.format(day))
views.addView(headerIds[index], header)
populateGridLines(packageName, views, columnId, hourHeightDp, palette, data.periods)
populateBreakBlocks(packageName, views, columnId, hourHeightDp, palette, data.periods)
for (lesson in data.lessons.filter { WidgetDateUtils.isSameDay(it.start, day) }) {
addLessonBlock(
context = context,
packageName = packageName,
parent = views,
containerId = columnId,
lesson = lesson,
hourHeightDp = hourHeightDp,
periods = data.periods,
subjectOnly = subjectOnly,
horizontalPaddingDp = 3,
)
}
}
views.setOnClickPendingIntent(R.id.widget_root, openAppIntent(context))
return views
}
/// Pulls the launcher-reported widget size out of the AppWidget options
/// bundle. The grid now spans `totalVirtualMin` minutes (lessons +
/// preserved big breaks), so we divide by that instead of a fixed hour
/// count to keep tiles readable across different timetables.
private fun resolveHourHeight(
options: Bundle?,
chromeDp: Int,
totalVirtualMin: Int,
): Float {
val virtualHours = (totalVirtualMin / 60.0f).coerceAtLeast(1f)
val rawHeightDp = options?.let {
max(
it.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 0),
it.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 0),
)
} ?: 0
if (rawHeightDp <= 0) return 32f
val gridHeightDp = (rawHeightDp - chromeDp)
.coerceAtLeast((MIN_HOUR_HEIGHT_DP * virtualHours).toInt())
return (gridHeightDp.toFloat() / virtualHours)
.coerceIn(MIN_HOUR_HEIGHT_DP.toFloat(), MAX_HOUR_HEIGHT_DP.toFloat())
}
/// Real wall-clock minute → position on the virtual axis. Inside a
/// period: linear. In a gap: linear across the virtual gap (zero for
/// squeezed small breaks, real width for big breaks).
private fun realMinutesToVirtual(
realMin: Int,
periods: List<WidgetPeriod>,
): Float {
if (periods.isEmpty()) return realMin.toFloat()
for (period in periods) {
if (realMin in period.startMinutes..period.endMinutes) {
return period.virtualStartMinutes + (realMin - period.startMinutes).toFloat()
}
}
val first = periods.first()
if (realMin < first.startMinutes) {
return (realMin - first.startMinutes + first.virtualStartMinutes).toFloat()
}
val last = periods.last()
if (realMin > last.endMinutes) {
return last.virtualEndMinutes + (realMin - last.endMinutes).toFloat()
}
var prev = first
for (i in 1 until periods.size) {
val curr = periods[i]
if (realMin in (prev.endMinutes + 1) until curr.startMinutes) {
val gap = curr.startMinutes - prev.endMinutes
val virtualGap = curr.virtualStartMinutes - prev.virtualEndMinutes
return if (gap > 0) {
prev.virtualEndMinutes +
(realMin - prev.endMinutes).toFloat() * virtualGap / gap
} else {
curr.virtualStartMinutes.toFloat()
}
}
prev = curr
}
return 0f
}
/// Below this per-hour height the two-line label collapses to a single
/// period number — time + number overlap otherwise.
private const val TIME_LABEL_COMPACT_THRESHOLD_DP = 26f
private fun populateTimeLabels(
packageName: String,
parent: RemoteViews,
containerId: Int,
hourHeightDp: Float,
palette: WidgetPalette,
periods: List<WidgetPeriod>,
) {
val compact = hourHeightDp < TIME_LABEL_COMPACT_THRESHOLD_DP
for (period in periods) {
val label = RemoteViews(packageName, R.layout.widget_time_label)
label.setTextViewText(R.id.widget_time_label_number, "${period.name}.")
label.setTextViewText(R.id.widget_time_label_time, formatHm(period.startMinutes))
if (compact) {
label.setViewVisibility(R.id.widget_time_label_time, View.GONE)
label.setTextViewTextSize(
R.id.widget_time_label_number,
TypedValue.COMPLEX_UNIT_SP,
9f,
)
label.setTextColor(R.id.widget_time_label_number, palette.textPrimary)
} else {
label.setViewVisibility(R.id.widget_time_label_time, View.VISIBLE)
label.setTextViewTextSize(
R.id.widget_time_label_number,
TypedValue.COMPLEX_UNIT_SP,
7f,
)
label.setTextColor(R.id.widget_time_label_number, palette.textSecondary)
}
label.setTextColor(R.id.widget_time_label_time, palette.textPrimary)
val topDp = period.virtualStartMinutes * hourHeightDp / 60.0f
label.setViewLayoutMargin(
R.id.widget_time_label_root,
RemoteViews.MARGIN_TOP,
topDp,
TypedValue.COMPLEX_UNIT_DIP,
)
parent.addView(containerId, label)
}
}
private fun populateGridLines(
packageName: String,
parent: RemoteViews,
containerId: Int,
hourHeightDp: Float,
palette: WidgetPalette,
periods: List<WidgetPeriod>,
) {
// Lines at every period start + end, deduped by virtual minute so
// adjacent periods share a line and big-break boundaries get both
// upper and lower edges.
val drawn = mutableSetOf<Int>()
for (period in periods) {
for (virtualMin in listOf(period.virtualStartMinutes, period.virtualEndMinutes)) {
if (!drawn.add(virtualMin)) continue
val line = RemoteViews(packageName, R.layout.widget_grid_line)
line.setInt(R.id.widget_grid_line_root, "setBackgroundColor", palette.divider)
val topDp = virtualMin * hourHeightDp / 60.0f
line.setViewLayoutMargin(
R.id.widget_grid_line_root,
RemoteViews.MARGIN_TOP,
topDp,
TypedValue.COMPLEX_UNIT_DIP,
)
parent.addView(containerId, line)
}
}
}
/// Faint translucent block in any virtual gap between two periods —
/// only big breaks (Hofpause, Mittagspause) survive the mapper's
/// small-break collapse.
private fun populateBreakBlocks(
packageName: String,
parent: RemoteViews,
containerId: Int,
hourHeightDp: Float,
palette: WidgetPalette,
periods: List<WidgetPeriod>,
) {
for (i in 0 until periods.size - 1) {
val curr = periods[i]
val next = periods[i + 1]
val virtualGap = next.virtualStartMinutes - curr.virtualEndMinutes
if (virtualGap <= 0) continue
val block = RemoteViews(packageName, R.layout.widget_break_block)
val topDp = curr.virtualEndMinutes * hourHeightDp / 60.0f
val heightDp = virtualGap * hourHeightDp / 60.0f
block.setViewLayoutMargin(
R.id.widget_break_block_root,
RemoteViews.MARGIN_TOP,
topDp,
TypedValue.COMPLEX_UNIT_DIP,
)
block.setViewLayoutHeight(
R.id.widget_break_block_root,
heightDp,
TypedValue.COMPLEX_UNIT_DIP,
)
block.setInt(
R.id.widget_break_block_root,
"setBackgroundColor",
palette.breakBlock,
)
parent.addView(containerId, block)
}
}
private fun formatHm(minutesSinceMidnight: Int): String {
val h = minutesSinceMidnight / 60
val m = minutesSinceMidnight % 60
return "%02d:%02d".format(h, m)
}
/// Overrides the chrome XML's `@color/widget_*` defaults when the user
/// pins a fixed light/dark theme, and resizes the watermark M to match
/// the current widget bounds.
private fun applyChrome(views: RemoteViews, palette: WidgetPalette, options: Bundle?) {
views.setInt(R.id.widget_root, "setBackgroundColor", palette.background)
views.setInt(R.id.widget_watermark, "setColorFilter", palette.textPrimary)
views.setFloat(R.id.widget_watermark, "setAlpha", palette.watermarkAlpha)
val (widthDp, heightDp) = widgetSizeDp(options)
// Sized to the longer edge so the M scales with widget resize.
// Negative end/bottom margin lets a sliver tuck behind the edge.
val markSize = (max(widthDp, heightDp) * 0.8f).coerceIn(160f, 400f)
val offsetEnd = -(markSize * 0.18f)
val offsetBottom = -(markSize * 0.18f)
views.setViewLayoutWidth(
R.id.widget_watermark,
markSize,
TypedValue.COMPLEX_UNIT_DIP,
)
views.setViewLayoutHeight(
R.id.widget_watermark,
markSize,
TypedValue.COMPLEX_UNIT_DIP,
)
views.setViewLayoutMargin(
R.id.widget_watermark,
RemoteViews.MARGIN_END,
offsetEnd,
TypedValue.COMPLEX_UNIT_DIP,
)
views.setViewLayoutMargin(
R.id.widget_watermark,
RemoteViews.MARGIN_BOTTOM,
offsetBottom,
TypedValue.COMPLEX_UNIT_DIP,
)
}
private fun widgetSizeDp(options: Bundle?): Pair<Int, Int> {
if (options == null) return Pair(220, 220)
val width = max(
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH, 0),
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH, 0),
).coerceAtLeast(140)
val height = max(
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT, 0),
options.getInt(AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT, 0),
).coerceAtLeast(140)
return Pair(width, height)
}
private fun addLessonBlock(
context: Context,
packageName: String,
parent: RemoteViews,
containerId: Int,
lesson: WidgetLesson,
hourHeightDp: Float,
periods: List<WidgetPeriod>,
subjectOnly: Boolean,
horizontalPaddingDp: Int,
) {
val cal = Calendar.getInstance()
cal.time = lesson.start
val startMinutes = cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE)
cal.time = lesson.end
val endMinutes = cal.get(Calendar.HOUR_OF_DAY) * 60 + cal.get(Calendar.MINUTE)
val durationMinutes = (endMinutes - startMinutes).coerceAtLeast(15)
val virtualStart = realMinutesToVirtual(startMinutes, periods)
val virtualEnd = realMinutesToVirtual(startMinutes + durationMinutes, periods)
if (virtualEnd <= virtualStart) return
// Half the gap above + half below so the grid line under the tile
// stays visible.
val topDp = virtualStart * hourHeightDp / 60.0f + LESSON_GAP_DP / 2f
val heightDp = ((virtualEnd - virtualStart) * hourHeightDp / 60.0f - LESSON_GAP_DP)
.coerceAtLeast(MIN_BLOCK_HEIGHT_DP.toFloat())
val block = RemoteViews(packageName, R.layout.widget_lesson_block)
block.setViewLayoutMargin(
R.id.widget_lesson_block_root,
RemoteViews.MARGIN_TOP,
topDp,
TypedValue.COMPLEX_UNIT_DIP,
)
block.setViewLayoutHeight(
R.id.widget_lesson_block_root,
heightDp,
TypedValue.COMPLEX_UNIT_DIP,
)
block.setInt(
R.id.widget_lesson_block_root,
"setBackgroundResource",
statusDrawable(lesson),
)
val density = context.resources.displayMetrics.density
val padXPx = (horizontalPaddingDp * density).toInt()
val padYPx = (3 * density).toInt()
block.setViewPadding(
R.id.widget_lesson_block_root,
padXPx, padYPx, padXPx, padYPx,
)
block.setTextViewText(R.id.widget_lesson_subject, subjectLabel(lesson))
// Separate fixed-size badge so the +N hint stays readable when
// autoSize shrinks the subject on narrow tiles.
if (lesson.siblingCount > 0) {
block.setTextViewText(
R.id.widget_lesson_sibling_badge,
"+${lesson.siblingCount}",
)
block.setViewVisibility(R.id.widget_lesson_sibling_badge, View.VISIBLE)
} else {
block.setViewVisibility(R.id.widget_lesson_sibling_badge, View.GONE)
}
val room = roomLabel(lesson)
val teacher = teacherLabel(lesson)
val noSecondaryContent = room.isNullOrEmpty() && teacher.isNullOrEmpty()
val hideSecondary = subjectOnly ||
heightDp < BLOCK_SHOW_ROOM_MIN_DP ||
noSecondaryContent
block.setViewVisibility(
R.id.widget_lesson_secondary_stack,
if (hideSecondary) View.GONE else View.VISIBLE,
)
// Custom-events have no room/teacher → let the subject wrap to 2 lines
// so long titles don't autoshrink to nothing.
block.setInt(
R.id.widget_lesson_subject,
"setMaxLines",
if (noSecondaryContent) 2 else 1,
)
when {
hideSecondary -> {
applyOptionalText(block, R.id.widget_lesson_room, null)
applyOptionalText(block, R.id.widget_lesson_teacher, null)
}
heightDp < BLOCK_SHOW_TEACHER_SEPARATE_MIN_DP -> {
applyOptionalText(block, R.id.widget_lesson_room, room)
applyOptionalText(block, R.id.widget_lesson_teacher, null)
}
else -> {
applyOptionalText(block, R.id.widget_lesson_room, room)
applyOptionalText(block, R.id.widget_lesson_teacher, teacher)
}
}
parent.addView(containerId, block)
}
private fun applyOptionalText(views: RemoteViews, viewId: Int, text: String?) {
if (text.isNullOrEmpty()) {
views.setViewVisibility(viewId, View.GONE)
} else {
views.setTextViewText(viewId, text)
views.setViewVisibility(viewId, View.VISIBLE)
}
}
/// Custom-events use the user-picked palette (orange/red/green/blue,
/// mirroring CustomTimetableColors).
private fun statusDrawable(lesson: WidgetLesson): Int {
if (lesson.status == WidgetLessonStatus.EVENT && lesson.customColor != null) {
return when (lesson.customColor) {
"orange" -> R.drawable.widget_lesson_block_event_orange
"red" -> R.drawable.widget_lesson_block_event_red
"green" -> R.drawable.widget_lesson_block_event_green
"blue" -> R.drawable.widget_lesson_block_event_blue
else -> R.drawable.widget_lesson_block_event_orange
}
}
return when (lesson.status) {
WidgetLessonStatus.CANCELLED -> R.drawable.widget_lesson_block_cancelled
WidgetLessonStatus.IRREGULAR -> R.drawable.widget_lesson_block_irregular
WidgetLessonStatus.TEACHER_CHANGED -> R.drawable.widget_lesson_block_teacher_changed
WidgetLessonStatus.PAST -> R.drawable.widget_lesson_block_past
WidgetLessonStatus.EVENT -> R.drawable.widget_lesson_block_event_orange
WidgetLessonStatus.ONGOING -> R.drawable.widget_lesson_block_ongoing
WidgetLessonStatus.REGULAR -> R.drawable.widget_lesson_block_regular
}
}
private fun subjectLabel(lesson: WidgetLesson): String {
return lesson.subjectShort.ifEmpty { lesson.subjectLong ?: "" }
}
private fun roomLabel(lesson: WidgetLesson): String? = lesson.room
private fun teacherLabel(lesson: WidgetLesson): String? =
lesson.teacher ?: lesson.originalTeacher
private fun dayLabel(context: Context, anchor: Date): String {
val today = WidgetDateUtils.startOfDay(Date())
val tomorrow = Calendar.getInstance().apply {
time = today
add(Calendar.DAY_OF_YEAR, 1)
}.time
val anchorStart = WidgetDateUtils.startOfDay(anchor)
return when {
anchorStart == today -> context.getString(R.string.widget_today)
anchorStart == tomorrow -> context.getString(R.string.widget_tomorrow)
else -> SimpleDateFormat("EEEE", Locale.GERMAN).format(anchor)
}
}
private fun freshnessLabel(context: Context, fetchedAt: Date): String {
val today = WidgetDateUtils.startOfDay(Date())
val fetchedDay = WidgetDateUtils.startOfDay(fetchedAt)
val yesterday = Calendar.getInstance().apply {
time = today
add(Calendar.DAY_OF_YEAR, -1)
}.time
val yesterdayPrefix = context.getString(R.string.widget_yesterday_prefix)
return when (fetchedDay) {
today -> timeFormat.format(fetchedAt)
yesterday -> "$yesterdayPrefix ${timeFormat.format(fetchedAt)}"
else -> dateTimeShort.format(fetchedAt)
}
}
private fun buildPlaceholder(
context: Context,
packageName: String,
message: String,
palette: WidgetPalette,
): RemoteViews {
val views = RemoteViews(packageName, R.layout.widget_placeholder)
applyChrome(views, palette, null)
views.setTextColor(R.id.widget_placeholder_title, palette.textPrimary)
views.setTextColor(R.id.widget_placeholder_message, palette.textSecondary)
views.setTextViewText(
R.id.widget_placeholder_title,
context.getString(R.string.widget_placeholder_title),
)
views.setTextViewText(R.id.widget_placeholder_message, message)
views.setOnClickPendingIntent(
R.id.widget_placeholder_message,
openAppIntent(context),
)
return views
}
private fun openAppIntent(context: Context): PendingIntent {
// ACTION_MAIN + LAUNCHER mirrors a launcher tap; the boolean extra
// is consumed by Dart via WidgetNavigation to route to the timetable.
val intent = Intent(context, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP
action = Intent.ACTION_MAIN
addCategory(Intent.CATEGORY_LAUNCHER)
putExtra("widget_open_timetable", true)
}
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE,
)
}
private fun sharedPrefs(context: Context): SharedPreferences {
return context.getSharedPreferences(
"HomeWidgetPreferences",
Context.MODE_PRIVATE,
)
}
const val KEY_DAY_DATA = "widget_data_day_v1"
const val KEY_WEEK_DATA = "widget_data_week_v1"
const val KEY_LOGGED_IN = "widget_data_logged_in_v1"
const val KEY_THEME_MODE = "widget_setting_theme_mode_v1"
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for widgets to make the rounded corners based on the
appWidgetRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetRadius" />
<solid android:color="?android:attr/colorBackground" />
</shape>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for views inside widgets to make the rounded corners based on the
appWidgetInnerRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="?attr/appWidgetInnerRadius" />
<solid android:color="?android:attr/colorAccent" />
</shape>
@@ -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>
@@ -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,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="6dp" />
<solid android:color="@color/widget_lesson_cancelled" />
<stroke android:width="1.5dp" android:color="#C8FF0000" />
</shape>
</item>
<item
android:left="3dp"
android:top="3dp"
android:right="3dp"
android:bottom="3dp"
android:drawable="@drawable/widget_lesson_cancelled_x" />
</layer-list>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="#FF2196F3" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="#FF4CAF50" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="#FFEF6C00" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="#FF993333" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="@color/widget_lesson_irregular" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="@color/widget_lesson_ongoing" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="@color/widget_lesson_past" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="@color/widget_lesson_regular" />
</shape>
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="6dp" />
<solid android:color="@color/widget_lesson_teacher_changed" />
</shape>
@@ -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="#C8FF0000"
android:strokeWidth="5"
android:pathData="M0,0 L100,100 M100,0 L0,100" />
</vector>
@@ -1,26 +0,0 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/background"
style="@style/Widget.Android.AppWidget.Container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"
android:padding="0dp"
android:theme="@style/Theme.Android.AppWidgetContainer">
<ImageView
android:id="@+id/widget_image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
android:layout_weight="1"
android:adjustViewBounds="false"
android:background="@android:color/transparent"
android:scaleType="fitCenter"
android:src="@drawable/timetable_widget_default"
android:visibility="visible"
tools:visibility="visible" />
</RelativeLayout>
@@ -0,0 +1,8 @@
<?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"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp" />
@@ -0,0 +1,91 @@
<?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. -->
<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">
<!-- Bottom-leading so the mark looks like it's peeking out of the lower
left corner. Width/height/start+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:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/widget_day_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/widget_text_primary"
android:singleLine="true"
android:ellipsize="end"
tools:text="Heute · 08.05." />
<TextView
android:id="@+id/widget_day_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textColor="@color/widget_text_secondary"
tools:text="Stand: 14:32" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_marginTop="6dp"
android:orientation="horizontal">
<FrameLayout
android:id="@+id/widget_day_time_labels"
android:layout_width="32dp"
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,185 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/widget_background">
<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:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/widget_text_primary"
android:singleLine="true"
android:text="Heute · 06.05." />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textColor="@color/widget_text_secondary"
android:text="Stand: 07:50" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:layout_marginTop="6dp">
<FrameLayout
android:layout_width="32dp"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:gravity="end" android:paddingEnd="3dp"
android:layout_marginTop="22dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@color/widget_text_primary" android:text="1." />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="7sp" android:textColor="@color/widget_text_secondary" android:text="07:55" />
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:gravity="end" android:paddingEnd="3dp"
android:layout_marginTop="50dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@color/widget_text_primary" android:text="2." />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="7sp" android:textColor="@color/widget_text_secondary" android:text="08:40" />
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:gravity="end" android:paddingEnd="3dp"
android:layout_marginTop="79dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@color/widget_text_primary" android:text="3." />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="7sp" android:textColor="@color/widget_text_secondary" android:text="09:30" />
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:gravity="end" android:paddingEnd="3dp"
android:layout_marginTop="115dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@color/widget_text_primary" android:text="4." />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="7sp" android:textColor="@color/widget_text_secondary" android:text="10:35" />
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:gravity="end" android:paddingEnd="3dp"
android:layout_marginTop="142dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@color/widget_text_primary" android:text="5." />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="7sp" android:textColor="@color/widget_text_secondary" android:text="11:25" />
</LinearLayout>
<LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"
android:orientation="vertical" android:gravity="end" android:paddingEnd="3dp"
android:layout_marginTop="169dp">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@color/widget_text_primary" android:text="6." />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="7sp" android:textColor="@color/widget_text_secondary" android:text="12:15" />
</LinearLayout>
</FrameLayout>
<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="29dp" android:background="@color/widget_divider" />
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="56dp" android:background="@color/widget_divider" />
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="83dp" android:background="@color/widget_divider" />
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="115dp" android:background="@color/widget_divider" />
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="143dp" android:background="@color/widget_divider" />
<FrameLayout android:layout_width="match_parent" android:layout_height="1dp" android:layout_marginTop="170dp" android:background="@color/widget_divider" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="22dp"
android:layout_marginTop="29dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:padding="3dp"
android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@android:color/white" android:text="MA-LK" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="55dp"
android:layout_marginTop="83dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:padding="3dp"
android:background="@drawable/widget_lesson_block_regular">
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@android:color/white" android:text="DE-GK" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="9sp" android:textColor="#CCFFFFFF" android:text="B11" />
</LinearLayout>
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="22dp"
android:layout_marginTop="143dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:padding="3dp"
android:background="@drawable/widget_lesson_block_cancelled">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@android:color/white" android:text="BIO" />
</FrameLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="22dp"
android:layout_marginTop="170dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:padding="3dp"
android:background="@drawable/widget_lesson_block_teacher_changed">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:textSize="11sp" android:textStyle="bold"
android:textColor="@android:color/white" android:text="GE" />
</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,93 @@
<?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_lesson_block_root"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:layout_marginTop="0dp"
android:paddingStart="7dp"
android:paddingEnd="7dp"
android:paddingTop="3dp"
android:paddingBottom="3dp"
android:background="@drawable/widget_lesson_block_regular">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="top"
android:baselineAligned="false">
<TextView
android:id="@+id/widget_lesson_subject"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textStyle="bold"
android:textColor="@android:color/white"
android:maxLines="1"
android:ellipsize="end"
android:gravity="top|start"
android:includeFontPadding="false"
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="5sp"
android:autoSizeMaxTextSize="11sp"
android:autoSizeStepGranularity="1sp"
tools:text="MA-LK" />
<LinearLayout
android:id="@+id/widget_lesson_secondary_stack"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:gravity="top|end"
android:layout_marginStart="4dp">
<TextView
android:id="@+id/widget_lesson_room"
android:layout_width="wrap_content"
android:layout_height="12dp"
android:textColor="#CCFFFFFF"
android:maxLines="1"
android:ellipsize="end"
android:gravity="end|top"
android:includeFontPadding="false"
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="5sp"
android:autoSizeMaxTextSize="11sp"
android:autoSizeStepGranularity="1sp"
tools:text="A12" />
<TextView
android:id="@+id/widget_lesson_teacher"
android:layout_width="wrap_content"
android:layout_height="12dp"
android:textColor="#B3FFFFFF"
android:maxLines="1"
android:ellipsize="end"
android:gravity="end|top"
android:includeFontPadding="false"
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="5sp"
android:autoSizeMaxTextSize="11sp"
android:autoSizeStepGranularity="1sp"
tools:text="Müller" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/widget_lesson_sibling_badge"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|start"
android:textStyle="bold"
android:textSize="12sp"
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,31 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="wrap_content"
android:layout_marginTop="0dp"
android:orientation="vertical"
android:gravity="end"
android:paddingEnd="3dp">
<TextView
android:id="@+id/widget_time_label_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="9sp"
android:textColor="@color/widget_text_primary"
android:singleLine="true"
android:lineSpacingExtra="-2dp"
tools:text="07:55" />
<TextView
android:id="@+id/widget_time_label_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="7sp"
android:textColor="@color/widget_text_secondary"
android:singleLine="true"
android:lineSpacingExtra="-2dp"
tools:text="1." />
</LinearLayout>
@@ -0,0 +1,185 @@
<?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:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/widget_week_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/widget_text_primary"
android:singleLine="true"
android:ellipsize="end"
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:textSize="10sp"
android:textColor="@color/widget_text_secondary"
tools:text="Stand: 14:32" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="6dp">
<FrameLayout
android:layout_width="28dp"
android:layout_height="wrap_content" />
<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="wrap_content"
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="wrap_content"
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="wrap_content"
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="wrap_content"
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="wrap_content"
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="28dp"
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,28 @@
<?xml version="1.0" encoding="utf-8"?>
<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="wrap_content"
android:orientation="vertical"
android:gravity="center"
android:paddingTop="2dp"
android:paddingBottom="3dp">
<TextView
android:id="@+id/widget_week_day_header_weekday"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="11sp"
android:textStyle="bold"
android:textColor="@color/widget_text_primary"
tools:text="Mo" />
<TextView
android:id="@+id/widget_week_day_header_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="9sp"
android:textColor="@color/widget_text_secondary"
tools:text="06.05." />
</LinearLayout>
@@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Static preview for the week widget. Five day columns with two short
demo blocks each so the structure is recognisable in the picker. -->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/widget_background">
<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:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="14sp"
android:textStyle="bold"
android:textColor="@color/widget_text_primary"
android:singleLine="true"
android:text="KW 19 · 06.05.10.05." />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="10sp"
android:textColor="@color/widget_text_secondary"
android:text="Stand: 07:50" />
</LinearLayout>
<!-- Day-name + date row -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="6dp">
<FrameLayout android:layout_width="20dp" android:layout_height="wrap_content" />
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:textStyle="bold" android:textColor="@color/widget_text_primary" android:text="Mo" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textColor="@color/widget_text_secondary" android:text="06.05." />
</LinearLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:textStyle="bold" android:textColor="@color/widget_text_primary" android:text="Di" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textColor="@color/widget_text_secondary" android:text="07.05." />
</LinearLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:textStyle="bold" android:textColor="@color/widget_text_primary" android:text="Mi" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textColor="@color/widget_text_secondary" android:text="08.05." />
</LinearLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:textStyle="bold" android:textColor="@color/widget_text_primary" android:text="Do" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textColor="@color/widget_text_secondary" android:text="09.05." />
</LinearLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="vertical" android:gravity="center">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="11sp" android:textStyle="bold" android:textColor="@color/widget_text_primary" android:text="Fr" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textColor="@color/widget_text_secondary" android:text="10.05." />
</LinearLayout>
</LinearLayout>
<!-- Time grid: time-label column + 5 day columns -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:layout_marginTop="2dp">
<FrameLayout android:layout_width="20dp" android:layout_height="match_parent">
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="0dp" android:gravity="end" android:paddingEnd="3dp" android:textSize="8sp" android:textColor="@color/widget_text_secondary" android:text="08" />
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="36dp" android:gravity="end" android:paddingEnd="3dp" android:textSize="8sp" android:textColor="@color/widget_text_secondary" android:text="10" />
<TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="72dp" android:gravity="end" android:paddingEnd="3dp" android:textSize="8sp" android:textColor="@color/widget_text_secondary" android:text="12" />
</FrameLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<!-- Mon -->
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="2dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="MA" />
</FrameLayout>
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="40dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="EN" />
</FrameLayout>
</FrameLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<!-- Tue -->
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="20dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_cancelled">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="BIO" />
</FrameLayout>
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="60dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="DE" />
</FrameLayout>
</FrameLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<!-- Wed -->
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
<FrameLayout android:layout_width="match_parent" android:layout_height="32dp" android:layout_marginTop="2dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="MA" />
</FrameLayout>
</FrameLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<!-- Thu -->
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="2dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_teacher_changed">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="GE" />
</FrameLayout>
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="40dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="PH" />
</FrameLayout>
</FrameLayout>
<FrameLayout android:layout_width="1dp" android:layout_height="match_parent" android:background="@color/widget_divider" />
<!-- Fri -->
<FrameLayout android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1">
<FrameLayout android:layout_width="match_parent" android:layout_height="14dp" android:layout_marginTop="20dp" android:layout_marginStart="1dp" android:layout_marginEnd="1dp" android:padding="2dp" android:background="@drawable/widget_lesson_block_regular">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="9sp" android:textStyle="bold" android:textColor="@android:color/white" android:text="EN" />
</FrameLayout>
</FrameLayout>
</LinearLayout>
</LinearLayout>
</FrameLayout>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Having themes.xml for night-v31 because of the priority order of the resource qualifiers.
-->
<style name="Theme.Android.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="appWidgetRadius">@android:dimen/system_app_widget_background_radius</item>
<item name="appWidgetInnerRadius">@android:dimen/system_app_widget_inner_radius</item>
</style>
</resources>
@@ -0,0 +1,7 @@
<?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>
</resources>
@@ -1,14 +0,0 @@
<resources>
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_background</item>
</style>
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_inner_view_background</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources>
@@ -18,18 +18,4 @@
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item> <item name="android:windowBackground">?android:colorBackground</item>
</style> </style>
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_background</item>
<item name="android:clipToOutline">true</item>
</style>
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
<item name="android:padding">?attr/appWidgetPadding</item>
<item name="android:background">@drawable/app_widget_inner_view_background</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
<item name="android:clipToOutline">true</item>
</style>
</resources> </resources>
@@ -1,11 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Having themes.xml for v31 variant because @android:dimen/system_app_widget_background_radius
and @android:dimen/system_app_widget_internal_padding requires API level 31
-->
<style name="Theme.Android.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="appWidgetRadius">@android:dimen/system_app_widget_background_radius</item>
<item name="appWidgetInnerRadius">@android:dimen/system_app_widget_inner_radius</item>
</style>
</resources>
@@ -1,7 +0,0 @@
<resources>
<declare-styleable name="AppWidgetAttrs">
<attr name="appWidgetPadding" format="dimension" />
<attr name="appWidgetInnerRadius" format="dimension" />
<attr name="appWidgetRadius" format="dimension" />
</declare-styleable>
</resources>
@@ -1,6 +0,0 @@
<resources>
<color name="light_blue_50">#FFE1F5FE</color>
<color name="light_blue_200">#FF81D4FA</color>
<color name="light_blue_600">#FF039BE5</color>
<color name="light_blue_900">#FF01579B</color>
</resources>
@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!--
Refer to App Widget Documentation for margin information
http://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout
-->
<dimen name="widget_margin">0dp</dimen>
</resources>
+15 -4
View File
@@ -1,6 +1,17 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<string name="appwidget_text">Marianum Vertretungsplan</string> <string name="widget_day_label">Marianum · Heute</string>
<string name="add_widget">Hinzufügen</string> <string name="widget_week_label">Marianum · Woche</string>
<string name="app_widget_description">Übersicht zum Vertretungsplan</string> <string name="widget_day_description">Stundenplan und Vertretungen für den anstehenden Schultag.</string>
</resources> <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_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>
@@ -19,14 +19,4 @@
<style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar"> <style name="NormalTheme" parent="@android:style/Theme.Light.NoTitleBar">
<item name="android:windowBackground">?android:colorBackground</item> <item name="android:windowBackground">?android:colorBackground</item>
</style> </style>
<style name="Widget.Android.AppWidget.Container" parent="android:Widget">
<item name="android:id">@android:id/background</item>
<item name="android:background">?android:attr/colorBackground</item>
</style>
<style name="Widget.Android.AppWidget.InnerView" parent="android:Widget">
<item name="android:background">?android:attr/colorBackground</item>
<item name="android:textColor">?android:attr/textColorPrimary</item>
</style>
</resources> </resources>
@@ -1,17 +0,0 @@
<resources>
<style name="Theme.Android.AppWidgetContainerParent" parent="@android:style/Theme.DeviceDefault">
<!-- Radius of the outer bound of widgets to make the rounded corners -->
<item name="appWidgetRadius">16dp</item>
<!--
Radius of the inner view's bound of widgets to make the rounded corners.
It needs to be 8dp or less than the value of appWidgetRadius
-->
<item name="appWidgetInnerRadius">8dp</item>
</style>
<style name="Theme.Android.AppWidgetContainer" parent="Theme.Android.AppWidgetContainerParent">
<!-- Apply padding to avoid the content of the widget colliding with the rounded corners -->
<item name="appWidgetPadding">16dp</item>
</style>
</resources>
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Status colors mirror lib/view/pages/timetable/data/lesson_color.dart
exactly so widget tiles match the in-app calendar. -->
<color name="widget_lesson_regular">#FF993333</color>
<color name="widget_lesson_ongoing">#FFC83333</color>
<color name="widget_lesson_past">#FF993333</color>
<color name="widget_lesson_cancelled">#FF000000</color>
<color name="widget_lesson_irregular">#FF8F19B3</color>
<color name="widget_lesson_teacher_changed">#FF29639B</color>
<color name="widget_lesson_event">#FF2E7D32</color>
<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>
</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" />
@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/app_widget_description"
android:initialKeyguardLayout="@layout/timetable_widget"
android:initialLayout="@layout/timetable_widget"
android:minWidth="220dp"
android:minHeight="294dp"
android:minResizeWidth="110dp"
android:minResizeHeight="147dp"
android:previewImage="@drawable/timetable_widget_preview"
android:previewLayout="@layout/timetable_widget"
android:resizeMode="horizontal|vertical"
android:targetCellWidth="3"
android:targetCellHeight="4"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen" />
+23 -15
View File
@@ -2,21 +2,6 @@ allprojects {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
// [required] background_fetch
maven {
url "${project(':background_fetch').projectDir}/libs"
}
}
}
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10'
} }
} }
@@ -24,6 +9,29 @@ rootProject.buildDir = '../build'
subprojects { subprojects {
project.buildDir = "${rootProject.buildDir}/${project.name}" project.buildDir = "${rootProject.buildDir}/${project.name}"
} }
// 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
}
}
}
sub.tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
jvmTarget = '17'
}
}
}
}
subprojects { subprojects {
project.evaluationDependsOn(':app') project.evaluationDependsOn(':app')
} }
@@ -0,0 +1,2 @@
#This file is generated by updateDaemonJvm
toolchainVersion=21
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-all.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
+4 -2
View File
@@ -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 '8.7.3' apply false id "com.android.application" version '8.13.2' apply false
id "org.jetbrains.kotlin.android" version "2.1.10" apply false id "com.android.library" version '8.13.2' apply false
id "org.jetbrains.kotlin.android" version "2.2.20" apply false
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.10.0'
} }
include ":app" include ":app"
Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 12 KiB

+21
View File
@@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 KiB

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

+3
View File
@@ -1 +1,4 @@
extensions: extensions:
- hive_ce: true
- shared_preferences: true
- provider: true
+9
View File
@@ -0,0 +1,9 @@
flutter_launcher_icons:
android: true
ios: true
remove_alpha_ios: true
image_path_android: "assets/logo/icon/ic_launcher.png"
image_path_ios: "assets/logo/icon/1024.png"
adaptive_icon_background: "assets/logo/icon/ic_launcher_adaptive_back.png" # only available for Android 8.0 devices and above
adaptive_icon_foreground: "assets/logo/icon/ic_launcher_adaptive_fore.png" # only available for Android 8.0 devices and above
min_sdk_android: 16 # android min sdk min:16, default 21
+1 -1
View File
@@ -54,7 +54,7 @@ flutter_native_splash:
# 640 pixels in diameter. # 640 pixels in diameter.
# App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle # App icon without an icon background: This should be 1152×1152 pixels, and fit within a circle
# 768 pixels in diameter. # 768 pixels in diameter.
image: assets/logo/icon-android12.png image: assets/logo/icon/icon-android12.png
# Splash screen background color. # Splash screen background color.
color: "#993333" color: "#993333"
-2
View File
@@ -20,7 +20,5 @@
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1.0</string> <string>1.0</string>
<key>MinimumOSVersion</key>
<string>13.0</string>
</dict> </dict>
</plist> </plist>
@@ -0,0 +1,2 @@
#include? "../Pods/Target Support Files/Pods-Share Extension/Pods-Share Extension.debug.xcconfig"
#include "Generated.xcconfig"
@@ -0,0 +1,2 @@
#include? "../Pods/Target Support Files/Pods-Share Extension/Pods-Share Extension.profile.xcconfig"
#include "Generated.xcconfig"
@@ -0,0 +1,2 @@
#include? "../Pods/Target Support Files/Pods-Share Extension/Pods-Share Extension.release.xcconfig"
#include "Generated.xcconfig"
@@ -0,0 +1 @@
#include "Generated.xcconfig"
@@ -0,0 +1 @@
#include "Generated.xcconfig"
@@ -0,0 +1 @@
#include "Generated.xcconfig"
+4
View File
@@ -34,6 +34,10 @@ target 'Runner' do
pod 'PhoneNumberKit', '~> 3.7.6' pod 'PhoneNumberKit', '~> 3.7.6'
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
target 'Share Extension' do
inherit! :search_paths
end
# target 'RunnerTests' do # target 'RunnerTests' do
# inherit! :search_paths # inherit! :search_paths
# end # end
+82 -76
View File
@@ -36,53 +36,37 @@ PODS:
- SwiftyGif - SwiftyGif
- emoji_picker_flutter (0.0.1): - emoji_picker_flutter (0.0.1):
- Flutter - Flutter
- fast_rsa (0.6.0): - eraser (0.0.1):
- Flutter - Flutter
- file_picker (0.0.1): - file_picker (0.0.1):
- DKImagePickerController/PhotoGallery - DKImagePickerController/PhotoGallery
- Flutter - Flutter
- Firebase/CoreOnly (12.2.0): - Firebase/CoreOnly (12.12.0):
- FirebaseCore (~> 12.2.0) - FirebaseCore (~> 12.12.0)
- Firebase/InAppMessaging (12.2.0): - Firebase/Messaging (12.12.0):
- Firebase/CoreOnly - Firebase/CoreOnly
- FirebaseInAppMessaging (~> 12.2.0-beta) - FirebaseMessaging (~> 12.12.0)
- Firebase/Messaging (12.2.0): - firebase_core (4.7.0):
- Firebase/CoreOnly - Firebase/CoreOnly (= 12.12.0)
- FirebaseMessaging (~> 12.2.0)
- firebase_core (4.1.0):
- Firebase/CoreOnly (= 12.2.0)
- Flutter - Flutter
- firebase_in_app_messaging (0.9.0-1): - firebase_messaging (16.2.0):
- Firebase/InAppMessaging (= 12.2.0) - Firebase/Messaging (= 12.12.0)
- firebase_core - firebase_core
- Flutter - Flutter
- firebase_messaging (16.0.1): - FirebaseCore (12.12.1):
- Firebase/Messaging (= 12.2.0) - FirebaseCoreInternal (~> 12.12.0)
- firebase_core
- Flutter
- FirebaseABTesting (12.2.0):
- FirebaseCore (~> 12.2.0)
- FirebaseCore (12.2.0):
- FirebaseCoreInternal (~> 12.2.0)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/Logger (~> 8.1) - GoogleUtilities/Logger (~> 8.1)
- FirebaseCoreInternal (12.2.0): - FirebaseCoreInternal (12.12.0):
- "GoogleUtilities/NSData+zlib (~> 8.1)" - "GoogleUtilities/NSData+zlib (~> 8.1)"
- FirebaseInAppMessaging (12.2.0-beta): - FirebaseInstallations (12.12.0):
- FirebaseABTesting (~> 12.2.0) - FirebaseCore (~> 12.12.0)
- FirebaseCore (~> 12.2.0)
- FirebaseInstallations (~> 12.2.0)
- GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1)
- nanopb (~> 3.30910.0)
- FirebaseInstallations (12.2.0):
- FirebaseCore (~> 12.2.0)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
- GoogleUtilities/UserDefaults (~> 8.1) - GoogleUtilities/UserDefaults (~> 8.1)
- PromisesObjC (~> 2.4) - PromisesObjC (~> 2.4)
- FirebaseMessaging (12.2.0): - FirebaseMessaging (12.12.0):
- FirebaseCore (~> 12.2.0) - FirebaseCore (~> 12.12.0)
- FirebaseInstallations (~> 12.2.0) - FirebaseInstallations (~> 12.12.0)
- GoogleDataTransport (~> 10.1) - GoogleDataTransport (~> 10.1)
- GoogleUtilities/AppDelegateSwizzler (~> 8.1) - GoogleUtilities/AppDelegateSwizzler (~> 8.1)
- GoogleUtilities/Environment (~> 8.1) - GoogleUtilities/Environment (~> 8.1)
@@ -96,6 +80,9 @@ PODS:
- Flutter - Flutter
- flutter_native_splash (2.4.3): - flutter_native_splash (2.4.3):
- Flutter - Flutter
- flutter_secure_storage_darwin (10.0.0):
- Flutter
- FlutterMacOS
- GoogleDataTransport (10.1.0): - GoogleDataTransport (10.1.0):
- nanopb (~> 3.30910.0) - nanopb (~> 3.30910.0)
- PromisesObjC (~> 2.4) - PromisesObjC (~> 2.4)
@@ -123,13 +110,12 @@ PODS:
- GoogleUtilities/UserDefaults (8.1.0): - GoogleUtilities/UserDefaults (8.1.0):
- GoogleUtilities/Logger - GoogleUtilities/Logger
- GoogleUtilities/Privacy - GoogleUtilities/Privacy
- home_widget (0.0.1):
- Flutter
- image_picker_ios (0.0.1): - image_picker_ios (0.0.1):
- Flutter - Flutter
- in_app_review (2.0.0): - in_app_review (2.0.0):
- Flutter - Flutter
- libphonenumber_plugin (0.0.1):
- Flutter
- PhoneNumberKit
- nanopb (3.30910.0): - nanopb (3.30910.0):
- nanopb/decode (= 3.30910.0) - nanopb/decode (= 3.30910.0)
- nanopb/encode (= 3.30910.0) - nanopb/encode (= 3.30910.0)
@@ -139,9 +125,6 @@ PODS:
- Flutter - Flutter
- package_info_plus (0.4.5): - package_info_plus (0.4.5):
- Flutter - Flutter
- path_provider_foundation (0.0.1):
- Flutter
- FlutterMacOS
- PhoneNumberKit (3.7.11): - PhoneNumberKit (3.7.11):
- PhoneNumberKit/PhoneNumberKitCore (= 3.7.11) - PhoneNumberKit/PhoneNumberKitCore (= 3.7.11)
- PhoneNumberKit/UIKit (= 3.7.11) - PhoneNumberKit/UIKit (= 3.7.11)
@@ -149,9 +132,13 @@ PODS:
- PhoneNumberKit/UIKit (3.7.11): - PhoneNumberKit/UIKit (3.7.11):
- PhoneNumberKit/PhoneNumberKitCore - PhoneNumberKit/PhoneNumberKitCore
- PromisesObjC (2.4.0) - PromisesObjC (2.4.0)
- SDWebImage (5.21.2): - receive_sharing_intent (1.8.1):
- SDWebImage/Core (= 5.21.2) - Flutter
- SDWebImage/Core (5.21.2) - screen_brightness_ios (2.1.3):
- Flutter
- SDWebImage (5.21.7):
- SDWebImage/Core (= 5.21.7)
- SDWebImage/Core (5.21.7)
- share_plus (0.0.1): - share_plus (0.0.1):
- Flutter - Flutter
- shared_preferences_foundation (0.0.1): - shared_preferences_foundation (0.0.1):
@@ -165,42 +152,51 @@ PODS:
- Flutter - Flutter
- url_launcher_ios (0.0.1): - url_launcher_ios (0.0.1):
- Flutter - Flutter
- video_player_avfoundation (0.0.1):
- Flutter
- FlutterMacOS
- wakelock_plus (0.0.1):
- Flutter
- workmanager_apple (0.0.1):
- Flutter
DEPENDENCIES: DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
- emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`) - emoji_picker_flutter (from `.symlinks/plugins/emoji_picker_flutter/ios`)
- fast_rsa (from `.symlinks/plugins/fast_rsa/ios`) - eraser (from `.symlinks/plugins/eraser/ios`)
- file_picker (from `.symlinks/plugins/file_picker/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`)
- firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`)
- firebase_in_app_messaging (from `.symlinks/plugins/firebase_in_app_messaging/ios`)
- firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`) - firebase_messaging (from `.symlinks/plugins/firebase_messaging/ios`)
- Flutter (from `Flutter`) - Flutter (from `Flutter`)
- flutter_app_badge (from `.symlinks/plugins/flutter_app_badge/ios`) - flutter_app_badge (from `.symlinks/plugins/flutter_app_badge/ios`)
- flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`) - flutter_local_notifications (from `.symlinks/plugins/flutter_local_notifications/ios`)
- flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
- flutter_secure_storage_darwin (from `.symlinks/plugins/flutter_secure_storage_darwin/darwin`)
- home_widget (from `.symlinks/plugins/home_widget/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_review (from `.symlinks/plugins/in_app_review/ios`) - in_app_review (from `.symlinks/plugins/in_app_review/ios`)
- libphonenumber_plugin (from `.symlinks/plugins/libphonenumber_plugin/ios`)
- open_filex (from `.symlinks/plugins/open_filex/ios`) - open_filex (from `.symlinks/plugins/open_filex/ios`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`)
- PhoneNumberKit (~> 3.7.6) - PhoneNumberKit (~> 3.7.6)
- receive_sharing_intent (from `.symlinks/plugins/receive_sharing_intent/ios`)
- screen_brightness_ios (from `.symlinks/plugins/screen_brightness_ios/ios`)
- share_plus (from `.symlinks/plugins/share_plus/ios`) - share_plus (from `.symlinks/plugins/share_plus/ios`)
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`)
- sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`) - sqflite_darwin (from `.symlinks/plugins/sqflite_darwin/darwin`)
- syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`) - syncfusion_flutter_pdfviewer (from `.symlinks/plugins/syncfusion_flutter_pdfviewer/ios`)
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
- video_player_avfoundation (from `.symlinks/plugins/video_player_avfoundation/darwin`)
- wakelock_plus (from `.symlinks/plugins/wakelock_plus/ios`)
- workmanager_apple (from `.symlinks/plugins/workmanager_apple/ios`)
SPEC REPOS: SPEC REPOS:
trunk: trunk:
- DKImagePickerController - DKImagePickerController
- DKPhotoGallery - DKPhotoGallery
- Firebase - Firebase
- FirebaseABTesting
- FirebaseCore - FirebaseCore
- FirebaseCoreInternal - FirebaseCoreInternal
- FirebaseInAppMessaging
- FirebaseInstallations - FirebaseInstallations
- FirebaseMessaging - FirebaseMessaging
- GoogleDataTransport - GoogleDataTransport
@@ -218,14 +214,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/device_info_plus/ios" :path: ".symlinks/plugins/device_info_plus/ios"
emoji_picker_flutter: emoji_picker_flutter:
:path: ".symlinks/plugins/emoji_picker_flutter/ios" :path: ".symlinks/plugins/emoji_picker_flutter/ios"
fast_rsa: eraser:
:path: ".symlinks/plugins/fast_rsa/ios" :path: ".symlinks/plugins/eraser/ios"
file_picker: file_picker:
:path: ".symlinks/plugins/file_picker/ios" :path: ".symlinks/plugins/file_picker/ios"
firebase_core: firebase_core:
:path: ".symlinks/plugins/firebase_core/ios" :path: ".symlinks/plugins/firebase_core/ios"
firebase_in_app_messaging:
:path: ".symlinks/plugins/firebase_in_app_messaging/ios"
firebase_messaging: firebase_messaging:
:path: ".symlinks/plugins/firebase_messaging/ios" :path: ".symlinks/plugins/firebase_messaging/ios"
Flutter: Flutter:
@@ -236,18 +230,22 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/flutter_local_notifications/ios" :path: ".symlinks/plugins/flutter_local_notifications/ios"
flutter_native_splash: flutter_native_splash:
:path: ".symlinks/plugins/flutter_native_splash/ios" :path: ".symlinks/plugins/flutter_native_splash/ios"
flutter_secure_storage_darwin:
:path: ".symlinks/plugins/flutter_secure_storage_darwin/darwin"
home_widget:
:path: ".symlinks/plugins/home_widget/ios"
image_picker_ios: image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios" :path: ".symlinks/plugins/image_picker_ios/ios"
in_app_review: in_app_review:
:path: ".symlinks/plugins/in_app_review/ios" :path: ".symlinks/plugins/in_app_review/ios"
libphonenumber_plugin:
:path: ".symlinks/plugins/libphonenumber_plugin/ios"
open_filex: open_filex:
:path: ".symlinks/plugins/open_filex/ios" :path: ".symlinks/plugins/open_filex/ios"
package_info_plus: package_info_plus:
:path: ".symlinks/plugins/package_info_plus/ios" :path: ".symlinks/plugins/package_info_plus/ios"
path_provider_foundation: receive_sharing_intent:
:path: ".symlinks/plugins/path_provider_foundation/darwin" :path: ".symlinks/plugins/receive_sharing_intent/ios"
screen_brightness_ios:
:path: ".symlinks/plugins/screen_brightness_ios/ios"
share_plus: share_plus:
:path: ".symlinks/plugins/share_plus/ios" :path: ".symlinks/plugins/share_plus/ios"
shared_preferences_foundation: shared_preferences_foundation:
@@ -258,6 +256,12 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios" :path: ".symlinks/plugins/syncfusion_flutter_pdfviewer/ios"
url_launcher_ios: url_launcher_ios:
:path: ".symlinks/plugins/url_launcher_ios/ios" :path: ".symlinks/plugins/url_launcher_ios/ios"
video_player_avfoundation:
:path: ".symlinks/plugins/video_player_avfoundation/darwin"
wakelock_plus:
:path: ".symlinks/plugins/wakelock_plus/ios"
workmanager_apple:
:path: ".symlinks/plugins/workmanager_apple/ios"
SPEC CHECKSUMS: SPEC CHECKSUMS:
connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd connectivity_plus: cb623214f4e1f6ef8fe7403d580fdad517d2f7dd
@@ -265,41 +269,43 @@ SPEC CHECKSUMS:
DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c
DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60
emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc emoji_picker_flutter: ece213fc274bdddefb77d502d33080dc54e616cc
fast_rsa: 8cf0f70421610bbe9462db881cdeef1cdd626153 eraser: 83a4b06985f3702aa3d8dec816f9693266012937
file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be file_picker: a0560bc09d61de87f12d246fc47d2119e6ef37be
Firebase: 26f6f8d460603af3df970ad505b16b15f5e2e9a1 Firebase: aa154fee4e9b8eac17aa42344988865b3e857d33
firebase_core: 3ff52146406557dddd01d570e807e203ec7e1302 firebase_core: 9156a152117c843440b0b990c785aa0259bc5447
firebase_in_app_messaging: 42894eb8e92aa83ac58f1c534dc9f9f9546f23b9 firebase_messaging: 0d962ab44ff24ed36deb8fa2ee043c4671858269
firebase_messaging: 3dcc998dd98e1e54af75d0cccae8606eba43553c FirebaseCore: 86241206e656f5c80c995e370e6c975913b9b284
FirebaseABTesting: 32f3fc079d72c9b93e000b60877c4e4f62ef7031 FirebaseCoreInternal: 7c12fc3011d889085e765e317d7b9fd1cef97af9
FirebaseCore: 311c48a147ad4a0ab7febbaed89e8025c67510cd FirebaseInstallations: 4e6e162aa4abaaeeeb01dd00179dfc5ad9c2194e
FirebaseCoreInternal: 56ea29f3dad2894f81b060f706f9d53509b6ed3b FirebaseMessaging: 341004946fa7ffc741344b20f1b667514fc93e31
FirebaseInAppMessaging: fecba63d44c5cd8f874e9d661a5aa5047380c7d0
FirebaseInstallations: 3e884b01feabdf67582a80f3250425a00979b4ed
FirebaseMessaging: 43ec73bbfedd0c385a849bb91593ab4ad4b9e48e
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467 Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_app_badge: ca742dd659a157c1090ef7cd881cb78f48f3bcdf flutter_app_badge: ca742dd659a157c1090ef7cd881cb78f48f3bcdf
flutter_local_notifications: a5a732f069baa862e728d839dd2ebb904737effb flutter_local_notifications: 643a3eda1ce1c0599413ca31672536d423dee214
flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf flutter_native_splash: c32d145d68aeda5502d5f543ee38c192065986cf
flutter_secure_storage_darwin: acdb3f316ed05a3e68f856e0353b133eec373a23
GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7 GoogleDataTransport: aae35b7ea0c09004c3797d53c8c41f66f219d6a7
GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1 GoogleUtilities: 00c88b9a86066ef77f0da2fab05f65d7768ed8e1
image_picker_ios: 7fe1ff8e34c1790d6fff70a32484959f563a928a home_widget: f169fc41fd807b4d46ab6615dc44d62adbf9f64f
in_app_review: 5596fe56fab799e8edb3561c03d053363ab13457 image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
libphonenumber_plugin: d134f173b22bfa5ede50887071f087f309277f8c in_app_review: 7dd1ea365263f834b8464673f9df72c80c17c937
nanopb: fad817b59e0457d11a5dfbde799381cd727c1275 nanopb: fad817b59e0457d11a5dfbde799381cd727c1275
open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1 open_filex: 432f3cd11432da3e39f47fcc0df2b1603854eff1
package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499 package_info_plus: af8e2ca6888548050f16fa2f1938db7b5a5df499
path_provider_foundation: 080d55be775b7414fd5a5ef3ac137b97b097e564
PhoneNumberKit: ced55861269312a5e3bc2ef82a58d6255b1c976a PhoneNumberKit: ced55861269312a5e3bc2ef82a58d6255b1c976a
PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47 PromisesObjC: f5707f49cb48b9636751c5b2e7d227e43fba9f47
SDWebImage: 9f177d83116802728e122410fb25ad88f5c7608a receive_sharing_intent: 222384f00ffe7e952bbfabaa9e3967cb87e5fe00
screen_brightness_ios: 212d950bb99c915eee971c884f4a6c87c92cd13d
SDWebImage: e9fc87c1aab89a8ab1bbd74eba378c6f53be8abf
share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a share_plus: 50da8cb520a8f0f65671c6c6a99b3617ed10a58a
shared_preferences_foundation: 9e1978ff2562383bd5676f64ec4e9aa8fa06a6f7 shared_preferences_foundation: 7036424c3d8ec98dfe75ff1667cb0cd531ec82bb
sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0 sqflite_darwin: 20b2a3a3b70e43edae938624ce550a3cbf66a3d0
SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4
syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14 syncfusion_flutter_pdfviewer: 90dc48305d2e33d4aa20681d1e98ddeda891bc14
url_launcher_ios: 694010445543906933d732453a59da0a173ae33d url_launcher_ios: 7a95fa5b60cc718a708b8f2966718e93db0cef1b
video_player_avfoundation: 3453f792138786248960ca029747fcd9f318ef52
wakelock_plus: e29112ab3ef0b318e58cfa5c32326458be66b556
workmanager_apple: 904529ae31e97fc5be632cf628507652294a0778
PODFILE CHECKSUM: e21c9d4c7b9623c73c6784ddc132fd50a603ad93 PODFILE CHECKSUM: 424a9b4c0fe81d8ebeaa9cb0dfedb60a68b19a0d
COCOAPODS: 1.16.2 COCOAPODS: 1.16.2
+518 -10
View File
@@ -7,17 +7,50 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
034BD2FF7A860C6DC2FED514 /* Pods_Share_Extension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F2428AC5384E0EF8DAB462A /* Pods_Share_Extension.framework */; };
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
3321F80F2FB1C00C0011C712 /* Share Extension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 3321F8052FB1C00C0011C712 /* Share Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
33FDB0982EE9ABDC000B2391 /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 33FDB0972EE9ABDC000B2391 /* GoogleService-Info.plist */; };
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
6483E4432A911EA00063B51E /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6483E4422A911EA00063B51E /* GoogleService-Info.plist */; };
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; };
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; };
AA0101070000000011111111 /* TimetableWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = AA0101020000000011111111 /* TimetableWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
AA0102010000000022222222 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA0102020000000022222222 /* SceneDelegate.swift */; };
B8263932DB64B022CCEE7A53 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90960A132A5F91779B3FBE28 /* Pods_Runner.framework */; }; B8263932DB64B022CCEE7A53 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 90960A132A5F91779B3FBE28 /* Pods_Runner.framework */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
3321F80D2FB1C00C0011C712 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = 3321F8042FB1C00C0011C712;
remoteInfo = "Share Extension";
};
AA0101080000000011111111 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 97C146E61CF9000F007C117D /* Project object */;
proxyType = 1;
remoteGlobalIDString = AA0101010000000011111111;
remoteInfo = TimetableWidgetExtension;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
3321F8102FB1C00C0011C712 /* Embed Foundation Extensions */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 13;
files = (
3321F80F2FB1C00C0011C712 /* Share Extension.appex in Embed Foundation Extensions */,
AA0101070000000011111111 /* TimetableWidgetExtension.appex in Embed Foundation Extensions */,
);
name = "Embed Foundation Extensions";
runOnlyForDeploymentPostprocessing = 0;
};
9705A1C41CF9048500538489 /* Embed Frameworks */ = { 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@@ -33,10 +66,13 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
3321F8052FB1C00C0011C712 /* Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
33FDB0972EE9ABDC000B2391 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = "<group>"; };
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
4509EC31CB08BA9BF367AF6C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; }; 4509EC31CB08BA9BF367AF6C /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = "<group>"; };
4F2428AC5384E0EF8DAB462A /* Pods_Share_Extension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Share_Extension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
60E1803A3FB28FCC6F435E99 /* Pods-Share Extension.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.release.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.release.xcconfig"; sourceTree = "<group>"; };
64801C012A9112D500E8B558 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; }; 64801C012A9112D500E8B558 /* Runner.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Runner.entitlements; sourceTree = "<group>"; };
6483E4422A911EA00063B51E /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "GoogleService-Info.plist"; path = "../../../../Downloads/GoogleService-Info.plist"; sourceTree = "<group>"; };
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = "<group>"; };
74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
@@ -48,11 +84,73 @@
97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
AA0101020000000011111111 /* TimetableWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = TimetableWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
AA0102020000000022222222 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
AA6B03D1433E7395021F7730 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; }; AA6B03D1433E7395021F7730 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = "<group>"; };
BB0001010000000011111111 /* ShareExtension-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "ShareExtension-Debug.xcconfig"; path = "Flutter/ShareExtension-Debug.xcconfig"; sourceTree = "<group>"; };
BB0001020000000011111111 /* ShareExtension-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "ShareExtension-Release.xcconfig"; path = "Flutter/ShareExtension-Release.xcconfig"; sourceTree = "<group>"; };
BB0001030000000011111111 /* ShareExtension-Profile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "ShareExtension-Profile.xcconfig"; path = "Flutter/ShareExtension-Profile.xcconfig"; sourceTree = "<group>"; };
BB0001040000000011111111 /* TimetableWidget-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "TimetableWidget-Debug.xcconfig"; path = "Flutter/TimetableWidget-Debug.xcconfig"; sourceTree = "<group>"; };
BB0001050000000011111111 /* TimetableWidget-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "TimetableWidget-Release.xcconfig"; path = "Flutter/TimetableWidget-Release.xcconfig"; sourceTree = "<group>"; };
BB0001060000000011111111 /* TimetableWidget-Profile.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "TimetableWidget-Profile.xcconfig"; path = "Flutter/TimetableWidget-Profile.xcconfig"; sourceTree = "<group>"; };
C7E1879BE78835C7E3256316 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; }; C7E1879BE78835C7E3256316 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = "<group>"; };
DD904D7C0FC0AD11449CEB80 /* Pods-Share Extension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.debug.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.debug.xcconfig"; sourceTree = "<group>"; };
EF5279D9BF8FCBB117AF998E /* Pods-Share Extension.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Share Extension.profile.xcconfig"; path = "Target Support Files/Pods-Share Extension/Pods-Share Extension.profile.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
AA01010E0000000011111111 /* Exceptions for "Share Extension" folder in "Share Extension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = 3321F8042FB1C00C0011C712 /* Share Extension */;
};
AA01010F0000000011111111 /* Exceptions for "TimetableWidgetExtension" folder in "TimetableWidgetExtension" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
);
target = AA0101010000000011111111 /* TimetableWidgetExtension */;
};
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
3321F8062FB1C00C0011C712 /* Share Extension */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
AA01010E0000000011111111 /* Exceptions for "Share Extension" folder in "Share Extension" target */,
);
explicitFileTypes = {
};
explicitFolders = (
);
path = "Share Extension";
sourceTree = "<group>";
};
AA0101030000000011111111 /* TimetableWidgetExtension */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
AA01010F0000000011111111 /* Exceptions for "TimetableWidgetExtension" folder in "TimetableWidgetExtension" target */,
);
explicitFileTypes = {
};
explicitFolders = (
);
path = TimetableWidgetExtension;
sourceTree = "<group>";
};
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
3321F8022FB1C00C0011C712 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
034BD2FF7A860C6DC2FED514 /* Pods_Share_Extension.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EB1CF9000F007C117D /* Frameworks */ = { 97C146EB1CF9000F007C117D /* Frameworks */ = {
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@@ -61,6 +159,13 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
AA0101050000000011111111 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
@@ -70,6 +175,9 @@
C7E1879BE78835C7E3256316 /* Pods-Runner.debug.xcconfig */, C7E1879BE78835C7E3256316 /* Pods-Runner.debug.xcconfig */,
AA6B03D1433E7395021F7730 /* Pods-Runner.release.xcconfig */, AA6B03D1433E7395021F7730 /* Pods-Runner.release.xcconfig */,
4509EC31CB08BA9BF367AF6C /* Pods-Runner.profile.xcconfig */, 4509EC31CB08BA9BF367AF6C /* Pods-Runner.profile.xcconfig */,
DD904D7C0FC0AD11449CEB80 /* Pods-Share Extension.debug.xcconfig */,
60E1803A3FB28FCC6F435E99 /* Pods-Share Extension.release.xcconfig */,
EF5279D9BF8FCBB117AF998E /* Pods-Share Extension.profile.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -78,6 +186,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
90960A132A5F91779B3FBE28 /* Pods_Runner.framework */, 90960A132A5F91779B3FBE28 /* Pods_Runner.framework */,
4F2428AC5384E0EF8DAB462A /* Pods_Share_Extension.framework */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -89,6 +198,12 @@
9740EEB21CF90195004384FC /* Debug.xcconfig */, 9740EEB21CF90195004384FC /* Debug.xcconfig */,
7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 7AFA3C8E1D35360C0083082E /* Release.xcconfig */,
9740EEB31CF90195004384FC /* Generated.xcconfig */, 9740EEB31CF90195004384FC /* Generated.xcconfig */,
BB0001010000000011111111 /* ShareExtension-Debug.xcconfig */,
BB0001020000000011111111 /* ShareExtension-Release.xcconfig */,
BB0001030000000011111111 /* ShareExtension-Profile.xcconfig */,
BB0001040000000011111111 /* TimetableWidget-Debug.xcconfig */,
BB0001050000000011111111 /* TimetableWidget-Release.xcconfig */,
BB0001060000000011111111 /* TimetableWidget-Profile.xcconfig */,
); );
name = Flutter; name = Flutter;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -98,6 +213,8 @@
children = ( children = (
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
3321F8062FB1C00C0011C712 /* Share Extension */,
AA0101030000000011111111 /* TimetableWidgetExtension */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
345F4BD4143471FDA71626DE /* Pods */, 345F4BD4143471FDA71626DE /* Pods */,
731388A08E3B330B216381D0 /* Frameworks */, 731388A08E3B330B216381D0 /* Frameworks */,
@@ -108,6 +225,8 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
97C146EE1CF9000F007C117D /* Runner.app */, 97C146EE1CF9000F007C117D /* Runner.app */,
3321F8052FB1C00C0011C712 /* Share Extension.appex */,
AA0101020000000011111111 /* TimetableWidgetExtension.appex */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -115,15 +234,16 @@
97C146F01CF9000F007C117D /* Runner */ = { 97C146F01CF9000F007C117D /* Runner */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
33FDB0972EE9ABDC000B2391 /* GoogleService-Info.plist */,
64801C012A9112D500E8B558 /* Runner.entitlements */, 64801C012A9112D500E8B558 /* Runner.entitlements */,
97C146FA1CF9000F007C117D /* Main.storyboard */, 97C146FA1CF9000F007C117D /* Main.storyboard */,
97C146FD1CF9000F007C117D /* Assets.xcassets */, 97C146FD1CF9000F007C117D /* Assets.xcassets */,
97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */,
97C147021CF9000F007C117D /* Info.plist */, 97C147021CF9000F007C117D /* Info.plist */,
6483E4422A911EA00063B51E /* GoogleService-Info.plist */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
74858FAE1ED2DC5600515810 /* AppDelegate.swift */, 74858FAE1ED2DC5600515810 /* AppDelegate.swift */,
AA0102020000000022222222 /* SceneDelegate.swift */,
74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */,
); );
path = Runner; path = Runner;
@@ -132,6 +252,27 @@
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
3321F8042FB1C00C0011C712 /* Share Extension */ = {
isa = PBXNativeTarget;
buildConfigurationList = 3321F8152FB1C00C0011C712 /* Build configuration list for PBXNativeTarget "Share Extension" */;
buildPhases = (
AC0316D13BD5FB74CD9B5223 /* [CP] Check Pods Manifest.lock */,
3321F8012FB1C00C0011C712 /* Sources */,
3321F8022FB1C00C0011C712 /* Frameworks */,
3321F8032FB1C00C0011C712 /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
3321F8062FB1C00C0011C712 /* Share Extension */,
);
name = "Share Extension";
productName = "Share Extension";
productReference = 3321F8052FB1C00C0011C712 /* Share Extension.appex */;
productType = "com.apple.product-type.app-extension";
};
97C146ED1CF9000F007C117D /* Runner */ = { 97C146ED1CF9000F007C117D /* Runner */ = {
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */;
@@ -142,6 +283,7 @@
97C146EB1CF9000F007C117D /* Frameworks */, 97C146EB1CF9000F007C117D /* Frameworks */,
97C146EC1CF9000F007C117D /* Resources */, 97C146EC1CF9000F007C117D /* Resources */,
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3321F8102FB1C00C0011C712 /* Embed Foundation Extensions */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
174B54D80220E5F588BD9737 /* [CP] Embed Pods Frameworks */, 174B54D80220E5F588BD9737 /* [CP] Embed Pods Frameworks */,
859FAB4E05FAC31B7B1A62D7 /* [CP] Copy Pods Resources */, 859FAB4E05FAC31B7B1A62D7 /* [CP] Copy Pods Resources */,
@@ -149,12 +291,34 @@
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
3321F80E2FB1C00C0011C712 /* PBXTargetDependency */,
AA0101090000000011111111 /* PBXTargetDependency */,
); );
name = Runner; name = Runner;
productName = Runner; productName = Runner;
productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productReference = 97C146EE1CF9000F007C117D /* Runner.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
AA0101010000000011111111 /* TimetableWidgetExtension */ = {
isa = PBXNativeTarget;
buildConfigurationList = AA01010D0000000011111111 /* Build configuration list for PBXNativeTarget "TimetableWidgetExtension" */;
buildPhases = (
AA0101040000000011111111 /* Sources */,
AA0101050000000011111111 /* Frameworks */,
AA0101060000000011111111 /* Resources */,
);
buildRules = (
);
dependencies = (
);
fileSystemSynchronizedGroups = (
AA0101030000000011111111 /* TimetableWidgetExtension */,
);
name = TimetableWidgetExtension;
productName = TimetableWidgetExtension;
productReference = AA0101020000000011111111 /* TimetableWidgetExtension.appex */;
productType = "com.apple.product-type.app-extension";
};
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
/* Begin PBXProject section */ /* Begin PBXProject section */
@@ -162,13 +326,20 @@
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
BuildIndependentTargetsInParallel = YES; BuildIndependentTargetsInParallel = YES;
LastSwiftUpdateCheck = 2610;
LastUpgradeCheck = 1510; LastUpgradeCheck = 1510;
ORGANIZATIONNAME = ""; ORGANIZATIONNAME = "";
TargetAttributes = { TargetAttributes = {
3321F8042FB1C00C0011C712 = {
CreatedOnToolsVersion = 26.1.1;
};
97C146ED1CF9000F007C117D = { 97C146ED1CF9000F007C117D = {
CreatedOnToolsVersion = 7.3.1; CreatedOnToolsVersion = 7.3.1;
LastSwiftMigration = 1100; LastSwiftMigration = 1100;
}; };
AA0101010000000011111111 = {
CreatedOnToolsVersion = 26.1.1;
};
}; };
}; };
buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */;
@@ -185,23 +356,39 @@
projectRoot = ""; projectRoot = "";
targets = ( targets = (
97C146ED1CF9000F007C117D /* Runner */, 97C146ED1CF9000F007C117D /* Runner */,
3321F8042FB1C00C0011C712 /* Share Extension */,
AA0101010000000011111111 /* TimetableWidgetExtension */,
); );
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
3321F8032FB1C00C0011C712 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EC1CF9000F007C117D /* Resources */ = { 97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
6483E4432A911EA00063B51E /* GoogleService-Info.plist in Resources */, 33FDB0982EE9ABDC000B2391 /* GoogleService-Info.plist in Resources */,
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
AA0101060000000011111111 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */ /* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */
@@ -270,6 +457,28 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build";
}; };
AC0316D13BD5FB74CD9B5223 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Share Extension-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
EE78ADC5E762D17A29097E92 /* [CP] Check Pods Manifest.lock */ = { EE78ADC5E762D17A29097E92 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
@@ -295,17 +504,45 @@
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */
3321F8012FB1C00C0011C712 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
97C146EA1CF9000F007C117D /* Sources */ = { 97C146EA1CF9000F007C117D /* Sources */ = {
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */,
AA0102010000000022222222 /* SceneDelegate.swift in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
AA0101040000000011111111 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
3321F80E2FB1C00C0011C712 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 3321F8042FB1C00C0011C712 /* Share Extension */;
targetProxy = 3321F80D2FB1C00C0011C712 /* PBXContainerItemProxy */;
};
AA0101090000000011111111 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = AA0101010000000011111111 /* TimetableWidgetExtension */;
targetProxy = AA0101080000000011111111 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = { 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
@@ -367,7 +604,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@@ -386,6 +623,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.mhsl.marianum.mobile.client.share;
DEVELOPMENT_TEAM = MY55VF3KPG; DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -395,7 +633,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "${FLUTTER_BUILD_NAME)"; MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client; PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -405,6 +643,132 @@
}; };
name = Profile; name = Profile;
}; };
3321F8112FB1C00C0011C712 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB0001010000000011111111 /* ShareExtension-Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.mhsl.marianum.mobile.client.share;
DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
INFOPLIST_FILE = "Share Extension/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "eu.mhsl.marianum.mobile.client.Share-Extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
3321F8122FB1C00C0011C712 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB0001020000000011111111 /* ShareExtension-Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.mhsl.marianum.mobile.client.share;
DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
INFOPLIST_FILE = "Share Extension/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "eu.mhsl.marianum.mobile.client.Share-Extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
3321F8132FB1C00C0011C712 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB0001030000000011111111 /* ShareExtension-Profile.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = "Share Extension/Share Extension.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.mhsl.marianum.mobile.client.share;
DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
INFOPLIST_FILE = "Share Extension/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "eu.mhsl.marianum.mobile.client.Share-Extension";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
STRING_CATALOG_GENERATE_SYMBOLS = YES;
SWIFT_APPROACHABLE_CONCURRENCY = YES;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Profile;
};
97C147031CF9000F007C117D /* Debug */ = { 97C147031CF9000F007C117D /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
buildSettings = { buildSettings = {
@@ -452,7 +816,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@@ -501,7 +865,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.0; IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos; SUPPORTED_PLATFORMS = iphoneos;
@@ -522,6 +886,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.mhsl.marianum.mobile.client.share;
DEVELOPMENT_TEAM = MY55VF3KPG; DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -531,7 +896,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "${FLUTTER_BUILD_NAME)"; MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client; PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -552,6 +917,7 @@
CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
CUSTOM_GROUP_ID = group.eu.mhsl.marianum.mobile.client.share;
DEVELOPMENT_TEAM = MY55VF3KPG; DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_BITCODE = NO; ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_FILE = Runner/Info.plist;
@@ -561,7 +927,7 @@
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
MARKETING_VERSION = "${FLUTTER_BUILD_NAME)"; MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client; PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client;
PRODUCT_NAME = "$(TARGET_NAME)"; PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
@@ -571,9 +937,141 @@
}; };
name = Release; name = Release;
}; };
AA01010A0000000011111111 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB0001040000000011111111 /* TimetableWidget-Debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = TimetableWidgetExtension/TimetableWidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
INFOPLIST_FILE = TimetableWidgetExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client.TimetableWidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
AA01010B0000000011111111 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB0001050000000011111111 /* TimetableWidget-Release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = TimetableWidgetExtension/TimetableWidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
INFOPLIST_FILE = TimetableWidgetExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client.TimetableWidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
AA01010C0000000011111111 /* Profile */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = BB0001060000000011111111 /* TimetableWidget-Profile.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = TimetableWidgetExtension/TimetableWidgetExtension.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)";
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = MY55VF3KPG;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
INFOPLIST_FILE = TimetableWidgetExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = "$(FLUTTER_BUILD_NAME)";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = eu.mhsl.marianum.mobile.client.TimetableWidgetExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Profile;
};
/* End XCBuildConfiguration section */ /* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */ /* Begin XCConfigurationList section */
3321F8152FB1C00C0011C712 /* Build configuration list for PBXNativeTarget "Share Extension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
3321F8112FB1C00C0011C712 /* Debug */,
3321F8122FB1C00C0011C712 /* Release */,
3321F8132FB1C00C0011C712 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = {
isa = XCConfigurationList; isa = XCConfigurationList;
buildConfigurations = ( buildConfigurations = (
@@ -594,6 +1092,16 @@
defaultConfigurationIsVisible = 0; defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release; defaultConfigurationName = Release;
}; };
AA01010D0000000011111111 /* Build configuration list for PBXNativeTarget "TimetableWidgetExtension" */ = {
isa = XCConfigurationList;
buildConfigurations = (
AA01010A0000000011111111 /* Debug */,
AA01010B0000000011111111 /* Release */,
AA01010C0000000011111111 /* Profile */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */ /* End XCConfigurationList section */
}; };
rootObject = 97C146E61CF9000F007C117D /* Project object */; rootObject = 97C146E61CF9000F007C117D /* Project object */;
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2610"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3321F8042FB1C00C0011C712"
BuildableName = "Share Extension.appex"
BlueprintName = "Share Extension"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "2610"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "AA0101010000000011111111"
BuildableName = "TimetableWidgetExtension.appex"
BlueprintName = "TimetableWidgetExtension"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES"
launchAutomaticallySubstyle = "2">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "97C146ED1CF9000F007C117D"
BuildableName = "Runner.app"
BlueprintName = "Runner"
ReferencedContainer = "container:Runner.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+6 -3
View File
@@ -1,13 +1,16 @@
import UIKit
import Flutter import Flutter
import UIKit
@main @main
@objc class AppDelegate: FlutterAppDelegate { @objc class AppDelegate: FlutterAppDelegate, FlutterImplicitEngineDelegate {
override func application( override func application(
_ application: UIApplication, _ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool { ) -> Bool {
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions) return super.application(application, didFinishLaunchingWithOptions: launchOptions)
} }
func didInitializeImplicitFlutterEngine(_ engineBridge: FlutterImplicitEngineBridge) {
GeneratedPluginRegistrant.register(with: engineBridge.pluginRegistry)
}
} }
+83 -47
View File
@@ -1,54 +1,90 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict>
<key>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string>
<key>CADisableMinimumFrameDurationOnPhone</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Marianum Fulda</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>client</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>ShareMedia-$(PRODUCT_BUNDLE_IDENTIFIER)</string>
</array>
</dict>
</array>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>Um Fotos direkt aus der App aufnehmen und teilen zu können wird Zugriff auf die Kamera benötigt.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Um Medien mit anderen zu teilen wird Zugriff zu deine Dateien benötigt.</string>
<key>UIApplicationSceneManifest</key>
<dict> <dict>
<key>CADisableMinimumFrameDurationOnPhone</key> <key>UIApplicationSupportsMultipleScenes</key>
<true/>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Marianum Fulda</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>client</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSPhotoLibraryUsageDescription</key>
<string>Um Medien mit anderen zu teilen wird Zugriff zu deine Dateien benötigt.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/> <false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneClassName</key>
<string>UIWindowScene</string>
<key>UISceneConfigurationName</key>
<string>flutter</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict> </dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>fetch</string>
<string>remote-notification</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIStatusBarHidden</key>
<false/>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist> </plist>
+5
View File
@@ -4,5 +4,10 @@
<dict> <dict>
<key>aps-environment</key> <key>aps-environment</key>
<string>development</string> <string>development</string>
<key>com.apple.security.application-groups</key>
<array>
<string>group.eu.mhsl.marianum.mobile.client.widget</string>
<string>group.eu.mhsl.marianum.mobile.client.share</string>
</array>
</dict> </dict>
</plist> </plist>
+33
View File
@@ -0,0 +1,33 @@
import Flutter
import UIKit
import receive_sharing_intent
// FlutterSceneDelegate has a fallback that forwards URL events to plugins
// registered via addApplicationDelegate, but the fallback is best-effort and
// has not always fired in our setup. This subclass forwards URLs explicitly
// to receive_sharing_intent so cold-start and warm shares both reach Dart.
class SceneDelegate: FlutterSceneDelegate {
override func scene(
_ scene: UIScene,
willConnectTo session: UISceneSession,
options connectionOptions: UIScene.ConnectionOptions
) {
super.scene(scene, willConnectTo: session, options: connectionOptions)
for context in connectionOptions.urlContexts {
_ = SwiftReceiveSharingIntentPlugin.instance.application(
UIApplication.shared,
didFinishLaunchingWithOptions: [UIApplication.LaunchOptionsKey.url: context.url]
)
}
}
override func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
for context in URLContexts {
_ = SwiftReceiveSharingIntentPlugin.instance.application(
UIApplication.shared,
open: context.url,
options: [:]
)
}
}
}
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="j1y-V4-xli">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Share View Controller-->
<scene sceneID="ceB-am-kn3">
<objects>
<viewController id="j1y-V4-xli" customClass="ShareViewController" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" opaque="NO" contentMode="scaleToFill" id="wbc-yd-nQP">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="0.0" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="1Xd-am-t49"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="CEy-Cv-SGf" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>
+54
View File
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>AppGroupId</key>
<string>$(CUSTOM_GROUP_ID)</string>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>Marianum Fulda</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(FLUTTER_BUILD_NAME)</string>
<key>CFBundleVersion</key>
<string>$(FLUTTER_BUILD_NUMBER)</string>
<key>NSExtension</key>
<dict>
<key>NSExtensionAttributes</key>
<dict>
<key>PHSupportedMediaTypes</key>
<array>
<string>Video</string>
<string>Image</string>
</array>
<key>NSExtensionActivationRule</key>
<dict>
<key>NSExtensionActivationSupportsText</key>
<true/>
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
<integer>1</integer>
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
<integer>10</integer>
<key>NSExtensionActivationSupportsMovieWithMaxCount</key>
<integer>10</integer>
<key>NSExtensionActivationSupportsFileWithMaxCount</key>
<integer>10</integer>
</dict>
</dict>
<key>NSExtensionMainStoryboard</key>
<string>MainInterface</string>
<key>NSExtensionPointIdentifier</key>
<string>com.apple.share-services</string>
</dict>
</dict>
</plist>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>group.eu.mhsl.marianum.mobile.client.share</string>
</array>
</dict>
</plist>
@@ -0,0 +1,240 @@
import UIKit
import UniformTypeIdentifiers
import AVFoundation
// Datenmodell muss byte-für-byte zu dem passen, was
// SwiftReceiveSharingIntentPlugin auf der Host-App-Seite decodiert.
private enum SharedMediaType: String, Codable {
case image, video, text, file, url
}
private struct SharedMediaFile: Codable {
let path: String
let mimeType: String?
let thumbnail: String?
let duration: Double?
let message: String?
let type: SharedMediaType
}
final class ShareViewController: UIViewController {
// Schlüssel sind die, die das Plugin liest.
private let userDefaultsKey = "ShareKey"
private let userDefaultsMessageKey = "ShareMessageKey"
private let urlSchemePrefix = "ShareMedia"
private var appGroupId = ""
private var hostBundleId = ""
override func viewDidLoad() {
super.viewDidLoad()
resolveIds()
setupPlaceholderUI()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
processAttachments()
}
private func resolveIds() {
let extBundleId = Bundle.main.bundleIdentifier ?? ""
if let lastDot = extBundleId.lastIndex(of: ".") {
hostBundleId = String(extBundleId[..<lastDot])
}
let custom = Bundle.main.object(forInfoDictionaryKey: "AppGroupId") as? String
if let custom, !custom.isEmpty, !custom.contains("$(") {
appGroupId = custom
} else {
appGroupId = "group.\(hostBundleId)"
}
}
private func setupPlaceholderUI() {
view.backgroundColor = .systemBackground
let spinner = UIActivityIndicatorView(style: .medium)
spinner.startAnimating()
let label = UILabel()
label.text = "Wird geteilt …"
label.font = .preferredFont(forTextStyle: .footnote)
label.textColor = .secondaryLabel
let stack = UIStackView(arrangedSubviews: [spinner, label])
stack.axis = .vertical
stack.alignment = .center
stack.spacing = 8
stack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(stack)
NSLayoutConstraint.activate([
stack.centerXAnchor.constraint(equalTo: view.centerXAnchor),
stack.centerYAnchor.constraint(equalTo: view.centerYAnchor),
])
}
private func processAttachments() {
let attachments: [NSItemProvider] = (extensionContext?.inputItems ?? [])
.compactMap { $0 as? NSExtensionItem }
.flatMap { $0.attachments ?? [] }
guard !attachments.isEmpty else {
finish()
return
}
let group = DispatchGroup()
var collected: [SharedMediaFile] = []
let lock = NSLock()
for provider in attachments {
group.enter()
handle(provider: provider) { file in
if let f = file {
lock.lock(); collected.append(f); lock.unlock()
}
group.leave()
}
}
group.notify(queue: .main) { [weak self] in
self?.saveAndRedirect(items: collected)
}
}
// Reihenfolge entspricht SharedMediaType.allCases im Plugin
// spezifische Typen (image, video) vor generischen (file, url).
private func handle(provider: NSItemProvider,
completion: @escaping (SharedMediaFile?) -> Void) {
let order: [(String, SharedMediaType)] = [
(UTType.image.identifier, .image),
(UTType.movie.identifier, .video),
(UTType.text.identifier, .text),
(UTType.fileURL.identifier, .file),
(UTType.url.identifier, .url),
(UTType.data.identifier, .file),
]
for (typeId, kind) in order {
if provider.hasItemConformingToTypeIdentifier(typeId) {
provider.loadItem(forTypeIdentifier: typeId) { [weak self] data, error in
guard let self else { completion(nil); return }
if error != nil { completion(nil); return }
completion(self.toSharedFile(data: data, kind: kind))
}
return
}
}
completion(nil)
}
private func toSharedFile(data: Any?, kind: SharedMediaType) -> SharedMediaFile? {
switch kind {
case .text:
guard let s = data as? String else { return nil }
return SharedMediaFile(path: s, mimeType: "text/plain",
thumbnail: nil, duration: nil, message: nil, type: .text)
case .url:
guard let u = data as? URL else { return nil }
return SharedMediaFile(path: u.absoluteString, mimeType: nil,
thumbnail: nil, duration: nil, message: nil, type: .url)
case .image:
if let u = data as? URL, let dst = copyIntoAppGroup(src: u) {
return SharedMediaFile(path: pathString(for: dst), mimeType: mime(for: u),
thumbnail: nil, duration: nil, message: nil, type: .image)
}
if let img = data as? UIImage, let dst = writePng(image: img) {
return SharedMediaFile(path: pathString(for: dst), mimeType: "image/png",
thumbnail: nil, duration: nil, message: nil, type: .image)
}
return nil
case .video:
guard let u = data as? URL, let dst = copyIntoAppGroup(src: u) else { return nil }
return SharedMediaFile(path: pathString(for: dst), mimeType: mime(for: u),
thumbnail: nil, duration: videoDurationMs(url: u),
message: nil, type: .video)
case .file:
guard let u = data as? URL, let dst = copyIntoAppGroup(src: u) else { return nil }
return SharedMediaFile(path: pathString(for: dst), mimeType: mime(for: u),
thumbnail: nil, duration: nil, message: nil, type: .file)
}
}
private func copyIntoAppGroup(src: URL) -> URL? {
guard let container = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: appGroupId) else {
return nil
}
let name = src.lastPathComponent.isEmpty ? UUID().uuidString : src.lastPathComponent
let dst = container.appendingPathComponent(name)
do {
if FileManager.default.fileExists(atPath: dst.path) {
try FileManager.default.removeItem(at: dst)
}
try FileManager.default.copyItem(at: src, to: dst)
return dst
} catch {
return nil
}
}
private func writePng(image: UIImage) -> URL? {
guard let container = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: appGroupId),
let data = image.pngData() else { return nil }
let dst = container.appendingPathComponent("\(UUID().uuidString).png")
return (try? data.write(to: dst)) != nil ? dst : nil
}
// Das Plugin macht `path.replacingOccurrences(of: "file://", with: "")`,
// also liefern wir absoluteString mit Prozent-Decoding selbes Format wie
// im Original-RSIShareViewController.
private func pathString(for url: URL) -> String {
url.absoluteString.removingPercentEncoding ?? url.absoluteString
}
private func mime(for url: URL) -> String? {
UTType(filenameExtension: url.pathExtension)?.preferredMIMEType
}
private func videoDurationMs(url: URL) -> Double {
(CMTimeGetSeconds(AVURLAsset(url: url).duration) * 1000).rounded()
}
private func saveAndRedirect(items: [SharedMediaFile]) {
guard !items.isEmpty else {
finish()
return
}
let defaults = UserDefaults(suiteName: appGroupId)
guard let encoded = try? JSONEncoder().encode(items) else {
finish()
return
}
defaults?.set(encoded, forKey: userDefaultsKey)
defaults?.removeObject(forKey: userDefaultsMessageKey)
let urlStr = "\(urlSchemePrefix)-\(hostBundleId):share"
guard let url = URL(string: urlStr) else {
finish()
return
}
// Apple-DTS says Share Extensions are not officially allowed to open
// URLs. Both `extensionContext.open` and the responder-chain trick
// succeed in some iOS versions and fail silently in others, so we fire
// both in parallel and let whichever Apple is honouring this release
// win the race.
extensionContext?.open(url, completionHandler: nil)
var responder: UIResponder? = self
while responder != nil {
if let app = responder as? UIApplication {
app.open(url, options: [:], completionHandler: nil)
break
}
responder = responder?.next
}
// Brief window so the open request reaches the system before we tear
// the extension down.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
self?.finish()
}
}
private func finish() {
extensionContext?.completeRequest(returningItems: [], completionHandler: nil)
}
}
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "marianum_m_white.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
@@ -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

Some files were not shown because too many files have changed in this diff Show More