Nikolas Rimikis
1 year ago
10 changed files with 185 additions and 31 deletions
@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart'; |
||||
|
||||
/// Returns whether the current platform is a Cupertino one. |
||||
/// |
||||
/// This is true for both `TargetPlatform.iOS` and `TargetPlatform.macOS`. |
||||
bool isCupertino(final BuildContext context) { |
||||
final theme = Theme.of(context); |
||||
|
||||
switch (theme.platform) { |
||||
case TargetPlatform.android: |
||||
case TargetPlatform.fuchsia: |
||||
case TargetPlatform.linux: |
||||
case TargetPlatform.windows: |
||||
return false; |
||||
case TargetPlatform.iOS: |
||||
case TargetPlatform.macOS: |
||||
return true; |
||||
} |
||||
} |
@ -0,0 +1,135 @@
|
||||
import 'dart:async'; |
||||
|
||||
import 'package:flutter/cupertino.dart'; |
||||
import 'package:flutter/material.dart'; |
||||
|
||||
/// A wrapper widget that adaptively displays a [ListTile] on Material platforms |
||||
/// and a [CupertinoListTile] on Cupertino ones. |
||||
class AdaptiveListTile extends StatelessWidget { |
||||
/// Creates a new adaptive list tile. |
||||
/// |
||||
/// If supplied the [subtitle] will be displayed below the title. |
||||
const AdaptiveListTile({ |
||||
required this.title, |
||||
this.enabled = true, |
||||
this.subtitle, |
||||
this.leading, |
||||
this.trailing, |
||||
this.onTap, |
||||
super.key, |
||||
}) : additionalInfo = null; |
||||
|
||||
/// Creates a new adaptive list tile. |
||||
/// |
||||
/// If supplied the [additionalInfo] will be displayed below the title on |
||||
/// Material platforms and as a trailing widget on Cupertino ones. |
||||
const AdaptiveListTile.additionalInfo({ |
||||
required this.title, |
||||
this.enabled = true, |
||||
this.additionalInfo, |
||||
this.leading, |
||||
this.trailing, |
||||
this.onTap, |
||||
super.key, |
||||
}) : subtitle = additionalInfo; |
||||
|
||||
/// {@template neon.AdaptiveListTile.title} |
||||
/// A [title] is used to convey the central information. Usually a [Text]. |
||||
/// {@endtemplate} |
||||
final Widget title; |
||||
|
||||
/// {@template neon.AdaptiveListTile.subtitle} |
||||
/// A [subtitle] is used to display additional information. It is located |
||||
/// below [title]. Usually a [Text] widget. |
||||
final Widget? subtitle; |
||||
|
||||
/// {@template neon.AdaptiveListTile.additionalInfo} |
||||
/// Similar to [subtitle], an [additionalInfo] is used to display additional |
||||
/// information. However, instead of being displayed below [title], it is |
||||
/// displayed on the right, before [trailing]. Usually a [Text] widget. |
||||
/// |
||||
/// This is only available on Cupertino platforms. |
||||
/// {@endtemplate} |
||||
final Widget? additionalInfo; |
||||
|
||||
/// {@template neon.AdaptiveListTile.leading} |
||||
/// A widget displayed at the start of the [AdaptiveListTile]. This is |
||||
/// typically an `Icon` or an `Image`. |
||||
/// {@endtemplate} |
||||
final Widget? leading; |
||||
|
||||
/// {@template neon.AdaptiveListTile.trailing} |
||||
/// A widget displayed at the end of the [AdaptiveListTile]. |
||||
/// {@endtemplate} |
||||
final Widget? trailing; |
||||
|
||||
/// {@template neon.AdaptiveListTile.onTap} |
||||
/// The [onTap] function is called when a user taps on the[AdaptiveListTile]. |
||||
/// If left `null`, the [AdaptiveListTile] will not react to taps. |
||||
/// |
||||
/// If the platform is a Cupertino one and this is a `Future<void> Function()`, |
||||
/// then the [AdaptiveListTile] remains activated until the returned future is |
||||
/// awaited. This is according to iOS behavior. |
||||
/// However, if this function is a `void Function()`, then the tile is active |
||||
/// only for the duration of invocation. |
||||
/// {@endtemplate} |
||||
final FutureOr<void> Function()? onTap; |
||||
|
||||
/// {@template neon.AdaptiveListTile.enabled} |
||||
/// Whether this list tile is interactive. |
||||
/// |
||||
/// If false, this list tile is styled with the disabled color from the |
||||
/// current [Theme] and the [onTap] callback is inoperative. |
||||
/// {@endtemplate} |
||||
final bool enabled; |
||||
|
||||
@override |
||||
Widget build(final BuildContext context) { |
||||
final theme = Theme.of(context); |
||||
|
||||
switch (theme.platform) { |
||||
case TargetPlatform.android: |
||||
case TargetPlatform.fuchsia: |
||||
case TargetPlatform.linux: |
||||
case TargetPlatform.windows: |
||||
return ListTile( |
||||
title: title, |
||||
subtitle: subtitle, |
||||
leading: leading, |
||||
trailing: trailing, |
||||
onTap: onTap, |
||||
enabled: enabled, |
||||
); |
||||
case TargetPlatform.iOS: |
||||
case TargetPlatform.macOS: |
||||
final tile = CupertinoListTile( |
||||
title: title, |
||||
subtitle: additionalInfo == null ? subtitle : null, |
||||
additionalInfo: additionalInfo, |
||||
leading: leading, |
||||
trailing: trailing, |
||||
onTap: enabled ? onTap : null, |
||||
); |
||||
|
||||
if (!enabled) { |
||||
var data = CupertinoTheme.of(context); |
||||
data = data.copyWith( |
||||
textTheme: data.resolveFrom(context).textTheme.copyWith( |
||||
textStyle: data.textTheme.textStyle.merge( |
||||
TextStyle( |
||||
color: theme.disabledColor, |
||||
), |
||||
), |
||||
), |
||||
); |
||||
|
||||
return CupertinoTheme( |
||||
data: data, |
||||
child: tile, |
||||
); |
||||
} |
||||
|
||||
return tile; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue