Shared Flutter library for the QuantumPhysique apps, such as trale: theme, preferences, notifier, widgets, settings pages and changelog generator.
It is built for these apps, not as a general-purpose package. It is not on pub.dev, and before 1.0 every minor release may break the API; the release notes say what an app has to change. The library is licensed under the AGPLv3+, so an app that includes it falls under the AGPLv3 as well.
- App shell:
QPAppshows the app once preferences, notifications and the app's own setup are ready, opens the app's onboarding screen, if it has one, until the app marks it as seen, and flags the changelog on the first start after an update. - State:
QPPreferencesandQPNotifier, the base classes for the app's settings and state, with theme, language, onboarding, date format, first day of the week and reminder settings built in. - Theme:
QPTheme, a Material 3 theme with built-in palettes, the system colours where the platform reports them, contrast levels and scheme variants, plus the shared paddings, radii and shapes. - Reminders:
QPNotificationServiceschedules notifications;QPReminderRegistrykeeps track of the armed ones across restarts. - Pages:
QPSettingsOverviewPage,QPThemeSettingsPage,QPLanguageSettingsPage,QPNotificationsSettingsPage,QPAboutPage,QPFAQPage,QPSplash, andQPHomePagewith its bottom navigation. - Widgets:
QPWidgetGroupwith theQPGrouped*tiles,QPBentoCardandQPBentoGrid,QPDialog,QPButtonGroup,QPFilterChip,QPSelectionCarousel,M3EFloatingActionButton, and the entrance animationsQPFadeInEffectandQPAnimateInEffect. - Changelog: a generator that turns the app's
CHANGELOG.mdinto Dart, andQPChangelogContentto show it. - Fonts: RobotoFlex and RobotoMono.
The package needs Flutter 3.47.1 or newer. Every release is a git tag
vX.Y.Z, and every fix or feature merged in between a preview tag
vX.Y.Z-dev.N. pub finds both through tag_pattern, and reads that key only
when the lower bound of the app's environment: sdk: is 3.9 or higher.
dependencies:
material_ui: ^1.8.0
quantumphysique:
git:
url: https://github.com/QuantumPhysique/quantumphysique.git
tag_pattern: v{{version}}
version: ^0.1.0
dependency_overrides:
phosphor_flutter:
git:
url: https://github.com/subarnaPdl/phosphor_icons.git
ref: 514f0a883571c4453dbd6ee3041d1dcba4fb8fc7material_ui is Flutter's Material library, published as its own package.
The app imports it directly, since the package does not re-export it.
The override is needed because phosphor_flutter 2.1.0 does not compile
against Flutter 3.47, and pub ignores the overrides of a dependency. Drop it
once upstream releases a version that compiles.
version: |
Takes |
|---|---|
^0.2.0 |
the newest 0.2.x; before 1.0 that is fixes only, features and breaking changes come as 0.3.0 |
0.2.1 |
exactly 0.2.1 |
^0.3.0-dev.1 |
the newest preview of 0.3.0, and 0.3.x releases once they exist |
pub prefers a release over a preview whenever both match, so to keep following previews after a release, raise the lower bound to the next preview. Ship only releases: previews carry no compatibility promise.
pubspec.lock pins the resolved commit, so flutter pub get keeps it.
flutter pub upgrade quantumphysique moves to the newest version within the
constraint; flutter pub upgrade --major-versions quantumphysique also takes
the next minor release before 1.0, or the next major from 1.0 on. The release
notes list what to change for it.
Everything is exported from package:quantumphysique/quantumphysique.dart.
An app subclasses QPPreferences and QPNotifier and starts through QPApp:
import 'package:material_ui/material_ui.dart';
import 'package:quantumphysique/quantumphysique.dart';
class MyPreferences extends QPPreferences {
MyPreferences() : super.base();
}
class MyNotifier extends QPNotifier {
MyNotifier() : super(MyPreferences());
}
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(
QPApp<MyNotifier>(
notifier: MyNotifier(),
buildRoutes: () => <String, WidgetBuilder>{'/': (_) => const Home()},
buildStrings: (BuildContext context) =>
qpStringsFromL10n(AppLocalizations.of(context)!),
localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
AppLocalizations.delegate,
...GlobalMaterialLocalizations.delegates,
],
supportedLocales: AppLocalizations.supportedLocales,
),
);
}AppLocalizations is the app's generated localisation class and Home its
first page. GlobalMaterialLocalizations comes from material_ui; the list
that gen-l10n generates in AppLocalizations.localizationsDelegates carries
the ones from flutter_localizations instead, which material_ui does not
use. onExtraInit runs the app's own async setup, such as opening a database,
before the first frame.
expressive: true opts the app into Material 3 Expressive, which material_ui
still marks as under development. So far it restyles the icon buttons; more
components and the package's own widgets follow with later releases, which
read the switch through QPTheme.of(context)!.expressive.
The package has no translations of its own. Every string comes in through
QPStrings, which buildStrings returns for the current locale, and
QPAboutStrings, which QPAboutPage takes.
trale has both in every language: copy the qp_* keys from its
ARB files
verbatim, and qpStringsFromL10n and qpAboutStringsFromL10n from its
l10n_extension.dart.
The fields that describe the app itself, such as translateSubtitle and
reminderSubtitle, and all of QPAboutStrings come from keys of the app's
own.
Notifications stay off unless QPApp gets a notificationIcon, the name of
an Android drawable such as '@drawable/ic_notification'. The app's
AndroidManifest.xml then needs these entries, which
flutter_local_notifications does not merge on its own. Without the
receivers, every scheduled reminder is silently dropped:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<!-- inside <application> -->
<receiver
android:exported="false"
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationReceiver" />
<receiver
android:exported="false"
android:name="com.dexterous.flutterlocalnotifications.ScheduledNotificationBootReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON" />
</intent-filter>
</receiver>Without SCHEDULE_EXACT_ALARM, reminders still fire, but Android may delay
them. The plugin also needs core library desugaring, see the Gradle setup in
the flutter_local_notifications README.
The generator turns the app's CHANGELOG.md into a const Changelog. From
the app's package root:
dart run quantumphysique:generate_changelog # ../CHANGELOG.md to lib/core/changelog.g.dart
dart run quantumphysique:generate_changelog --check # exits 1 if that file is stale, for CI--changelog, --output and --part-of change the defaults. The output is a
part file, so the app needs the library it belongs to, by default
lib/core/changelog.dart:
import 'package:quantumphysique/quantumphysique.dart';
part 'changelog.g.dart';The generator reads ## [Unreleased] and ## [X.Y.Z] - YYYY-MM-DD headings
with the sections Added Features and Improvements, Bugfix,
Other Changes and API Changes Warning; anything else in a section heading,
such as an emoji, is ignored.
On the first start after an update, QPApp sets showChangelog on the
notifier. The app shows QPChangelogContent then and resets the flag.
QPAboutPage lists the whole changelog when it gets changelog.
flutter pub get --enforce-lockfile
dart format .
flutter analyze
flutter testCI runs the same checks on every pull request, with the lowest Flutter
version that pubspec.yaml allows. Pull requests go into dev and are
squash-merged, so the title is a conventional commit: it decides the next
version and becomes the line in the release notes. CI tags every merge that
releases; CLAUDE.md has the details.
To run an app against a local clone, put a pubspec_overrides.yaml next to
the app's pubspec.yaml:
dependency_overrides:
quantumphysique:
path: ../../quantumphysiqueThe path is relative to the app's pubspec.yaml. List the file in the app's
.gitignore and never commit it: no other checkout has that path, so CI and
every other build would fail.
GNU AGPLv3+. The fonts in fonts/ are under the SIL Open Font
License, in the -OFL.txt file next to each.