shlink-manager/lib/views/home_view.dart

247 lines
9.4 KiB
Dart
Raw Normal View History

2023-06-26 23:40:05 +02:00
import 'package:flutter/material.dart';
2023-07-10 17:32:46 +02:00
import 'package:qr_flutter/qr_flutter.dart';
2024-01-27 23:07:06 +01:00
import 'package:shlink_app/API/Classes/ShlinkStats/shlink_stats.dart';
import 'package:shlink_app/API/server_manager.dart';
import 'package:shlink_app/views/short_url_edit_view.dart';
import 'package:shlink_app/views/url_list_view.dart';
2024-03-31 17:55:01 +02:00
import 'package:shlink_app/widgets/shlink_stats_card_widget.dart';
2024-01-27 23:07:06 +01:00
import '../API/Classes/ShortURL/short_url.dart';
import '../globals.dart' as globals;
2023-06-26 23:40:05 +02:00
class HomeView extends StatefulWidget {
2024-01-28 00:32:09 +01:00
const HomeView({super.key});
2023-06-26 23:40:05 +02:00
@override
State<HomeView> createState() => _HomeViewState();
}
class _HomeViewState extends State<HomeView> {
2023-07-09 23:00:00 +02:00
ShlinkStats? shlinkStats;
2023-07-10 17:32:46 +02:00
List<ShortURL> shortUrls = [];
bool shortUrlsLoaded = false;
bool _qrCodeShown = false;
String _qrUrl = "";
2023-06-26 23:40:05 +02:00
@override
void initState() {
super.initState();
2024-01-28 00:32:09 +01:00
WidgetsBinding.instance.addPostFrameCallback((_) {
loadAllData();
2023-07-10 17:32:46 +02:00
});
}
Future<void> loadAllData() async {
2024-01-27 23:07:06 +01:00
await loadShlinkStats();
await loadRecentShortUrls();
2023-07-10 17:32:46 +02:00
return;
2023-07-09 23:00:00 +02:00
}
2023-07-10 17:32:46 +02:00
Future<void> loadShlinkStats() async {
2023-07-09 23:00:00 +02:00
final response = await globals.serverManager.getShlinkStats();
response.fold((l) {
setState(() {
shlinkStats = l;
});
}, (r) {
var text = "";
if (r is RequestFailure) {
text = r.description;
2024-01-28 00:32:09 +01:00
} else {
2023-07-09 23:00:00 +02:00
text = (r as ApiFailure).detail;
}
2024-01-28 00:32:09 +01:00
final snackBar = SnackBar(
content: Text(text),
backgroundColor: Colors.red[400],
behavior: SnackBarBehavior.floating);
2023-07-09 23:00:00 +02:00
ScaffoldMessenger.of(context).showSnackBar(snackBar);
});
2023-06-26 23:40:05 +02:00
}
2023-07-10 17:32:46 +02:00
Future<void> loadRecentShortUrls() async {
final response = await globals.serverManager.getRecentShortUrls();
response.fold((l) {
setState(() {
shortUrls = l;
shortUrlsLoaded = true;
});
}, (r) {
var text = "";
if (r is RequestFailure) {
text = r.description;
2024-01-28 00:32:09 +01:00
} else {
2023-07-10 17:32:46 +02:00
text = (r as ApiFailure).detail;
}
2024-01-28 00:32:09 +01:00
final snackBar = SnackBar(
content: Text(text),
backgroundColor: Colors.red[400],
behavior: SnackBarBehavior.floating);
2023-07-10 17:32:46 +02:00
ScaffoldMessenger.of(context).showSnackBar(snackBar);
});
}
2023-06-26 23:40:05 +02:00
@override
Widget build(BuildContext context) {
return Scaffold(
2024-01-28 00:32:09 +01:00
body: Stack(
children: [
ColorFiltered(
colorFilter: ColorFilter.mode(
Colors.black.withOpacity(_qrCodeShown ? 0.4 : 0),
BlendMode.srcOver),
child: RefreshIndicator(
onRefresh: () async {
return loadAllData();
},
child: CustomScrollView(
slivers: [
SliverAppBar.medium(
expandedHeight: 160,
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("Shlink",
style: TextStyle(fontWeight: FontWeight.bold)),
Text(globals.serverManager.getServerUrl(),
style: TextStyle(
fontSize: 16, color: Colors.grey[600]))
],
)),
SliverToBoxAdapter(
child: Wrap(
alignment: WrapAlignment.spaceEvenly,
2023-07-10 17:32:46 +02:00
children: [
2024-03-31 17:55:01 +02:00
ShlinkStatsCardWidget(
2024-01-28 00:32:09 +01:00
icon: Icons.link,
text:
"${shlinkStats?.shortUrlsCount.toString() ?? "0"} Short URLs",
borderColor: Colors.blue),
2024-03-31 17:55:01 +02:00
ShlinkStatsCardWidget(
2024-01-28 00:32:09 +01:00
icon: Icons.remove_red_eye,
text:
"${shlinkStats?.nonOrphanVisits.total ?? "0"} Visits",
borderColor: Colors.green),
2024-03-31 17:55:01 +02:00
ShlinkStatsCardWidget(
2024-01-28 00:32:09 +01:00
icon: Icons.warning,
text:
"${shlinkStats?.orphanVisits.total ?? "0"} Orphan Visits",
borderColor: Colors.red),
2024-03-31 17:55:01 +02:00
ShlinkStatsCardWidget(
2024-01-28 00:32:09 +01:00
icon: Icons.sell,
text:
"${shlinkStats?.tagsCount.toString() ?? "0"} Tags",
borderColor: Colors.purple),
2023-07-10 17:32:46 +02:00
],
2024-01-28 00:32:09 +01:00
),
2023-07-10 17:32:46 +02:00
),
2024-01-28 00:32:09 +01:00
if (shortUrlsLoaded && shortUrls.isEmpty)
SliverToBoxAdapter(
child: Center(
child: Padding(
padding: const EdgeInsets.only(top: 50),
child: Column(
children: [
const Text(
"No Short URLs",
style: TextStyle(
fontSize: 24,
fontWeight: FontWeight.bold),
),
Padding(
padding: const EdgeInsets.only(top: 8),
child: Text(
'Create one by tapping the "+" button below',
style: TextStyle(
fontSize: 16,
color: Colors.grey[600]),
),
)
],
))))
else
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
if (index == 0) {
return const Padding(
padding:
EdgeInsets.only(top: 16, left: 12, right: 12),
child: Text("Recent Short URLs",
style: TextStyle(
fontSize: 20, fontWeight: FontWeight.bold)),
);
} else {
final shortURL = shortUrls[index - 1];
return ShortURLCell(
shortURL: shortURL,
reload: () {
loadRecentShortUrls();
},
showQRCode: (String url) {
setState(() {
_qrUrl = url;
_qrCodeShown = true;
});
},
isLast: index == shortUrls.length);
}
}, childCount: shortUrls.length + 1))
],
),
2023-07-10 17:32:46 +02:00
),
2023-07-09 23:00:00 +02:00
),
2024-01-28 00:32:09 +01:00
if (_qrCodeShown)
GestureDetector(
onTap: () {
setState(() {
_qrCodeShown = false;
});
},
child: Container(
color: Colors.black.withOpacity(0),
2023-07-10 17:32:46 +02:00
),
),
2024-01-28 00:32:09 +01:00
if (_qrCodeShown)
Center(
child: SizedBox(
width: MediaQuery.of(context).size.width / 1.7,
height: MediaQuery.of(context).size.width / 1.7,
child: Card(
child: Padding(
padding: const EdgeInsets.all(16),
child: QrImageView(
data: _qrUrl,
size: 200.0,
eyeStyle: QrEyeStyle(
eyeShape: QrEyeShape.square,
color:
MediaQuery.of(context).platformBrightness ==
Brightness.dark
? Colors.white
: Colors.black,
),
dataModuleStyle: QrDataModuleStyle(
dataModuleShape: QrDataModuleShape.square,
color:
MediaQuery.of(context).platformBrightness ==
Brightness.dark
? Colors.white
: Colors.black,
),
))),
),
)
],
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await Navigator.of(context).push(MaterialPageRoute(
builder: (context) => const ShortURLEditView()));
loadRecentShortUrls();
},
child: const Icon(Icons.add),
));
2023-07-09 23:00:00 +02:00
}
2024-03-31 17:55:01 +02:00
}