initial upload
This commit is contained in:
64
lib/widgets/about_dialog.dart
Normal file
64
lib/widgets/about_dialog.dart
Normal file
@ -0,0 +1,64 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AppAboutDialog extends StatelessWidget {
|
||||
const AppAboutDialog({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AboutDialog(
|
||||
applicationName: 'UnityUDP',
|
||||
applicationVersion: '1.0.0',
|
||||
applicationIcon: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Icon(
|
||||
Icons.send,
|
||||
size: 32,
|
||||
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||
),
|
||||
),
|
||||
children: [
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'A simple and efficient app for sending UDP packages over custom ports.',
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Features:',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
const Text('• Create and manage multiple projects'),
|
||||
const Text('• Configure custom UDP ports'),
|
||||
const Text('• Store pre-defined packages'),
|
||||
const Text('• Quick send functionality'),
|
||||
const Text('• Persistent local storage'),
|
||||
const SizedBox(height: 16),
|
||||
const Divider(),
|
||||
const SizedBox(height: 16),
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.code,
|
||||
size: 20,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Text(
|
||||
'Developed by Tom Hempel',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
142
lib/widgets/package_dialog.dart
Normal file
142
lib/widgets/package_dialog.dart
Normal file
@ -0,0 +1,142 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../models/udp_package.dart';
|
||||
|
||||
class PackageDialog extends StatefulWidget {
|
||||
final UdpPackage? package;
|
||||
final Function(UdpPackage) onSave;
|
||||
|
||||
const PackageDialog({
|
||||
super.key,
|
||||
this.package,
|
||||
required this.onSave,
|
||||
});
|
||||
|
||||
@override
|
||||
State<PackageDialog> createState() => _PackageDialogState();
|
||||
}
|
||||
|
||||
class _PackageDialogState extends State<PackageDialog> {
|
||||
late TextEditingController _nameController;
|
||||
late TextEditingController _ipController;
|
||||
late TextEditingController _dataController;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_nameController = TextEditingController(text: widget.package?.name ?? '');
|
||||
_ipController = TextEditingController(
|
||||
text: widget.package?.ipAddress ?? '127.0.0.1',
|
||||
);
|
||||
_dataController = TextEditingController(text: widget.package?.data ?? '');
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_ipController.dispose();
|
||||
_dataController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool _isValidIp(String ip) {
|
||||
final parts = ip.split('.');
|
||||
if (parts.length != 4) return false;
|
||||
for (final part in parts) {
|
||||
final num = int.tryParse(part);
|
||||
if (num == null || num < 0 || num > 255) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void _save() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
final package = UdpPackage(
|
||||
id: widget.package?.id ?? DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
name: _nameController.text.trim(),
|
||||
ipAddress: _ipController.text.trim(),
|
||||
data: _dataController.text,
|
||||
);
|
||||
widget.onSave(package);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(widget.package == null ? 'New Package' : 'Edit Package'),
|
||||
content: SingleChildScrollView(
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Package Name',
|
||||
prefixIcon: Icon(Icons.label),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return 'Please enter a package name';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
autofocus: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _ipController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'IP Address',
|
||||
prefixIcon: Icon(Icons.computer),
|
||||
hintText: '192.168.1.100',
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
validator: (value) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return 'Please enter an IP address';
|
||||
}
|
||||
if (!_isValidIp(value.trim())) {
|
||||
return 'Invalid IP address';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _dataController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Data',
|
||||
prefixIcon: Icon(Icons.data_object),
|
||||
hintText: 'Enter the data to send',
|
||||
),
|
||||
maxLines: 4,
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter data to send';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: _save,
|
||||
child: const Text('Save'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
113
lib/widgets/project_dialog.dart
Normal file
113
lib/widgets/project_dialog.dart
Normal file
@ -0,0 +1,113 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../models/project.dart';
|
||||
|
||||
class ProjectDialog extends StatefulWidget {
|
||||
final Project? project;
|
||||
final Function(Project) onSave;
|
||||
|
||||
const ProjectDialog({
|
||||
super.key,
|
||||
this.project,
|
||||
required this.onSave,
|
||||
});
|
||||
|
||||
@override
|
||||
State<ProjectDialog> createState() => _ProjectDialogState();
|
||||
}
|
||||
|
||||
class _ProjectDialogState extends State<ProjectDialog> {
|
||||
late TextEditingController _nameController;
|
||||
late TextEditingController _portController;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_nameController = TextEditingController(text: widget.project?.name ?? '');
|
||||
_portController = TextEditingController(
|
||||
text: widget.project?.port.toString() ?? '8888',
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_nameController.dispose();
|
||||
_portController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _save() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
final project = Project(
|
||||
id: widget.project?.id ?? DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
name: _nameController.text.trim(),
|
||||
port: int.parse(_portController.text),
|
||||
packages: widget.project?.packages ?? [],
|
||||
);
|
||||
widget.onSave(project);
|
||||
Navigator.pop(context);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: Text(widget.project == null ? 'New Project' : 'Edit Project'),
|
||||
content: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextFormField(
|
||||
controller: _nameController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Project Name',
|
||||
prefixIcon: Icon(Icons.folder),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.trim().isEmpty) {
|
||||
return 'Please enter a project name';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
autofocus: true,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
TextFormField(
|
||||
controller: _portController,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'UDP Port',
|
||||
prefixIcon: Icon(Icons.router),
|
||||
),
|
||||
keyboardType: TextInputType.number,
|
||||
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter a port number';
|
||||
}
|
||||
final port = int.tryParse(value);
|
||||
if (port == null || port < 1 || port > 65535) {
|
||||
return 'Port must be between 1 and 65535';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: const Text('Cancel'),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: _save,
|
||||
child: const Text('Save'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user