Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions commet/lib/config/preferences.dart
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,12 @@ class Preferences {
defaultGetter: () => Layout.mobile ? false : true,
defaultValue: false);

BoolPreference autoRotateImages =
BoolPreference("lightbox_rotate_images", defaultValue: false);

BoolPreference autoRotateVideos =
BoolPreference("lightbox_rotate_videos", defaultValue: false);

DoublePreference textScale =
DoublePreference("text_scale", defaultValue: 1.0);

Expand Down
223 changes: 147 additions & 76 deletions commet/lib/ui/atoms/lightbox.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:async';
import 'package:commet/cache/file_provider.dart';
import 'package:commet/config/build_config.dart';
import 'package:commet/config/layout_config.dart';
import 'package:commet/main.dart';
import 'package:commet/ui/atoms/scaled_safe_area.dart';
import 'package:commet/ui/molecules/video_player/video_player.dart';
import 'package:commet/ui/molecules/video_player/video_player_controller.dart';
Expand Down Expand Up @@ -72,17 +73,47 @@ class Lightbox extends StatefulWidget {
}
}

class _LightboxState extends State<Lightbox> {
class _LightboxState extends State<Lightbox> with TickerProviderStateMixin {
double aspectRatio = 1;
bool dismissing = false;
final controller = TransformationController();
bool loadingHighQuality = false;

StreamSubscription? onLodChanged;

bool rotate = false;

late final AnimationController _controller = AnimationController(
duration: const Duration(milliseconds: 850),
vsync: this,
);

late final Animation<double> rotationAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeInOutCubic,
).drive(Tween(begin: -0.25, end: 0.0));

late final Animation<double> scaleAnimation = CurvedAnimation(
parent: _controller,
curve: Curves.easeOut,
).drive(Tween(begin: 0.6, end: 1.0));

late final Animation<double> rotation =
ConstantTween(0.0).animate(_controller);
late final Animation<double> scale = ConstantTween(1.0).animate(_controller);

@override
void dispose() {
onLodChanged?.cancel();
super.dispose();
}

@override
void initState() {
super.initState();

_controller.stop(canceled: true);

if (widget.aspectRatio != null) {
aspectRatio = widget.aspectRatio!;
}
Expand All @@ -95,13 +126,20 @@ class _LightboxState extends State<Lightbox> {
getVideoInfo();
}

if (widget.image is LODImageProvider) {
if (widget.image case LODImageProvider lod) {
onLodChanged = lod.onLODChanged.listen((_) {
getImageInfo();
});

loadingHighQuality = true;
(widget.image as LODImageProvider).fetchFullRes().then((_) {
if (mounted)
lod.fetchFullRes().then((_) {
if (mounted) {
getImageInfo();

setState(() {
loadingHighQuality = false;
});
}
});
}
}
Expand All @@ -117,6 +155,10 @@ class _LightboxState extends State<Lightbox> {

void getVideoInfo() async {
WidgetsBinding.instance.addPostFrameCallback((_) async {
if (widget.aspectRatio != null) {
shouldRotate();
}

var size = await widget.videoController?.getSize();
print(size);
if (size != null) {
Expand All @@ -129,18 +171,35 @@ class _LightboxState extends State<Lightbox> {
});
}

double counterRotation = 0.25;

void shouldRotate() {
if (!Layout.mobile) {
return;
}

if (widget.image != null && preferences.autoRotateImages.value == false) {
return;
}

if (widget.video != null && preferences.autoRotateVideos.value == false) {
return;
}

var size = MediaQuery.sizeOf(context);
var screenRatio = size.width / size.height;

bool prevValue = rotate;
setState(() {
rotate = (aspectRatio < 1 && screenRatio > 1) ||
(aspectRatio > 1 && screenRatio < 1);
});

if (rotate != prevValue) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_controller.value = 0;
_controller.animateTo(1);
});
}
}

Future<ui.Image> getImage() {
Expand Down Expand Up @@ -176,79 +235,91 @@ class _LightboxState extends State<Lightbox> {
child: ScaledSafeArea(
child: RotatedBox(
quarterTurns: rotate ? 1 : 0,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: InteractiveViewer(
trackpadScrollCausesScale: true,
transformationController: controller,
maxScale: 3.5,
child: Container(
alignment: Alignment.center,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: GestureDetector(
onTap: () {},
child: AspectRatio(
aspectRatio: aspectRatio,
child: widget.customWidget ??
(widget.image != null
? Stack(
fit: StackFit.expand,
children: [
Image(
fit: BoxFit.cover,
image: widget.image!,
isAntiAlias: true,
filterQuality: FilterQuality.medium,
),
if (loadingHighQuality)
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding:
const EdgeInsets.all(8.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context)
.colorScheme
.surfaceContainer,
borderRadius:
BorderRadius
.circular(8)),
child: Padding(
padding:
const EdgeInsets.all(
8.0),
child: SizedBox(
width: 12,
height: 12,
child:
CircularProgressIndicator()),
)),
child: ScaleTransition(
scale: rotate ? scaleAnimation : scale,
child: RotationTransition(
turns: rotate ? rotationAnimation : rotation,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: InteractiveViewer(
trackpadScrollCausesScale: true,
transformationController: controller,
maxScale: 3.5,
child: Container(
alignment: Alignment.center,
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: GestureDetector(
onTap: () {},
child: AspectRatio(
aspectRatio: aspectRatio,
child: widget.customWidget ??
(widget.image != null
? Stack(
fit: StackFit.expand,
children: [
Image(
fit: BoxFit.cover,
image: widget.image!,
isAntiAlias: true,
filterQuality:
FilterQuality.medium,
),
)
],
)
: widget.video != null
? dismissing
? widget.thumbnail != null
? Image(
fit: BoxFit.cover,
image: widget.thumbnail!,
)
: Container(
color: Colors.black,
if (loadingHighQuality)
Align(
alignment:
Alignment.bottomRight,
child: Padding(
padding:
const EdgeInsets.all(
8.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(
context)
.colorScheme
.surfaceContainer,
borderRadius:
BorderRadius
.circular(
8)),
child: Padding(
padding:
const EdgeInsets
.all(8.0),
child: SizedBox(
width: 12,
height: 12,
child:
CircularProgressIndicator()),
)),
),
)
],
)
: widget.video != null
? dismissing
? widget.thumbnail != null
? Image(
fit: BoxFit.cover,
image:
widget.thumbnail!,
)
: Container(
color: Colors.black,
)
: VideoPlayer(
widget.video!,
controller:
widget.videoController,
showProgressBar: true,
canGoFullscreen: false,
thumbnail: widget.thumbnail,
key: widget.contentKey,
)
: VideoPlayer(
widget.video!,
controller:
widget.videoController,
showProgressBar: true,
canGoFullscreen: false,
thumbnail: widget.thumbnail,
key: widget.contentKey,
)
: const Placeholder())),
: const Placeholder())),
),
),
),
),
),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:commet/config/layout_config.dart';
import 'package:commet/main.dart';
import 'package:commet/ui/pages/settings/categories/app/boolean_toggle.dart';
import 'package:commet/ui/pages/setup/menus/check_for_updates.dart';
Expand Down Expand Up @@ -72,6 +73,10 @@ class GeneralSettingsPageState extends State<GeneralSettingsPage> {
desc: "Header for the settings tile for for media preview toggles",
name: "labelMediaPreviewSettingsTitle");

String get labelMediaSettings => Intl.message("Media",
desc: "Header for the settings tile for for media",
name: "labelMediaSettings");

String get labelMediaPreviewPrivateRoomsToggle => Intl.message(
"Private Rooms",
desc:
Expand Down Expand Up @@ -166,7 +171,7 @@ class GeneralSettingsPageState extends State<GeneralSettingsPage> {
height: 10,
),
Panel(
header: labelMediaPreviewSettingsTitle,
header: labelMediaSettings,
mode: TileType.surfaceContainerLow,
child: Column(children: [
BooleanPreferenceToggle(
Expand All @@ -179,6 +184,21 @@ class GeneralSettingsPageState extends State<GeneralSettingsPage> {
title: labelMediaPreviewPublicRoomsToggle,
description: labelMediaPreviewPublicRoomsToggleDescription,
),
if (Layout.mobile) ...[
Seperator(),
BooleanPreferenceToggle(
preference: preferences.autoRotateImages,
title: "Rotate Images",
description:
"When showing images in fullscreen, automatically rotate the image to best fill the screen",
),
BooleanPreferenceToggle(
preference: preferences.autoRotateVideos,
title: "Rotate Videos",
description:
"When showing videos in fullscreen, automatically rotate the video to best fill the screen",
),
]
]),
),
],
Expand Down
Loading