Merge pull request #122 from tommyxchow/116-transparent-chat-fullscreen-overlay
Add landscape chat overlay, chat side, and size options
This commit is contained in:
commit
21cb9820f9
10 changed files with 236 additions and 74 deletions
|
|
@ -108,7 +108,7 @@ class Chat extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (chatStore.settings.showBottomBar) ChatBottomBar(chatStore: chatStore),
|
||||
if (chatStore.settings.showBottomBar && !chatStore.settings.fullScreen) ChatBottomBar(chatStore: chatStore),
|
||||
if (chatStore.assetsStore.showEmoteMenu)
|
||||
SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 3,
|
||||
|
|
|
|||
|
|
@ -73,42 +73,54 @@ class ChatBottomBar extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
|
||||
child: TextField(
|
||||
textInputAction: TextInputAction.send,
|
||||
focusNode: chatStore.textFieldFocusNode,
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
enabled: chatStore.auth.isLoggedIn ? true : false,
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: IconButton(
|
||||
color: chatStore.assetsStore.showEmoteMenu ? Colors.deepPurple : null,
|
||||
tooltip: 'Emote Menu',
|
||||
icon: const Icon(Icons.emoji_emotions_outlined),
|
||||
onPressed: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
chatStore.assetsStore.showEmoteMenu = !chatStore.assetsStore.showEmoteMenu;
|
||||
},
|
||||
if (!chatStore.expandChat &&
|
||||
chatStore.settings.landscapeChatWidth < 0.3 &&
|
||||
MediaQuery.of(context).orientation == Orientation.landscape)
|
||||
IconButton(
|
||||
tooltip: 'Send a Message',
|
||||
onPressed: () {
|
||||
chatStore.expandChat = true;
|
||||
chatStore.textFieldFocusNode.requestFocus();
|
||||
},
|
||||
icon: const Icon(Icons.chat))
|
||||
else
|
||||
Expanded(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 5.0, horizontal: 10.0),
|
||||
child: TextField(
|
||||
textInputAction: TextInputAction.send,
|
||||
focusNode: chatStore.textFieldFocusNode,
|
||||
minLines: 1,
|
||||
maxLines: 5,
|
||||
enabled: chatStore.auth.isLoggedIn ? true : false,
|
||||
decoration: InputDecoration(
|
||||
suffixIcon: IconButton(
|
||||
color: chatStore.assetsStore.showEmoteMenu ? Colors.deepPurple : null,
|
||||
tooltip: 'Emote Menu',
|
||||
icon: const Icon(Icons.emoji_emotions_outlined),
|
||||
onPressed: () {
|
||||
FocusScope.of(context).unfocus();
|
||||
chatStore.assetsStore.showEmoteMenu = !chatStore.assetsStore.showEmoteMenu;
|
||||
},
|
||||
),
|
||||
hintMaxLines: 1,
|
||||
contentPadding: const EdgeInsets.all(10.0),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
),
|
||||
labelText: chatStore.auth.isLoggedIn ? 'Send a message' : 'Log in to chat',
|
||||
),
|
||||
hintMaxLines: 1,
|
||||
contentPadding: const EdgeInsets.all(10.0),
|
||||
border: const OutlineInputBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(15.0)),
|
||||
),
|
||||
labelText: chatStore.auth.isLoggedIn ? 'Send a message' : 'Log in to chat',
|
||||
controller: chatStore.textController,
|
||||
onSubmitted: chatStore.sendMessage,
|
||||
),
|
||||
controller: chatStore.textController,
|
||||
onSubmitted: chatStore.sendMessage,
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Send',
|
||||
icon: const Icon(Icons.send),
|
||||
onPressed: chatStore.auth.isLoggedIn ? () => chatStore.sendMessage(chatStore.textController.text) : null,
|
||||
)
|
||||
if (chatStore.settings.landscapeChatWidth > 0.3 || chatStore.expandChat || MediaQuery.of(context).orientation == Orientation.portrait)
|
||||
IconButton(
|
||||
tooltip: 'Send',
|
||||
icon: const Icon(Icons.send),
|
||||
onPressed: chatStore.auth.isLoggedIn ? () => chatStore.sendMessage(chatStore.textController.text) : null,
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
|
|
|
|||
|
|
@ -78,6 +78,9 @@ abstract class ChatStoreBase with Store {
|
|||
@readonly
|
||||
var _userState = const USERSTATE();
|
||||
|
||||
@observable
|
||||
var expandChat = false;
|
||||
|
||||
final reactions = <ReactionDisposer>[];
|
||||
|
||||
ChatStoreBase({
|
||||
|
|
@ -116,6 +119,8 @@ abstract class ChatStoreBase with Store {
|
|||
// Add a listener to the textfield focus that will hide the emote menu if it is currently shown.
|
||||
textFieldFocusNode.addListener(() {
|
||||
if (textFieldFocusNode.hasFocus && assetsStore.showEmoteMenu) assetsStore.showEmoteMenu = false;
|
||||
|
||||
if (!textFieldFocusNode.hasFocus) expandChat = false;
|
||||
});
|
||||
|
||||
// Add a listener to the textfield that will show/hide the autocomplete bar if focused.
|
||||
|
|
|
|||
|
|
@ -81,6 +81,22 @@ mixin _$ChatStore on ChatStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
late final _$expandChatAtom =
|
||||
Atom(name: 'ChatStoreBase.expandChat', context: context);
|
||||
|
||||
@override
|
||||
bool get expandChat {
|
||||
_$expandChatAtom.reportRead();
|
||||
return super.expandChat;
|
||||
}
|
||||
|
||||
@override
|
||||
set expandChat(bool value) {
|
||||
_$expandChatAtom.reportWrite(value, super.expandChat, () {
|
||||
super.expandChat = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$ChatStoreBaseActionController =
|
||||
ActionController(name: 'ChatStoreBase', context: context);
|
||||
|
||||
|
|
@ -142,7 +158,7 @@ mixin _$ChatStore on ChatStoreBase, Store {
|
|||
@override
|
||||
String toString() {
|
||||
return '''
|
||||
|
||||
expandChat: ${expandChat}
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,10 @@ abstract class VideoStoreBase with Store {
|
|||
_streamInfo = await twitchApi.getStream(userLogin: userLogin, headers: authStore.headersTwitch);
|
||||
} catch (e) {
|
||||
debugPrint(e.toString());
|
||||
|
||||
_streamInfo = null;
|
||||
_overlayTimer.cancel();
|
||||
_overlayVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -117,6 +117,13 @@ class VideoOverlay extends StatelessWidget {
|
|||
),
|
||||
);
|
||||
|
||||
final chatOverlayButton = IconButton(
|
||||
tooltip: 'Toggle Chat Overlay',
|
||||
onPressed: () => videoStore.settingsStore.fullScreenChatOverlay = !videoStore.settingsStore.fullScreenChatOverlay,
|
||||
icon: const Icon(Icons.chat_bubble_outline),
|
||||
color: Colors.white,
|
||||
);
|
||||
|
||||
final refreshButton = IconButton(
|
||||
tooltip: 'Refresh',
|
||||
icon: const Icon(
|
||||
|
|
@ -167,6 +174,7 @@ class VideoOverlay extends StatelessWidget {
|
|||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
if (videoStore.settingsStore.fullScreen && orientation == Orientation.landscape) chatOverlayButton,
|
||||
refreshButton,
|
||||
if (orientation == Orientation.landscape) fullScreenButton,
|
||||
],
|
||||
|
|
@ -292,6 +300,7 @@ class VideoOverlay extends StatelessWidget {
|
|||
),
|
||||
),
|
||||
),
|
||||
if (videoStore.settingsStore.fullScreen) chatOverlayButton,
|
||||
refreshButton,
|
||||
if (Platform.isIOS && videoStore.settingsStore.pictureInPicture)
|
||||
IconButton(
|
||||
|
|
|
|||
|
|
@ -154,45 +154,60 @@ class _VideoChatState extends State<VideoChat> {
|
|||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
|
||||
|
||||
return Observer(
|
||||
builder: (context) => ColoredBox(
|
||||
color: settingsStore.showVideo ? Colors.black : Theme.of(context).scaffoldBackgroundColor,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: settingsStore.showVideo
|
||||
? settingsStore.fullScreen
|
||||
? Stack(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: false,
|
||||
maintainState: true,
|
||||
child: chat,
|
||||
),
|
||||
video,
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: [
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: video,
|
||||
),
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: ColoredBox(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child: chat,
|
||||
builder: (context) {
|
||||
final landscapeChat = AnimatedContainer(
|
||||
duration: const Duration(milliseconds: 200),
|
||||
width: _chatStore.expandChat
|
||||
? MediaQuery.of(context).size.width / 2
|
||||
: MediaQuery.of(context).size.width * _chatStore.settings.landscapeChatWidth,
|
||||
curve: Curves.ease,
|
||||
color: _chatStore.settings.fullScreen ? null : Theme.of(context).scaffoldBackgroundColor,
|
||||
child: chat,
|
||||
);
|
||||
|
||||
return ColoredBox(
|
||||
color: settingsStore.showVideo ? Colors.black : Theme.of(context).scaffoldBackgroundColor,
|
||||
child: SafeArea(
|
||||
bottom: false,
|
||||
child: settingsStore.showVideo
|
||||
? settingsStore.fullScreen
|
||||
? Stack(
|
||||
alignment: settingsStore.landscapeChatLeftSide ? Alignment.topLeft : Alignment.topRight,
|
||||
children: [
|
||||
video,
|
||||
IgnorePointer(
|
||||
ignoring: _videoStore.overlayVisible,
|
||||
child: Visibility(
|
||||
visible: settingsStore.fullScreenChatOverlay,
|
||||
maintainState: true,
|
||||
child: DefaultTextStyle(
|
||||
style: const TextStyle(color: Colors.white),
|
||||
child: landscapeChat,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
appBar,
|
||||
Expanded(child: chat),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
: Row(
|
||||
children: settingsStore.landscapeChatLeftSide
|
||||
? [
|
||||
landscapeChat,
|
||||
Expanded(child: video),
|
||||
]
|
||||
: [
|
||||
Expanded(child: video),
|
||||
landscapeChat,
|
||||
],
|
||||
)
|
||||
: Column(
|
||||
children: [
|
||||
appBar,
|
||||
Expanded(child: chat),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -90,6 +90,27 @@ class _ChatSettingsState extends State<ChatSettings> {
|
|||
.toList(),
|
||||
),
|
||||
),
|
||||
SwitchListTile.adaptive(
|
||||
title: const Text('Landscape Chat on Left Side'),
|
||||
value: settingsStore.landscapeChatLeftSide,
|
||||
onChanged: (newValue) => settingsStore.landscapeChatLeftSide = newValue,
|
||||
),
|
||||
ListTile(
|
||||
title: Row(
|
||||
children: [
|
||||
const Text('Landscape Chat Width'),
|
||||
const Spacer(),
|
||||
Text('${(settingsStore.landscapeChatWidth * 100).toInt()}%'),
|
||||
],
|
||||
),
|
||||
subtitle: Slider.adaptive(
|
||||
value: settingsStore.landscapeChatWidth,
|
||||
min: 0.2,
|
||||
max: 0.8,
|
||||
divisions: 12,
|
||||
onChanged: (newValue) => settingsStore.landscapeChatWidth = newValue,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 10.0),
|
||||
const SectionHeader('Message Appearance'),
|
||||
ExpansionTile(
|
||||
|
|
|
|||
|
|
@ -87,6 +87,10 @@ abstract class _SettingsStoreBase with Store {
|
|||
|
||||
static const defaultEmoteAutocomplete = true;
|
||||
|
||||
static const defaultLandscapeChatWidth = 0.35;
|
||||
|
||||
static const defaultLandscapeChatLeftSide = false;
|
||||
|
||||
@JsonKey(defaultValue: defaultShowBottomBar)
|
||||
@observable
|
||||
var showBottomBar = defaultShowBottomBar;
|
||||
|
|
@ -135,6 +139,14 @@ abstract class _SettingsStoreBase with Store {
|
|||
@observable
|
||||
var emoteAutocomplete = defaultEmoteAutocomplete;
|
||||
|
||||
@JsonKey(defaultValue: defaultLandscapeChatWidth)
|
||||
@observable
|
||||
var landscapeChatWidth = defaultLandscapeChatWidth;
|
||||
|
||||
@JsonKey(defaultValue: defaultLandscapeChatLeftSide)
|
||||
@observable
|
||||
var landscapeChatLeftSide = defaultLandscapeChatLeftSide;
|
||||
|
||||
// * Other settings
|
||||
static const defaultSendCrashLogs = true;
|
||||
|
||||
|
|
@ -147,6 +159,8 @@ abstract class _SettingsStoreBase with Store {
|
|||
|
||||
static const defaultExpandInfo = true;
|
||||
|
||||
static const defaultFullScreenChatOverlay = false;
|
||||
|
||||
@JsonKey(defaultValue: defaultFullScreen)
|
||||
@observable
|
||||
var fullScreen = defaultFullScreen;
|
||||
|
|
@ -155,6 +169,10 @@ abstract class _SettingsStoreBase with Store {
|
|||
@observable
|
||||
var expandInfo = defaultExpandInfo;
|
||||
|
||||
@JsonKey(defaultValue: defaultFullScreenChatOverlay)
|
||||
@observable
|
||||
var fullScreenChatOverlay = defaultFullScreenChatOverlay;
|
||||
|
||||
@action
|
||||
void reset() {
|
||||
// * General Settings
|
||||
|
|
@ -182,6 +200,8 @@ abstract class _SettingsStoreBase with Store {
|
|||
badgeScale = defaultBadgeScale;
|
||||
emoteScale = defaultEmoteScale;
|
||||
emoteAutocomplete = defaultEmoteAutocomplete;
|
||||
landscapeChatWidth = defaultLandscapeChatWidth;
|
||||
landscapeChatLeftSide = false;
|
||||
|
||||
// * Other settings
|
||||
sendCrashLogs = defaultSendCrashLogs;
|
||||
|
|
|
|||
|
|
@ -34,9 +34,13 @@ SettingsStore _$SettingsStoreFromJson(Map<String, dynamic> json) =>
|
|||
..badgeScale = (json['badgeScale'] as num?)?.toDouble() ?? 1.0
|
||||
..emoteScale = (json['emoteScale'] as num?)?.toDouble() ?? 1.0
|
||||
..emoteAutocomplete = json['emoteAutocomplete'] as bool? ?? true
|
||||
..landscapeChatWidth =
|
||||
(json['landscapeChatWidth'] as num?)?.toDouble() ?? 0.35
|
||||
..landscapeChatLeftSide = json['landscapeChatLeftSide'] as bool? ?? false
|
||||
..sendCrashLogs = json['sendCrashLogs'] as bool? ?? true
|
||||
..fullScreen = json['fullScreen'] as bool? ?? false
|
||||
..expandInfo = json['expandInfo'] as bool? ?? true;
|
||||
..expandInfo = json['expandInfo'] as bool? ?? true
|
||||
..fullScreenChatOverlay = json['fullScreenChatOverlay'] as bool? ?? false;
|
||||
|
||||
Map<String, dynamic> _$SettingsStoreToJson(SettingsStore instance) =>
|
||||
<String, dynamic>{
|
||||
|
|
@ -60,9 +64,12 @@ Map<String, dynamic> _$SettingsStoreToJson(SettingsStore instance) =>
|
|||
'badgeScale': instance.badgeScale,
|
||||
'emoteScale': instance.emoteScale,
|
||||
'emoteAutocomplete': instance.emoteAutocomplete,
|
||||
'landscapeChatWidth': instance.landscapeChatWidth,
|
||||
'landscapeChatLeftSide': instance.landscapeChatLeftSide,
|
||||
'sendCrashLogs': instance.sendCrashLogs,
|
||||
'fullScreen': instance.fullScreen,
|
||||
'expandInfo': instance.expandInfo,
|
||||
'fullScreenChatOverlay': instance.fullScreenChatOverlay,
|
||||
};
|
||||
|
||||
const _$ThemeTypeEnumMap = {
|
||||
|
|
@ -406,6 +413,39 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
late final _$landscapeChatWidthAtom =
|
||||
Atom(name: '_SettingsStoreBase.landscapeChatWidth', context: context);
|
||||
|
||||
@override
|
||||
double get landscapeChatWidth {
|
||||
_$landscapeChatWidthAtom.reportRead();
|
||||
return super.landscapeChatWidth;
|
||||
}
|
||||
|
||||
@override
|
||||
set landscapeChatWidth(double value) {
|
||||
_$landscapeChatWidthAtom.reportWrite(value, super.landscapeChatWidth, () {
|
||||
super.landscapeChatWidth = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$landscapeChatLeftSideAtom =
|
||||
Atom(name: '_SettingsStoreBase.landscapeChatLeftSide', context: context);
|
||||
|
||||
@override
|
||||
bool get landscapeChatLeftSide {
|
||||
_$landscapeChatLeftSideAtom.reportRead();
|
||||
return super.landscapeChatLeftSide;
|
||||
}
|
||||
|
||||
@override
|
||||
set landscapeChatLeftSide(bool value) {
|
||||
_$landscapeChatLeftSideAtom.reportWrite(value, super.landscapeChatLeftSide,
|
||||
() {
|
||||
super.landscapeChatLeftSide = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$sendCrashLogsAtom =
|
||||
Atom(name: '_SettingsStoreBase.sendCrashLogs', context: context);
|
||||
|
||||
|
|
@ -454,6 +494,23 @@ mixin _$SettingsStore on _SettingsStoreBase, Store {
|
|||
});
|
||||
}
|
||||
|
||||
late final _$fullScreenChatOverlayAtom =
|
||||
Atom(name: '_SettingsStoreBase.fullScreenChatOverlay', context: context);
|
||||
|
||||
@override
|
||||
bool get fullScreenChatOverlay {
|
||||
_$fullScreenChatOverlayAtom.reportRead();
|
||||
return super.fullScreenChatOverlay;
|
||||
}
|
||||
|
||||
@override
|
||||
set fullScreenChatOverlay(bool value) {
|
||||
_$fullScreenChatOverlayAtom.reportWrite(value, super.fullScreenChatOverlay,
|
||||
() {
|
||||
super.fullScreenChatOverlay = value;
|
||||
});
|
||||
}
|
||||
|
||||
late final _$_SettingsStoreBaseActionController =
|
||||
ActionController(name: '_SettingsStoreBase', context: context);
|
||||
|
||||
|
|
@ -491,9 +548,12 @@ messageScale: ${messageScale},
|
|||
badgeScale: ${badgeScale},
|
||||
emoteScale: ${emoteScale},
|
||||
emoteAutocomplete: ${emoteAutocomplete},
|
||||
landscapeChatWidth: ${landscapeChatWidth},
|
||||
landscapeChatLeftSide: ${landscapeChatLeftSide},
|
||||
sendCrashLogs: ${sendCrashLogs},
|
||||
fullScreen: ${fullScreen},
|
||||
expandInfo: ${expandInfo}
|
||||
expandInfo: ${expandInfo},
|
||||
fullScreenChatOverlay: ${fullScreenChatOverlay}
|
||||
''';
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue