mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-22 01:20:47 +02:00
fix(ui): improve adaptive phone and tablet layouts
This commit is contained in:
@@ -3,6 +3,7 @@ import 'dart:ui';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotiflac_android/theme/app_tokens.dart';
|
||||
import 'package:spotiflac_android/theme/cover_palette.dart';
|
||||
import 'package:spotiflac_android/utils/adaptive_layout.dart';
|
||||
|
||||
/// Collapsing album-detail header shared by the album, local-album, and
|
||||
/// downloaded-album screens: full-bleed [background] (optionally blurred and
|
||||
@@ -91,6 +92,11 @@ class AlbumDetailHeader extends StatelessWidget {
|
||||
|
||||
Widget _buildAppBar(BuildContext context, ColorScheme headerScheme) {
|
||||
final tokens = context.tokens;
|
||||
// iOS does not add horizontal safe-area padding in portrait. Give toolbar
|
||||
// controls and header content an explicit inset so circular actions do not
|
||||
// sit against the glass edge on either iPhone or iPad. Android retains its
|
||||
// existing spacing.
|
||||
final iosEdgeInset = detailHeaderEdgeInset(context);
|
||||
// Scrim and gradient are drawn from the palette surface instead of black,
|
||||
// so a light theme gets a light header with dark text and a dark theme
|
||||
// keeps the familiar dark treatment — both tinted by the artwork.
|
||||
@@ -157,8 +163,8 @@ class AlbumDetailHeader extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: 20,
|
||||
right: 20,
|
||||
left: 20 + iosEdgeInset,
|
||||
right: 20 + iosEdgeInset,
|
||||
bottom: 40,
|
||||
child: AnimatedOpacity(
|
||||
duration: tokens.motionFast,
|
||||
@@ -235,20 +241,25 @@ class AlbumDetailHeader extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
leading:
|
||||
leading ??
|
||||
IconButton.filledTonal(
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
style: IconButton.styleFrom(
|
||||
minimumSize: Size.square(tokens.minTouchTarget),
|
||||
backgroundColor: headerScheme.surfaceContainerHigh.withValues(
|
||||
alpha: 0.75,
|
||||
leadingWidth: kToolbarHeight + iosEdgeInset,
|
||||
leading: Padding(
|
||||
padding: EdgeInsets.only(left: iosEdgeInset),
|
||||
child:
|
||||
leading ??
|
||||
IconButton.filledTonal(
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
style: IconButton.styleFrom(
|
||||
minimumSize: Size.square(tokens.minTouchTarget),
|
||||
backgroundColor: headerScheme.surfaceContainerHigh.withValues(
|
||||
alpha: 0.75,
|
||||
),
|
||||
foregroundColor: headerScheme.onSurfaceVariant,
|
||||
),
|
||||
foregroundColor: headerScheme.onSurfaceVariant,
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
),
|
||||
actionsPadding: EdgeInsets.only(right: iosEdgeInset),
|
||||
actions: appBarActions,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:spotiflac_android/theme/app_tokens.dart';
|
||||
import 'package:spotiflac_android/utils/adaptive_layout.dart';
|
||||
import 'package:spotiflac_android/utils/app_bar_layout.dart';
|
||||
|
||||
/// The collapsing header used by every top-level tab and every settings-style
|
||||
@@ -44,6 +45,7 @@ class AppSliverHeader extends StatelessWidget {
|
||||
final topPadding = normalizedHeaderTopPadding(context);
|
||||
final maxHeight = tokens.headerExpandedHeight + topPadding;
|
||||
final minHeight = kToolbarHeight + topPadding;
|
||||
final edgeInset = detailHeaderEdgeInset(context);
|
||||
|
||||
return SliverAppBar(
|
||||
expandedHeight: maxHeight,
|
||||
@@ -53,14 +55,22 @@ class AppSliverHeader extends StatelessWidget {
|
||||
backgroundColor: colorScheme.surface,
|
||||
surfaceTintColor: Colors.transparent,
|
||||
automaticallyImplyLeading: false,
|
||||
leadingWidth: _showLeading ? kToolbarHeight + edgeInset : null,
|
||||
leading: _showLeading
|
||||
? leading ??
|
||||
IconButton(
|
||||
tooltip: MaterialLocalizations.of(context).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
)
|
||||
? Padding(
|
||||
padding: EdgeInsets.only(left: edgeInset),
|
||||
child:
|
||||
leading ??
|
||||
IconButton(
|
||||
tooltip: MaterialLocalizations.of(
|
||||
context,
|
||||
).backButtonTooltip,
|
||||
icon: const Icon(Icons.arrow_back),
|
||||
onPressed: () => Navigator.pop(context),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
actionsPadding: EdgeInsets.only(right: edgeInset),
|
||||
actions: actions,
|
||||
flexibleSpace: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
@@ -68,8 +78,9 @@ class AppSliverHeader extends StatelessWidget {
|
||||
((constraints.maxHeight - minHeight) / (maxHeight - minHeight))
|
||||
.clamp(0.0, 1.0);
|
||||
final leftPadding = _showLeading
|
||||
? _leadingClearance -
|
||||
((_leadingClearance - _contentMargin) * expandRatio)
|
||||
? (_leadingClearance + edgeInset) -
|
||||
(((_leadingClearance + edgeInset) - _contentMargin) *
|
||||
expandRatio)
|
||||
: _contentMargin;
|
||||
final fontSize =
|
||||
tokens.headerCollapsedTitleSize +
|
||||
@@ -78,6 +89,7 @@ class AppSliverHeader extends StatelessWidget {
|
||||
expandRatio;
|
||||
|
||||
return FlexibleSpaceBar(
|
||||
centerTitle: false,
|
||||
expandedTitleScale: 1.0,
|
||||
titlePadding: EdgeInsets.only(
|
||||
left: leftPadding,
|
||||
|
||||
@@ -13,7 +13,6 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
|
||||
final String? coverUrl;
|
||||
final void Function(String quality, String service) onSelect;
|
||||
final String? recommendedService;
|
||||
final ScrollController? scrollController;
|
||||
|
||||
const DownloadServicePicker({
|
||||
super.key,
|
||||
@@ -22,7 +21,6 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
|
||||
this.coverUrl,
|
||||
required this.onSelect,
|
||||
this.recommendedService,
|
||||
this.scrollController,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -44,16 +42,15 @@ class DownloadServicePicker extends ConsumerStatefulWidget {
|
||||
useRootNavigator: true,
|
||||
backgroundColor: colorScheme.surfaceContainerHigh,
|
||||
isScrollControlled: true,
|
||||
enableDrag: false,
|
||||
builder: (context) => AppDraggableSheet(
|
||||
builder: (context, scrollController) => DownloadServicePicker(
|
||||
trackName: trackName,
|
||||
artistName: artistName,
|
||||
coverUrl: coverUrl,
|
||||
onSelect: onSelect,
|
||||
recommendedService: recommendedService,
|
||||
scrollController: scrollController,
|
||||
),
|
||||
constraints: BoxConstraints(
|
||||
maxHeight: MediaQuery.sizeOf(context).height * 0.88,
|
||||
),
|
||||
builder: (context) => DownloadServicePicker(
|
||||
trackName: trackName,
|
||||
artistName: artistName,
|
||||
coverUrl: coverUrl,
|
||||
onSelect: onSelect,
|
||||
recommendedService: recommendedService,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -126,7 +123,6 @@ class _DownloadServicePickerState extends ConsumerState<DownloadServicePicker> {
|
||||
|
||||
return SafeArea(
|
||||
child: SingleChildScrollView(
|
||||
controller: widget.scrollController,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
||||
Reference in New Issue
Block a user