v1.0.7: updater, website button, timer sync indicator, server flow fix

- App: manual update checker (GitHub API, Play Store redirect)
- App: website button in sidebar
- App: timer_box shows Connecting/Syncing spinner during handshake
- App: synced app_config.example.dart with app_config.dart
- Sidebar: 6 rows (added Website, Check for updates)
- Server: add_vless_client now includes flow xtls-rprx-vision
- Deps: added package_info_plus
- Version bump: 1.0.6+10 → 1.0.7+11
- CHANGELOG.md created
This commit is contained in:
esefxdz committed 2026-07-29 20:37:33 +03:00
1 parent d6c56e8345
commit f01a610182
8 files changed
+480 -25

No files matched your search

@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:revoltvpn/logic/app_colors.dart';
class WebsiteButton extends StatelessWidget {
const WebsiteButton({super.key});
static Future<void> launchWebsite() async {
final Uri url = Uri.parse('https://getrevolt.app');
if (!await launchUrl(url, mode: LaunchMode.externalApplication)) {
debugPrint('Could not launch $url');
}
}
@override
Widget build(BuildContext context) {
return IconButton(
icon: const Icon(Icons.language, color: AppColors.textWhite, size: 28),
onPressed: launchWebsite,
tooltip: 'Website',
splashRadius: 24,
);
}
}
+21 -1
View File
@@ -4,6 +4,8 @@ import 'package:revoltvpn/components/sidebar_contents/gdpr_button.dart';
import 'package:revoltvpn/components/sidebar_contents/privacy_policy_button.dart';
import 'package:revoltvpn/components/sidebar_contents/info_button.dart';
import 'package:revoltvpn/components/sidebar_contents/discord_link_button.dart';
import 'package:revoltvpn/components/sidebar_contents/website_button.dart';
import 'package:revoltvpn/logic/updater.dart';
class SidebarDrawer extends StatelessWidget {
const SidebarDrawer({super.key});
@@ -84,11 +86,29 @@ class SidebarDrawer extends StatelessWidget {
},
),
_Row(
icon: Icons.language,
label: 'Website',
onTap: () {
Navigator.of(context).pop();
WebsiteButton.launchWebsite();
},
),
_Row(
icon: Icons.system_update_alt,
label: 'Check for updates',
onTap: () {
Navigator.of(context).pop();
Updater.check(context);
},
),
const Spacer(),
const Padding(
padding: EdgeInsets.all(20),
child: Text('ReVoltVPN · v1.0.6', textAlign: TextAlign.center,
child: Text('ReVoltVPN · v1.0.7', textAlign: TextAlign.center,
style: TextStyle(color: AppColors.slate, fontSize: 11, letterSpacing: 1),
),
),
+58 -14
View File
@@ -2,14 +2,19 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:revoltvpn/logic/app_colors.dart';
import 'package:revoltvpn/logic/session_timer.dart';
import 'package:revoltvpn/logic/vpn_connection.dart';
class TimerBox extends StatelessWidget {
const TimerBox({super.key});
@override
Widget build(BuildContext context) {
return Consumer<SessionTimer>(
builder: (context, timer, _) {
return Consumer2<SessionTimer, VpnConnection>(
builder: (context, timer, vpn, _) {
final isConnecting = vpn.status == VpnStatus.connecting;
final isSyncing = vpn.status == VpnStatus.connected && !timer.hasSyncedOnce;
final showIndicator = isConnecting || isSyncing;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 14),
decoration: BoxDecoration(
@@ -17,20 +22,59 @@ class TimerBox extends StatelessWidget {
borderRadius: BorderRadius.circular(16),
border: Border.all(color: AppColors.slate15),
),
child: Text(
timer.hasSyncedOnce ? timer.formatted : '00:00:00',
style: const TextStyle(
fontSize: 32,
fontWeight: FontWeight.w700,
color: AppColors.textWhite,
letterSpacing: 2,
shadows: [
Shadow(
color: AppColors.accent50,
blurRadius: 16,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// ── Countdown text (always visible) ──────────────────────
Text(
timer.hasSyncedOnce ? timer.formatted : '00:00:00',
style: TextStyle(
fontSize: 32,
fontWeight: FontWeight.w700,
color: timer.hasSyncedOnce
? AppColors.textWhite
: AppColors.slate70,
letterSpacing: 2,
shadows: timer.hasSyncedOnce
? const [
Shadow(
color: AppColors.accent50,
blurRadius: 16,
),
]
: [],
),
),
// ── Syncing indicator (only shown while connecting or
// waiting for the first server poll) ──────────────────
if (showIndicator) ...[
const SizedBox(height: 8),
Row(
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
width: 14,
height: 14,
child: CircularProgressIndicator(
strokeWidth: 2,
color: AppColors.accent60,
),
),
const SizedBox(width: 8),
Text(
isConnecting ? 'Connecting…' : 'Syncing…',
style: const TextStyle(
fontSize: 12,
color: AppColors.accent60,
fontWeight: FontWeight.w600,
letterSpacing: 1,
),
),
],
),
],
),
],
),
);
},