Skip to content

Commit

Permalink
feat: Add PlatformWidgetBuilder. (#319)
Browse files Browse the repository at this point in the history
* feat: Add PlatformWidgetBuilder.

This widget abstracts the functionality to detect the platform
used by the user. Related to #139.

* feat: Add basic test for PlatformWidgetBuilder.

* chore: Spell check.

* refactor: Switch name from `PlatformWidgetBuilder` to `PlatformAwareBuilder`.

* refactor: Use platform identifiers to select proper data to be used.

* refactor: Use `PlatformKey` enum for platform identifiers.

* docs: Add `PlatformAwareBuilder` documentation.

* docs: Improve `PlatformAwareBuilder` description.
  • Loading branch information
coire1 authored Mar 21, 2024
1 parent ed394c7 commit 40046a3
Show file tree
Hide file tree
Showing 9 changed files with 177 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export 'platform/catalyst_platform.dart';
export 'platform_aware_builder/platform_aware_builder.dart';
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import 'dart:io';

import 'package:catalyst_voices_shared/src/platform/platform_key.dart';

final class CatalystPlatform {
static bool get isAndroid => Platform.isAndroid;

Expand All @@ -23,4 +25,18 @@ final class CatalystPlatform {
static bool get isWebDesktop => false;

static bool get isWindows => Platform.isWindows;

static Map<PlatformKey, bool> get identifiers => {
PlatformKey.android: isAndroid,
PlatformKey.desktop: isDesktop,
PlatformKey.fuchsia: isFuchsia,
PlatformKey.iOS: isIOS,
PlatformKey.linux: isLinux,
PlatformKey.macOS: isMacOS,
PlatformKey.mobile: isMobile,
PlatformKey.mobileWeb: isMobileWeb,
PlatformKey.web: isWeb,
PlatformKey.webDesktop: isWebDesktop,
PlatformKey.windows: isWindows,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
enum PlatformKey {
android,
desktop,
fuchsia,
iOS,
linux,
macOS,
mobile,
mobileWeb,
web,
webDesktop,
windows,
other,
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'package:catalyst_voices_shared/src/platform/platform_key.dart';

final class CatalystPlatform {
static bool get isAndroid {
throw UnimplementedError('Stub CatalystPlatform');
Expand Down Expand Up @@ -43,5 +45,9 @@ final class CatalystPlatform {
throw UnimplementedError('Stub CatalystPlatform');
}

static Map<PlatformKey, bool> get identifiers {
throw UnimplementedError('Stub CatalystPlatform');
}

const CatalystPlatform._();
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:catalyst_voices_shared/src/platform/platform_key.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:web/web.dart';

Expand Down Expand Up @@ -33,6 +34,20 @@ final class CatalystPlatform {
];
return mobileIdentifiers.any(userAgent.contains);
}

static Map<PlatformKey, bool> get identifiers => {
PlatformKey.android: isAndroid,
PlatformKey.desktop: isDesktop,
PlatformKey.fuchsia: isFuchsia,
PlatformKey.iOS: isIOS,
PlatformKey.linux: isLinux,
PlatformKey.macOS: isMacOS,
PlatformKey.mobile: isMobile,
PlatformKey.mobileWeb: isMobileWeb,
PlatformKey.web: isWeb,
PlatformKey.webDesktop: isWebDesktop,
PlatformKey.windows: isWindows,
};

const CatalystPlatform._();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import 'package:catalyst_voices_shared/src/platform/catalyst_platform.dart';
import 'package:catalyst_voices_shared/src/platform/platform_key.dart';
import 'package:flutter/widgets.dart';

// A [PlatformAwareBuilder] is a StatelessWidget that is aware of the current
// platform.
//
// This is an abstract widget that has a required argument [builder] that can
// consume platform-specific data automatically based on platform that is
// detected.
//
// The platform detection happens in [CatalystPlatform].
//
// The widget accepts an argument for each specific platform defined in
// [PlatformKey]. The platform specific [data] is selected when two conditions
// are verified at the same time:
// - the platform is detected
// - the platform-specific argument is present
// In case those conditions are not verified the [other] argument is used (and
// because of this it is required).
// The type of the platform specific data is generic.
//
// A simple usage is to render a string based on the platform:
//
// ```dart
// PlatformWidgetBuilder<String>(
// android: 'This is an Android platform.',
// other: 'This is an other platform.',
// builder: (context, title) => Text(title!),
// );
// ```
//
// or to have a specific Padding:
//
// ```dart
// PlatformWidgetBuilder<EdgeInsetsGeometry>(
// android: EdgeInsets.all(10.0),
// other: EdgeInsets.all(40.0),
// builder: (context, padding) => Padding(
// padding: padding,
// child: Text('This is an example.')
// ),
// );
// ```

class PlatformAwareBuilder<T> extends StatelessWidget {
final Widget Function(BuildContext context, T? data) builder;
final Map<PlatformKey, T?> _platformData;

PlatformAwareBuilder({
super.key,
required this.builder,
T? android,
T? desktop,
T? fuchsia,
T? iOS,
T? linux,
T? macOS,
T? mobile,
T? mobileWeb,
T? web,
T? webDesktop,
T? windows,
required T other,
}) : _platformData = {
PlatformKey.android: android,
PlatformKey.desktop: desktop,
PlatformKey.fuchsia: fuchsia,
PlatformKey.iOS: iOS,
PlatformKey.linux: linux,
PlatformKey.macOS: macOS,
PlatformKey.mobile: mobile,
PlatformKey.mobileWeb: mobileWeb,
PlatformKey.web: web,
PlatformKey.webDesktop: webDesktop,
PlatformKey.windows: windows,
PlatformKey.other: other,
};

@override
Widget build(BuildContext context) {
return builder(context, _getPlatformData());
}

T _getPlatformData() {
final currentPlatformKey = CatalystPlatform.identifiers.entries
.firstWhere(
// We select the platform only if the platform-specific data
// is also present.
(entry) => entry.value && (_platformData[entry.key] != null),
orElse: () => const MapEntry(PlatformKey.other, true),
)
.key;
return _platformData[currentPlatformKey]!;
}
}
2 changes: 2 additions & 0 deletions catalyst_voices/packages/catalyst_voices_shared/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ dependencies:
dev_dependencies:
catalyst_analysis:
path: ../../../catalyst_voices_packages/catalyst_analysis
flutter_test:
sdk: flutter
test: ^1.24.9

Original file line number Diff line number Diff line change
@@ -1 +1 @@
void main() {}
export 'platform_aware_builder/platform_aware_builder_test.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'package:catalyst_voices_shared/src/catalyst_voices_shared.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

void main() {

Widget buildApp() => MaterialApp(
home: Scaffold(
body: PlatformAwareBuilder<String>(
other: 'other',
builder: (context, platformData) => Text(platformData!),
),
),
);

group('Test platform detection', () {
testWidgets('PlatformWidgetBuilder fallbacks to other', (tester) async {
await tester.pumpWidget(buildApp());
// Verify the Widget renders properly
expect(find.byType(Text), findsOneWidget);
// Check the output contains the platform that was tested.
expect(find.text('other'), findsOneWidget);

});
});
}

0 comments on commit 40046a3

Please sign in to comment.