@@ -151,6 +151,12 @@ class _ServicesSettingsTabState extends State<ServicesSettingsTab> {
151151 bool _dsEnabled = false ;
152152 bool _dsTokenVisible = false ;
153153
154+ // DonateX controllers
155+ final _dxWidgetUrlController = TextEditingController ();
156+ final _dxGroupUrlController = TextEditingController ();
157+ bool _dxEnabled = false ;
158+ bool _dxTokenVisible = false ;
159+
154160 // Available socket servers for DonationAlerts
155161 static const List <String > _socketServers = [
156162 'socket5' ,
@@ -195,6 +201,14 @@ class _ServicesSettingsTabState extends State<ServicesSettingsTab> {
195201 _dsTokenController.text = dsConfig.getCredential ('token' ) ?? '' ;
196202 }
197203
204+ // DonateX
205+ final dxConfig = settings.getServiceConfig ('DonateX' );
206+ if (dxConfig != null ) {
207+ _dxEnabled = dxConfig.enabled;
208+ _dxWidgetUrlController.text = dxConfig.getCredential ('widgetUrl' ) ?? '' ;
209+ _dxGroupUrlController.text = dxConfig.getCredential ('groupUrl' ) ?? '' ;
210+ }
211+
198212 setState (() {});
199213 }
200214
@@ -203,6 +217,8 @@ class _ServicesSettingsTabState extends State<ServicesSettingsTab> {
203217 _daTokenController.dispose ();
204218 _dpApiKeyController.dispose ();
205219 _dsTokenController.dispose ();
220+ _dxWidgetUrlController.dispose ();
221+ _dxGroupUrlController.dispose ();
206222 super .dispose ();
207223 }
208224
@@ -294,6 +310,10 @@ class _ServicesSettingsTabState extends State<ServicesSettingsTab> {
294310
295311 // Donate.Stream
296312 _buildDonateStreamSection (localization),
313+ const SizedBox (height: 16 ),
314+
315+ // DonateX
316+ _buildDonateXSection (localization),
297317 ],
298318 ),
299319 );
@@ -536,6 +556,122 @@ class _ServicesSettingsTabState extends State<ServicesSettingsTab> {
536556 ),
537557 );
538558 }
559+
560+ Widget _buildDonateXSection (LocalizationProvider localization) {
561+ final status = _getAdapterStatus ('DonateX' );
562+ return NesContainer (
563+ label: localization.tr ('donatex' ),
564+ child: Padding (
565+ padding: const EdgeInsets .all (16 ),
566+ child: Column (
567+ crossAxisAlignment: CrossAxisAlignment .start,
568+ children: [
569+ // Enable checkbox + status indicator
570+ Row (
571+ children: [
572+ NesCheckBox (
573+ value: _dxEnabled,
574+ onChange: (value) => setState (() => _dxEnabled = value),
575+ ),
576+ const SizedBox (width: 12 ),
577+ Text (
578+ _dxEnabled
579+ ? localization.tr ('enabled' )
580+ : localization.tr ('disabled' ),
581+ ),
582+ const Spacer (),
583+ _buildStatusIndicator (status),
584+ const SizedBox (width: 8 ),
585+ ],
586+ ),
587+ const SizedBox (height: 16 ),
588+
589+ // Widget URL field (for token extraction)
590+ Text ('${localization .tr ('donatex_widget_url' )}:' ),
591+ const SizedBox (height: 8 ),
592+ TextField (
593+ controller: _dxWidgetUrlController,
594+ obscureText: ! _dxTokenVisible,
595+ decoration: InputDecoration (
596+ hintText: 'https://donatex.gg/recent-donations?token=...' ,
597+ border: const OutlineInputBorder (),
598+ contentPadding: const EdgeInsets .symmetric (
599+ horizontal: 12 ,
600+ vertical: 8 ,
601+ ),
602+ suffixIcon: IconButton (
603+ icon: Icon (_dxTokenVisible ? Icons .visibility_off : Icons .visibility),
604+ onPressed: () => setState (() => _dxTokenVisible = ! _dxTokenVisible),
605+ ),
606+ ),
607+ ),
608+ const SizedBox (height: 16 ),
609+
610+ // Group URL field (for widget_id extraction)
611+ Text ('${localization .tr ('donatex_group_url' )}:' ),
612+ const SizedBox (height: 8 ),
613+ TextField (
614+ controller: _dxGroupUrlController,
615+ decoration: InputDecoration (
616+ hintText: 'https://donatex.gg/widgets/donations/...' ,
617+ border: const OutlineInputBorder (),
618+ contentPadding: const EdgeInsets .symmetric (
619+ horizontal: 12 ,
620+ vertical: 8 ,
621+ ),
622+ ),
623+ ),
624+ const SizedBox (height: 4 ),
625+ Text (
626+ 'Виджет последних сообщений → токен, Группа оповещалки → widget_id' ,
627+ style: const TextStyle (fontSize: 10 , color: Colors .grey),
628+ ),
629+ const SizedBox (height: 16 ),
630+
631+ // Save button
632+ NesButton .text (
633+ type: NesButtonType .success,
634+ text: localization.tr ('save' ),
635+ onPressed: () => _saveDonateXConfig (),
636+ ),
637+ ],
638+ ),
639+ ),
640+ );
641+ }
642+
643+ void _saveDonateXConfig () {
644+ // Extract token from widget URL
645+ String ? token;
646+ final widgetUrl = _dxWidgetUrlController.text;
647+ if (widgetUrl.contains ('token=' )) {
648+ final uri = Uri .tryParse (widgetUrl);
649+ token = uri? .queryParameters['token' ];
650+ } else {
651+ token = widgetUrl; // Assume it's just the token
652+ }
653+
654+ // Extract widget_id from group URL
655+ String ? widgetId;
656+ final groupUrl = _dxGroupUrlController.text;
657+ final donationsMatch = RegExp (r'/widgets/donations/([a-f0-9-]+)' ).firstMatch (groupUrl);
658+ if (donationsMatch != null ) {
659+ widgetId = donationsMatch.group (1 );
660+ } else {
661+ widgetId = groupUrl; // Assume it's just the widget_id
662+ }
663+
664+ _saveServiceConfig (
665+ 'DonateX' ,
666+ _dxEnabled,
667+ {
668+ 'token' : token ?? '' ,
669+ 'widgetId' : widgetId ?? '' ,
670+ 'widgetUrl' : _dxWidgetUrlController.text,
671+ 'groupUrl' : _dxGroupUrlController.text,
672+ },
673+ );
674+ }
539675}
540676
541677
0 commit comments