1- import 'dart:async' ;
21import 'dart:developer' ;
32import 'package:flutter/material.dart' ;
3+ import 'package:provider/provider.dart' ;
44import 'package:vpn_client/design/colors.dart' ;
55import 'package:vpn_client/design/dimensions.dart' ;
66import 'package:vpnclient_engine_flutter/vpnclient_engine_flutter.dart' ;
7+ import 'package:flutter_v2ray/flutter_v2ray.dart' ;
8+ import 'package:flutter_gen/gen_l10n/app_localizations.dart' ;
9+ import 'package:vpn_client/vpn_state.dart' ;
10+
11+ final FlutterV2ray flutterV2ray = FlutterV2ray (
12+ onStatusChanged: (status) {
13+ // Handle status changes if needed
14+ },
15+ );
716
817class MainBtn extends StatefulWidget {
918 const MainBtn ({super .key});
@@ -13,142 +22,100 @@ class MainBtn extends StatefulWidget {
1322}
1423
1524class MainBtnState extends State <MainBtn > with SingleTickerProviderStateMixin {
16- ///static const platform = MethodChannel('vpnclient_engine2');
17- ///
18- late CustomString statusText;
19- late String connectionStatus;
20- late String connectionStatusDisconnected;
21- late String connectionStatusDisconnecting;
22- late String connectionStatusConnected;
23- late String connectionStatusConnecting;
24-
25- @override
26- void didChangeDependencies () {
27- super .didChangeDependencies ();
28- final statusText = CustomString (context);
29- connectionStatus = statusText.disconnected;
30- connectionStatusDisconnected = statusText.disconnected;
31- connectionStatusConnected = statusText.connected;
32- connectionStatusDisconnecting = statusText.disconnecting;
33- connectionStatusConnecting = statusText.connecting;
34- }
35-
36- String connectionTime = "00:00:00" ;
37- Timer ? _timer;
3825 late AnimationController _animationController;
3926 late Animation <double > _sizeAnimation;
4027
4128 @override
4229 void initState () {
4330 super .initState ();
44-
4531 _animationController = AnimationController (
4632 vsync: this ,
4733 duration: const Duration (seconds: 1 ),
4834 );
4935 _sizeAnimation = Tween <double >(begin: 0 , end: 150 ).animate (
5036 CurvedAnimation (parent: _animationController, curve: Curves .ease),
5137 );
38+
39+ // Синхронизировать анимацию с текущим статусом подключения
40+ WidgetsBinding .instance.addPostFrameCallback ((_) {
41+ final vpnState = Provider .of <VpnState >(context, listen: false );
42+ final localizations = AppLocalizations .of (context)! ;
43+ if (vpnState.connectionStatus == localizations.connected) {
44+ _animationController.forward ();
45+ }
46+ });
5247 }
5348
5449 @override
5550 void dispose () {
56- _timer? .cancel ();
5751 _animationController.dispose ();
5852 super .dispose ();
5953 }
6054
61- void startTimer () {
62- int seconds = 1 ;
63- _timer = Timer .periodic (const Duration (seconds: 1 ), (timer) {
64- setState (() {
65- int hours = seconds ~ / 3600 ;
66- int minutes = (seconds % 3600 ) ~ / 60 ;
67- int remainingSeconds = seconds % 60 ;
68- connectionTime =
69- '${hours .toString ().padLeft (2 , '0' )}:${minutes .toString ().padLeft (2 , '0' )}:${remainingSeconds .toString ().padLeft (2 , '0' )}' ;
70- });
71- seconds++ ;
72- });
73- }
55+ Future <void > _handleConnection (BuildContext context) async {
56+ final vpnState = Provider .of <VpnState >(context, listen: false );
57+ final localizations = AppLocalizations .of (context)! ;
7458
75- void stopTimer () {
76- _timer? .cancel ();
77- setState (() {
78- connectionTime = "00:00:00" ;
79- connectionStatus = connectionStatusDisconnected;
80- });
81- }
82-
83- Future <void > _handleConnection () async {
84- if (connectionStatus != connectionStatusConnected &&
85- connectionStatus != connectionStatusDisconnected) {
59+ if (vpnState.connectionStatus != localizations.connected &&
60+ vpnState.connectionStatus != localizations.disconnected) {
8661 return ;
8762 }
8863
89- setState (() {
90- if (connectionStatus == connectionStatusConnected) {
91- connectionStatus = connectionStatusDisconnecting;
92- } else if (connectionStatus == connectionStatusDisconnected) {
93- connectionStatus = connectionStatusConnecting;
94- }
95- });
96-
97- if (connectionStatus == connectionStatusConnecting) {
64+ if (vpnState.connectionStatus == localizations.connected) {
65+ vpnState.setConnectionStatus (localizations.disconnecting);
66+ _animationController.repeat (reverse: true );
67+ await flutterV2ray.stopV2Ray ();
68+ await VPNclientEngine .disconnect ();
69+ vpnState.stopTimer ();
70+ vpnState.setConnectionStatus (localizations.disconnected);
71+ await _animationController.reverse ();
72+ _animationController.stop ();
73+ } else if (vpnState.connectionStatus == localizations.disconnected) {
74+ vpnState.setConnectionStatus (localizations.connecting);
9875 _animationController.repeat (reverse: true );
9976
100- VPNclientEngine .ClearSubscriptions ();
101- VPNclientEngine .addSubscription (
102- subscriptionURL: "https://pastebin.com/raw/ZCYiJ98W" ,
103- );
104- await VPNclientEngine .updateSubscription (subscriptionIndex: 0 );
105- VPNclientEngine .pingServer (subscriptionIndex: 0 , index: 1 );
106- VPNclientEngine .onPingResult.listen ((result) {
107- log (
108- "Ping result: ${result .latencyInMs } ms" ,
109- name: 'PingLogger' ,
110- ); // <- Use dev.log instead of print.(It build to log meta data)
111- });
112-
113- ///final result = await platform.invokeMethod('startVPN');
77+ String link = "https://pastebin.com/raw/K8SYCauu" ;
78+ V2RayURL parser = FlutterV2ray .parseFromURL (link);
79+
80+ if (await flutterV2ray.requestPermission ()) {
81+ await flutterV2ray.startV2Ray (
82+ remark: parser.remark,
83+ config: parser.getFullConfiguration (),
84+ blockedApps: null ,
85+ bypassSubnets: null ,
86+ proxyOnly: false ,
87+ );
88+ }
11489
11590 await VPNclientEngine .connect (subscriptionIndex: 0 , serverIndex: 1 );
116- startTimer ();
117- setState (() {
118- connectionStatus = connectionStatusConnected;
119- });
91+ vpnState.startTimer ();
92+ vpnState.setConnectionStatus (localizations.connected);
12093 await _animationController.forward ();
12194 _animationController.stop ();
122- } else if (connectionStatus == connectionStatusDisconnecting) {
123- _animationController.repeat (reverse: true );
124- stopTimer ();
125- await VPNclientEngine .disconnect ();
126- setState (() {
127- connectionStatus = connectionStatusDisconnected;
128- });
129- await _animationController.reverse ();
130- _animationController.stop ();
13195 }
13296 }
13397
13498 @override
13599 Widget build (BuildContext context) {
100+ final vpnState = Provider .of <VpnState >(context);
101+ final localizations = AppLocalizations .of (context)! ;
102+
136103 return Column (
137104 children: [
138105 Text (
139- connectionTime,
106+ vpnState. connectionTime,
140107 style: TextStyle (
141108 fontSize: 40 ,
142109 fontWeight: FontWeight .w600,
143110 color:
144- connectionStatus == connectionStatusConnected
111+ vpnState. connectionStatus == localizations.connected
145112 ? Theme .of (context).colorScheme.primary
146113 : Theme .of (context).colorScheme.secondary,
147114 ),
148115 ),
149116 const SizedBox (height: 70 ),
150117 GestureDetector (
151- onTap: _handleConnection,
118+ onTap: () => _handleConnection (context) ,
152119 child: Stack (
153120 alignment: Alignment .center,
154121 children: [
@@ -188,7 +155,7 @@ class MainBtnState extends State<MainBtn> with SingleTickerProviderStateMixin {
188155 ),
189156 const SizedBox (height: 20 ),
190157 Text (
191- connectionStatus,
158+ vpnState. connectionStatus,
192159 style: TextStyle (
193160 fontSize: 16 ,
194161 fontWeight: FontWeight .w500,
@@ -199,7 +166,3 @@ class MainBtnState extends State<MainBtn> with SingleTickerProviderStateMixin {
199166 );
200167 }
201168}
202-
203- void main () {
204- runApp (MaterialApp (home: Scaffold (body: Center (child: MainBtn ()))));
205- }
0 commit comments