update styles
This commit is contained in:
parent
56961c7010
commit
2008d2c688
13 changed files with 217 additions and 262 deletions
|
|
@ -5,11 +5,12 @@ import 'package:frosty/screens/home/home_store.dart';
|
|||
import 'package:frosty/screens/home/search/search.dart';
|
||||
import 'package:frosty/screens/home/stream_list/stream_list_store.dart';
|
||||
import 'package:frosty/screens/home/stream_list/streams_list.dart';
|
||||
import 'package:frosty/screens/home/top/top.dart';
|
||||
import 'package:frosty/screens/home/top/categories/categories.dart';
|
||||
import 'package:frosty/screens/settings/settings.dart';
|
||||
import 'package:frosty/screens/settings/stores/auth_store.dart';
|
||||
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
||||
import 'package:frosty/screens/settings/widgets/release_notes.dart';
|
||||
import 'package:frosty/widgets/app_bar.dart';
|
||||
import 'package:frosty/widgets/profile_picture.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
|
@ -63,13 +64,15 @@ class _HomeState extends State<Home> {
|
|||
return GestureDetector(
|
||||
onTap: FocusScope.of(context).unfocus,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
shape: const Border(),
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: FrostyAppBar(
|
||||
showBackButton: false,
|
||||
title: Observer(
|
||||
builder: (_) {
|
||||
final titles = [
|
||||
if (_authStore.isLoggedIn) 'Following',
|
||||
'Top',
|
||||
'Top Streams',
|
||||
'Top Categories',
|
||||
'Search',
|
||||
];
|
||||
|
||||
|
|
@ -99,6 +102,7 @@ class _HomeState extends State<Home> {
|
|||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
child: Observer(
|
||||
builder: (_) => IndexedStack(
|
||||
index: _homeStore.selectedIndex,
|
||||
|
|
@ -107,9 +111,15 @@ class _HomeState extends State<Home> {
|
|||
StreamsList(
|
||||
listType: ListType.followed,
|
||||
scrollController: _homeStore.followedScrollController,
|
||||
addTopPadding: true,
|
||||
),
|
||||
TopSection(
|
||||
homeStore: _homeStore,
|
||||
StreamsList(
|
||||
listType: ListType.top,
|
||||
scrollController: _homeStore.topSectionScrollControllers[0],
|
||||
addTopPadding: true,
|
||||
),
|
||||
Categories(
|
||||
scrollController: _homeStore.topSectionScrollControllers[1],
|
||||
),
|
||||
Search(
|
||||
scrollController: _homeStore.searchScrollController,
|
||||
|
|
@ -139,8 +149,16 @@ class _HomeState extends State<Home> {
|
|||
Icons.arrow_upward_rounded,
|
||||
),
|
||||
selectedIcon: Icon(Icons.arrow_upward_rounded),
|
||||
label: 'Top',
|
||||
tooltip: 'Top',
|
||||
label: 'Top streams',
|
||||
tooltip: 'Top streams',
|
||||
),
|
||||
const NavigationDestination(
|
||||
icon: Icon(
|
||||
Icons.gamepad_outlined,
|
||||
),
|
||||
selectedIcon: Icon(Icons.gamepad_rounded),
|
||||
label: 'Top categories',
|
||||
tooltip: 'Top categories',
|
||||
),
|
||||
const NavigationDestination(
|
||||
icon: Icon(
|
||||
|
|
|
|||
|
|
@ -33,126 +33,133 @@ class _SearchState extends State<Search> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextField(
|
||||
controller: _searchStore.textEditingController,
|
||||
focusNode: _searchStore.textFieldFocusNode,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.search_rounded),
|
||||
hintText: 'Find a channel or category',
|
||||
suffixIcon: _searchStore.textFieldFocusNode.hasFocus ||
|
||||
_searchStore.searchText.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
tooltip: _searchStore.searchText.isEmpty
|
||||
? 'Cancel'
|
||||
: 'Clear',
|
||||
onPressed: () {
|
||||
if (_searchStore.searchText.isEmpty) {
|
||||
_searchStore.textFieldFocusNode.unfocus();
|
||||
}
|
||||
_searchStore.textEditingController.clear();
|
||||
},
|
||||
)
|
||||
: null,
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
Observer(
|
||||
builder: (context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: TextField(
|
||||
controller: _searchStore.textEditingController,
|
||||
focusNode: _searchStore.textFieldFocusNode,
|
||||
autocorrect: false,
|
||||
decoration: InputDecoration(
|
||||
prefixIcon: const Icon(Icons.search_rounded),
|
||||
hintText: 'Find a channel or category',
|
||||
suffixIcon: _searchStore.textFieldFocusNode.hasFocus ||
|
||||
_searchStore.searchText.isNotEmpty
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.close_rounded),
|
||||
tooltip: _searchStore.searchText.isEmpty
|
||||
? 'Cancel'
|
||||
: 'Clear',
|
||||
onPressed: () {
|
||||
if (_searchStore.searchText.isEmpty) {
|
||||
_searchStore.textFieldFocusNode.unfocus();
|
||||
}
|
||||
_searchStore.textEditingController.clear();
|
||||
},
|
||||
)
|
||||
: null,
|
||||
),
|
||||
onSubmitted: _searchStore.handleQuery,
|
||||
),
|
||||
onSubmitted: _searchStore.handleQuery,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
AnimatedScrollBorder(scrollController: widget.scrollController),
|
||||
Expanded(
|
||||
child: Scrollbar(
|
||||
controller: widget.scrollController,
|
||||
child: Observer(
|
||||
builder: (context) {
|
||||
if (_searchStore.textEditingController.text.isEmpty) {
|
||||
if (_searchStore.searchHistory.isEmpty) {
|
||||
return const AlertMessage(message: 'No recent searches');
|
||||
}
|
||||
);
|
||||
},
|
||||
),
|
||||
AnimatedScrollBorder(scrollController: widget.scrollController),
|
||||
Expanded(
|
||||
child: Scrollbar(
|
||||
controller: widget.scrollController,
|
||||
child: Observer(
|
||||
builder: (context) {
|
||||
if (_searchStore.textEditingController.text.isEmpty) {
|
||||
if (_searchStore.searchHistory.isEmpty) {
|
||||
return const AlertMessage(
|
||||
message: 'No recent searches',
|
||||
);
|
||||
}
|
||||
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const SectionHeader(
|
||||
'History',
|
||||
padding: EdgeInsets.zero,
|
||||
isFirst: true,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _searchStore.searchHistory.clear,
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 16, right: 4),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const SectionHeader(
|
||||
'History',
|
||||
padding: EdgeInsets.zero,
|
||||
isFirst: true,
|
||||
),
|
||||
TextButton(
|
||||
onPressed: _searchStore.searchHistory.clear,
|
||||
child: const Text('Clear'),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
controller: widget.scrollController,
|
||||
children: _searchStore.searchHistory
|
||||
.mapIndexed(
|
||||
(index, searchTerm) => ListTile(
|
||||
leading: const Icon(Icons.history_rounded),
|
||||
title: Text(searchTerm),
|
||||
onTap: () {
|
||||
_searchStore.textEditingController.text =
|
||||
searchTerm;
|
||||
_searchStore.handleQuery(searchTerm);
|
||||
_searchStore
|
||||
.textEditingController.selection =
|
||||
TextSelection.fromPosition(
|
||||
TextPosition(
|
||||
offset: _searchStore
|
||||
.textEditingController
|
||||
.text
|
||||
.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
slivers: [
|
||||
const SliverToBoxAdapter(
|
||||
child: SectionHeader(
|
||||
'Channels',
|
||||
isFirst: true,
|
||||
padding: EdgeInsets.fromLTRB(16, 12, 16, 8),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
controller: widget.scrollController,
|
||||
children: _searchStore.searchHistory
|
||||
.mapIndexed(
|
||||
(index, searchTerm) => ListTile(
|
||||
leading: const Icon(Icons.history_rounded),
|
||||
title: Text(searchTerm),
|
||||
onTap: () {
|
||||
_searchStore.textEditingController.text =
|
||||
searchTerm;
|
||||
_searchStore.handleQuery(searchTerm);
|
||||
_searchStore.textEditingController
|
||||
.selection = TextSelection.fromPosition(
|
||||
TextPosition(
|
||||
offset: _searchStore
|
||||
.textEditingController.text.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
SearchResultsChannels(
|
||||
searchStore: _searchStore,
|
||||
query: _searchStore.searchText,
|
||||
),
|
||||
const SliverToBoxAdapter(
|
||||
child: SectionHeader(
|
||||
'Categories',
|
||||
),
|
||||
),
|
||||
SearchResultsCategories(searchStore: _searchStore),
|
||||
],
|
||||
);
|
||||
}
|
||||
return CustomScrollView(
|
||||
controller: widget.scrollController,
|
||||
slivers: [
|
||||
const SliverToBoxAdapter(
|
||||
child: SectionHeader(
|
||||
'Channels',
|
||||
isFirst: true,
|
||||
padding: EdgeInsets.fromLTRB(16, 12, 16, 8),
|
||||
),
|
||||
),
|
||||
SearchResultsChannels(
|
||||
searchStore: _searchStore,
|
||||
query: _searchStore.searchText,
|
||||
),
|
||||
const SliverToBoxAdapter(
|
||||
child: SectionHeader(
|
||||
'Categories',
|
||||
),
|
||||
),
|
||||
SearchResultsCategories(searchStore: _searchStore),
|
||||
],
|
||||
);
|
||||
},
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ import 'package:frosty/screens/home/top/categories/category_card.dart';
|
|||
import 'package:frosty/screens/settings/stores/auth_store.dart';
|
||||
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
||||
import 'package:frosty/widgets/alert_message.dart';
|
||||
import 'package:frosty/widgets/animated_scroll_border.dart';
|
||||
import 'package:frosty/widgets/loading_indicator.dart';
|
||||
import 'package:frosty/widgets/scroll_to_top_button.dart';
|
||||
import 'package:frosty/widgets/section_header.dart';
|
||||
|
|
@ -27,6 +26,7 @@ class StreamsList extends StatefulWidget {
|
|||
final ScrollController? scrollController;
|
||||
|
||||
final bool showJumpButton;
|
||||
final bool addTopPadding;
|
||||
|
||||
const StreamsList({
|
||||
super.key,
|
||||
|
|
@ -34,6 +34,7 @@ class StreamsList extends StatefulWidget {
|
|||
this.categoryId,
|
||||
this.scrollController,
|
||||
this.showJumpButton = false,
|
||||
this.addTopPadding = false,
|
||||
});
|
||||
|
||||
@override
|
||||
|
|
@ -74,9 +75,13 @@ class _StreamsListState extends State<StreamsList>
|
|||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
|
||||
final double topPadding =
|
||||
widget.addTopPadding ? MediaQuery.of(context).padding.top : 0;
|
||||
|
||||
_listStore.checkLastTimeRefreshedAndUpdate();
|
||||
|
||||
return RefreshIndicator.adaptive(
|
||||
edgeOffset: topPadding,
|
||||
onRefresh: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
|
||||
|
|
@ -152,10 +157,6 @@ class _StreamsListState extends State<StreamsList>
|
|||
category: _listStore.categoryDetails!,
|
||||
isTappable: false,
|
||||
),
|
||||
if (_listStore.scrollController != null)
|
||||
AnimatedScrollBorder(
|
||||
scrollController: _listStore.scrollController!,
|
||||
),
|
||||
Expanded(
|
||||
child: Scrollbar(
|
||||
controller: _listStore.scrollController,
|
||||
|
|
@ -163,6 +164,12 @@ class _StreamsListState extends State<StreamsList>
|
|||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
controller: _listStore.scrollController,
|
||||
slivers: [
|
||||
if (widget.addTopPadding)
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
top: topPadding,
|
||||
),
|
||||
),
|
||||
if (isFollowingTab &&
|
||||
_listStore.pinnedStreams.isNotEmpty) ...[
|
||||
const SliverToBoxAdapter(
|
||||
|
|
|
|||
|
|
@ -54,6 +54,7 @@ class _CategoriesState extends State<Categories>
|
|||
_categoriesStore.checkLastTimeRefreshedAndUpdate();
|
||||
|
||||
return RefreshIndicator.adaptive(
|
||||
edgeOffset: MediaQuery.of(context).padding.top,
|
||||
onRefresh: () async {
|
||||
HapticFeedback.lightImpact();
|
||||
await _categoriesStore.refreshCategories();
|
||||
|
|
|
|||
|
|
@ -1,71 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:frosty/screens/home/home_store.dart';
|
||||
import 'package:frosty/screens/home/stream_list/stream_list_store.dart';
|
||||
import 'package:frosty/screens/home/stream_list/streams_list.dart';
|
||||
import 'package:frosty/screens/home/top/categories/categories.dart';
|
||||
|
||||
class TopSection extends StatefulWidget {
|
||||
final HomeStore homeStore;
|
||||
|
||||
const TopSection({
|
||||
super.key,
|
||||
required this.homeStore,
|
||||
});
|
||||
|
||||
@override
|
||||
State<TopSection> createState() => _TopSectionState();
|
||||
}
|
||||
|
||||
class _TopSectionState extends State<TopSection>
|
||||
with SingleTickerProviderStateMixin {
|
||||
late final _tabBarController = TabController(length: 2, vsync: this);
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_tabBarController.addListener(
|
||||
() => widget.homeStore.topSectionCurrentIndex = _tabBarController.index,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
TabBar(
|
||||
isScrollable: true,
|
||||
controller: _tabBarController,
|
||||
tabs: const [
|
||||
Tab(
|
||||
child: Text('Streams'),
|
||||
),
|
||||
Tab(child: Text('Categories')),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: TabBarView(
|
||||
controller: _tabBarController,
|
||||
children: [
|
||||
StreamsList(
|
||||
listType: ListType.top,
|
||||
scrollController:
|
||||
widget.homeStore.topSectionScrollControllers[0],
|
||||
),
|
||||
Categories(
|
||||
scrollController:
|
||||
widget.homeStore.topSectionScrollControllers[1],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabBarController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
|
@ -31,7 +31,6 @@ class _ChatSettingsState extends State<ChatSettings> {
|
|||
|
||||
return Observer(
|
||||
builder: (context) => ListView(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
children: [
|
||||
const SectionHeader(
|
||||
'Message sizing',
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ class GeneralSettings extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) => ListView(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
children: [
|
||||
const SectionHeader(
|
||||
'Theme',
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ class Settings extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: FrostyAppBar(
|
||||
title: const Text('Settings'),
|
||||
actions: [
|
||||
|
|
@ -53,12 +54,12 @@ class Settings extends StatelessWidget {
|
|||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: ListView(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
children: [
|
||||
const SectionHeader(
|
||||
'Profile',
|
||||
'Account',
|
||||
isFirst: true,
|
||||
),
|
||||
ProfileCard(authStore: context.read<AuthStore>()),
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ class VideoSettings extends StatelessWidget {
|
|||
Widget build(BuildContext context) {
|
||||
return Observer(
|
||||
builder: (context) => ListView(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
children: [
|
||||
const SectionHeader(
|
||||
'Player',
|
||||
|
|
@ -34,7 +33,7 @@ class VideoSettings extends StatelessWidget {
|
|||
value: settingsStore.defaultToHighestQuality,
|
||||
onChanged: (newValue) =>
|
||||
settingsStore.defaultToHighestQuality = newValue,
|
||||
),
|
||||
),
|
||||
if (Platform.isAndroid)
|
||||
SettingsListSwitch(
|
||||
title: 'Use enhanced rendering',
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ class SettingsTileRoute extends StatelessWidget {
|
|||
MaterialPageRoute(
|
||||
builder: (context) => useScaffold
|
||||
? Scaffold(
|
||||
extendBodyBehindAppBar: true,
|
||||
appBar: FrostyAppBar(title: Text(title)),
|
||||
body: SafeArea(
|
||||
top: false,
|
||||
bottom: false,
|
||||
child: child,
|
||||
),
|
||||
|
|
|
|||
|
|
@ -7,24 +7,29 @@ class FrostyThemes {
|
|||
|
||||
const FrostyThemes({required this.colorSchemeSeed});
|
||||
|
||||
ThemeData get light => createBaseTheme(
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: colorSchemeSeed),
|
||||
backgroundColor: const Color.fromRGBO(248, 248, 248, 1),
|
||||
);
|
||||
|
||||
ThemeData get dark => createBaseTheme(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: colorSchemeSeed,
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
backgroundColor: Colors.black,
|
||||
);
|
||||
|
||||
ThemeData createBaseTheme({
|
||||
required Brightness brightness,
|
||||
required Color colorSchemeSeed,
|
||||
required ColorScheme colorScheme,
|
||||
Color? backgroundColor,
|
||||
}) {
|
||||
final colorScheme = ColorScheme.fromSeed(
|
||||
seedColor: colorSchemeSeed,
|
||||
brightness: brightness,
|
||||
);
|
||||
|
||||
final borderColor = colorScheme.outlineVariant;
|
||||
|
||||
const borderWidth = 0.5;
|
||||
|
||||
return ThemeData(
|
||||
fontFamily: 'Inter',
|
||||
brightness: brightness,
|
||||
colorScheme: colorScheme,
|
||||
fontFamily: 'Inter',
|
||||
splashFactory: Platform.isIOS ? NoSplash.splashFactory : null,
|
||||
scaffoldBackgroundColor: backgroundColor,
|
||||
bottomSheetTheme: BottomSheetThemeData(
|
||||
|
|
@ -37,11 +42,14 @@ class FrostyThemes {
|
|||
surfaceTintColor: backgroundColor,
|
||||
),
|
||||
appBarTheme: AppBarTheme(
|
||||
elevation: 0,
|
||||
backgroundColor: backgroundColor,
|
||||
backgroundColor: Colors.transparent,
|
||||
surfaceTintColor: backgroundColor,
|
||||
shape: Border(
|
||||
bottom: BorderSide(color: borderColor, width: borderWidth),
|
||||
),
|
||||
listTileTheme: ListTileThemeData(
|
||||
titleTextStyle: TextStyle(
|
||||
color: colorScheme.onSurface,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w500,
|
||||
),
|
||||
),
|
||||
inputDecorationTheme: InputDecorationTheme(
|
||||
|
|
@ -61,7 +69,6 @@ class FrostyThemes {
|
|||
),
|
||||
),
|
||||
navigationBarTheme: NavigationBarThemeData(
|
||||
elevation: 0,
|
||||
backgroundColor: backgroundColor,
|
||||
height: 64,
|
||||
labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,
|
||||
|
|
@ -71,6 +78,7 @@ class FrostyThemes {
|
|||
tabAlignment: TabAlignment.start,
|
||||
),
|
||||
tooltipTheme: TooltipThemeData(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||
|
|
@ -133,24 +141,4 @@ class FrostyThemes {
|
|||
),
|
||||
);
|
||||
}
|
||||
|
||||
ThemeData get light {
|
||||
final theme = createBaseTheme(
|
||||
brightness: Brightness.light,
|
||||
colorSchemeSeed: colorSchemeSeed,
|
||||
backgroundColor: const Color.fromRGBO(248, 248, 248, 1),
|
||||
);
|
||||
|
||||
return theme;
|
||||
}
|
||||
|
||||
ThemeData get dark {
|
||||
final theme = createBaseTheme(
|
||||
brightness: Brightness.dark,
|
||||
colorSchemeSeed: colorSchemeSeed,
|
||||
backgroundColor: Colors.black,
|
||||
);
|
||||
|
||||
return theme;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,37 @@
|
|||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FrostyAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||
final Widget title;
|
||||
final Widget? title;
|
||||
final List<Widget>? actions;
|
||||
final bool showBackButton;
|
||||
|
||||
const FrostyAppBar({
|
||||
super.key,
|
||||
required this.title,
|
||||
this.title,
|
||||
this.actions,
|
||||
this.showBackButton = true,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AppBar(
|
||||
leading: IconButton(
|
||||
tooltip: 'Back',
|
||||
icon: Icon(Icons.adaptive.arrow_back_rounded),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
return ClipRRect(
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 16, sigmaY: 16),
|
||||
child: AppBar(
|
||||
leading: showBackButton
|
||||
? IconButton(
|
||||
tooltip: 'Back',
|
||||
icon: Icon(Icons.adaptive.arrow_back_rounded),
|
||||
onPressed: Navigator.of(context).pop,
|
||||
)
|
||||
: null,
|
||||
title: title,
|
||||
actions: actions,
|
||||
centerTitle: false,
|
||||
),
|
||||
),
|
||||
title: title,
|
||||
actions: actions,
|
||||
centerTitle: false,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,23 +17,17 @@ class SectionHeader extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: padding ?? const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!isFirst) ...[
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
Text(
|
||||
text,
|
||||
style: TextStyle(
|
||||
fontSize: fontSize ?? 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
padding: padding ??
|
||||
(isFirst
|
||||
? const EdgeInsets.fromLTRB(16, 16, 16, 8)
|
||||
: const EdgeInsets.fromLTRB(16, 48, 16, 8)),
|
||||
child: Text(
|
||||
text.toUpperCase(),
|
||||
style: TextStyle(
|
||||
fontSize: fontSize ?? 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue