fixed rendering bug on linux + ip configuration

This commit is contained in:
2025-10-15 14:20:31 +02:00
parent 86e89b5ed8
commit 74a918d62b
7 changed files with 146 additions and 24 deletions

View File

@ -279,7 +279,7 @@ class _HomeScreenState extends State<HomeScreen> {
),
const SizedBox(height: 4),
Text(
'Port: ${project.port}${project.packages.length} package(s)',
'${project.ipAddress}:${project.port}${project.packages.length} package(s)',
style:
Theme.of(context).textTheme.bodySmall,
),

View File

@ -20,17 +20,20 @@ class _ProjectScreenState extends State<ProjectScreen> {
final UdpService _udpService = UdpService();
String? _lastSentPackageId;
bool _isSending = false;
late TextEditingController _ipController;
late TextEditingController _portController;
@override
void initState() {
super.initState();
_project = widget.project;
_ipController = TextEditingController(text: _project.ipAddress);
_portController = TextEditingController(text: _project.port.toString());
}
@override
void dispose() {
_ipController.dispose();
_portController.dispose();
super.dispose();
}
@ -75,17 +78,58 @@ class _ProjectScreenState extends State<ProjectScreen> {
);
}
void _updatePort() {
void _updateSettings() {
final ip = _ipController.text.trim();
final port = int.tryParse(_portController.text);
if (port != null && port >= 1 && port <= 65535) {
// Validate IP address
final ipPattern = RegExp(r'^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$');
bool isValidIp = ipPattern.hasMatch(ip);
if (isValidIp) {
final parts = ip.split('.');
for (final part in parts) {
final num = int.tryParse(part);
if (num == null || num < 0 || num > 255) {
isValidIp = false;
break;
}
}
}
// Validate port
final isValidPort = port != null && port >= 1 && port <= 65535;
if (isValidIp && isValidPort) {
setState(() {
_project = _project.copyWith(port: port);
_project = _project.copyWith(
ipAddress: ip,
port: port,
);
});
} else {
_portController.text = _project.port.toString();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Invalid port number (1-65535)'),
content: Text('Settings updated successfully!'),
backgroundColor: Colors.green,
behavior: SnackBarBehavior.floating,
),
);
} else {
// Revert to current project values
_ipController.text = _project.ipAddress;
_portController.text = _project.port.toString();
String errorMessage = 'Invalid ';
if (!isValidIp && !isValidPort) {
errorMessage += 'IP address and port number';
} else if (!isValidIp) {
errorMessage += 'IP address';
} else {
errorMessage += 'port number (1-65535)';
}
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(errorMessage),
backgroundColor: Colors.red,
behavior: SnackBarBehavior.floating,
),
@ -128,7 +172,7 @@ class _ProjectScreenState extends State<ProjectScreen> {
final success = await _udpService.sendPackage(
data: package.data,
ipAddress: package.ipAddress,
ipAddress: _project.ipAddress, // Use project IP to override package IP
port: _project.port,
);
@ -212,6 +256,18 @@ class _ProjectScreenState extends State<ProjectScreen> {
const SizedBox(height: 16),
Row(
children: [
Expanded(
child: TextField(
controller: _ipController,
decoration: const InputDecoration(
labelText: 'IP Address',
prefixIcon: Icon(Icons.computer),
isDense: true,
),
onSubmitted: (_) => _updateSettings(),
),
),
const SizedBox(width: 8),
Expanded(
child: TextField(
controller: _portController,
@ -224,12 +280,12 @@ class _ProjectScreenState extends State<ProjectScreen> {
inputFormatters: [
FilteringTextInputFormatter.digitsOnly
],
onSubmitted: (_) => _updatePort(),
onSubmitted: (_) => _updateSettings(),
),
),
const SizedBox(width: 8),
FilledButton.icon(
onPressed: _updatePort,
onPressed: _updateSettings,
icon: const Icon(Icons.check, size: 18),
label: const Text('Apply'),
),
@ -265,15 +321,26 @@ class _ProjectScreenState extends State<ProjectScreen> {
],
),
)
: ListView.builder(
padding: const EdgeInsets.all(16),
itemCount: _project.packages.length,
itemBuilder: (context, index) {
final package = _project.packages[index];
final wasSent = _lastSentPackageId == package.id;
: LayoutBuilder(
builder: (context, constraints) {
// Use 2 columns when width is >= 800px, otherwise 1 column
final crossAxisCount = constraints.maxWidth >= 800 ? 2 : 1;
final aspectRatio = constraints.maxWidth >= 800 ? 2.5 : 2.0;
return GridView.builder(
padding: const EdgeInsets.all(16),
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: crossAxisCount,
childAspectRatio: aspectRatio,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
),
itemCount: _project.packages.length,
itemBuilder: (context, index) {
final package = _project.packages[index];
final wasSent = _lastSentPackageId == package.id;
return Card(
margin: const EdgeInsets.only(bottom: 12),
return Card(
color: wasSent
? Theme.of(context).colorScheme.primaryContainer
: null,
@ -335,7 +402,7 @@ class _ProjectScreenState extends State<ProjectScreen> {
),
const SizedBox(height: 4),
Text(
'To: ${package.ipAddress}',
'To: ${_project.ipAddress}:${_project.port}',
style:
Theme.of(context).textTheme.bodySmall,
),
@ -455,6 +522,8 @@ class _ProjectScreenState extends State<ProjectScreen> {
),
);
},
);
},
),
),
],