166 lines
4.8 KiB
Dart
166 lines
4.8 KiB
Dart
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:url_launcher/url_launcher.dart';
|
|
|
|
import 'shorten_service.dart';
|
|
|
|
void main() {
|
|
runApp(const MyApp());
|
|
}
|
|
|
|
class MyApp extends StatelessWidget {
|
|
const MyApp({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
home: Home(),
|
|
);
|
|
}
|
|
}
|
|
|
|
class Home extends StatefulWidget {
|
|
const Home({super.key});
|
|
|
|
@override
|
|
State<Home> createState() => _HomeState();
|
|
}
|
|
|
|
class _HomeState extends State<Home> {
|
|
late final TextEditingController controller;
|
|
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
|
|
String? shortenedUrl;
|
|
bool loading = false;
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
controller = TextEditingController();
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
super.dispose();
|
|
controller.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
body: Center(
|
|
child: Stack(
|
|
children: <Widget>[
|
|
Column(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
const Text(
|
|
'Url shortner',
|
|
style: TextStyle(fontSize: 24),
|
|
),
|
|
Row(
|
|
mainAxisAlignment: MainAxisAlignment.center,
|
|
children: <Widget>[
|
|
const SizedBox(width: 30),
|
|
ConstrainedBox(
|
|
constraints: const BoxConstraints(maxWidth: 300),
|
|
child: Form(
|
|
key: formKey,
|
|
child: TextFormField(
|
|
controller: controller,
|
|
onFieldSubmitted: loading ? null : (_) => processUrl(),
|
|
validator: (String? url) {
|
|
try {
|
|
if (url == null || url.isEmpty) {
|
|
return 'No url entered.';
|
|
}
|
|
final Uri uri = Uri.parse(url);
|
|
if (!uri.hasScheme || (!uri.isScheme('HTTP') && !uri.isScheme('HTTPS'))) {
|
|
throw const FormatException();
|
|
}
|
|
return null;
|
|
} on FormatException {
|
|
return 'Bad URL';
|
|
}
|
|
},
|
|
),
|
|
),
|
|
),
|
|
IconButton(
|
|
icon: const Icon(Icons.arrow_circle_right_rounded),
|
|
onPressed: loading ? null : () => processUrl(),
|
|
),
|
|
],
|
|
),
|
|
AnimatedOpacity(
|
|
opacity: shortenedUrl == null ? 0.0 : 1.0,
|
|
duration: const Duration(milliseconds: 200),
|
|
child: Padding(
|
|
padding: const EdgeInsets.only(top: 14.0),
|
|
child: Column(
|
|
children: <Widget>[
|
|
const Text('Short URL:'),
|
|
InkWell(
|
|
onTap: shortenedUrl == null ? null : () => launchUrl(Uri.parse(shortenedUrl!)),
|
|
child: Text(
|
|
shortenedUrl ?? '',
|
|
style: const TextStyle(color: Colors.blue, fontSize: 24),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
],
|
|
),
|
|
Center(
|
|
child: AnimatedOpacity(
|
|
opacity: loading ? 1.0 : 0.0,
|
|
duration: const Duration(milliseconds: 200),
|
|
child: const CircularProgressIndicator(),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> processUrl() async {
|
|
try {
|
|
assert(formKey.currentState != null, 'Could not validate form, formKey currentState is null');
|
|
|
|
if (loading) {
|
|
return;
|
|
}
|
|
setState(() => loading = true);
|
|
final bool isValid = formKey.currentState!.validate();
|
|
|
|
if (!isValid) {
|
|
setState(() => loading = false);
|
|
return;
|
|
}
|
|
|
|
final String? shortUrl = await shortenUrl(controller.text);
|
|
if (shortUrl != null) {
|
|
setState(() {
|
|
shortenedUrl = shortUrl;
|
|
loading = false;
|
|
});
|
|
} else {
|
|
// show error
|
|
setState(() {
|
|
shortenedUrl = null;
|
|
loading = false;
|
|
});
|
|
}
|
|
} catch (err, st) {
|
|
if (kDebugMode) {
|
|
print(st);
|
|
print('An error occurred trying to shorten the url: $err');
|
|
}
|
|
setState(() => loading = false);
|
|
}
|
|
}
|
|
}
|