| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // Acknowledgements page
- //
- // Various code from:
- // https://github.com/flutter/flutter/blob/efb1346767e67d2577461baf671eb2d5d2c4bb90/packages/flutter/lib/src/material/about.dart
- import 'package:flutter/foundation.dart';
- import 'package:flutter/widgets.dart';
- import 'package:flutter/material.dart'
- show
- CircularProgressIndicator,
- Divider,
- ListTile,
- Material,
- MaterialPageRoute,
- Theme;
- import '../ui/adaptive.dart' show AppScaffold;
- import '../l10n/app_localizations.dart';
- class AcknowledgementsPage extends StatefulWidget {
- const AcknowledgementsPage({
- super.key,
- });
- @override
- State<AcknowledgementsPage> createState() => _AcknowledgementsPageState();
- }
- /// Acknowledgements page for used libraries.
- class _AcknowledgementsPageState extends State<AcknowledgementsPage> {
- // Adapted from flutter/flutter
- final Future<_LicenseData> licenses = LicenseRegistry.licenses
- .fold<_LicenseData>(
- _LicenseData(),
- (_LicenseData prev, LicenseEntry license) => prev..addLicense(license),
- )
- .then((_LicenseData licenseData) => licenseData..sortPackages());
- @override
- Widget build(BuildContext context) {
- return AppScaffold(
- title: Text(AppLocalizations.of(context)!.licenses),
- body: FutureBuilder<_LicenseData>(
- future: licenses,
- builder: (BuildContext context, AsyncSnapshot<_LicenseData> snapshot) {
- return LayoutBuilder(
- key: ValueKey<ConnectionState>(snapshot.connectionState),
- builder: (BuildContext context, BoxConstraints constraints) {
- switch (snapshot.connectionState) {
- case ConnectionState.done:
- if (snapshot.hasError) {
- return Center(child: Text(snapshot.error.toString()));
- }
- return Material(
- child: ListView.separated(
- itemCount: snapshot.data!.count(),
- separatorBuilder: (BuildContext context, int index) =>
- const SizedBox(height: 0, width: 0),
- itemBuilder: (BuildContext context, int index) {
- return ListTile(
- dense: true,
- title: Text(snapshot.data!.getTitle(index)),
- onTap: () {
- Navigator.of(context).push(
- MaterialPageRoute(
- builder: (context) => FullScreenLicense(
- snapshot.data!.getTitle(index),
- snapshot.data!.getLicenses(index),
- ),
- ),
- );
- },
- );
- },
- ),
- );
- case ConnectionState.none:
- case ConnectionState.active:
- case ConnectionState.waiting:
- return Material(
- color: Theme.of(context).cardColor,
- child: const Center(child: CircularProgressIndicator()),
- );
- }
- },
- );
- },
- ),
- );
- }
- }
- /// Full screen license widget
- class FullScreenLicense extends StatelessWidget {
- /// The name
- final String title;
- /// License
- final List<LicenseEntry> licenseEntries;
- const FullScreenLicense(this.title, this.licenseEntries, {super.key});
- @override
- Widget build(BuildContext context) {
- List<Widget> licenses = <Widget>[];
- for (var (index, licenseEntry) in licenseEntries.indexed) {
- if (index != 0) {
- licenses.add(const Divider());
- }
- licenses.addAll(licenseEntry.paragraphs.map((p) {
- // Adapted from flutter/flutter
- if (p.indent == LicenseParagraph.centeredIndent) {
- return Padding(
- padding: const EdgeInsets.only(top: 16.0),
- child: Text(
- p.text,
- style: const TextStyle(fontWeight: FontWeight.bold),
- textAlign: TextAlign.center,
- ),
- );
- } else {
- return Padding(
- padding:
- EdgeInsetsDirectional.only(top: 8.0, start: 16.0 * p.indent),
- child: Text(p.text),
- );
- }
- }));
- }
- return AppScaffold(
- title: Text(title),
- body: Material(
- child: SingleChildScrollView(
- child: Padding(
- padding: const EdgeInsets.only(left: 12, right: 12, bottom: 12),
- child: Column(children: licenses),
- ),
- ),
- ),
- );
- }
- }
- /// Adapted from flutter/flutter
- /// With renames and addition of helper methods.
- ///
- /// This is a collection of licenses and the packages to which they apply.
- /// [_packageLicenseBindings] records the m+:n+ relationship between the license
- /// and packages as a map of package names to license indexes.
- class _LicenseData {
- final List<LicenseEntry> _licenses = <LicenseEntry>[];
- final Map<String, List<int>> _packageLicenseBindings = <String, List<int>>{};
- final List<String> _packages = <String>[];
- // Special treatment for the first package since it should be the package
- // for delivered application.
- String? firstPackage;
- void addLicense(LicenseEntry entry) {
- // Before the license can be added, we must first record the packages to
- // which it belongs.
- for (final String package in entry.packages) {
- _addPackage(package);
- // Bind this license to the package using the next index value. This
- // creates a contract that this license must be inserted at this same
- // index value.
- _packageLicenseBindings[package]!.add(_licenses.length);
- }
- _licenses.add(entry); // Completion of the contract above.
- }
- /// Add a package and initialize package license binding. This is a no-op if
- /// the package has been seen before.
- void _addPackage(String package) {
- if (!_packageLicenseBindings.containsKey(package)) {
- _packageLicenseBindings[package] = <int>[];
- firstPackage ??= package;
- _packages.add(package);
- }
- }
- /// Sort the packages using some comparison method, or by the default manner,
- /// which is to put the application package first, followed by every other
- /// package in case-insensitive alphabetical order.
- void sortPackages([int Function(String a, String b)? compare]) {
- _packages.sort(compare ??
- (String a, String b) {
- // Based on how LicenseRegistry currently behaves, the first package
- // returned is the end user application license. This should be
- // presented first in the list. So here we make sure that first package
- // remains at the front regardless of alphabetical sorting.
- if (a == firstPackage) {
- return -1;
- }
- if (b == firstPackage) {
- return 1;
- }
- return a.toLowerCase().compareTo(b.toLowerCase());
- });
- }
- int count() {
- return _packages.length;
- }
- String getTitle(int index) {
- return _packages[index];
- }
- List<LicenseEntry> getLicenses(int index) {
- var package = _packages[index];
- return _getLicensesForPackage(package);
- }
- List<LicenseEntry> _getLicensesForPackage(String package) {
- var bindings = _packageLicenseBindings[package]!;
- return bindings.map((b) => _licenses[b]).toList();
- }
- }
|