diff --git a/.woodpecker/workflow.yaml b/.woodpecker/workflow.yaml index 1c0ace2..774ef9a 100644 --- a/.woodpecker/workflow.yaml +++ b/.woodpecker/workflow.yaml @@ -12,8 +12,9 @@ steps: - git config --global --add safe.directory /home/mobiledevops/.flutter-sdk - echo "Getting Dependencies" - flutter pub get + - flutter pub upgrade - echo "Building..." - - flutter build apk + - flutter build apk --debug - echo "Build Completed!" - name: windows build image: debian diff --git a/lib/widgets/sessions/session_list.dart b/lib/widgets/sessions/session_list.dart index b683db7..48dd348 100644 --- a/lib/widgets/sessions/session_list.dart +++ b/lib/widgets/sessions/session_list.dart @@ -1,3 +1,4 @@ +import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:OpenContacts/auxiliary.dart'; import 'package:OpenContacts/clients/session_client.dart'; @@ -5,9 +6,15 @@ import 'package:OpenContacts/models/session.dart'; import 'package:OpenContacts/widgets/default_error_widget.dart'; import 'package:OpenContacts/widgets/formatted_text.dart'; import 'package:OpenContacts/widgets/sessions/session_view.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_local_notifications/flutter_local_notifications.dart'; +import 'package:html/dom.dart' hide Text; +import 'package:indexed/indexed.dart'; import 'package:provider/provider.dart'; import 'package:flutter/services.dart'; +import 'package:gradient_borders/gradient_borders.dart'; class SessionList extends StatefulWidget { const SessionList({super.key}); @@ -74,50 +81,175 @@ class _SessionListState extends State with AutomaticKeepAliveClient ), itemBuilder: (context, index) { final session = data[index]; - return Card( - elevation: 0, - shape: RoundedRectangleBorder( - side: BorderSide( - color: Theme.of(context).colorScheme.outline, - ), - borderRadius: BorderRadius.circular(30), + return Container( //Make this a container, shit doesn't like it when it's a class already + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Color.fromARGB(255, 248, 248, 112), + Color.fromARGB(255, 230, 158, 80), + ] ), + border: GradientBoxBorder( + width: 2, + gradient: LinearGradient( + begin: Alignment.centerLeft, + end: Alignment.centerRight, + colors: [ + Color.fromARGB(255, 248, 248, 112), + Color.fromARGB(255, 230, 158, 80), + ] + ) + ), + borderRadius: BorderRadius.all( // I wouldn't have known that this was the right way to write + Radius.circular(10) + ), + ), child: InkWell( onTap: () { Navigator.of(context) .push(MaterialPageRoute(builder: (context) => SessionView(session: session))); }, borderRadius: BorderRadius.circular(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, + child: Indexer( children: [ - Expanded( - flex: 5, - child: ClipRRect( - borderRadius: BorderRadius.circular(30), - child: Hero( - tag: session.id, - child: CachedNetworkImage( - imageUrl: Aux.resdbToHttp(session.thumbnailUrl), - fit: BoxFit.cover, - errorWidget: (context, url, error) => const Center( - child: Icon( + Indexed( + index: 1, + child: Positioned( + top: 0, + bottom: 80, + left: 0, + right: 0, + child: ClipRRect( + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(10), + topRight: Radius.circular(10), + ), + child: Hero( + tag: session.id, + child: CachedNetworkImage( + imageUrl: Aux.resdbToHttp(session.thumbnailUrl), + fit: BoxFit.cover, + errorWidget:(context, url, error) => const Center( + child: Icon( Icons.broken_image, size: 64, ), ), - placeholder: (context, uri) => - const Center(child: CircularProgressIndicator()), + placeholder: (context, url) => + const Center(child: CircularProgressIndicator(), + ), + ), ), ), ), ), - Expanded( - flex: 1 - child: Padding(padding: ,), - + Indexed( + index: 2, + child: Positioned( + top: 160, + bottom: 0, + left: 0, + right: 0, + child: Container( + width: 200, + height: 50, + decoration: BoxDecoration( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(10), + bottomRight: Radius.circular(10), + ), + color: Theme.of(context).colorScheme.onPrimary, + ), + ), + ) ), - Expanded( + Indexed( + index: 3, + child: Positioned( + top: 140, + bottom: 75, + left: 0, + right: 100, + child: Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.onPrimary, + borderRadius: BorderRadius.only( + topRight: Radius.circular(10) + ) + ), + ), + ), + ), + const Indexed( + index: 4, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + height: 130, + ), + Expanded( + child:Icon( + Icons.group + ) + ), + SizedBox( + height: 15, + ), + Expanded( + child: Icon( + Icons.dns + ) + ) + ], + ) + ), //Due to some limitations, Icons and Texts are on different layers + Indexed( + index: 5, + child: Column( + //mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox( + height: 143, + ), + Expanded( + child: Text( + " ${(session.sessionUsers.length - (session.headlessHost? 1 : 0)).toString().padLeft(2, "0")}/${session.maxUsers.toString().padLeft(2, "0")}", + style: const TextStyle( + fontSize: 20, + ) + ), + ), + Expanded( + child: FormattedText( + //textAlign: Align(1,1), + session.formattedName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ) + ), + Expanded( + child: Text( + " ${session.hostUsername}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle( + fontSize: 20, + ), + ) + ) + ], + ), + + ) + ] + ), + /*child: Column( + Expanded( //2 flex: 2, child: Padding( padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 16), @@ -178,7 +310,7 @@ class _SessionListState extends State with AutomaticKeepAliveClient ), ) ], - ), + ),*/ ), ); }, diff --git a/lib/widgets/sessions/session_list_app_bar.dart b/lib/widgets/sessions/session_list_app_bar.dart index b0d3c31..98d6e3b 100644 --- a/lib/widgets/sessions/session_list_app_bar.dart +++ b/lib/widgets/sessions/session_list_app_bar.dart @@ -31,7 +31,7 @@ class _SessionListAppBarState extends State { ), ); }, - icon: const Icon(Icons.filter_alt_outlined), + icon: const Icon(Icons.filter_list), ), ) ], diff --git a/lib/widgets/sessions/session_list_next.dart b/lib/widgets/sessions/session_list_next.dart index 421477c..c668d8c 100644 --- a/lib/widgets/sessions/session_list_next.dart +++ b/lib/widgets/sessions/session_list_next.dart @@ -7,4 +7,189 @@ import 'package:OpenContacts/widgets/formatted_text.dart'; import 'package:OpenContacts/widgets/sessions/session_view.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; -import 'package:flutter/services.dart'; \ No newline at end of file +import 'package:flutter/services.dart'; + +class NextSessionList extends StatefulWidget { + const NextSessionList({super.key}); + + @override + State createState() => _SessionListState(); +} +class onKeyIntent extends Intent{ + const onKeyIntent(); +} + +const onKey = SingleActivator(LogicalKeyboardKey.f5); + +class _SessionListState extends State with AutomaticKeepAliveClientMixin { + @override + void didChangeDependencies() { + super.didChangeDependencies(); + final sClient = Provider.of(context, listen: false); + if (sClient.sessionsFuture == null) { + sClient.initSessions(); + } + } + + @override + Widget build(BuildContext context) { + super.build(context); + return ChangeNotifierProvider.value( + value: Provider.of(context), + child: Consumer( + builder: (BuildContext context, SessionClient sClient, Widget? child) { + return FutureBuilder>( + future: sClient.sessionsFuture, + builder: (context, snapshot) { + final data = snapshot.data ?? []; + return Stack( + children: [ + RefreshIndicator( + onRefresh: () async { + sClient.reloadSessions(); + try { + await sClient.sessionsFuture; + } catch (e) { + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.toString()))); + } + } + }, + child: data.isEmpty && snapshot.connectionState == ConnectionState.done + ? const DefaultErrorWidget( + title: "No Sessions Found", + message: "Try to adjust your filters", + iconOverride: Icons.question_mark, + ) + : Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: GridView.builder( + padding: const EdgeInsets.only(top: 10), + itemCount: data.length, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 256, + crossAxisSpacing: 4, + mainAxisSpacing: 1, + childAspectRatio: .8, + ), + itemBuilder: (context, index) { + final session = data[index]; + return Card( + elevation: 0, + shape: RoundedRectangleBorder( + side: BorderSide( + color: Theme.of(context).colorScheme.outline, + ), + borderRadius: BorderRadius.circular(30), + ), + child: InkWell( + onTap: () { + Navigator.of(context) + .push(MaterialPageRoute(builder: (context) => SessionView(session: session))); + }, + borderRadius: BorderRadius.circular(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + flex: 5, + child: ClipRRect( + borderRadius: BorderRadius.circular(30), + child: Hero( + tag: session.id, + child: CachedNetworkImage( + imageUrl: Aux.resdbToHttp(session.thumbnailUrl), + fit: BoxFit.cover, + errorWidget: (context, url, error) => const Center( + child: Icon( + Icons.broken_image, + size: 64, + ), + ), + placeholder: (context, uri) => + const Center(child: CircularProgressIndicator()), + ), + ), + ), + ), + Expanded( + flex: 2, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 0, horizontal: 16), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Expanded( + child: FormattedText( + session.formattedName, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + ), + ], + ), + const SizedBox( + height: 2, + ), + Row( + children: [ + Expanded( + child: Text( + "Host: ${session.hostUsername}", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: Color.fromARGB(234, 151, 107, 61) + ), + ), + ), + ], + ), + const SizedBox( + height: 2, + ), + Row( + children: [ + Expanded( + child: Text( + "${(session.sessionUsers.length - (session.headlessHost? 1 : 0)).toString().padLeft(2, "0")}/${session.maxUsers.toString().padLeft(2, "0")} Online", + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: Theme.of(context).textTheme.bodySmall?.copyWith( + color: Theme.of(context) + .colorScheme + .onSurface + .withOpacity(.5), + ), + ), + ), + ], + ), + ], + ), + ), + ) + ], + ), + ), + ); + }, + ), + ), + ), + if (snapshot.connectionState == ConnectionState.waiting) const LinearProgressIndicator() + ], + ); + }, + ); + }, + ), + ); + } + + @override + bool get wantKeepAlive => true; +} diff --git a/pubspec.lock b/pubspec.lock index 0db820f..ffe313b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -408,6 +408,14 @@ packages: description: flutter source: sdk version: "0.0.0" + gradient_borders: + dependency: "direct main" + description: + name: gradient_borders + sha256: b1cd969552c83f458ff755aa68e13a0327d09f06c3f42f471b423b01427f21f8 + url: "https://pub.dev" + source: hosted + version: "1.0.1" hive: dependency: "direct main" description: @@ -520,6 +528,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.1+1" + indexed: + dependency: "direct main" + description: + name: indexed + sha256: "3509a2a7ad1dbd7280da377661129e0b0a2f5e8d6d75f10400f07397f95324df" + url: "https://pub.dev" + source: hosted + version: "0.0.8" intl: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 3edfd87..0be2237 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -65,6 +65,8 @@ dependencies: share_plus: ^7.1.0 ffmpeg_kit_flutter_audio: ^6.0.3 background_downloader: ^7.12.2 + indexed: ^0.0.8 + gradient_borders: ^1.0.1 dev_dependencies: flutter_test: