2025-04-18 18:56:17 +02:00
import ' dart:developer ' ;
2025-04-13 19:47:18 +02:00
import ' package:flutter/material.dart ' ;
import ' package:font_awesome_flutter/font_awesome_flutter.dart ' ;
import ' package:intl/intl.dart ' ;
import ' package:simplecloudnotifier/api/api_client.dart ' ;
2025-04-18 14:07:31 +02:00
import ' package:simplecloudnotifier/components/error_display/error_display.dart ' ;
2025-04-13 19:47:18 +02:00
import ' package:simplecloudnotifier/components/layout/scaffold.dart ' ;
2025-04-18 18:56:17 +02:00
import ' package:simplecloudnotifier/models/channel.dart ' ;
2025-04-13 19:47:18 +02:00
import ' package:simplecloudnotifier/models/keytoken.dart ' ;
import ' package:simplecloudnotifier/models/user.dart ' ;
import ' package:simplecloudnotifier/pages/filtered_message_view/filtered_message_view.dart ' ;
2025-04-18 18:56:17 +02:00
import ' package:simplecloudnotifier/pages/keytoken_view/keytoken_channel_modal.dart ' ;
import ' package:simplecloudnotifier/pages/keytoken_view/keytoken_permission_modal.dart ' ;
2025-04-13 19:47:18 +02:00
import ' package:simplecloudnotifier/state/app_auth.dart ' ;
import ' package:simplecloudnotifier/state/app_bar_state.dart ' ;
import ' package:simplecloudnotifier/state/application_log.dart ' ;
2025-04-18 18:56:17 +02:00
import ' package:simplecloudnotifier/state/scn_data_cache.dart ' ;
2025-04-13 19:47:18 +02:00
import ' package:simplecloudnotifier/types/immediate_future.dart ' ;
2025-04-18 18:56:17 +02:00
import ' package:simplecloudnotifier/utils/dialogs.dart ' ;
2025-04-13 19:47:18 +02:00
import ' package:simplecloudnotifier/utils/navi.dart ' ;
import ' package:simplecloudnotifier/utils/toaster.dart ' ;
import ' package:simplecloudnotifier/utils/ui.dart ' ;
import ' package:provider/provider.dart ' ;
class KeyTokenViewPage extends StatefulWidget {
const KeyTokenViewPage ( {
required this . keytokenID ,
required this . preloadedData ,
required this . needsReload ,
super . key ,
} ) ;
final String keytokenID ;
final KeyToken ? preloadedData ;
final void Function ( ) ? needsReload ;
@ override
State < KeyTokenViewPage > createState ( ) = > _KeyTokenViewPageState ( ) ;
}
enum EditState { none , editing , saving }
enum KeyTokenViewPageInitState { loading , okay , error }
class _KeyTokenViewPageState extends State < KeyTokenViewPage > {
static final _dateFormat = DateFormat ( ' yyyy-MM-dd HH:mm ' ) ; //TODO setting
2025-04-18 18:56:17 +02:00
ImmediateFuture < UserPreview > _futureOwner = ImmediateFuture . ofPending ( ) ;
ImmediateFuture < Map < String , ChannelPreview > > _futureAllChannels = ImmediateFuture . ofPending ( ) ;
ImmediateFuture < List < Channel > > _futureOwnedChannels = ImmediateFuture . ofPending ( ) ;
2025-04-13 19:47:18 +02:00
final TextEditingController _ctrlName = TextEditingController ( ) ;
int _loadingIndeterminateCounter = 0 ;
EditState _editName = EditState . none ;
String ? _nameOverride = null ;
KeyTokenPreview ? keytokenPreview ;
KeyToken ? keytoken ;
KeyTokenViewPageInitState loadingState = KeyTokenViewPageInitState . loading ;
String errorMessage = ' ' ;
2025-04-18 18:56:17 +02:00
KeyToken ? keytokenUserAccAdmin ;
KeyToken ? keytokenUserAccSend ;
2025-04-13 19:47:18 +02:00
@ override
void initState ( ) {
_initStateAsync ( true ) ;
super . initState ( ) ;
}
Future < void > _initStateAsync ( bool usePreload ) async {
final userAcc = Provider . of < AppAuth > ( context , listen: false ) ;
if ( widget . preloadedData ! = null & & usePreload ) {
keytoken = widget . preloadedData ! ;
keytokenPreview = widget . preloadedData ! . toPreview ( ) ;
} else {
try {
var p = await APIClient . getKeyTokenPreviewByID ( userAcc , widget . keytokenID ) ;
setState ( ( ) {
keytokenPreview = p ;
} ) ;
if ( p . ownerUserID = = userAcc . userID ) {
var r = await APIClient . getKeyToken ( userAcc , widget . keytokenID ) ;
setState ( ( ) {
keytoken = r ;
} ) ;
} else {
setState ( ( ) {
keytoken = null ;
} ) ;
}
} catch ( exc , trace ) {
ApplicationLog . error ( ' Failed to load data: ' + exc . toString ( ) , trace: trace ) ;
Toaster . error ( " Error " , ' Failed to load data ' ) ;
this . errorMessage = ' Failed to load data: ' + exc . toString ( ) ;
this . loadingState = KeyTokenViewPageInitState . error ;
return ;
}
}
setState ( ( ) {
this . loadingState = KeyTokenViewPageInitState . okay ;
assert ( keytokenPreview ! = null ) ;
if ( this . keytokenPreview ! . ownerUserID = = userAcc . userID ) {
var cacheUser = userAcc . getUserOrNull ( ) ;
if ( cacheUser ! = null ) {
2025-04-18 18:56:17 +02:00
_futureOwner = ImmediateFuture . ofValue ( cacheUser . toPreview ( ) ) ;
2025-04-13 19:47:18 +02:00
} else {
2025-04-18 18:56:17 +02:00
_futureOwner = ImmediateFuture . ofFuture ( _getOwner ( userAcc ) ) ;
2025-04-13 19:47:18 +02:00
}
} else {
2025-04-18 18:56:17 +02:00
_futureOwner = ImmediateFuture . ofFuture ( APIClient . getUserPreview ( userAcc , this . keytokenPreview ! . ownerUserID ) ) ;
2025-04-13 19:47:18 +02:00
}
} ) ;
2025-04-18 18:56:17 +02:00
setState ( ( ) {
_futureAllChannels = ImmediateFuture . ofFuture ( APIClient . getChannelList ( userAcc , ChannelSelector . allAny ) . then ( ( lst ) async {
Map < String , ChannelPreview > result = { } ;
for ( var c in lst ) result [ c . channel . channelID ] = c . channel . toPreview ( c . subscription ) ;
if ( keytokenPreview ! = null ) {
for ( var cid in keytokenPreview ! . channels ) {
if ( ! result . containsKey ( cid ) ) {
result [ cid ] = await APIClient . getChannelPreview ( userAcc , cid ) ;
}
}
}
return result ;
} ) ) ;
} ) ;
setState ( ( ) {
_futureOwnedChannels = ImmediateFuture . ofFuture ( APIClient . getChannelList ( userAcc , ChannelSelector . owned ) . then ( ( p ) = > p . map ( ( c ) = > c . channel ) . toList ( ) ) ) ;
} ) ;
SCNDataCache ( ) . getOrQueryTokenByValue ( userAcc . userID ! , userAcc . tokenAdmin ! ) . then ( ( token ) {
setState ( ( ) {
keytokenUserAccAdmin = token ;
} ) ;
} ) ;
SCNDataCache ( ) . getOrQueryTokenByValue ( userAcc . userID ! , userAcc . tokenSend ! ) . then ( ( token ) {
setState ( ( ) {
keytokenUserAccSend = token ;
} ) ;
} ) ;
2025-04-13 19:47:18 +02:00
}
@ override
void dispose ( ) {
_ctrlName . dispose ( ) ;
super . dispose ( ) ;
}
@ override
Widget build ( BuildContext context ) {
final userAcc = Provider . of < AppAuth > ( context , listen: false ) ;
var title = " Key " ;
Widget child ;
if ( loadingState = = KeyTokenViewPageInitState . loading ) {
child = Center ( child: CircularProgressIndicator ( ) ) ;
} else if ( loadingState = = KeyTokenViewPageInitState . error ) {
2025-04-18 14:07:31 +02:00
child = ErrorDisplay ( errorMessage: errorMessage ) ;
2025-04-13 19:47:18 +02:00
} else if ( loadingState = = KeyTokenViewPageInitState . okay & & keytokenPreview ! . ownerUserID = = userAcc . userID ) {
child = _buildOwnedKeyTokenView ( context , this . keytoken ! ) ;
title = this . keytoken ! . name ;
} else {
child = _buildForeignKeyTokenView ( context , this . keytokenPreview ! ) ;
title = keytokenPreview ! . name ;
}
return SCNScaffold (
title: title ,
showSearch: false ,
showShare: false ,
child: child ,
) ;
}
Widget _buildOwnedKeyTokenView ( BuildContext context , KeyToken keytoken ) {
return SingleChildScrollView (
child: Padding (
padding: const EdgeInsets . fromLTRB ( 24 , 16 , 24 , 16 ) ,
child: Column (
crossAxisAlignment: CrossAxisAlignment . stretch ,
children: [
SizedBox ( height: 8 ) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidIdCardClip ,
title: ' KeyTokenID ' ,
2025-04-18 18:56:17 +02:00
values: [
keytoken . keytokenID ,
if ( keytokenUserAccAdmin ? . keytokenID = = keytoken . keytokenID ) ' (Currently used as Admin-Token) ' ,
if ( keytokenUserAccSend ? . keytokenID = = keytoken . keytokenID ) ' (Currently used as Send-Token) ' ,
] ,
2025-04-13 19:47:18 +02:00
) ,
_buildNameCard ( context , true ) ,
UI . metaCard (
context: context ,
2025-04-18 18:56:17 +02:00
icon: FontAwesomeIcons . solidClock ,
2025-04-13 19:47:18 +02:00
title: ' Created ' ,
values: [ _KeyTokenViewPageState . _dateFormat . format ( DateTime . parse ( keytoken . timestampCreated ) . toLocal ( ) ) ] ,
) ,
UI . metaCard (
context: context ,
2025-04-18 18:56:17 +02:00
icon: FontAwesomeIcons . solidClockTwo ,
2025-04-13 19:47:18 +02:00
title: ' Last Used ' ,
values: [ ( keytoken . timestampLastUsed = = null ) ? ' Never ' : _KeyTokenViewPageState . _dateFormat . format ( DateTime . parse ( keytoken . timestampLastUsed ! ) . toLocal ( ) ) ] ,
) ,
_buildOwnerCard ( context , true ) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidEnvelope ,
title: ' Messages ' ,
values: [ keytoken . messagesSent . toString ( ) ] ,
mainAction: ( ) {
Navi . push ( context , ( ) = > FilteredMessageViewPage ( title: keytoken . name , filter: MessageFilter ( usedKeys: [ keytoken . keytokenID ] ) ) ) ;
} ,
) ,
. . . _buildPermissionCard ( context , true , keytoken . toPreview ( ) ) ,
UI . button ( text: " Delete Key " , onPressed: _deleteKey , color: Colors . red [ 900 ] ) ,
] ,
) ,
) ,
) ;
}
Widget _buildForeignKeyTokenView ( BuildContext context , KeyTokenPreview keytoken ) {
return SingleChildScrollView (
child: Padding (
padding: const EdgeInsets . fromLTRB ( 24 , 16 , 24 , 16 ) ,
child: Column (
crossAxisAlignment: CrossAxisAlignment . stretch ,
children: [
SizedBox ( height: 8 ) ,
UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidIdCardClip ,
title: ' KeyTokenID ' ,
values: [ keytoken . keytokenID ] ,
) ,
_buildNameCard ( context , false ) ,
_buildOwnerCard ( context , false ) ,
. . . _buildPermissionCard ( context , false , keytoken ) ,
] ,
) ,
) ,
) ;
}
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: [ keytokenPreview ! . ownerUserID + ( isOwned ? ' (you) ' : ' ' ) , if ( snapshot . data ? . username ! = null ) snapshot . data ! . username ! ] ,
) ;
} else {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidUser ,
title: ' Owner ' ,
values: [ keytokenPreview ! . ownerUserID + ( isOwned ? ' (you) ' : ' ' ) ] ,
) ;
}
} ,
) ;
}
Widget _buildNameCard ( BuildContext context , bool isOwned ) {
if ( _editName = = EditState . editing ) {
return Padding (
padding: EdgeInsets . symmetric ( vertical: 4 , horizontal: 0 ) ,
child: UI . box (
context: context ,
padding: EdgeInsets . fromLTRB ( 16 , 2 , 4 , 2 ) ,
child: Row (
children: [
Container ( child: Center ( child: FaIcon ( FontAwesomeIcons . solidInputText , size: 18 ) ) , height: 43 ) ,
SizedBox ( width: 16 ) ,
Expanded (
child: TextField (
autofocus: true ,
controller: _ctrlName ,
decoration: new InputDecoration . collapsed ( hintText: ' Name ' ) ,
) ,
) ,
SizedBox ( width: 12 ) ,
SizedBox ( width: 4 ) ,
IconButton ( icon: FaIcon ( FontAwesomeIcons . solidFloppyDisk ) , onPressed: _saveName ) ,
] ,
) ,
) ,
) ;
} else if ( _editName = = EditState . none ) {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidInputText ,
title: ' Name ' ,
values: [ _nameOverride ? ? keytokenPreview ! . name ] ,
2025-04-18 00:11:01 +02:00
iconActions: isOwned ? [ ( FontAwesomeIcons . penToSquare , null , _showEditName ) ] : [ ] ,
2025-04-13 19:47:18 +02:00
) ;
} else if ( _editName = = EditState . saving ) {
return Padding (
padding: EdgeInsets . symmetric ( vertical: 4 , horizontal: 0 ) ,
child: UI . box (
context: context ,
padding: EdgeInsets . fromLTRB ( 16 , 2 , 4 , 2 ) ,
child: Row (
children: [
Container ( child: Center ( child: FaIcon ( FontAwesomeIcons . solidInputText , size: 18 ) ) , height: 43 ) ,
SizedBox ( width: 16 ) ,
Expanded ( child: SizedBox ( ) ) ,
SizedBox ( width: 12 ) ,
SizedBox ( width: 4 ) ,
Padding ( padding: const EdgeInsets . all ( 8.0 ) , child: SizedBox ( width: 18 , height: 18 , child: CircularProgressIndicator ( ) ) ) ,
] ,
) ,
) ,
) ;
} else {
throw ' Invalid EditDisplayNameState: $ _editName ' ;
}
}
void _showEditName ( ) {
setState ( ( ) {
_ctrlName . text = _nameOverride ? ? keytokenPreview ? . name ? ? ' ' ;
_editName = EditState . editing ;
} ) ;
}
void _saveName ( ) async {
final userAcc = Provider . of < AppAuth > ( context , listen: false ) ;
final newName = _ctrlName . text ;
try {
setState ( ( ) {
_editName = EditState . saving ;
} ) ;
final newKeyToken = await APIClient . updateKeyToken ( userAcc , widget . keytokenID , name: newName ) ;
setState ( ( ) {
_editName = EditState . none ;
_nameOverride = newKeyToken . name ;
} ) ;
widget . needsReload ? . call ( ) ;
} catch ( exc , trace ) {
ApplicationLog . error ( ' Failed to save DisplayName: ' + exc . toString ( ) , trace: trace ) ;
Toaster . error ( " Error " , ' Failed to save DisplayName ' ) ;
}
}
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 , keytokenPreview ! . ownerUserID ) ;
//await Future.delayed(const Duration(seconds: 10), () {});
return owner ;
} finally {
_incLoadingIndeterminateCounter ( - 1 ) ;
}
}
void _incLoadingIndeterminateCounter ( int delta ) {
setState ( ( ) {
_loadingIndeterminateCounter + = delta ;
AppBarState ( ) . setLoadingIndeterminate ( _loadingIndeterminateCounter > 0 ) ;
} ) ;
}
List < Widget > _buildPermissionCard ( BuildContext context , bool isOwned , KeyTokenPreview keyToken ) {
Widget w1 ;
Widget w2 ;
if ( isOwned ) {
w1 = UI . metaCard (
context: context ,
2025-04-18 18:56:17 +02:00
icon: FontAwesomeIcons . solidShieldKeyhole ,
2025-04-13 19:47:18 +02:00
title: ' Permissions ' ,
values: _formatPermissions ( keyToken . permissions ) ,
2025-04-18 00:11:01 +02:00
iconActions: [ ( FontAwesomeIcons . penToSquare , null , _editPermissions ) ] ,
2025-04-13 19:47:18 +02:00
) ;
} else {
w1 = UI . metaCard (
context: context ,
2025-04-18 18:56:17 +02:00
icon: FontAwesomeIcons . solidShieldKeyhole ,
2025-04-13 19:47:18 +02:00
title: ' Permissions ' ,
values: _formatPermissions ( keyToken . permissions ) ,
) ;
}
2025-04-18 18:56:17 +02:00
w2 = FutureBuilder (
future: _futureAllChannels . future ,
builder: ( context , snapshot ) {
if ( snapshot . hasData ) {
var cmap = snapshot . data ! ;
if ( isOwned ) {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidSnake ,
title: ' Channels ' ,
values: ( keyToken . allChannels ) ? ( [ ' All Channels ' ] ) : ( keyToken . channels . isEmpty ? [ ' (None) ' ] : ( keyToken . channels . map ( ( c ) = > cmap [ c ] ? . displayName ? ? c ) . toList ( ) ) ) ,
iconActions: [ ( FontAwesomeIcons . penToSquare , null , _editChannels ) ] ,
) ;
} else {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidSnake ,
title: ' Channels ' ,
values: ( keyToken . allChannels ) ? ( [ ' All Channels ' ] ) : ( keyToken . channels . isEmpty ? [ ' (None) ' ] : ( keyToken . channels . map ( ( c ) = > cmap [ c ] ? . displayName ? ? c ) . toList ( ) ) ) ,
) ;
}
} else {
if ( isOwned ) {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidSnake ,
title: ' Channels ' ,
values: ( keyToken . allChannels ) ? [ ' All Channels ' ] : ( keyToken . channels . isEmpty ? [ ' (None) ' ] : keyToken . channels ) ,
iconActions: [ ( FontAwesomeIcons . penToSquare , null , _editChannels ) ] ,
) ;
} else {
return UI . metaCard (
context: context ,
icon: FontAwesomeIcons . solidSnake ,
title: ' Channels ' ,
values: ( keyToken . allChannels ) ? [ ' All Channels ' ] : ( keyToken . channels . isEmpty ? [ ' (None) ' ] : keyToken . channels ) ,
) ;
}
}
} ,
) ;
2025-04-13 19:47:18 +02:00
return [ w1 , w2 ] ;
}
List < String > _formatPermissions ( String v ) {
var splt = v . split ( ' ; ' ) ;
if ( splt . length = = 0 ) return [ " None " ] ;
List < String > result = [ ] ;
if ( splt . contains ( " A " ) ) result . add ( " Admin " ) ;
if ( splt . contains ( " UR " ) ) result . add ( " Read Account " ) ;
if ( splt . contains ( " CR " ) ) result . add ( " Read Messages " ) ;
if ( splt . contains ( " CS " ) ) result . add ( " Send Messages " ) ;
return result ;
}
2025-04-18 18:56:17 +02:00
void _editPermissions ( ) async {
final acc = Provider . of < AppAuth > ( context , listen: false ) ;
if ( keytokenUserAccAdmin = = null | | keytokenUserAccAdmin ! . keytokenID = = keytokenPreview ! . keytokenID ) {
Toaster . error ( " Error " , " You cannot edit the currently used token " ) ;
return ;
}
if ( keytokenUserAccSend = = null | | keytokenUserAccSend ! . keytokenID = = keytokenPreview ! . keytokenID ) {
Toaster . error ( " Error " , " You cannot edit the currently used token " ) ;
return ;
}
await showDialog < void > (
context: context ,
builder: ( context ) = > EditKeyTokenPermissionsDialog (
keytoken: keytokenPreview ! ,
onUpdatePermissions: _updatePermissions ,
) ,
) ;
}
void _editChannels ( ) async {
2025-04-13 19:47:18 +02:00
final acc = Provider . of < AppAuth > ( context , listen: false ) ;
2025-04-18 18:56:17 +02:00
if ( keytokenUserAccAdmin = = null | | keytokenUserAccAdmin ! . keytokenID = = keytokenPreview ! . keytokenID ) {
Toaster . error ( " Error " , " You cannot edit the currently used token " ) ;
return ;
}
if ( keytokenUserAccSend = = null | | keytokenUserAccSend ! . keytokenID = = keytokenPreview ! . keytokenID ) {
Toaster . error ( " Error " , " You cannot edit the currently used token " ) ;
return ;
}
2025-04-13 19:47:18 +02:00
2025-04-18 18:56:17 +02:00
var ownChannels = ( await _futureOwnedChannels . future ) ;
ownChannels . sort ( ( a , b ) = > a . displayName . toLowerCase ( ) . compareTo ( b . displayName . toLowerCase ( ) ) ) ;
2025-04-13 19:47:18 +02:00
2025-04-18 18:56:17 +02:00
await showDialog < void > (
context: context ,
builder: ( context ) = > EditKeyTokenChannelsDialog (
ownedChannels: ownChannels ,
keytoken: keytokenPreview ! ,
onUpdateChannels: _updateChannelsSelected ,
onUpdateSetAllChannels: _updateChannelsAll ,
) ,
) ;
2025-04-13 19:47:18 +02:00
}
2025-04-18 18:56:17 +02:00
void _deleteKey ( ) async {
2025-04-13 19:47:18 +02:00
final acc = Provider . of < AppAuth > ( context , listen: false ) ;
2025-04-18 18:56:17 +02:00
if ( keytokenUserAccAdmin = = null | | keytokenUserAccAdmin ! . keytokenID = = keytokenPreview ! . keytokenID ) {
Toaster . error ( " Error " , " You cannot delete the currently used token " ) ;
return ;
}
if ( keytokenUserAccSend = = null | | keytokenUserAccSend ! . keytokenID = = keytokenPreview ! . keytokenID ) {
Toaster . error ( " Error " , " You cannot delete the currently used token " ) ;
return ;
}
try {
final r = await UIDialogs . showConfirmDialog ( context , ' Really (permanently) delete this Key? ' , okText: ' Unsubscribe ' , cancelText: ' Cancel ' ) ;
if ( ! r ) return ;
await APIClient . deleteKeyToken ( acc , keytokenPreview ! . keytokenID ) ;
widget . needsReload ? . call ( ) ;
2025-04-13 19:47:18 +02:00
2025-04-18 18:56:17 +02:00
Toaster . info ( ' Logout ' , ' Successfully deleted the key ' ) ;
2025-04-13 19:47:18 +02:00
2025-04-18 18:56:17 +02:00
Navi . pop ( context ) ;
} catch ( exc , trace ) {
Toaster . error ( " Error " , ' Failed to delete key ' ) ;
ApplicationLog . error ( ' Failed to delete key: ' + exc . toString ( ) , trace: trace ) ;
}
2025-04-13 19:47:18 +02:00
}
2025-04-18 18:56:17 +02:00
void _updateChannelsSelected ( Set < String > selectedEntries ) async {
2025-04-13 19:47:18 +02:00
final acc = Provider . of < AppAuth > ( context , listen: false ) ;
2025-04-18 18:56:17 +02:00
try {
final r = await APIClient . updateKeyToken ( acc , widget . keytokenID , channels: selectedEntries . toList ( ) , allChannels: false ) ;
setState ( ( ) {
keytoken = r ;
keytokenPreview = r . toPreview ( ) ;
} ) ;
Toaster . info ( " Success " , " Key updated " ) ;
2025-04-13 19:47:18 +02:00
2025-04-18 18:56:17 +02:00
widget . needsReload ? . call ( ) ;
} catch ( exc , trace ) {
ApplicationLog . error ( ' Failed to update key: ' + exc . toString ( ) , trace: trace ) ;
Toaster . error ( " Error " , ' Failed to update key ' ) ;
}
}
2025-04-13 19:47:18 +02:00
2025-04-18 18:56:17 +02:00
void _updateChannelsAll ( ) async {
final acc = Provider . of < AppAuth > ( context , listen: false ) ;
try {
final r = await APIClient . updateKeyToken ( acc , widget . keytokenID , channels: [ ] , allChannels: true ) ;
setState ( ( ) {
keytoken = r ;
keytokenPreview = r . toPreview ( ) ;
} ) ;
Toaster . info ( " Success " , " Key updated " ) ;
widget . needsReload ? . call ( ) ;
} catch ( exc , trace ) {
ApplicationLog . error ( ' Failed to update key: ' + exc . toString ( ) , trace: trace ) ;
Toaster . error ( " Error " , ' Failed to update key ' ) ;
}
}
void _updatePermissions ( String perm ) async {
final acc = Provider . of < AppAuth > ( context , listen: false ) ;
try {
final r = await APIClient . updateKeyToken ( acc , widget . keytokenID , permissions: perm ) ;
setState ( ( ) {
keytoken = r ;
keytokenPreview = r . toPreview ( ) ;
} ) ;
Toaster . info ( " Success " , " Key updated " ) ;
widget . needsReload ? . call ( ) ;
} catch ( exc , trace ) {
ApplicationLog . error ( ' Failed to update key: ' + exc . toString ( ) , trace: trace ) ;
Toaster . error ( " Error " , ' Failed to update key ' ) ;
}
2025-04-13 19:47:18 +02:00
}
}