Spaces:
Running
Running
| import 'package:flutter/material.dart'; | |
| import 'package:virtual_keyboard_multi_language/virtual_keyboard_multi_language.dart'; | |
| import 'package:google_fonts/google_fonts.dart'; | |
| import '../services/grammar_service.dart'; | |
| import '../services/llm_service.dart'; | |
| import '../services/storage_service.dart'; | |
| import '../kavacha/threat_pack/outgoing_data_shield.dart'; | |
| import 'hinglish_ngram.dart'; | |
| import 'keyboard_channel.dart'; | |
| import 'shortcut_bar.dart'; | |
| class PremithiusKeyboard extends StatefulWidget { | |
| const PremithiusKeyboard({Key? key}) : super(key: key); | |
| _PremithiusKeyboardState createState() => _PremithiusKeyboardState(); | |
| } | |
| class _PremithiusKeyboardState extends State<PremithiusKeyboard> { | |
| bool _isGenerating = false; | |
| final _grammarService = GrammarService(); | |
| final _llmService = LlmService(); | |
| final _storageService = StorageService(); | |
| final _outgoingShield = OutgoingDataShield(); | |
| final _hinglish = HinglishNgram(); | |
| void initState() { | |
| super.initState(); | |
| _grammarService.init(); | |
| } | |
| Future<void> _onShortcutAction(String action) async { | |
| setState(() => _isGenerating = true); | |
| // Fetch current text from IME | |
| String originalText = await KeyboardChannel.getText(); | |
| String newText = originalText; | |
| if (action == 'Fix') { | |
| newText = await _grammarService.fixGrammar(originalText); | |
| } else { | |
| newText = await _llmService.processAction(originalText, action); | |
| } | |
| await KeyboardChannel.replaceText(newText); | |
| // Log asynchronously | |
| try { | |
| await _storageService.insertKeyboardLog({ | |
| 'app_context': 'premithus_ime', // Default context | |
| 'original_text': originalText, | |
| 'action': action, | |
| 'result_text': newText, | |
| 'accepted': 1, | |
| 'created_at': DateTime.now().millisecondsSinceEpoch, | |
| }); | |
| } catch (e) { | |
| debugPrint('Error inserting keyboard log: \$e'); | |
| } | |
| if (mounted) { | |
| setState(() => _isGenerating = false); | |
| } | |
| } | |
| void _onKeyPress(VirtualKeyboardKey key) async { | |
| if (key.keyType == VirtualKeyboardKeyType.String) { | |
| KeyboardChannel.commitText(key.text ?? ''); | |
| } else if (key.keyType == VirtualKeyboardKeyType.Action) { | |
| switch (key.action) { | |
| case VirtualKeyboardKeyAction.Backspace: | |
| KeyboardChannel.deleteBackward(); | |
| break; | |
| case VirtualKeyboardKeyAction.Space: | |
| case VirtualKeyboardKeyAction.Return: | |
| // Check for data leaks on word boundaries | |
| String fullText = await KeyboardChannel.getText(); | |
| final shieldResult = _outgoingShield.check(fullText); | |
| if (!shieldResult.isSafe) { | |
| // In a real app we would show a confirmation dialog or red overlay | |
| debugPrint("SHIELD WARNING: \${shieldResult.warningTitle}"); | |
| // Simulate temporary block | |
| ScaffoldMessenger.of(context).showSnackBar( | |
| SnackBar(content: Text(shieldResult.warningMessage ?? "Blocked"), backgroundColor: Colors.red), | |
| ); | |
| } else { | |
| KeyboardChannel.commitText(key.action == VirtualKeyboardKeyAction.Space ? ' ' : '\n'); | |
| } | |
| break; | |
| default: | |
| break; | |
| } | |
| } | |
| } | |
| Widget build(BuildContext context) { | |
| return Material( | |
| color: Colors.black, | |
| child: Column( | |
| mainAxisSize: MainAxisSize.min, | |
| children: [ | |
| Container( | |
| padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4), | |
| decoration: BoxDecoration( | |
| color: Colors.black54, | |
| border: Border(bottom: BorderSide(color: Colors.white.withValues(alpha: 0.05))), | |
| ), | |
| child: Row( | |
| mainAxisAlignment: MainAxisAlignment.spaceBetween, | |
| children: [ | |
| Row( | |
| children: [ | |
| const Icon(Icons.shield_rounded, color: Colors.blueAccent, size: 14), | |
| const SizedBox(width: 6), | |
| Text( | |
| "KAVACHA PROTECTED", | |
| style: GoogleFonts.outfit( | |
| color: Colors.blueAccent, | |
| fontSize: 10, | |
| fontWeight: FontWeight.w800, | |
| letterSpacing: 1.1, | |
| ), | |
| ), | |
| ], | |
| ), | |
| Container( | |
| padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), | |
| decoration: BoxDecoration( | |
| color: Colors.greenAccent.withValues(alpha: 0.1), | |
| borderRadius: BorderRadius.circular(4), | |
| ), | |
| child: Text( | |
| "SAFE", | |
| style: GoogleFonts.outfit( | |
| color: Colors.greenAccent, | |
| fontSize: 10, | |
| fontWeight: FontWeight.bold, | |
| ), | |
| ), | |
| ), | |
| ], | |
| ), | |
| ), | |
| ShortcutBar( | |
| onAction: _onShortcutAction, | |
| isGenerating: _isGenerating, | |
| ), | |
| Container( | |
| color: Colors.black, | |
| child: VirtualKeyboard( | |
| height: 250, | |
| textColor: Colors.white, | |
| type: VirtualKeyboardType.Alphanumeric, | |
| textController: TextEditingController(), | |
| postKeyPress: _onKeyPress, | |
| ), | |
| ), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |