Compare commits
6 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
21d388fa02 | ||
|
|
2008d2c688 | ||
|
|
56961c7010 | ||
|
|
29c84858a0 | ||
|
|
a2d30ec086 | ||
|
|
60a97e6a24 |
22 changed files with 270 additions and 416 deletions
|
|
@ -123,7 +123,6 @@ class IRCMessage {
|
||||||
void Function()? onTapName,
|
void Function()? onTapName,
|
||||||
void Function(String)? onTapPingedUser,
|
void Function(String)? onTapPingedUser,
|
||||||
bool showMessage = true,
|
bool showMessage = true,
|
||||||
bool useReadableColors = false,
|
|
||||||
Map<String, UserTwitch>? channelIdToUserTwitch,
|
Map<String, UserTwitch>? channelIdToUserTwitch,
|
||||||
TimestampType timestamp = TimestampType.disabled,
|
TimestampType timestamp = TimestampType.disabled,
|
||||||
}) {
|
}) {
|
||||||
|
|
@ -370,7 +369,6 @@ class IRCMessage {
|
||||||
int.parse((tags['color'] ?? '#868686').replaceFirst('#', '0xFF')),
|
int.parse((tags['color'] ?? '#868686').replaceFirst('#', '0xFF')),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (useReadableColors) {
|
|
||||||
final hsl = HSLColor.fromColor(color);
|
final hsl = HSLColor.fromColor(color);
|
||||||
if (isLightTheme == true) {
|
if (isLightTheme == true) {
|
||||||
if (hsl.lightness >= 0.5) {
|
if (hsl.lightness >= 0.5) {
|
||||||
|
|
@ -385,7 +383,6 @@ class IRCMessage {
|
||||||
.toColor();
|
.toColor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Add the display name (username) to the span and apply the onLongPressName callback.
|
// Add the display name (username) to the span and apply the onLongPressName callback.
|
||||||
final displayName = tags['display-name']!;
|
final displayName = tags['display-name']!;
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ abstract class ChatStoreBase with Store {
|
||||||
required this.displayName,
|
required this.displayName,
|
||||||
}) {
|
}) {
|
||||||
// Enable wakelock to prevent the chat from sleeping.
|
// Enable wakelock to prevent the chat from sleeping.
|
||||||
if (settings.chatOnlyPreventSleep) WakelockPlus.enable();
|
WakelockPlus.enable();
|
||||||
|
|
||||||
// Create a reaction that will reconnect to chat when logging in or out.
|
// Create a reaction that will reconnect to chat when logging in or out.
|
||||||
// Closing the channel will trigger a reconnect with the new credentials.
|
// Closing the channel will trigger a reconnect with the new credentials.
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ class ChatBottomBar extends StatelessWidget {
|
||||||
assetsStore: chatStore.assetsStore,
|
assetsStore: chatStore.assetsStore,
|
||||||
emoteScale: chatStore.settings.emoteScale,
|
emoteScale: chatStore.settings.emoteScale,
|
||||||
badgeScale: chatStore.settings.badgeScale,
|
badgeScale: chatStore.settings.badgeScale,
|
||||||
useReadableColors: chatStore.settings.useReadableColors,
|
|
||||||
launchExternal: chatStore.settings.launchUrlExternal,
|
launchExternal: chatStore.settings.launchUrlExternal,
|
||||||
timestamp: chatStore.settings.timestampType,
|
timestamp: chatStore.settings.timestampType,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,6 @@ class ChatMessage extends StatelessWidget {
|
||||||
assetsStore: chatStore.assetsStore,
|
assetsStore: chatStore.assetsStore,
|
||||||
emoteScale: chatStore.settings.emoteScale,
|
emoteScale: chatStore.settings.emoteScale,
|
||||||
badgeScale: chatStore.settings.badgeScale,
|
badgeScale: chatStore.settings.badgeScale,
|
||||||
useReadableColors: chatStore.settings.useReadableColors,
|
|
||||||
launchExternal: chatStore.settings.launchUrlExternal,
|
launchExternal: chatStore.settings.launchUrlExternal,
|
||||||
timestamp: chatStore.settings.timestampType,
|
timestamp: chatStore.settings.timestampType,
|
||||||
channelIdToUserTwitch:
|
channelIdToUserTwitch:
|
||||||
|
|
@ -172,7 +171,6 @@ class ChatMessage extends StatelessWidget {
|
||||||
assetsStore: chatStore.assetsStore,
|
assetsStore: chatStore.assetsStore,
|
||||||
emoteScale: chatStore.settings.emoteScale,
|
emoteScale: chatStore.settings.emoteScale,
|
||||||
badgeScale: chatStore.settings.badgeScale,
|
badgeScale: chatStore.settings.badgeScale,
|
||||||
useReadableColors: chatStore.settings.useReadableColors,
|
|
||||||
launchExternal: chatStore.settings.launchUrlExternal,
|
launchExternal: chatStore.settings.launchUrlExternal,
|
||||||
timestamp: chatStore.settings.timestampType,
|
timestamp: chatStore.settings.timestampType,
|
||||||
channelIdToUserTwitch:
|
channelIdToUserTwitch:
|
||||||
|
|
@ -305,7 +303,6 @@ class ChatMessage extends StatelessWidget {
|
||||||
emoteScale: chatStore.settings.emoteScale,
|
emoteScale: chatStore.settings.emoteScale,
|
||||||
badgeScale: chatStore.settings.badgeScale,
|
badgeScale: chatStore.settings.badgeScale,
|
||||||
showMessage: chatStore.settings.showDeletedMessages,
|
showMessage: chatStore.settings.showDeletedMessages,
|
||||||
useReadableColors: chatStore.settings.useReadableColors,
|
|
||||||
launchExternal: chatStore.settings.launchUrlExternal,
|
launchExternal: chatStore.settings.launchUrlExternal,
|
||||||
timestamp: chatStore.settings.timestampType,
|
timestamp: chatStore.settings.timestampType,
|
||||||
channelIdToUserTwitch:
|
channelIdToUserTwitch:
|
||||||
|
|
@ -399,8 +396,6 @@ class ChatMessage extends StatelessWidget {
|
||||||
assetsStore: chatStore.assetsStore,
|
assetsStore: chatStore.assetsStore,
|
||||||
emoteScale: chatStore.settings.emoteScale,
|
emoteScale: chatStore.settings.emoteScale,
|
||||||
badgeScale: chatStore.settings.badgeScale,
|
badgeScale: chatStore.settings.badgeScale,
|
||||||
useReadableColors:
|
|
||||||
chatStore.settings.useReadableColors,
|
|
||||||
launchExternal: chatStore.settings.launchUrlExternal,
|
launchExternal: chatStore.settings.launchUrlExternal,
|
||||||
timestamp: chatStore.settings.timestampType,
|
timestamp: chatStore.settings.timestampType,
|
||||||
channelIdToUserTwitch:
|
channelIdToUserTwitch:
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ class VideoBar extends StatelessWidget {
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: 'Streamer: $streamerName',
|
message: streamerName,
|
||||||
showDuration: const Duration(seconds: 3),
|
showDuration: const Duration(seconds: 3),
|
||||||
child: Text(
|
child: Text(
|
||||||
streamerName,
|
streamerName,
|
||||||
|
|
@ -62,7 +62,7 @@ class VideoBar extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: 'Title: ${streamInfo.title.trim()}',
|
message: streamTitle,
|
||||||
showDuration: const Duration(seconds: 5),
|
showDuration: const Duration(seconds: 5),
|
||||||
child: Text(
|
child: Text(
|
||||||
streamTitle,
|
streamTitle,
|
||||||
|
|
@ -91,8 +91,7 @@ class VideoBar extends StatelessWidget {
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message:
|
message: category,
|
||||||
'Category: ${streamInfo.gameName.isNotEmpty ? streamInfo.gameName : 'None'}',
|
|
||||||
showDuration: const Duration(seconds: 3),
|
showDuration: const Duration(seconds: 3),
|
||||||
child: Text(
|
child: Text(
|
||||||
category,
|
category,
|
||||||
|
|
|
||||||
|
|
@ -352,9 +352,7 @@ class VideoOverlay extends StatelessWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (orientation == Orientation.landscape &&
|
if (orientation == Orientation.landscape) latencyTooltip,
|
||||||
settingsStore.showLatency)
|
|
||||||
latencyTooltip,
|
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: 'Enter picture-in-picture',
|
message: 'Enter picture-in-picture',
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||||
|
|
@ -5,11 +7,12 @@ import 'package:frosty/screens/home/home_store.dart';
|
||||||
import 'package:frosty/screens/home/search/search.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/stream_list_store.dart';
|
||||||
import 'package:frosty/screens/home/stream_list/streams_list.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/settings.dart';
|
||||||
import 'package:frosty/screens/settings/stores/auth_store.dart';
|
import 'package:frosty/screens/settings/stores/auth_store.dart';
|
||||||
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
||||||
import 'package:frosty/screens/settings/widgets/release_notes.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:frosty/widgets/profile_picture.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
@ -63,14 +66,16 @@ class _HomeState extends State<Home> {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: FocusScope.of(context).unfocus,
|
onTap: FocusScope.of(context).unfocus,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
appBar: AppBar(
|
extendBodyBehindAppBar: true,
|
||||||
centerTitle: false,
|
extendBody: true,
|
||||||
shape: const Border(),
|
appBar: FrostyAppBar(
|
||||||
|
showBackButton: false,
|
||||||
title: Observer(
|
title: Observer(
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
final titles = [
|
final titles = [
|
||||||
if (_authStore.isLoggedIn) 'Following',
|
if (_authStore.isLoggedIn) 'Following',
|
||||||
'Top',
|
'Top Streams',
|
||||||
|
'Top Categories',
|
||||||
'Search',
|
'Search',
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -100,6 +105,8 @@ class _HomeState extends State<Home> {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
|
top: false,
|
||||||
|
bottom: false,
|
||||||
child: Observer(
|
child: Observer(
|
||||||
builder: (_) => IndexedStack(
|
builder: (_) => IndexedStack(
|
||||||
index: _homeStore.selectedIndex,
|
index: _homeStore.selectedIndex,
|
||||||
|
|
@ -108,9 +115,15 @@ class _HomeState extends State<Home> {
|
||||||
StreamsList(
|
StreamsList(
|
||||||
listType: ListType.followed,
|
listType: ListType.followed,
|
||||||
scrollController: _homeStore.followedScrollController,
|
scrollController: _homeStore.followedScrollController,
|
||||||
|
addTopPadding: true,
|
||||||
),
|
),
|
||||||
TopSection(
|
StreamsList(
|
||||||
homeStore: _homeStore,
|
listType: ListType.top,
|
||||||
|
scrollController: _homeStore.topSectionScrollControllers[0],
|
||||||
|
addTopPadding: true,
|
||||||
|
),
|
||||||
|
Categories(
|
||||||
|
scrollController: _homeStore.topSectionScrollControllers[1],
|
||||||
),
|
),
|
||||||
Search(
|
Search(
|
||||||
scrollController: _homeStore.searchScrollController,
|
scrollController: _homeStore.searchScrollController,
|
||||||
|
|
@ -119,12 +132,15 @@ class _HomeState extends State<Home> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bottomNavigationBar: Column(
|
bottomNavigationBar: ClipRRect(
|
||||||
mainAxisSize: MainAxisSize.min,
|
child: BackdropFilter(
|
||||||
children: [
|
filter: ImageFilter.blur(sigmaX: 16, sigmaY: 16),
|
||||||
const Divider(),
|
child: Observer(
|
||||||
Observer(
|
|
||||||
builder: (_) => NavigationBar(
|
builder: (_) => NavigationBar(
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.surface
|
||||||
|
.withValues(alpha: 0.6),
|
||||||
destinations: [
|
destinations: [
|
||||||
if (_authStore.isLoggedIn)
|
if (_authStore.isLoggedIn)
|
||||||
const NavigationDestination(
|
const NavigationDestination(
|
||||||
|
|
@ -140,8 +156,16 @@ class _HomeState extends State<Home> {
|
||||||
Icons.arrow_upward_rounded,
|
Icons.arrow_upward_rounded,
|
||||||
),
|
),
|
||||||
selectedIcon: Icon(Icons.arrow_upward_rounded),
|
selectedIcon: Icon(Icons.arrow_upward_rounded),
|
||||||
label: 'Top',
|
label: 'Top streams',
|
||||||
tooltip: 'Top',
|
tooltip: 'Top streams',
|
||||||
|
),
|
||||||
|
const NavigationDestination(
|
||||||
|
icon: Icon(
|
||||||
|
Icons.gamepad_outlined,
|
||||||
|
),
|
||||||
|
selectedIcon: Icon(Icons.gamepad_rounded),
|
||||||
|
label: 'Top categories',
|
||||||
|
tooltip: 'Top categories',
|
||||||
),
|
),
|
||||||
const NavigationDestination(
|
const NavigationDestination(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
|
|
@ -156,7 +180,7 @@ class _HomeState extends State<Home> {
|
||||||
onDestinationSelected: _homeStore.handleTap,
|
onDestinationSelected: _homeStore.handleTap,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,8 @@ class _SearchState extends State<Search> {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return SafeArea(
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Observer(
|
Observer(
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
|
|
@ -75,7 +76,9 @@ class _SearchState extends State<Search> {
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
if (_searchStore.textEditingController.text.isEmpty) {
|
if (_searchStore.textEditingController.text.isEmpty) {
|
||||||
if (_searchStore.searchHistory.isEmpty) {
|
if (_searchStore.searchHistory.isEmpty) {
|
||||||
return const AlertMessage(message: 'No recent searches');
|
return const AlertMessage(
|
||||||
|
message: 'No recent searches',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
|
@ -110,11 +113,14 @@ class _SearchState extends State<Search> {
|
||||||
_searchStore.textEditingController.text =
|
_searchStore.textEditingController.text =
|
||||||
searchTerm;
|
searchTerm;
|
||||||
_searchStore.handleQuery(searchTerm);
|
_searchStore.handleQuery(searchTerm);
|
||||||
_searchStore.textEditingController
|
_searchStore
|
||||||
.selection = TextSelection.fromPosition(
|
.textEditingController.selection =
|
||||||
|
TextSelection.fromPosition(
|
||||||
TextPosition(
|
TextPosition(
|
||||||
offset: _searchStore
|
offset: _searchStore
|
||||||
.textEditingController.text.length,
|
.textEditingController
|
||||||
|
.text
|
||||||
|
.length,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
@ -153,6 +159,7 @@ class _SearchState extends State<Search> {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,10 @@ class StreamCard extends StatelessWidget {
|
||||||
final streamerName =
|
final streamerName =
|
||||||
getReadableName(streamInfo.userName, streamInfo.userLogin);
|
getReadableName(streamInfo.userName, streamInfo.userLogin);
|
||||||
|
|
||||||
|
final streamTitle = streamInfo.title.trim();
|
||||||
|
final category =
|
||||||
|
streamInfo.gameName.isNotEmpty ? streamInfo.gameName : 'No Category';
|
||||||
|
|
||||||
const subFontSize = 14.0;
|
const subFontSize = 14.0;
|
||||||
|
|
||||||
final fontColor = DefaultTextStyle.of(context).style.color;
|
final fontColor = DefaultTextStyle.of(context).style.color;
|
||||||
|
|
@ -126,7 +130,7 @@ class StreamCard extends StatelessWidget {
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message: 'Streamer: $streamerName',
|
message: streamerName,
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
child: Text(
|
child: Text(
|
||||||
streamerName,
|
streamerName,
|
||||||
|
|
@ -143,10 +147,10 @@ class StreamCard extends StatelessWidget {
|
||||||
),
|
),
|
||||||
const SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
Tooltip(
|
Tooltip(
|
||||||
message: 'Title: ${streamInfo.title.trim()}',
|
message: streamTitle,
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
child: Text(
|
child: Text(
|
||||||
streamInfo.title.trim(),
|
streamTitle,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: subFontSize,
|
fontSize: subFontSize,
|
||||||
|
|
@ -168,13 +172,10 @@ class StreamCard extends StatelessWidget {
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
child: Tooltip(
|
child: Tooltip(
|
||||||
message:
|
message: category,
|
||||||
'Category: ${streamInfo.gameName.isNotEmpty ? streamInfo.gameName : 'None'}',
|
|
||||||
preferBelow: false,
|
preferBelow: false,
|
||||||
child: Text(
|
child: Text(
|
||||||
streamInfo.gameName.isNotEmpty
|
category,
|
||||||
? streamInfo.gameName
|
|
||||||
: 'No Category',
|
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: subFontSize,
|
fontSize: subFontSize,
|
||||||
|
|
|
||||||
|
|
@ -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/auth_store.dart';
|
||||||
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
import 'package:frosty/screens/settings/stores/settings_store.dart';
|
||||||
import 'package:frosty/widgets/alert_message.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/loading_indicator.dart';
|
||||||
import 'package:frosty/widgets/scroll_to_top_button.dart';
|
import 'package:frosty/widgets/scroll_to_top_button.dart';
|
||||||
import 'package:frosty/widgets/section_header.dart';
|
import 'package:frosty/widgets/section_header.dart';
|
||||||
|
|
@ -27,6 +26,7 @@ class StreamsList extends StatefulWidget {
|
||||||
final ScrollController? scrollController;
|
final ScrollController? scrollController;
|
||||||
|
|
||||||
final bool showJumpButton;
|
final bool showJumpButton;
|
||||||
|
final bool addTopPadding;
|
||||||
|
|
||||||
const StreamsList({
|
const StreamsList({
|
||||||
super.key,
|
super.key,
|
||||||
|
|
@ -34,6 +34,7 @@ class StreamsList extends StatefulWidget {
|
||||||
this.categoryId,
|
this.categoryId,
|
||||||
this.scrollController,
|
this.scrollController,
|
||||||
this.showJumpButton = false,
|
this.showJumpButton = false,
|
||||||
|
this.addTopPadding = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|
@ -74,9 +75,13 @@ class _StreamsListState extends State<StreamsList>
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
super.build(context);
|
super.build(context);
|
||||||
|
|
||||||
|
final double topPadding =
|
||||||
|
widget.addTopPadding ? MediaQuery.of(context).padding.top : 0;
|
||||||
|
|
||||||
_listStore.checkLastTimeRefreshedAndUpdate();
|
_listStore.checkLastTimeRefreshedAndUpdate();
|
||||||
|
|
||||||
return RefreshIndicator.adaptive(
|
return RefreshIndicator.adaptive(
|
||||||
|
edgeOffset: topPadding,
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
HapticFeedback.lightImpact();
|
HapticFeedback.lightImpact();
|
||||||
|
|
||||||
|
|
@ -130,12 +135,14 @@ class _StreamsListState extends State<StreamsList>
|
||||||
|
|
||||||
final settingsStore = context.watch<SettingsStore>();
|
final settingsStore = context.watch<SettingsStore>();
|
||||||
|
|
||||||
final unpinnedStreams = _listStore.streams
|
final unpinnedStreams = widget.listType == ListType.followed
|
||||||
|
? _listStore.streams
|
||||||
.where(
|
.where(
|
||||||
(stream) =>
|
(stream) =>
|
||||||
!settingsStore.pinnedChannelIds.contains(stream.userId),
|
!settingsStore.pinnedChannelIds.contains(stream.userId),
|
||||||
)
|
)
|
||||||
.toList();
|
.toList()
|
||||||
|
: _listStore.streams;
|
||||||
|
|
||||||
final isFollowingTab = widget.listType == ListType.followed;
|
final isFollowingTab = widget.listType == ListType.followed;
|
||||||
|
|
||||||
|
|
@ -150,10 +157,6 @@ class _StreamsListState extends State<StreamsList>
|
||||||
category: _listStore.categoryDetails!,
|
category: _listStore.categoryDetails!,
|
||||||
isTappable: false,
|
isTappable: false,
|
||||||
),
|
),
|
||||||
if (_listStore.scrollController != null)
|
|
||||||
AnimatedScrollBorder(
|
|
||||||
scrollController: _listStore.scrollController!,
|
|
||||||
),
|
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Scrollbar(
|
child: Scrollbar(
|
||||||
controller: _listStore.scrollController,
|
controller: _listStore.scrollController,
|
||||||
|
|
@ -161,6 +164,12 @@ class _StreamsListState extends State<StreamsList>
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
controller: _listStore.scrollController,
|
controller: _listStore.scrollController,
|
||||||
slivers: [
|
slivers: [
|
||||||
|
if (widget.addTopPadding)
|
||||||
|
SliverPadding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: topPadding,
|
||||||
|
),
|
||||||
|
),
|
||||||
if (isFollowingTab &&
|
if (isFollowingTab &&
|
||||||
_listStore.pinnedStreams.isNotEmpty) ...[
|
_listStore.pinnedStreams.isNotEmpty) ...[
|
||||||
const SliverToBoxAdapter(
|
const SliverToBoxAdapter(
|
||||||
|
|
@ -263,6 +272,11 @@ class _StreamsListState extends State<StreamsList>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
SliverPadding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
bottom: MediaQuery.of(context).padding.bottom,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -54,6 +54,7 @@ class _CategoriesState extends State<Categories>
|
||||||
_categoriesStore.checkLastTimeRefreshedAndUpdate();
|
_categoriesStore.checkLastTimeRefreshedAndUpdate();
|
||||||
|
|
||||||
return RefreshIndicator.adaptive(
|
return RefreshIndicator.adaptive(
|
||||||
|
edgeOffset: MediaQuery.of(context).padding.top,
|
||||||
onRefresh: () async {
|
onRefresh: () async {
|
||||||
HapticFeedback.lightImpact();
|
HapticFeedback.lightImpact();
|
||||||
await _categoriesStore.refreshCategories();
|
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(
|
return Observer(
|
||||||
builder: (context) => ListView(
|
builder: (context) => ListView(
|
||||||
padding: const EdgeInsets.only(top: 16),
|
|
||||||
children: [
|
children: [
|
||||||
const SectionHeader(
|
const SectionHeader(
|
||||||
'Message sizing',
|
'Message sizing',
|
||||||
|
|
@ -146,14 +145,6 @@ class _ChatSettingsState extends State<ChatSettings> {
|
||||||
onChanged: (newValue) => settingsStore.fontSize = newValue,
|
onChanged: (newValue) => settingsStore.fontSize = newValue,
|
||||||
),
|
),
|
||||||
const SectionHeader('Message appearance'),
|
const SectionHeader('Message appearance'),
|
||||||
SettingsListSwitch(
|
|
||||||
title: 'Use readable name colors',
|
|
||||||
subtitle: const Text(
|
|
||||||
'Adjusts the lightness value of overly bright and dark names.',
|
|
||||||
),
|
|
||||||
value: settingsStore.useReadableColors,
|
|
||||||
onChanged: (newValue) => settingsStore.useReadableColors = newValue,
|
|
||||||
),
|
|
||||||
SettingsListSwitch(
|
SettingsListSwitch(
|
||||||
title: 'Show deleted messages',
|
title: 'Show deleted messages',
|
||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
|
|
@ -275,16 +266,6 @@ class _ChatSettingsState extends State<ChatSettings> {
|
||||||
onChanged: (newValue) =>
|
onChanged: (newValue) =>
|
||||||
settingsStore.fullScreenChatOverlayOpacity = newValue,
|
settingsStore.fullScreenChatOverlayOpacity = newValue,
|
||||||
),
|
),
|
||||||
const SectionHeader('Sleep'),
|
|
||||||
SettingsListSwitch(
|
|
||||||
title: 'Prevent sleep in chat-only mode',
|
|
||||||
subtitle: const Text(
|
|
||||||
'Requires restarting the chat in order to take effect.',
|
|
||||||
),
|
|
||||||
value: settingsStore.chatOnlyPreventSleep,
|
|
||||||
onChanged: (newValue) =>
|
|
||||||
settingsStore.chatOnlyPreventSleep = newValue,
|
|
||||||
),
|
|
||||||
const SectionHeader('Muted keywords'),
|
const SectionHeader('Muted keywords'),
|
||||||
SettingsMutedWords(settingsStore: settingsStore),
|
SettingsMutedWords(settingsStore: settingsStore),
|
||||||
SettingsListSwitch(
|
SettingsListSwitch(
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ class GeneralSettings extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (context) => ListView(
|
builder: (context) => ListView(
|
||||||
padding: const EdgeInsets.only(top: 16),
|
|
||||||
children: [
|
children: [
|
||||||
const SectionHeader(
|
const SectionHeader(
|
||||||
'Theme',
|
'Theme',
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ class Settings extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
appBar: FrostyAppBar(
|
appBar: FrostyAppBar(
|
||||||
title: const Text('Settings'),
|
title: const Text('Settings'),
|
||||||
actions: [
|
actions: [
|
||||||
|
|
@ -53,12 +54,12 @@ class Settings extends StatelessWidget {
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
|
top: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: ListView(
|
child: ListView(
|
||||||
padding: const EdgeInsets.only(top: 16),
|
|
||||||
children: [
|
children: [
|
||||||
const SectionHeader(
|
const SectionHeader(
|
||||||
'Profile',
|
'Account',
|
||||||
isFirst: true,
|
isFirst: true,
|
||||||
),
|
),
|
||||||
ProfileCard(authStore: context.read<AuthStore>()),
|
ProfileCard(authStore: context.read<AuthStore>()),
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
// Player defaults
|
// Player defaults
|
||||||
static const defaultShowVideo = true;
|
static const defaultShowVideo = true;
|
||||||
static const defaultDefaultToHighestQuality = false;
|
static const defaultDefaultToHighestQuality = false;
|
||||||
static const defaultShowLatency = true;
|
|
||||||
static const defaultUseEnhancedRendering = false;
|
static const defaultUseEnhancedRendering = false;
|
||||||
|
|
||||||
// Overlay defaults
|
// Overlay defaults
|
||||||
|
|
@ -80,10 +79,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
var defaultToHighestQuality = defaultDefaultToHighestQuality;
|
var defaultToHighestQuality = defaultDefaultToHighestQuality;
|
||||||
|
|
||||||
@JsonKey(defaultValue: defaultShowLatency)
|
|
||||||
@observable
|
|
||||||
var showLatency = defaultShowLatency;
|
|
||||||
|
|
||||||
@JsonKey(defaultValue: defaultUseEnhancedRendering)
|
@JsonKey(defaultValue: defaultUseEnhancedRendering)
|
||||||
@observable
|
@observable
|
||||||
var useEnhancedRendering = defaultUseEnhancedRendering;
|
var useEnhancedRendering = defaultUseEnhancedRendering;
|
||||||
|
|
@ -105,7 +100,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
void resetVideoSettings() {
|
void resetVideoSettings() {
|
||||||
showVideo = defaultShowVideo;
|
showVideo = defaultShowVideo;
|
||||||
defaultToHighestQuality = defaultDefaultToHighestQuality;
|
defaultToHighestQuality = defaultDefaultToHighestQuality;
|
||||||
showLatency = defaultShowLatency;
|
|
||||||
useEnhancedRendering = defaultUseEnhancedRendering;
|
useEnhancedRendering = defaultUseEnhancedRendering;
|
||||||
|
|
||||||
showOverlay = defaultShowOverlay;
|
showOverlay = defaultShowOverlay;
|
||||||
|
|
@ -122,7 +116,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
static const defaultFontSize = 12.0;
|
static const defaultFontSize = 12.0;
|
||||||
|
|
||||||
// Message appearance defaults
|
// Message appearance defaults
|
||||||
static const defaultUseReadableColors = true;
|
|
||||||
static const defaultShowDeletedMessages = false;
|
static const defaultShowDeletedMessages = false;
|
||||||
static const defaultShowChatMessageDividers = false;
|
static const defaultShowChatMessageDividers = false;
|
||||||
static const defaultTimestampType = TimestampType.disabled;
|
static const defaultTimestampType = TimestampType.disabled;
|
||||||
|
|
@ -147,9 +140,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
static const defaultChatWidth = 0.25;
|
static const defaultChatWidth = 0.25;
|
||||||
static const defaultFullScreenChatOverlayOpacity = 0.5;
|
static const defaultFullScreenChatOverlayOpacity = 0.5;
|
||||||
|
|
||||||
// Sleep defaults
|
|
||||||
static const defaultChatOnlyPreventSleep = false;
|
|
||||||
|
|
||||||
// mute words defaults
|
// mute words defaults
|
||||||
static const defaultMutedWords = <String>[];
|
static const defaultMutedWords = <String>[];
|
||||||
static const defaultMatchWholeWord = true;
|
static const defaultMatchWholeWord = true;
|
||||||
|
|
@ -191,10 +181,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
var fontSize = defaultFontSize;
|
var fontSize = defaultFontSize;
|
||||||
|
|
||||||
// Message appearance options
|
// Message appearance options
|
||||||
@JsonKey(defaultValue: defaultUseReadableColors)
|
|
||||||
@observable
|
|
||||||
var useReadableColors = defaultUseReadableColors;
|
|
||||||
|
|
||||||
@JsonKey(defaultValue: defaultShowDeletedMessages)
|
@JsonKey(defaultValue: defaultShowDeletedMessages)
|
||||||
@observable
|
@observable
|
||||||
var showDeletedMessages = defaultShowDeletedMessages;
|
var showDeletedMessages = defaultShowDeletedMessages;
|
||||||
|
|
@ -262,11 +248,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
@observable
|
@observable
|
||||||
var fullScreenChatOverlayOpacity = defaultFullScreenChatOverlayOpacity;
|
var fullScreenChatOverlayOpacity = defaultFullScreenChatOverlayOpacity;
|
||||||
|
|
||||||
// Sleep options
|
|
||||||
@JsonKey(defaultValue: defaultChatOnlyPreventSleep)
|
|
||||||
@observable
|
|
||||||
var chatOnlyPreventSleep = defaultChatOnlyPreventSleep;
|
|
||||||
|
|
||||||
// Autocomplete options
|
// Autocomplete options
|
||||||
@JsonKey(defaultValue: defaultAutocomplete)
|
@JsonKey(defaultValue: defaultAutocomplete)
|
||||||
@observable
|
@observable
|
||||||
|
|
@ -322,7 +303,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
messageSpacing = defaultMessageSpacing;
|
messageSpacing = defaultMessageSpacing;
|
||||||
fontSize = defaultFontSize;
|
fontSize = defaultFontSize;
|
||||||
|
|
||||||
useReadableColors = defaultUseReadableColors;
|
|
||||||
showDeletedMessages = defaultShowDeletedMessages;
|
showDeletedMessages = defaultShowDeletedMessages;
|
||||||
showChatMessageDividers = defaultShowChatMessageDividers;
|
showChatMessageDividers = defaultShowChatMessageDividers;
|
||||||
timestampType = defaultTimestampType;
|
timestampType = defaultTimestampType;
|
||||||
|
|
@ -343,8 +323,6 @@ abstract class _SettingsStoreBase with Store {
|
||||||
chatWidth = defaultChatWidth;
|
chatWidth = defaultChatWidth;
|
||||||
fullScreenChatOverlayOpacity = defaultFullScreenChatOverlayOpacity;
|
fullScreenChatOverlayOpacity = defaultFullScreenChatOverlayOpacity;
|
||||||
|
|
||||||
chatOnlyPreventSleep = defaultChatOnlyPreventSleep;
|
|
||||||
|
|
||||||
mutedWords = defaultMutedWords;
|
mutedWords = defaultMutedWords;
|
||||||
matchWholeWord = defaultMatchWholeWord;
|
matchWholeWord = defaultMatchWholeWord;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ SettingsStore _$SettingsStoreFromJson(Map<String, dynamic> json) =>
|
||||||
..showVideo = json['showVideo'] as bool? ?? true
|
..showVideo = json['showVideo'] as bool? ?? true
|
||||||
..defaultToHighestQuality =
|
..defaultToHighestQuality =
|
||||||
json['defaultToHighestQuality'] as bool? ?? false
|
json['defaultToHighestQuality'] as bool? ?? false
|
||||||
..showLatency = json['showLatency'] as bool? ?? true
|
|
||||||
..useEnhancedRendering = json['useEnhancedRendering'] as bool? ?? false
|
..useEnhancedRendering = json['useEnhancedRendering'] as bool? ?? false
|
||||||
..showOverlay = json['showOverlay'] as bool? ?? true
|
..showOverlay = json['showOverlay'] as bool? ?? true
|
||||||
..toggleableOverlay = json['toggleableOverlay'] as bool? ?? false
|
..toggleableOverlay = json['toggleableOverlay'] as bool? ?? false
|
||||||
|
|
@ -28,7 +27,6 @@ SettingsStore _$SettingsStoreFromJson(Map<String, dynamic> json) =>
|
||||||
..messageScale = (json['messageScale'] as num?)?.toDouble() ?? 1.0
|
..messageScale = (json['messageScale'] as num?)?.toDouble() ?? 1.0
|
||||||
..messageSpacing = (json['messageSpacing'] as num?)?.toDouble() ?? 8.0
|
..messageSpacing = (json['messageSpacing'] as num?)?.toDouble() ?? 8.0
|
||||||
..fontSize = (json['fontSize'] as num?)?.toDouble() ?? 12.0
|
..fontSize = (json['fontSize'] as num?)?.toDouble() ?? 12.0
|
||||||
..useReadableColors = json['useReadableColors'] as bool? ?? true
|
|
||||||
..showDeletedMessages = json['showDeletedMessages'] as bool? ?? false
|
..showDeletedMessages = json['showDeletedMessages'] as bool? ?? false
|
||||||
..showChatMessageDividers =
|
..showChatMessageDividers =
|
||||||
json['showChatMessageDividers'] as bool? ?? false
|
json['showChatMessageDividers'] as bool? ?? false
|
||||||
|
|
@ -54,7 +52,6 @@ SettingsStore _$SettingsStoreFromJson(Map<String, dynamic> json) =>
|
||||||
..chatWidth = (json['chatWidth'] as num?)?.toDouble() ?? 0.25
|
..chatWidth = (json['chatWidth'] as num?)?.toDouble() ?? 0.25
|
||||||
..fullScreenChatOverlayOpacity =
|
..fullScreenChatOverlayOpacity =
|
||||||
(json['fullScreenChatOverlayOpacity'] as num?)?.toDouble() ?? 0.5
|
(json['fullScreenChatOverlayOpacity'] as num?)?.toDouble() ?? 0.5
|
||||||
..chatOnlyPreventSleep = json['chatOnlyPreventSleep'] as bool? ?? false
|
|
||||||
..autocomplete = json['autocomplete'] as bool? ?? true
|
..autocomplete = json['autocomplete'] as bool? ?? true
|
||||||
..showTwitchEmotes = json['showTwitchEmotes'] as bool? ?? true
|
..showTwitchEmotes = json['showTwitchEmotes'] as bool? ?? true
|
||||||
..showTwitchBadges = json['showTwitchBadges'] as bool? ?? true
|
..showTwitchBadges = json['showTwitchBadges'] as bool? ?? true
|
||||||
|
|
@ -87,7 +84,6 @@ Map<String, dynamic> _$SettingsStoreToJson(SettingsStore instance) =>
|
||||||
'launchUrlExternal': instance.launchUrlExternal,
|
'launchUrlExternal': instance.launchUrlExternal,
|
||||||
'showVideo': instance.showVideo,
|
'showVideo': instance.showVideo,
|
||||||
'defaultToHighestQuality': instance.defaultToHighestQuality,
|
'defaultToHighestQuality': instance.defaultToHighestQuality,
|
||||||
'showLatency': instance.showLatency,
|
|
||||||
'useEnhancedRendering': instance.useEnhancedRendering,
|
'useEnhancedRendering': instance.useEnhancedRendering,
|
||||||
'showOverlay': instance.showOverlay,
|
'showOverlay': instance.showOverlay,
|
||||||
'toggleableOverlay': instance.toggleableOverlay,
|
'toggleableOverlay': instance.toggleableOverlay,
|
||||||
|
|
@ -97,7 +93,6 @@ Map<String, dynamic> _$SettingsStoreToJson(SettingsStore instance) =>
|
||||||
'messageScale': instance.messageScale,
|
'messageScale': instance.messageScale,
|
||||||
'messageSpacing': instance.messageSpacing,
|
'messageSpacing': instance.messageSpacing,
|
||||||
'fontSize': instance.fontSize,
|
'fontSize': instance.fontSize,
|
||||||
'useReadableColors': instance.useReadableColors,
|
|
||||||
'showDeletedMessages': instance.showDeletedMessages,
|
'showDeletedMessages': instance.showDeletedMessages,
|
||||||
'showChatMessageDividers': instance.showChatMessageDividers,
|
'showChatMessageDividers': instance.showChatMessageDividers,
|
||||||
'timestampType': _$TimestampTypeEnumMap[instance.timestampType]!,
|
'timestampType': _$TimestampTypeEnumMap[instance.timestampType]!,
|
||||||
|
|
@ -114,7 +109,6 @@ Map<String, dynamic> _$SettingsStoreToJson(SettingsStore instance) =>
|
||||||
_$LandscapeCutoutTypeEnumMap[instance.landscapeCutout]!,
|
_$LandscapeCutoutTypeEnumMap[instance.landscapeCutout]!,
|
||||||
'chatWidth': instance.chatWidth,
|
'chatWidth': instance.chatWidth,
|
||||||
'fullScreenChatOverlayOpacity': instance.fullScreenChatOverlayOpacity,
|
'fullScreenChatOverlayOpacity': instance.fullScreenChatOverlayOpacity,
|
||||||
'chatOnlyPreventSleep': instance.chatOnlyPreventSleep,
|
|
||||||
'autocomplete': instance.autocomplete,
|
'autocomplete': instance.autocomplete,
|
||||||
'showTwitchEmotes': instance.showTwitchEmotes,
|
'showTwitchEmotes': instance.showTwitchEmotes,
|
||||||
'showTwitchBadges': instance.showTwitchBadges,
|
'showTwitchBadges': instance.showTwitchBadges,
|
||||||
|
|
@ -271,22 +265,6 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
late final _$showLatencyAtom =
|
|
||||||
Atom(name: '_SettingsStoreBase.showLatency', context: context);
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get showLatency {
|
|
||||||
_$showLatencyAtom.reportRead();
|
|
||||||
return super.showLatency;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
set showLatency(bool value) {
|
|
||||||
_$showLatencyAtom.reportWrite(value, super.showLatency, () {
|
|
||||||
super.showLatency = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
late final _$useEnhancedRenderingAtom =
|
late final _$useEnhancedRenderingAtom =
|
||||||
Atom(name: '_SettingsStoreBase.useEnhancedRendering', context: context);
|
Atom(name: '_SettingsStoreBase.useEnhancedRendering', context: context);
|
||||||
|
|
||||||
|
|
@ -432,22 +410,6 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
late final _$useReadableColorsAtom =
|
|
||||||
Atom(name: '_SettingsStoreBase.useReadableColors', context: context);
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get useReadableColors {
|
|
||||||
_$useReadableColorsAtom.reportRead();
|
|
||||||
return super.useReadableColors;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
set useReadableColors(bool value) {
|
|
||||||
_$useReadableColorsAtom.reportWrite(value, super.useReadableColors, () {
|
|
||||||
super.useReadableColors = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
late final _$showDeletedMessagesAtom =
|
late final _$showDeletedMessagesAtom =
|
||||||
Atom(name: '_SettingsStoreBase.showDeletedMessages', context: context);
|
Atom(name: '_SettingsStoreBase.showDeletedMessages', context: context);
|
||||||
|
|
||||||
|
|
@ -696,23 +658,6 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
late final _$chatOnlyPreventSleepAtom =
|
|
||||||
Atom(name: '_SettingsStoreBase.chatOnlyPreventSleep', context: context);
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get chatOnlyPreventSleep {
|
|
||||||
_$chatOnlyPreventSleepAtom.reportRead();
|
|
||||||
return super.chatOnlyPreventSleep;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
set chatOnlyPreventSleep(bool value) {
|
|
||||||
_$chatOnlyPreventSleepAtom.reportWrite(value, super.chatOnlyPreventSleep,
|
|
||||||
() {
|
|
||||||
super.chatOnlyPreventSleep = value;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
late final _$autocompleteAtom =
|
late final _$autocompleteAtom =
|
||||||
Atom(name: '_SettingsStoreBase.autocomplete', context: context);
|
Atom(name: '_SettingsStoreBase.autocomplete', context: context);
|
||||||
|
|
||||||
|
|
@ -1034,7 +979,6 @@ largeStreamCard: ${largeStreamCard},
|
||||||
launchUrlExternal: ${launchUrlExternal},
|
launchUrlExternal: ${launchUrlExternal},
|
||||||
showVideo: ${showVideo},
|
showVideo: ${showVideo},
|
||||||
defaultToHighestQuality: ${defaultToHighestQuality},
|
defaultToHighestQuality: ${defaultToHighestQuality},
|
||||||
showLatency: ${showLatency},
|
|
||||||
useEnhancedRendering: ${useEnhancedRendering},
|
useEnhancedRendering: ${useEnhancedRendering},
|
||||||
showOverlay: ${showOverlay},
|
showOverlay: ${showOverlay},
|
||||||
toggleableOverlay: ${toggleableOverlay},
|
toggleableOverlay: ${toggleableOverlay},
|
||||||
|
|
@ -1044,7 +988,6 @@ emoteScale: ${emoteScale},
|
||||||
messageScale: ${messageScale},
|
messageScale: ${messageScale},
|
||||||
messageSpacing: ${messageSpacing},
|
messageSpacing: ${messageSpacing},
|
||||||
fontSize: ${fontSize},
|
fontSize: ${fontSize},
|
||||||
useReadableColors: ${useReadableColors},
|
|
||||||
showDeletedMessages: ${showDeletedMessages},
|
showDeletedMessages: ${showDeletedMessages},
|
||||||
showChatMessageDividers: ${showChatMessageDividers},
|
showChatMessageDividers: ${showChatMessageDividers},
|
||||||
timestampType: ${timestampType},
|
timestampType: ${timestampType},
|
||||||
|
|
@ -1060,7 +1003,6 @@ landscapeForceVerticalChat: ${landscapeForceVerticalChat},
|
||||||
landscapeCutout: ${landscapeCutout},
|
landscapeCutout: ${landscapeCutout},
|
||||||
chatWidth: ${chatWidth},
|
chatWidth: ${chatWidth},
|
||||||
fullScreenChatOverlayOpacity: ${fullScreenChatOverlayOpacity},
|
fullScreenChatOverlayOpacity: ${fullScreenChatOverlayOpacity},
|
||||||
chatOnlyPreventSleep: ${chatOnlyPreventSleep},
|
|
||||||
autocomplete: ${autocomplete},
|
autocomplete: ${autocomplete},
|
||||||
showTwitchEmotes: ${showTwitchEmotes},
|
showTwitchEmotes: ${showTwitchEmotes},
|
||||||
showTwitchBadges: ${showTwitchBadges},
|
showTwitchBadges: ${showTwitchBadges},
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ class VideoSettings extends StatelessWidget {
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Observer(
|
return Observer(
|
||||||
builder: (context) => ListView(
|
builder: (context) => ListView(
|
||||||
padding: const EdgeInsets.only(top: 16),
|
|
||||||
children: [
|
children: [
|
||||||
const SectionHeader(
|
const SectionHeader(
|
||||||
'Player',
|
'Player',
|
||||||
|
|
@ -35,11 +34,6 @@ class VideoSettings extends StatelessWidget {
|
||||||
onChanged: (newValue) =>
|
onChanged: (newValue) =>
|
||||||
settingsStore.defaultToHighestQuality = newValue,
|
settingsStore.defaultToHighestQuality = newValue,
|
||||||
),
|
),
|
||||||
SettingsListSwitch(
|
|
||||||
title: 'Show latency',
|
|
||||||
value: settingsStore.showLatency,
|
|
||||||
onChanged: (newValue) => settingsStore.showLatency = newValue,
|
|
||||||
),
|
|
||||||
if (Platform.isAndroid)
|
if (Platform.isAndroid)
|
||||||
SettingsListSwitch(
|
SettingsListSwitch(
|
||||||
title: 'Use enhanced rendering',
|
title: 'Use enhanced rendering',
|
||||||
|
|
|
||||||
|
|
@ -25,8 +25,10 @@ class SettingsTileRoute extends StatelessWidget {
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => useScaffold
|
builder: (context) => useScaffold
|
||||||
? Scaffold(
|
? Scaffold(
|
||||||
|
extendBodyBehindAppBar: true,
|
||||||
appBar: FrostyAppBar(title: Text(title)),
|
appBar: FrostyAppBar(title: Text(title)),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
|
top: false,
|
||||||
bottom: false,
|
bottom: false,
|
||||||
child: child,
|
child: child,
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -7,24 +7,29 @@ class FrostyThemes {
|
||||||
|
|
||||||
const FrostyThemes({required this.colorSchemeSeed});
|
const FrostyThemes({required this.colorSchemeSeed});
|
||||||
|
|
||||||
ThemeData createBaseTheme({
|
ThemeData get light => createBaseTheme(
|
||||||
required Brightness brightness,
|
colorScheme: ColorScheme.fromSeed(seedColor: colorSchemeSeed),
|
||||||
required Color colorSchemeSeed,
|
backgroundColor: const Color.fromRGBO(248, 248, 248, 1),
|
||||||
Color? backgroundColor,
|
|
||||||
}) {
|
|
||||||
final colorScheme = ColorScheme.fromSeed(
|
|
||||||
seedColor: colorSchemeSeed,
|
|
||||||
brightness: brightness,
|
|
||||||
);
|
);
|
||||||
|
|
||||||
final borderColor = colorScheme.outlineVariant;
|
ThemeData get dark => createBaseTheme(
|
||||||
|
colorScheme: ColorScheme.fromSeed(
|
||||||
|
seedColor: colorSchemeSeed,
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
),
|
||||||
|
backgroundColor: Colors.black,
|
||||||
|
);
|
||||||
|
|
||||||
|
ThemeData createBaseTheme({
|
||||||
|
required ColorScheme colorScheme,
|
||||||
|
Color? backgroundColor,
|
||||||
|
}) {
|
||||||
|
final borderColor = colorScheme.outlineVariant;
|
||||||
const borderWidth = 0.5;
|
const borderWidth = 0.5;
|
||||||
|
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
fontFamily: 'Inter',
|
|
||||||
brightness: brightness,
|
|
||||||
colorScheme: colorScheme,
|
colorScheme: colorScheme,
|
||||||
|
fontFamily: 'Inter',
|
||||||
splashFactory: Platform.isIOS ? NoSplash.splashFactory : null,
|
splashFactory: Platform.isIOS ? NoSplash.splashFactory : null,
|
||||||
scaffoldBackgroundColor: backgroundColor,
|
scaffoldBackgroundColor: backgroundColor,
|
||||||
bottomSheetTheme: BottomSheetThemeData(
|
bottomSheetTheme: BottomSheetThemeData(
|
||||||
|
|
@ -37,11 +42,14 @@ class FrostyThemes {
|
||||||
surfaceTintColor: backgroundColor,
|
surfaceTintColor: backgroundColor,
|
||||||
),
|
),
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: AppBarTheme(
|
||||||
elevation: 0,
|
backgroundColor: Colors.transparent,
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
surfaceTintColor: backgroundColor,
|
surfaceTintColor: backgroundColor,
|
||||||
shape: Border(
|
),
|
||||||
bottom: BorderSide(color: borderColor, width: borderWidth),
|
listTileTheme: ListTileThemeData(
|
||||||
|
titleTextStyle: TextStyle(
|
||||||
|
color: colorScheme.onSurface,
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: FontWeight.w500,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
inputDecorationTheme: InputDecorationTheme(
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
|
@ -61,7 +69,6 @@ class FrostyThemes {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
navigationBarTheme: NavigationBarThemeData(
|
navigationBarTheme: NavigationBarThemeData(
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: backgroundColor,
|
backgroundColor: backgroundColor,
|
||||||
height: 64,
|
height: 64,
|
||||||
labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,
|
labelBehavior: NavigationDestinationLabelBehavior.alwaysHide,
|
||||||
|
|
@ -71,6 +78,7 @@ class FrostyThemes {
|
||||||
tabAlignment: TabAlignment.start,
|
tabAlignment: TabAlignment.start,
|
||||||
),
|
),
|
||||||
tooltipTheme: TooltipThemeData(
|
tooltipTheme: TooltipThemeData(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: backgroundColor,
|
color: backgroundColor,
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
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,28 +1,39 @@
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class FrostyAppBar extends StatelessWidget implements PreferredSizeWidget {
|
class FrostyAppBar extends StatelessWidget implements PreferredSizeWidget {
|
||||||
final Widget title;
|
final Widget? title;
|
||||||
final bool? centerTitle;
|
|
||||||
final List<Widget>? actions;
|
final List<Widget>? actions;
|
||||||
|
final bool showBackButton;
|
||||||
|
|
||||||
const FrostyAppBar({
|
const FrostyAppBar({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
this.title,
|
||||||
this.centerTitle,
|
|
||||||
this.actions,
|
this.actions,
|
||||||
|
this.showBackButton = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppBar(
|
return ClipRRect(
|
||||||
leading: IconButton(
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 16, sigmaY: 16),
|
||||||
|
child: AppBar(
|
||||||
|
backgroundColor:
|
||||||
|
Theme.of(context).colorScheme.surface.withValues(alpha: 0.6),
|
||||||
|
leading: showBackButton
|
||||||
|
? IconButton(
|
||||||
tooltip: 'Back',
|
tooltip: 'Back',
|
||||||
icon: Icon(Icons.adaptive.arrow_back_rounded),
|
icon: Icon(Icons.adaptive.arrow_back_rounded),
|
||||||
onPressed: Navigator.of(context).pop,
|
onPressed: Navigator.of(context).pop,
|
||||||
),
|
)
|
||||||
|
: null,
|
||||||
title: title,
|
title: title,
|
||||||
centerTitle: centerTitle,
|
|
||||||
actions: actions,
|
actions: actions,
|
||||||
|
centerTitle: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,24 +17,18 @@ class SectionHeader extends StatelessWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: padding ?? const EdgeInsets.fromLTRB(16, 0, 16, 8),
|
padding: padding ??
|
||||||
child: Column(
|
(isFirst
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
? const EdgeInsets.fromLTRB(16, 16, 16, 8)
|
||||||
mainAxisSize: MainAxisSize.min,
|
: const EdgeInsets.fromLTRB(16, 32, 16, 8)),
|
||||||
children: [
|
child: Text(
|
||||||
if (!isFirst) ...[
|
text.toUpperCase(),
|
||||||
const Divider(),
|
|
||||||
const SizedBox(height: 16),
|
|
||||||
],
|
|
||||||
Text(
|
|
||||||
text,
|
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: fontSize ?? 16,
|
fontSize: fontSize ?? 14,
|
||||||
fontWeight: FontWeight.w600,
|
fontWeight: FontWeight.w600,
|
||||||
|
color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue