diff --git a/lib/utils/tools.dart b/lib/utils/tools.dart new file mode 100644 index 0000000..8846976 --- /dev/null +++ b/lib/utils/tools.dart @@ -0,0 +1,53 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +class Tools { + + //private constructor + Tools._(); + + static String extractCourseIds(String title) { + final pattern = RegExp(r'(?:CIT|IN|MA|CH|MW|PH)\d[\w-]*'); + final matches = pattern.allMatches(title); + List ids = []; + for (var match in matches) { + ids.add(match.group(0)!); + } + return ids.join(' , '); + } + + static String formatDuration(int durationInMinutes) { + int hours = durationInMinutes ~/ 60; + int minutes = durationInMinutes % 60; + int seconds = 0; + + String formattedHours = hours < 10 ? '0$hours' : '$hours'; + String formattedMinutes = minutes < 10 ? '0$minutes' : '$minutes'; + String formattedSeconds = seconds < 10 ? '0$seconds' : '$seconds'; + + return '$formattedHours:$formattedMinutes:$formattedSeconds'; + } + + static Color colorPicker(tumID) { + if (tumID.length < 2) return Colors.grey; + switch (tumID.substring(0, 2)) { + case 'IN': + return Colors.blue; + case 'MA': + return Colors.purple; + case 'CH': + return Colors.green; + case 'PH': + return Colors.orange; + case 'MW': + return Colors.red; + case 'EL': + return Colors.black87; + case 'CI': + return Colors.teal; + default: + return Colors.grey; + } + } +} \ No newline at end of file diff --git a/lib/view_models/download_view_model.dart b/lib/view_models/download_view_model.dart index 0794345..8f072e6 100644 --- a/lib/view_models/download_view_model.dart +++ b/lib/view_models/download_view_model.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:gocast_mobile/models/download/download_state_model.dart'; +import 'package:gocast_mobile/utils/tools.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:path_provider/path_provider.dart'; import 'package:dio/dio.dart'; @@ -59,7 +60,7 @@ class DownloadViewModel extends StateNotifier { final videoDetailsMap = { 'filePath': filePath, 'name': streamName, - 'duration': _formatDuration(stream.end.toDateTime().difference(stream.start.toDateTime()).inMinutes), + 'duration': Tools.formatDuration(stream.end.toDateTime().difference(stream.start.toDateTime()).inMinutes), 'description': stream.description, 'date': streamDate, }; @@ -170,17 +171,6 @@ class DownloadViewModel extends StateNotifier { } } - String _formatDuration(int durationInMinutes) { - int hours = durationInMinutes ~/ 60; - int minutes = durationInMinutes % 60; - int seconds = 0; - - String formattedHours = hours < 10 ? '0$hours' : '$hours'; - String formattedMinutes = minutes < 10 ? '0$minutes' : '$minutes'; - String formattedSeconds = seconds < 10 ? '0$seconds' : '$seconds'; - - return '$formattedHours:$formattedMinutes:$formattedSeconds'; - } } diff --git a/lib/views/components/custom_search_filter_top_nav_bar.dart b/lib/views/components/custom_search_filter_top_nav_bar.dart deleted file mode 100644 index 78cbf46..0000000 --- a/lib/views/components/custom_search_filter_top_nav_bar.dart +++ /dev/null @@ -1,66 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/app_localizations.dart'; - - -class CustomSearchFilterTopNavBar extends StatelessWidget - implements PreferredSizeWidget { - final TextEditingController searchController; - final VoidCallback? onBackButtonPressed; - final VoidCallback? onFilterButtonPressed; - - const CustomSearchFilterTopNavBar({ - super.key, - required this.searchController, - this.onBackButtonPressed, - this.onFilterButtonPressed, - }); - - @override - Widget build(BuildContext context) { - return AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back_ios), - onPressed: onBackButtonPressed ?? - () { - // TODO: Define back button functionality - }, - ), - title: Container( - height: 40, - margin: const EdgeInsets.only(right: 8, left: 8), - decoration: BoxDecoration( - color: const Color(0xEDFAFAFA), - borderRadius: BorderRadius.circular(10), - ), - child: TextField( - controller: searchController, - decoration: InputDecoration( - border: InputBorder.none, - hintText: AppLocalizations.of(context)!.search, - prefixIcon: const Icon(Icons.search, color: Color(0x993C3C43)), - hintStyle: const TextStyle( - color: Color(0x993C3C43), - fontSize: 17, - fontFamily: 'SF Pro Text', - fontWeight: FontWeight.w400, - letterSpacing: -0.41, - ), - ), - ), - ), - actions: [ - IconButton( - icon: const Icon(Icons.filter_list_rounded), - onPressed: onFilterButtonPressed ?? - () { - // TODO: Define filter button functionality - }, - ), - ], - titleSpacing: 0.0, - ); - } - - @override - Size get preferredSize => const Size.fromHeight(kToolbarHeight); -} diff --git a/lib/views/course_view/components/course_card.dart b/lib/views/course_view/components/course_card.dart index 1a2f440..313448e 100644 --- a/lib/views/course_view/components/course_card.dart +++ b/lib/views/course_view/components/course_card.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:gocast_mobile/base/networking/api/gocast/api_v2.pb.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; +import 'package:gocast_mobile/utils/tools.dart'; class CourseCard extends StatelessWidget { final String title; @@ -48,7 +49,7 @@ class CourseCard extends StatelessWidget { bool? isPinned, required bool isLoggedIn, }) { - final tumID = _extractCourseIds(title); + final tumID = Tools.extractCourseIds(title); return CourseCard._( key: key, title: title, @@ -208,10 +209,6 @@ class CourseCard extends StatelessWidget { false; } - - - - Widget _buildCourseIsLive(BuildContext context) { if (live == null) return const SizedBox(); return live! @@ -238,31 +235,11 @@ class CourseCard extends StatelessWidget { Widget _buildCourseColor() { return Container( width: 5, - color: _colorPicker(), + color: Tools.colorPicker(tumID), ); } - Color _colorPicker() { - if (tumID.length < 2) return Colors.grey; - switch (tumID.substring(0, 2)) { - case 'IN': - return Colors.blue; - case 'MA': - return Colors.purple; - case 'CH': - return Colors.green; - case 'PH': - return Colors.orange; - case 'MW': - return Colors.red; - case 'EL': - return Colors.black87; - case 'CI': - return Colors.teal; - default: - return Colors.grey; - } - } + Widget _buildCourseTitle(TextTheme textTheme) { return Text( @@ -291,25 +268,5 @@ class CourseCard extends StatelessWidget { ); } - static String _extractCourseIds(String title) { - // This pattern is designed to repeatedly capture course IDs with specified prefixes, - // followed by alphanumeric characters and possibly separated by commas within brackets or parentheses. - // It uses a global search to find all occurrences of such patterns. - final pattern = RegExp(r'(?:CIT|IN|MA|CH|MW|PH)\d[\w-]*'); - final matches = pattern.allMatches(title); - - // Initialize an empty list to collect IDs. - List ids = []; - - // Iterate over all matches and add the matched ID to the list. - for (var match in matches) { - ids.add(match.group(0)!); // Safe to use `!` as allMatches() only returns non-null matches. - } - - // Join extracted IDs with a dash. - return ids.join(' , '); - } - - } diff --git a/lib/views/course_view/components/live_stream_section.dart b/lib/views/course_view/components/live_stream_section.dart index 92ec595..81c0a04 100644 --- a/lib/views/course_view/components/live_stream_section.dart +++ b/lib/views/course_view/components/live_stream_section.dart @@ -1,6 +1,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/utils/tools.dart'; import 'package:gocast_mobile/views/course_view/components/pulse_background.dart'; import 'package:gocast_mobile/views/course_view/components/small_stream_card.dart'; @@ -85,7 +86,7 @@ class LiveStreamSection extends StatelessWidget { return SmallStreamCard( title: stream.item1.name, subtitle: course.name, - tumID: course.tUMOnlineIdentifier, + tumID: Tools.extractCourseIds(course.name), roomName: stream.item1.roomName, roomNumber: stream.item1.roomCode, path: imagePath, diff --git a/lib/views/course_view/components/stream_card.dart b/lib/views/course_view/components/stream_card.dart index 293b2c4..f6f841e 100644 --- a/lib/views/course_view/components/stream_card.dart +++ b/lib/views/course_view/components/stream_card.dart @@ -3,6 +3,7 @@ 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/utils/tools.dart'; import 'package:gocast_mobile/views/video_view/video_player.dart'; import 'package:intl/intl.dart'; @@ -168,17 +169,7 @@ class StreamCardState extends ConsumerState { ); } - String formatDuration(int durationInMinutes) { - int hours = durationInMinutes ~/ 60; - int minutes = durationInMinutes % 60; - int seconds = 0; - String formattedHours = hours < 10 ? '0$hours' : '$hours'; - String formattedMinutes = minutes < 10 ? '0$minutes' : '$minutes'; - String formattedSeconds = seconds < 10 ? '0$seconds' : '$seconds'; - - return '$formattedHours:$formattedMinutes:$formattedSeconds'; - } Widget _buildStreamDate(ThemeData themeData) { return Container( @@ -205,7 +196,7 @@ class StreamCardState extends ConsumerState { ), padding: const EdgeInsets.all(5), child: Text( - formatDuration(widget.stream.end.toDateTime().difference(widget.stream.start.toDateTime()).inMinutes), + Tools.formatDuration(widget.stream.end.toDateTime().difference(widget.stream.start.toDateTime()).inMinutes), style: themeData.textTheme.labelSmall?.copyWith( fontSize: 12, color: Colors.white,