vnc_viewer 0.0.6
vnc_viewer: ^0.0.6 copied to clipboard
Flutter plugin for embedding an Android VNC client that renders remote desktops and sends keyboard and pointer input to VNC/RFB servers.
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:vnc_viewer_example/viewer.dart';
void main() {
runZonedGuarded(
() => runApp(const MyApp()),
(error, stackTrace) {
debugPrint('Unhandled error: $error');
debugPrintStack(stackTrace: stackTrace);
},
);
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'VNC Viewer Demo',
theme: ThemeData(
primaryColor: Colors.blue,
primarySwatch: Colors.blue,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
static const String _defaultHost = String.fromEnvironment('VNC_HOST');
static const String _defaultPort = String.fromEnvironment(
'VNC_PORT',
defaultValue: '5900',
);
static const String _defaultPassword = String.fromEnvironment('VNC_PASSWORD');
static const bool _autoConnect =
bool.fromEnvironment('VNC_AUTO_CONNECT', defaultValue: false);
final TextEditingController _hostNameEditingController =
TextEditingController(text: _defaultHost);
final TextEditingController _portEditingController =
TextEditingController(text: _defaultPort);
final TextEditingController _passwordEditingController =
TextEditingController(text: _defaultPassword);
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
bool _didAutoOpen = false;
@override
void initState() {
super.initState();
if (_autoConnect) {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (!mounted || _didAutoOpen) {
return;
}
_didAutoOpen = true;
_openViewer();
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('VNC Viewer Demo')),
body: Padding(
padding: const EdgeInsets.all(16),
child: Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _hostNameEditingController,
decoration: const InputDecoration(
labelText: 'Host',
hintText: '192.168.1.100',
),
validator: (String? value) {
if (value == null || value.trim().isEmpty) {
return 'Please enter a host name or IP address.';
}
return null;
},
),
TextFormField(
controller: _portEditingController,
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: 'Port',
hintText: '5900',
),
validator: (String? value) {
final port = int.tryParse(value ?? '');
if (port == null || port <= 0 || port > 65535) {
return 'Please enter a valid TCP port.';
}
return null;
},
),
TextFormField(
controller: _passwordEditingController,
obscureText: true,
decoration: const InputDecoration(
labelText: 'Password',
hintText: 'Optional',
),
),
const SizedBox(height: 16),
FilledButton(
onPressed: _openViewer,
child: const Text('Open Viewer'),
),
],
),
),
),
);
}
void _openViewer() {
if (!_formKey.currentState!.validate()) {
return;
}
final hostName = _hostNameEditingController.text.trim();
final port = int.parse(_portEditingController.text);
final password = _passwordEditingController.text;
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ExampleViewer(
hostName: hostName,
password: password,
port: port,
),
),
);
}
@override
void dispose() {
_hostNameEditingController.dispose();
_portEditingController.dispose();
_passwordEditingController.dispose();
super.dispose();
}
}