Skip to content

Commit

Permalink
fetch live now thumbnails
Browse files Browse the repository at this point in the history
  • Loading branch information
Sainaamr committed Jan 28, 2024
1 parent 696235b commit 7eb8076
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 81 deletions.
11 changes: 6 additions & 5 deletions lib/models/video/stream_state_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ class StreamState {
final bool isLoading;
final List<Stream>? streams;
final List<Stream>? liveStreams;
final List<String>? thumbnails;
final AppError? error;
final Progress? progress;
final bool isWatched;
final String? videoSource;
final List<Tuple2<Stream, String>>? streamsWithThumb;
final List<Tuple2<Stream, String>>? liveStreamsWithThumb;
final List<Tuple2<Stream, String>>? displayedStreams;
final String selectedFilterOption;

const StreamState({
this.isLoading = false,
this.streams,
this.liveStreams,
this.thumbnails,
this.error,
this.progress,
this.isWatched = false,
this.videoSource,
this.streamsWithThumb,
this.liveStreamsWithThumb,
this.displayedStreams,
this.selectedFilterOption = 'Oldest First',
});
Expand All @@ -42,19 +42,20 @@ class StreamState {
String? videoSource,
Map<int, String>? downloadedVideos,
List<Tuple2<Stream, String>>? streamsWithThumb,
List<Tuple2<Stream, String>>? liveStreamsWithThumb,
List<Tuple2<Stream, String>>? displayedStreams,
String? selectedFilterOption,
}) {
return StreamState(
isLoading: isLoading ?? this.isLoading,
streams: streams ?? this.streams,
liveStreams: liveStreams ?? this.liveStreams,
thumbnails: thumbnails ?? this.thumbnails,
error: error ?? this.error,
progress: progress ?? this.progress,
isWatched: isWatched ?? this.isWatched,
videoSource: videoSource ?? this.videoSource,
streamsWithThumb: streamsWithThumb ?? this.streamsWithThumb,
liveStreamsWithThumb: liveStreamsWithThumb ?? this.liveStreamsWithThumb,
displayedStreams: displayedStreams ?? this.displayedStreams,
selectedFilterOption: selectedFilterOption ?? this.selectedFilterOption,
);
Expand All @@ -65,11 +66,11 @@ class StreamState {
isLoading: isLoading,
streams: streams,
liveStreams: liveStreams,
thumbnails: thumbnails,
progress: progress,
isWatched: isWatched,
videoSource: videoSource,
streamsWithThumb: streamsWithThumb,
liveStreamsWithThumb: liveStreamsWithThumb,
displayedStreams: displayedStreams,
error: null,
);
Expand All @@ -80,11 +81,11 @@ class StreamState {
isLoading: isLoading,
streams: streams,
liveStreams: liveStreams,
thumbnails: thumbnails,
progress: progress,
isWatched: isWatched,
videoSource: videoSource,
streamsWithThumb: streamsWithThumb,
liveStreamsWithThumb: liveStreamsWithThumb,
displayedStreams: displayedStreams,
error: null,
);
Expand Down
58 changes: 41 additions & 17 deletions lib/view_models/stream_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,28 @@ class StreamViewModel extends StateNotifier<StreamState> {
}
}



void updatedDisplayedStreams(List<Tuple2<Stream, String>> allStreams) {
state = state.copyWith(displayedStreams: allStreams);
}

void setUpDisplayedCourses(List<Tuple2<Stream, String>> allStreams) {
updatedDisplayedStreams(
CourseUtils.sortStreams(allStreams, state.selectedFilterOption),
);
}

void updateSelectedFilterOption(
String option,
List<Tuple2<Stream, String>> allStreams,
) {
state = state.copyWith(selectedFilterOption: option);
updatedDisplayedStreams(
CourseUtils.sortStreams(allStreams, state.selectedFilterOption),
);
}

/// This asynchronous function fetches thumbnails for all available streams in the current state.
/// only if there are streams in the current state.
/// It initiates fetching of thumbnails for each stream by invoking `fetchThumbnailForStream`.
Expand All @@ -51,23 +73,25 @@ class StreamViewModel extends StateNotifier<StreamState> {
setUpDisplayedCourses(fetchedStreamsWithThumbnails);
}

void updatedDisplayedStreams(List<Tuple2<Stream, String>> allStreams) {
state = state.copyWith(displayedStreams: allStreams);
}

void setUpDisplayedCourses(List<Tuple2<Stream, String>> allStreams) {
updatedDisplayedStreams(
CourseUtils.sortStreams(allStreams, state.selectedFilterOption),
);
}

void updateSelectedFilterOption(
String option,
List<Tuple2<Stream, String>> allStreams,
) {
state = state.copyWith(selectedFilterOption: option);
updatedDisplayedStreams(
CourseUtils.sortStreams(allStreams, state.selectedFilterOption),
/// This asynchronous function fetches thumbnails for all available live streams in the current state.
/// only if there are live streams in the current state.
/// It initiates fetching of thumbnails for each live stream by invoking `fetchThumbnailForStream`.
Future<void> fetchLiveThumbnails() async {
if (state.liveStreams == null) {
return;
}
var fetchLiveThumbnailTasks = <Future<Tuple2<Stream, String>>>[];
for (var stream in state.liveStreams!) {
fetchLiveThumbnailTasks.add(
fetchStreamThumbnail(stream.id)
.then((thumbnail) => Tuple2(stream, thumbnail)),
);
}
var fetchedStreamsWithThumbnails =
await Future.wait(fetchLiveThumbnailTasks);
state = state.copyWith(
liveStreamsWithThumb: fetchedStreamsWithThumbnails,
isLoading: false,
);
}

Expand Down
35 changes: 18 additions & 17 deletions lib/views/course_view/components/live_stream_section.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart';
import 'package:gocast_mobile/utils/constants.dart';

import 'package:gocast_mobile/views/course_view/components/pulse_background.dart';
import 'package:gocast_mobile/views/course_view/components/small_stream_card.dart';
import 'package:gocast_mobile/views/video_view/video_player.dart';
import 'package:tuple/tuple.dart';

/// CourseSection
///
Expand All @@ -27,7 +25,7 @@ import 'package:gocast_mobile/views/video_view/video_player.dart';
class LiveStreamSection extends StatelessWidget {
final String sectionTitle;
final List<Course> courses;
final List<Stream> streams;
final List<Tuple2<Stream, String>> streams;
final VoidCallback? onViewAll;
final WidgetRef ref;
final String baseUrl = 'https://live.rbg.tum.de';
Expand Down Expand Up @@ -76,32 +74,28 @@ class LiveStreamSection extends StatelessWidget {
scrollDirection: Axis.horizontal,
child: Row(
children: streams.map((stream) {
final Random random = Random();
String imagePath;
List<String> imagePaths = [
AppImages.course1,
AppImages.course2,
];
imagePath = imagePaths[random.nextInt(imagePaths.length)];

final course =
courses.where((course) => course.id == stream.courseID).first;
imagePath = _getThumbnailUrl(stream.item2);

final course = courses
.where((course) => course.id == stream.item1.courseID)
.first;

return SmallStreamCard(
title: stream.name,
title: stream.item1.name,
subtitle: course.name,
tumID: course.tUMOnlineIdentifier,
roomName: stream.roomName,
roomNumber: stream.roomCode,
viewerCount: stream.vodViews,
roomName: stream.item1.roomName,
roomNumber: stream.item1.roomCode,
path: imagePath,
courseId: course.id,
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoPlayerPage(
stream: stream,
stream: stream.item1,
),
),
);
Expand Down Expand Up @@ -139,4 +133,11 @@ class LiveStreamSection extends StatelessWidget {
),
);
}

String _getThumbnailUrl(String thumbnail) {
if (!thumbnail.startsWith('http')) {
thumbnail = '$baseUrl$thumbnail';
}
return thumbnail;
}
}
54 changes: 29 additions & 25 deletions lib/views/course_view/components/small_stream_card.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart';
import 'package:gocast_mobile/utils/constants.dart';
import 'package:url_launcher/url_launcher.dart';

class SmallStreamCard extends StatelessWidget {
Expand All @@ -17,7 +18,7 @@ class SmallStreamCard extends StatelessWidget {
final String? subtitle;
final String? roomName;
final String? roomNumber;
final int viewerCount;

final String? path;

const SmallStreamCard({
Expand All @@ -27,7 +28,6 @@ class SmallStreamCard extends StatelessWidget {
required this.tumID,
this.roomName,
this.roomNumber,
required this.viewerCount,
this.path,
required this.courseId,
required this.onTap,
Expand Down Expand Up @@ -82,7 +82,6 @@ class SmallStreamCard extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
_buildCourseTumID(),
_buildCourseViewerCount(themeData),
],
),
const SizedBox(height: 2),
Expand Down Expand Up @@ -113,18 +112,41 @@ class SmallStreamCard extends StatelessWidget {
}

Widget _buildCourseImage() {
// Assuming `path` is now a URL string
return Stack(
children: [
AspectRatio(
aspectRatio: 16 / 12,
aspectRatio: 16 / 12, // Maintain the same aspect ratio
child: ClipRRect(
borderRadius: BorderRadius.circular(8.0),
child: Image.asset(
path!,
fit: BoxFit.cover,
// Keep the rounded corners
child: Image.network(
path!, // Use the image URL
fit: BoxFit.cover, // Maintain the cover fit
loadingBuilder: (context, child, loadingProgress) {
if (loadingProgress == null)
return child; // Image is fully loaded
return Center(
child: CircularProgressIndicator(
value: loadingProgress.expectedTotalBytes != null
? loadingProgress.cumulativeBytesLoaded /
(loadingProgress.expectedTotalBytes ?? 1)
: null,
),
);
},
errorBuilder: (context, error, stackTrace) {
// Provide a fallback asset image in case of error
return Image.asset(
AppImages.course1,
// Path to your default/fallback image asset
fit: BoxFit.cover,
);
},
),
),
),
// If you have additional overlays like in the thumbnail widget, add them here
],
);
}
Expand Down Expand Up @@ -210,22 +232,4 @@ class SmallStreamCard extends StatelessWidget {
const TextStyle(),
);
}

Widget _buildCourseViewerCount(ThemeData themeData) {
return Container(
decoration: BoxDecoration(
color: themeData.shadowColor.withOpacity(0.15),
borderRadius: BorderRadius.circular(4),
),
padding: const EdgeInsets.all(3),
child: Text(
"$viewerCount viewers",
style: themeData.textTheme.labelSmall?.copyWith(
fontSize: 12,
height: 1,
) ??
const TextStyle(),
),
);
}
}
3 changes: 2 additions & 1 deletion lib/views/course_view/components/stream_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart';
import 'package:gocast_mobile/providers.dart';
import 'package:gocast_mobile/utils/constants.dart';
import 'package:gocast_mobile/views/video_view/video_player.dart';
import 'package:intl/intl.dart';

Expand Down Expand Up @@ -119,7 +120,7 @@ class StreamCardState extends ConsumerState<StreamCard> {
},
errorBuilder: (context, error, stackTrace) {
return Image.asset(
'assets/images/default_image.png',
AppImages.course1,
fit: BoxFit.cover,
);
},
Expand Down
Loading

0 comments on commit 7eb8076

Please sign in to comment.