96 lines
3.1 KiB
Dart
96 lines
3.1 KiB
Dart
/*
|
|
* Copyright (c) 2024-2026 Fabian Freund.
|
|
*
|
|
* This file is part of WebLibre
|
|
* (see https://weblibre.eu).
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
import 'package:flutter/material.dart';
|
|
|
|
class SlidingPillToggle extends StatelessWidget {
|
|
final int selectedIndex;
|
|
final List<String> labels;
|
|
final ValueChanged<int> onChanged;
|
|
|
|
const SlidingPillToggle({
|
|
super.key,
|
|
required this.selectedIndex,
|
|
required this.labels,
|
|
required this.onChanged,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final theme = Theme.of(context);
|
|
final colorScheme = theme.colorScheme;
|
|
final disableAnimations = MediaQuery.disableAnimationsOf(context);
|
|
|
|
return Container(
|
|
height: 36,
|
|
decoration: BoxDecoration(
|
|
color: colorScheme.surfaceContainerHighest,
|
|
borderRadius: BorderRadius.circular(18),
|
|
),
|
|
child: Stack(
|
|
children: [
|
|
AnimatedAlign(
|
|
alignment: Alignment(
|
|
-1.0 + (2.0 * selectedIndex / (labels.length - 1)),
|
|
0.0,
|
|
),
|
|
duration: disableAnimations
|
|
? Duration.zero
|
|
: const Duration(milliseconds: 250),
|
|
curve: Curves.easeOutCubic,
|
|
child: FractionallySizedBox(
|
|
widthFactor: 1.0 / labels.length,
|
|
child: Container(
|
|
decoration: BoxDecoration(
|
|
color: colorScheme.primary,
|
|
borderRadius: BorderRadius.circular(18),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
Row(
|
|
children: [
|
|
for (var i = 0; i < labels.length; i++)
|
|
Expanded(
|
|
child: GestureDetector(
|
|
behavior: HitTestBehavior.opaque,
|
|
onTap: () => onChanged(i),
|
|
child: Center(
|
|
child: Text(
|
|
labels[i],
|
|
style: theme.textTheme.labelMedium?.copyWith(
|
|
color: i == selectedIndex
|
|
? colorScheme.onPrimary
|
|
: colorScheme.onSurfaceVariant,
|
|
fontWeight: i == selectedIndex
|
|
? FontWeight.w600
|
|
: FontWeight.normal,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
],
|
|
),
|
|
);
|
|
}
|
|
}
|