Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minimizing mode #258

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
238 changes: 145 additions & 93 deletions lib/screens/channel/channel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ class _VideoChatState extends State<VideoChat> {
? () => settingsStore.fullScreen = !settingsStore.fullScreen
: null,
onTap: () {
if (_videoStore.miniVedioMode) {
_videoStore.setMiniVedioMode(false);
return;
}
if (_chatStore.assetsStore.showEmoteMenu) {
_chatStore.assetsStore.showEmoteMenu = false;
} else {
Expand Down Expand Up @@ -204,9 +208,8 @@ class _VideoChatState extends State<VideoChat> {
final data =
await Clipboard.getData(Clipboard.kTextPlain);

if (data != null) {
if (data != null)
_chatStore.textController.text = data.text!;
}

_chatStore.updateNotification('');
},
Expand All @@ -219,102 +222,151 @@ class _VideoChatState extends State<VideoChat> {
},
);

final videoChat = Scaffold(
body: Observer(
builder: (context) {
if (orientation == Orientation.landscape &&
!settingsStore.landscapeForceVerticalChat) {
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);

final landscapeChat = AnimatedContainer(
curve: Curves.ease,
duration: const Duration(milliseconds: 200),
width: _chatStore.expandChat
? MediaQuery.of(context).size.width / 2
: MediaQuery.of(context).size.width *
_chatStore.settings.chatWidth,
color: _chatStore.settings.fullScreen
? Colors.black.withOpacity(
_chatStore.settings.fullScreenChatOverlayOpacity)
: Theme.of(context).scaffoldBackgroundColor,
child: chat,
);

final overlayChat = Visibility(
visible: settingsStore.fullScreenChatOverlay,
maintainState: true,
child: Theme(
data: darkTheme,
child: DefaultTextStyle(
style: DefaultTextStyle.of(context)
.style
.copyWith(color: Colors.white),
child: landscapeChat,
final videoChat = Observer(builder: (_) {
return _videoStore.miniVedioMode
? Positioned(
right: 10,
bottom: 60,
child: SizedBox(
width: 180,
height: 100,
child: Dismissible(
key: ValueKey('${widget.key}_mini'),
direction: DismissDirection.horizontal,
onDismissed: (direction) {
Navigator.of(context).pop();
},
child: Scaffold(
body: Observer(builder: (context) {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: SystemUiOverlay.values,
);
return AspectRatio(aspectRatio: 16 / 9, child: video);
}),
),
),
),
);

return ColoredBox(
color: settingsStore.showVideo
? Colors.black
: Theme.of(context).scaffoldBackgroundColor,
child: SafeArea(
bottom: false,
left: (settingsStore.landscapeCutout ==
LandscapeCutoutType.both ||
settingsStore.landscapeCutout ==
LandscapeCutoutType.left)
? false
: true,
right: (settingsStore.landscapeCutout ==
LandscapeCutoutType.both ||
settingsStore.landscapeCutout ==
LandscapeCutoutType.right)
? false
: true,
child: settingsStore.showVideo
? settingsStore.fullScreen
? Stack(
children: [
player,
if (settingsStore.showOverlay)
Row(
children: settingsStore.landscapeChatLeftSide
? [overlayChat, Expanded(child: overlay)]
: [Expanded(child: overlay), overlayChat],
)
],
)
: Row(
children: settingsStore.landscapeChatLeftSide
? [landscapeChat, Expanded(child: video)]
: [Expanded(child: video), landscapeChat],
)
: Column(
children: [appBar, Expanded(child: chat)],
)
: Dismissible(
key: ValueKey(widget.key),
direction: DismissDirection.vertical,
onDismissed: (direction) {
_videoStore.setMiniVedioMode(true);
},
child: Scaffold(
body: Observer(
builder: (context) {
if (orientation == Orientation.landscape &&
!settingsStore.landscapeForceVerticalChat) {
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.immersiveSticky);

final landscapeChat = AnimatedContainer(
curve: Curves.ease,
duration: const Duration(milliseconds: 200),
width: _chatStore.expandChat
? MediaQuery.of(context).size.width / 2
: MediaQuery.of(context).size.width *
_chatStore.settings.chatWidth,
color: _chatStore.settings.fullScreen
? Colors.black.withOpacity(_chatStore
.settings.fullScreenChatOverlayOpacity)
: Theme.of(context).scaffoldBackgroundColor,
child: chat,
);

final overlayChat = Visibility(
visible: settingsStore.fullScreenChatOverlay,
maintainState: true,
child: Theme(
data: darkTheme,
child: DefaultTextStyle(
style: DefaultTextStyle.of(context)
.style
.copyWith(color: Colors.white),
child: landscapeChat,
),
),
);

return ColoredBox(
color: settingsStore.showVideo
? Colors.black
: Theme.of(context).scaffoldBackgroundColor,
child: SafeArea(
bottom: false,
left: (settingsStore.landscapeCutout ==
LandscapeCutoutType.both ||
settingsStore.landscapeCutout ==
LandscapeCutoutType.left)
? false
: true,
right: (settingsStore.landscapeCutout ==
LandscapeCutoutType.both ||
settingsStore.landscapeCutout ==
LandscapeCutoutType.right)
? false
: true,
child: settingsStore.showVideo
? settingsStore.fullScreen
? Stack(
children: [
player,
if (settingsStore.showOverlay)
Row(
children: settingsStore
.landscapeChatLeftSide
? [
overlayChat,
Expanded(child: overlay)
]
: [
Expanded(child: overlay),
overlayChat
],
)
],
)
: Row(
children:
settingsStore.landscapeChatLeftSide
? [
landscapeChat,
Expanded(child: video)
]
: [
Expanded(child: video),
landscapeChat
],
)
: Column(
children: [appBar, Expanded(child: chat)],
),
),
);
}

SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: SystemUiOverlay.values,
);
return SafeArea(
child: Column(
children: [
if (!settingsStore.showVideo)
appBar
else
AspectRatio(aspectRatio: 16 / 9, child: video),
Expanded(child: chat),
],
),
);
},
),
),
);
}

SystemChrome.setEnabledSystemUIMode(
SystemUiMode.manual,
overlays: SystemUiOverlay.values,
);
return SafeArea(
child: Column(
children: [
if (!settingsStore.showVideo)
appBar
else
AspectRatio(aspectRatio: 16 / 9, child: video),
Expanded(child: chat),
],
),
);
},
),
);
});

// If on Android, use PiPSwitcher to enable PiP functionality.
if (Platform.isAndroid) {
Expand Down
9 changes: 7 additions & 2 deletions lib/screens/channel/video/video_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,20 @@ class VideoBar extends StatelessWidget {
const SizedBox(height: 5.0),
InkWell(
onTap: tappableCategory && streamInfo.gameName.isNotEmpty
? () => Navigator.push(
? () {
// remove until this page is the top level
Navigator.popUntil(
context, (route) => route.isFirst);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CategoryStreams(
categoryName: streamInfo.gameName,
categoryId: streamInfo.gameId,
),
),
)
);
}
: null,
child: Tooltip(
message:
Expand Down
17 changes: 17 additions & 0 deletions lib/screens/channel/video/video_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ abstract class VideoStoreBase with Store {
@readonly
var _isIPad = false;

/// For pip mode while in app.
@readonly
var _miniVedioMode = false;

/// The current stream info, used for displaying relevant info on the overlay.
@readonly
StreamTwitch? _streamInfo;
Expand Down Expand Up @@ -174,6 +178,19 @@ abstract class VideoStoreBase with Store {
}
}

/// Allows to switch between full mode and pip mode.
@action
void setMiniVedioMode(bool mode) {
// close overlay if open for mini vedio mode
if (mode) {
_overlayTimer.cancel();
if (_overlayVisible) {
_overlayVisible = false;
}
}
_miniVedioMode = mode;
}

/// Updates the stream info from the Twitch API.
///
/// If the stream is offline, disables the overlay.
Expand Down
29 changes: 29 additions & 0 deletions lib/screens/channel/video/video_store.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading