2024-06-25 12:00:34 +02:00
import ' package:flutter/material.dart ' ;
import ' package:font_awesome_flutter/font_awesome_flutter.dart ' ;
import ' package:qr_flutter/qr_flutter.dart ' ;
import ' package:share_plus/share_plus.dart ' ;
import ' package:simplecloudnotifier/api/api_client.dart ' ;
import ' package:simplecloudnotifier/components/layout/scaffold.dart ' ;
import ' package:simplecloudnotifier/models/channel.dart ' ;
import ' package:simplecloudnotifier/models/subscription.dart ' ;
import ' package:simplecloudnotifier/models/user.dart ' ;
import ' package:simplecloudnotifier/state/app_auth.dart ' ;
import ' package:simplecloudnotifier/state/app_bar_state.dart ' ;
2024-06-25 20:49:40 +02:00
import ' package:simplecloudnotifier/types/immediate_future.dart ' ;
2024-06-25 12:00:34 +02:00
import ' package:simplecloudnotifier/utils/ui.dart ' ;
2024-06-25 20:49:40 +02:00
import ' package:provider/provider.dart ' ;
2024-06-25 12:00:34 +02:00
class ChannelViewPage extends StatefulWidget {
const ChannelViewPage ( {
required this . channel ,
required this . subscription ,
super . key ,
} ) ;
final Channel channel ;
final Subscription ? subscription ;
@ override
State < ChannelViewPage > createState ( ) = > _ChannelViewPageState ( ) ;
}
class _ChannelViewPageState extends State < ChannelViewPage > {
2024-06-25 20:49:40 +02:00
late ImmediateFuture < String ? > _futureSubscribeKey ;
late ImmediateFuture < List < Subscription > > _futureSubscriptions ;
late ImmediateFuture < UserPreview > _futureOwner ;
int _loadingIndeterminateCounter = 0 ;
2024-06-25 12:00:34 +02:00
@ override
void initState ( ) {
2024-06-25 20:49:40 +02:00
final userAcc = Provider . of < AppAuth > ( context , listen: false ) ;
if ( widget . channel . ownerUserID = = userAcc . userID ) {
if ( widget . channel . subscribeKey ! = null ) {
_futureSubscribeKey = ImmediateFuture < String ? > . ofValue ( widget . channel . subscribeKey ) ;
} else {
_futureSubscribeKey = ImmediateFuture < String ? > . ofFuture ( _getSubScribeKey ( userAcc ) ) ;
}
_futureSubscriptions = ImmediateFuture < List < Subscription > > . ofFuture ( _listSubscriptions ( userAcc ) ) ;
} else {
_futureSubscribeKey = ImmediateFuture < String ? > . ofValue ( null ) ;
_futureSubscriptions = ImmediateFuture < List < Subscription > > . ofValue ( [ ] ) ;
}
if ( widget . channel . ownerUserID = = userAcc . userID ) {
var cacheUser = userAcc . getUserOrNull ( ) ;
if ( cacheUser ! = null ) {
_futureOwner = ImmediateFuture < UserPreview > . ofValue ( cacheUser . toPreview ( ) ) ;
} else {
_futureOwner = ImmediateFuture < UserPreview > . ofFuture ( _getOwner ( userAcc ) ) ;
}
} else {
_futureOwner = ImmediateFuture < UserPreview > . ofFuture ( APIClient . getUserPreview ( userAcc , widget . channel . ownerUserID ) ) ;
}
2024-06-25 12:00:34 +02:00
super . initState ( ) ;
}
@ override
void dispose ( ) {
super . dispose ( ) ;
}
@ override
Widget build ( BuildContext context ) {
return SCNScaffold (
title: ' Channel ' ,
showSearch: false ,
showShare: false ,
child: _buildChannelView ( context ) ,
) ;
}
Widget _buildChannelView ( BuildContext context ) {
final userAccUserID = context . select < AppAuth , String ? > ( ( v ) = > v . userID ) ;
2024-06-25 20:49:40 +02:00
final isOwned = ( widget . channel . ownerUserID = = userAccUserID ) ;
final isSubscribed = ( widget . subscription ! = null & & widget . subscription ! . confirmed ) ;
2024-06-25 12:00:34 +02:00
return SingleChildScrollView (
child: Padding (
padding: const EdgeInsets . fromLTRB ( 24 , 16 , 24 , 16 ) ,
child: Column (
crossAxisAlignment: CrossAxisAlignment . stretch ,
children: [
_buildQRCode ( context ) ,
SizedBox ( height: 8 ) ,
2024-06-25 20:49:40 +02:00
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidIdCardClip ,
title: ' ChannelID ' ,
values: [ widget . channel . channelID ] ,
) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidInputNumeric ,
title: ' InternalName ' ,
values: [ widget . channel . internalName ] ,
) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidInputText ,
title: ' DisplayName ' ,
values: [ widget . channel . displayName ] ,
iconActions: isOwned ? [ ( FontAwesomeIcons . penToSquare , _rename ) ] : [ ] ,
) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidDiagramSubtask ,
title: ' Subscription (own) ' ,
values: [ _formatSubscriptionStatus ( widget . subscription ) ] ,
iconActions: isSubscribed ? [ ( FontAwesomeIcons . solidSquareXmark , _unsubscribe ) ] : [ ( FontAwesomeIcons . solidSquareRss , _subscribe ) ] ,
) ,
_buildForeignSubscriptions ( context ) ,
_buildOwnerCard ( context , isOwned ) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidEnvelope ,
title: ' Messages ' ,
values: [ widget . channel . messagesSent . toString ( ) ] ,
mainAction: ( ) { /*TODO*/ } ,
) ,
2024-06-25 12:00:34 +02:00
] ,
) ,
) ,
) ;
}
2024-06-25 20:49:40 +02:00
Widget _buildForeignSubscriptions ( BuildContext context ) {
return FutureBuilder (
future: _futureSubscriptions . future ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
return Column (
crossAxisAlignment: CrossAxisAlignment . stretch ,
2024-06-25 12:00:34 +02:00
children: [
2024-06-25 20:49:40 +02:00
for ( final sub in snapshot . data ! . where ( ( sub ) = > sub . subscriptionID ! = widget . subscription ? . subscriptionID ) )
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidDiagramSuccessor ,
title: ' Subscription (other) ' ,
values: [ _formatSubscriptionStatus ( sub ) ] ,
iconActions: _getForignSubActions ( sub ) ,
) ,
2024-06-25 12:00:34 +02:00
] ,
2024-06-25 20:49:40 +02:00
) ;
} else {
return SizedBox ( ) ;
}
} ,
2024-06-25 12:00:34 +02:00
) ;
2024-06-25 20:49:40 +02:00
}
Widget _buildOwnerCard ( BuildContext context , bool isOwned ) {
return FutureBuilder (
future: _futureOwner . future ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidUser ,
title: ' Owner ' ,
values: [ widget . channel . ownerUserID + ( isOwned ? ' (you) ' : ' ' ) , if ( snapshot . data ? . username ! = null ) snapshot . data ! . username ! ] ,
) ;
} else {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidUser ,
title: ' Owner ' ,
values: [ widget . channel . ownerUserID + ( isOwned ? ' (you) ' : ' ' ) ] ,
) ;
}
} ,
) ;
}
Widget _buildQRCode ( BuildContext context ) {
return FutureBuilder (
future: _futureSubscribeKey . future ,
builder: ( context , snapshot ) {
if ( snapshot . hasData & & snapshot . data ! = null ) {
var text = ' TODO ' + ' \n ' + widget . channel . channelID + ' \n ' + snapshot . data ! ; //TODO deeplink-y (also perhaps just bas64 everything together?)
return GestureDetector (
onTap: ( ) {
Share . share ( text , subject: widget . channel . displayName ) ;
} ,
child: Center (
child: QrImageView (
data: text ,
version: QrVersions . auto ,
size: 300.0 ,
eyeStyle: QrEyeStyle (
eyeShape: QrEyeShape . square ,
color: Theme . of ( context ) . textTheme . bodyLarge ? . color ,
) ,
dataModuleStyle: QrDataModuleStyle (
dataModuleShape: QrDataModuleShape . square ,
color: Theme . of ( context ) . textTheme . bodyLarge ? . color ,
) ,
) ,
) ,
) ;
} else if ( snapshot . hasData & & snapshot . data = = null ) {
return const SizedBox (
width: 300.0 ,
height: 300.0 ,
child: Center ( child: Icon ( FontAwesomeIcons . solidSnake , size: 64 ) ) ,
) ;
} else {
return const SizedBox (
width: 300.0 ,
height: 300.0 ,
child: Center ( child: CircularProgressIndicator ( ) ) ,
) ;
}
} ,
) ;
}
void _rename ( ) {
//TODO
}
void _subscribe ( ) {
//TODO
}
void _unsubscribe ( ) {
//TODO
}
2024-06-25 12:00:34 +02:00
2024-06-25 20:49:40 +02:00
void _cancelForeignSubscription ( Subscription sub ) {
//TODO
}
void _confirmForeignSubscription ( Subscription sub ) {
//TODO
}
void _denyForeignSubscription ( Subscription sub ) {
//TODO
}
String _formatSubscriptionStatus ( Subscription ? subscription ) {
if ( subscription = = null ) {
return ' Not Subscribed ' ;
} else if ( subscription . confirmed ) {
return ' Subscribed ' ;
2024-06-25 12:00:34 +02:00
} else {
2024-06-25 20:49:40 +02:00
return ' Requested ' ;
}
}
Future < String ? > _getSubScribeKey ( AppAuth auth ) async {
try {
await Future . delayed ( const Duration ( seconds: 0 ) , ( ) { } ) ; // this is annoyingly important - otherwise we call setLoadingIndeterminate directly in initStat() and get an exception....
_incLoadingIndeterminateCounter ( 1 ) ;
var channel = await APIClient . getChannel ( auth , widget . channel . channelID ) ;
//await Future.delayed(const Duration(seconds: 10), () {});
return channel . channel . subscribeKey ;
} finally {
_incLoadingIndeterminateCounter ( - 1 ) ;
}
}
Future < List < Subscription > > _listSubscriptions ( AppAuth auth ) async {
try {
await Future . delayed ( const Duration ( seconds: 0 ) , ( ) { } ) ; // this is annoyingly important - otherwise we call setLoadingIndeterminate directly in initStat() and get an exception....
_incLoadingIndeterminateCounter ( 1 ) ;
var subs = await APIClient . getChannelSubscriptions ( auth , widget . channel . channelID ) ;
//await Future.delayed(const Duration(seconds: 10), () {});
return subs ;
} finally {
_incLoadingIndeterminateCounter ( - 1 ) ;
2024-06-25 12:00:34 +02:00
}
}
2024-06-25 20:49:40 +02:00
Future < UserPreview > _getOwner ( AppAuth auth ) async {
try {
await Future . delayed ( const Duration ( seconds: 0 ) , ( ) { } ) ; // this is annoyingly important - otherwise we call setLoadingIndeterminate directly in initStat() and get an exception....
_incLoadingIndeterminateCounter ( 1 ) ;
final owner = APIClient . getUserPreview ( auth , widget . channel . ownerUserID ) ;
//await Future.delayed(const Duration(seconds: 10), () {});
return owner ;
} finally {
_incLoadingIndeterminateCounter ( - 1 ) ;
}
2024-06-25 12:00:34 +02:00
}
2024-06-25 20:49:40 +02:00
List < ( IconData , void Function ( ) ) > _getForignSubActions ( Subscription sub ) {
if ( sub . confirmed ) {
return [ ( FontAwesomeIcons . solidSquareXmark , ( ) = > _cancelForeignSubscription ( sub ) ) ] ;
} else {
return [
( FontAwesomeIcons . solidSquareCheck , ( ) = > _confirmForeignSubscription ( sub ) ) ,
( FontAwesomeIcons . solidSquareXmark , ( ) = > _denyForeignSubscription ( sub ) ) ,
] ;
2024-06-25 12:00:34 +02:00
}
}
2024-06-25 20:49:40 +02:00
void _incLoadingIndeterminateCounter ( int delta ) {
setState ( ( ) {
_loadingIndeterminateCounter + = delta ;
AppBarState ( ) . setLoadingIndeterminate ( _loadingIndeterminateCounter > 0 ) ;
} ) ;
2024-06-25 12:00:34 +02:00
}
}