Skip to content

Commit

Permalink
Add video previews
Browse files Browse the repository at this point in the history
  • Loading branch information
Hedon-dev committed Mar 30, 2024
1 parent ed61c8f commit 3f4644a
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 72 deletions.
1 change: 1 addition & 0 deletions lib/backend/managers/shared_prefs_manager.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class SharedPrefsManager {
sharedStorage.setString("search_provider", "xHamster.com");
sharedStorage.setStringList("homepage_providers", ["xHamster.com"]);
sharedStorage.setString("theme_mode", "Follow device theme");
sharedStorage.setBool("play_previews_video_list", true);
}

getThemeMode() {
Expand Down
138 changes: 95 additions & 43 deletions lib/ui/custom_widgets/video_list.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:hedon_viewer/backend/universal_formats.dart';
import 'package:hedon_viewer/main.dart';
import 'package:hedon_viewer/ui/screens/video_player.dart';
import 'package:skeletonizer/skeletonizer.dart';
import 'package:video_player/video_player.dart';

class VideoList extends StatelessWidget {
final Future<List<UniversalSearchResult>> videoResults;
Expand All @@ -28,7 +30,10 @@ class _VideoListWidget extends StatefulWidget {
}

class _VideoListWidgetState extends State<_VideoListWidget> {
VideoPlayerController previewVideoController =
VideoPlayerController.networkUrl(Uri.parse(""));
int? _clickedChildIndex;
int? _tappedChildIndex;
bool isLoadingResults = true;

// List with 10 empty UniversalSearchResults
Expand Down Expand Up @@ -89,8 +94,30 @@ class _VideoListWidgetState extends State<_VideoListWidget> {
});
}

@override
void dispose() {
super.dispose();
previewVideoController.dispose();
}

void setVideoSource(int index) {
previewVideoController =
VideoPlayerController.networkUrl(videoResults[index].videoPreview);
previewVideoController.initialize().then((value) {
// previews typically don't have audio, but set to 0 just in case
previewVideoController.setVolume(0);
previewVideoController.play();
previewVideoController.setLooping(true);
setState(() {});
});
}

@override
Widget build(BuildContext context) {
TextStyle smallElementStyle = Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Theme.of(context).colorScheme.tertiary);
return videoResults.isEmpty
? Center(
child: Container(
Expand All @@ -111,8 +138,20 @@ class _VideoListWidgetState extends State<_VideoListWidget> {
itemCount: videoResults.length,
itemBuilder: (context, index) {
return GestureDetector(
onTapDown: (details) {
if (sharedStorage.getBool("play_previews_video_list")! ==
false) {
print("Previews disabled, not playing");
return;
}
setVideoSource(index);
setState(() {
_tappedChildIndex = index;
});
},
onTap: () async {
setState(() {
_tappedChildIndex = null;
_clickedChildIndex = index;
});
UniversalVideoMetadata videoMeta =
Expand Down Expand Up @@ -151,13 +190,20 @@ class _VideoListWidgetState extends State<_VideoListWidget> {
? const Center(
child:
CircularProgressIndicator())
: videoResults[index].thumbnail !=
""
? Image.network(
videoResults[index]
.thumbnail,
fit: BoxFit.fill)
: const Placeholder())),
: previewVideoController.value
.isInitialized ==
true &&
_tappedChildIndex == index
? VideoPlayer(
previewVideoController)
: videoResults[index]
.thumbnail !=
""
? Image.network(
videoResults[index]
.thumbnail,
fit: BoxFit.fill)
: const Placeholder())),
// show video quality
Positioned(
right: 2.0,
Expand Down Expand Up @@ -218,46 +264,34 @@ class _VideoListWidgetState extends State<_VideoListWidget> {
: "1h+")))
])),
Padding(
padding: const EdgeInsets.all(8.0),
padding: const EdgeInsets.only(
right: 8, left: 8, top: 2),
child: Text(
// make sure the text is at least 2 lines, so that other widgets dont move up
videoResults[index].title + '\n',
overflow: TextOverflow.ellipsis,
maxLines: 2,
style: const TextStyle(fontSize: 16),
style: Theme.of(context)
.textTheme
.titleMedium,
)),
Row(children: [
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Row(children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(children: [
Row(children: [
Skeleton.shade(
child: Icon(
color: Theme.of(context)
.colorScheme
.secondary,
Icons.remove_red_eye)),
const SizedBox(width: 5),
Text(convertViewsIntoHumanReadable(
videoResults[index].viewsTotal))
])),
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Row(children: [
Skeleton.shade(
child: Icon(
color: Theme.of(context)
.colorScheme
.secondary,
Icons.thumb_up)),
const SizedBox(width: 5),
Text(videoResults[index]
.ratingsPositivePercent !=
-1
? "${videoResults[index].ratingsPositivePercent}%"
: "-")
])),
Expanded(
child: Padding(
Text(
convertViewsIntoHumanReadable(
videoResults[index].viewsTotal),
style: smallElementStyle)
]),
Padding(
padding: const EdgeInsets.only(
left: 8.0, right: 8.0),
child: Row(children: [
Expand All @@ -266,16 +300,34 @@ class _VideoListWidgetState extends State<_VideoListWidget> {
color: Theme.of(context)
.colorScheme
.secondary,
Icons.person)),
Icons.thumb_up)),
const SizedBox(width: 5),
Expanded(
child: Text(
videoResults[index].author,
overflow: TextOverflow.clip,
maxLines: 1,
))
])))
])
Text(
videoResults[index]
.ratingsPositivePercent !=
-1
? "${videoResults[index].ratingsPositivePercent}%"
: "-",
style: smallElementStyle,
)
])),
Expanded(
child: Row(children: [
Skeleton.shade(
child: Icon(
color: Theme.of(context)
.colorScheme
.secondary,
Icons.person)),
const SizedBox(width: 5),
Expanded(
child: Text(
videoResults[index].author,
overflow: TextOverflow.clip,
maxLines: 1,
style: smallElementStyle))
]))
]))
],
);
},
Expand Down
65 changes: 37 additions & 28 deletions lib/ui/screens/settings/settings_appearance.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:hedon_viewer/main.dart';
import 'package:hedon_viewer/ui/custom_widgets/options_dialog.dart';
import 'package:hedon_viewer/ui/custom_widgets/options_switch.dart';

class AppearanceScreen extends StatefulWidget {
const AppearanceScreen({super.key});
Expand All @@ -20,33 +21,41 @@ class _AppearanceScreenState extends State<AppearanceScreen> {
),
body: SafeArea(
child: Padding(
padding: const EdgeInsets.all(8),
child: Column(
children: <Widget>[
ListTile(
title: const Text('Theme'),
subtitle: Text(sharedStorage.getString("theme_mode")!),
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return OptionsDialog(
title: "Theme",
options: const [
"Follow device theme",
"Light theme",
"Dark theme"
],
selectedOption:
sharedStorage.getString("theme_mode")!,
onSelected: (value) {
sharedStorage.setString("theme_mode", value);
// TODO: Fix visual glitch when user returns to previous screen
ViewerApp.of(context)?.setState(() {});
});
});
})
],
))));
padding: const EdgeInsets.all(8),
child: Column(
children: <Widget>[
ListTile(
title: const Text('Theme'),
subtitle: Text(sharedStorage.getString("theme_mode")!),
onTap: () {
showDialog(
context: context,
builder: (BuildContext context) {
return OptionsDialog(
title: "Theme",
options: const [
"Follow device theme",
"Light theme",
"Dark theme"
],
selectedOption:
sharedStorage.getString("theme_mode")!,
onSelected: (value) {
sharedStorage.setString(
"theme_mode", value);
// TODO: Fix visual glitch when user returns to previous screen
ViewerApp.of(context)?.setState(() {});
});
});
}),
OptionsSwitch(
title: "Play previews",
subTitle: "Play previews on homepage/results page",
switchState:
sharedStorage.getBool("play_previews_video_list")!,
onSelected: (value) => sharedStorage.setBool(
"play_previews_video_list", value))
],
))));
}
}
2 changes: 1 addition & 1 deletion lib/ui/screens/settings/settings_main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
),
ListTile(
title: const Text("Appearance"),
subtitle: const Text("Default theme"),
subtitle: const Text("Default theme, play previews"),
leading: const Icon(Icons.palette),
onTap: () {
Navigator.push(
Expand Down

0 comments on commit 3f4644a

Please sign in to comment.