Skip to content

Commit 757d754

Browse files
author
code3-dev
committed
add base
1 parent 9b876b9 commit 757d754

19 files changed

+529
-277
lines changed

README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ Proxy Cloud is an open-source Flutter application that provides a user-friendly
1313
### V2Ray VPN
1414
- Connect to V2Ray servers with a single tap
1515
- Import configurations via subscription URLs
16-
- Manage multiple server configurations
1716
- Monitor connection status
18-
- Auto-reconnect functionality
1917

2018
### Telegram Proxies
2119
- Browse and connect to MTProto proxies

lib/main.dart

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
import 'package:flutter/material.dart';
22
import 'package:provider/provider.dart';
3+
import 'package:shared_preferences/shared_preferences.dart';
34
import 'providers/v2ray_provider.dart';
45
import 'providers/telegram_proxy_provider.dart';
56
import 'screens/main_navigation_screen.dart';
7+
import 'screens/privacy_welcome_screen.dart';
68
import 'theme/app_theme.dart';
79

8-
void main() {
10+
void main() async {
911
WidgetsFlutterBinding.ensureInitialized();
10-
runApp(const MyApp());
12+
13+
// Check if user has accepted privacy policy
14+
final prefs = await SharedPreferences.getInstance();
15+
final bool privacyAccepted = prefs.getBool('privacy_accepted') ?? false;
16+
17+
runApp(MyApp(privacyAccepted: privacyAccepted));
1118
}
1219

1320
class MyApp extends StatelessWidget {
14-
const MyApp({super.key});
21+
final bool privacyAccepted;
22+
23+
const MyApp({super.key, required this.privacyAccepted});
1524

1625
@override
1726
Widget build(BuildContext context) {
@@ -24,7 +33,9 @@ class MyApp extends StatelessWidget {
2433
title: 'Proxy Cloud',
2534
debugShowCheckedModeBanner: false,
2635
theme: AppTheme.darkTheme(),
27-
home: const MainNavigationScreen(),
36+
home: privacyAccepted
37+
? const MainNavigationScreen()
38+
: const PrivacyWelcomeScreen(),
2839
),
2940
);
3041
}

lib/models/telegram_proxy.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,10 @@ class TelegramProxy {
6969
String get telegramUrl {
7070
return 'tg://proxy?server=$host&port=$port&secret=$secret';
7171
}
72+
73+
String get telegramHttpsUrl {
74+
return 'https://t.me/proxy?server=$host&port=$port&secret=$secret';
75+
}
7276

7377
@override
7478
String toString() {

lib/providers/v2ray_provider.dart

Lines changed: 46 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -164,15 +164,25 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
164164
notifyListeners();
165165

166166
try {
167+
// Fetch servers from service
167168
final servers = await _serverService.fetchServers(customUrl: customUrl);
169+
168170
if (servers.isNotEmpty) {
171+
// Load and display servers immediately
169172
_configs = servers;
173+
174+
// Save configs and update UI immediately to show servers
170175
await _v2rayService.saveConfigs(_configs);
176+
177+
// Mark loading as complete
178+
_isLoadingServers = false;
179+
notifyListeners();
180+
181+
// Server delay functionality removed as requested
171182
} else {
172183
// If no servers found online, try to load from local storage
173184
_configs = await _v2rayService.loadConfigs();
174185
}
175-
notifyListeners();
176186
} catch (e) {
177187
_setError('Failed to fetch servers: $e');
178188
// Try to load from local storage as fallback
@@ -197,7 +207,10 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
197207
}
198208

199209
Future<void> addConfig(V2RayConfig config) async {
210+
// Add config and display it immediately
200211
_configs.add(config);
212+
213+
// Save the configuration immediately to display it
201214
await _v2rayService.saveConfigs(_configs);
202215
notifyListeners();
203216
}
@@ -230,8 +243,19 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
230243
return;
231244
}
232245

233-
// Add configs
246+
// Add configs and display them immediately
234247
_configs.addAll(configs);
248+
249+
// Save configs and update UI immediately to show servers
250+
await _v2rayService.saveConfigs(_configs);
251+
_setLoading(false);
252+
notifyListeners();
253+
254+
final newConfigIds = configs.map((c) => c.id).toList();
255+
256+
// Server delay functionality removed as requested
257+
258+
// Save configs
235259
await _v2rayService.saveConfigs(_configs);
236260

237261
// Create subscription
@@ -240,13 +264,11 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
240264
name: name,
241265
url: url,
242266
lastUpdated: DateTime.now(),
243-
configIds: configs.map((c) => c.id).toList(),
267+
configIds: newConfigIds,
244268
);
245269

246270
_subscriptions.add(subscription);
247271
await _v2rayService.saveSubscriptions(_subscriptions);
248-
249-
notifyListeners();
250272
} catch (e) {
251273
_setError('Failed to add subscription: $e');
252274
} finally {
@@ -256,32 +278,44 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
256278

257279
Future<void> updateSubscription(Subscription subscription) async {
258280
_setLoading(true);
281+
_isLoadingServers = true;
259282
_errorMessage = '';
283+
notifyListeners();
284+
260285
try {
261286
final configs = await _v2rayService.parseSubscriptionUrl(subscription.url);
262287
if (configs.isEmpty) {
263288
_setError('No valid configurations found in subscription');
289+
_isLoadingServers = false;
290+
notifyListeners();
264291
return;
265292
}
266293

267294
// Remove old configs
268295
_configs.removeWhere((c) => subscription.configIds.contains(c.id));
269296

270-
// Add new configs
297+
// Add new configs and display them immediately
271298
_configs.addAll(configs);
299+
300+
// Save configs and update UI immediately to show servers
272301
await _v2rayService.saveConfigs(_configs);
273302

303+
// Mark loading as complete
304+
_isLoadingServers = false;
305+
_setLoading(false);
306+
notifyListeners();
307+
308+
final newConfigIds = configs.map((c) => c.id).toList();
309+
274310
// Update subscription
275311
final index = _subscriptions.indexWhere((s) => s.id == subscription.id);
276312
if (index != -1) {
277313
_subscriptions[index] = subscription.copyWith(
278314
lastUpdated: DateTime.now(),
279-
configIds: configs.map((c) => c.id).toList(),
315+
configIds: newConfigIds,
280316
);
281317
await _v2rayService.saveSubscriptions(_subscriptions);
282318
}
283-
284-
notifyListeners();
285319
} catch (e) {
286320
_setError('Failed to update subscription: $e');
287321
} finally {
@@ -368,130 +402,9 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
368402
}
369403
}
370404

371-
Future<int> testServerDelay(V2RayConfig config) async {
372-
try {
373-
final delay = await _v2rayService.getServerDelay(config);
374-
if (delay >= 0) {
375-
// Clear any previous error messages if successful
376-
clearError();
377-
} else {
378-
// Set a user-friendly error message for failed pings
379-
_setError('Could not ping server ${config.remark}. Server may be offline or unreachable.');
380-
}
381-
return delay;
382-
} catch (e) {
383-
String errorMessage = 'Error testing server delay';
384-
385-
// Provide more specific error messages based on error type
386-
if (e.toString().contains('closed pipe')) {
387-
errorMessage = 'Connection to ${config.remark} was interrupted. Please try again.';
388-
} else if (e.toString().contains('timeout')) {
389-
errorMessage = 'Connection to ${config.remark} timed out. Server may be slow or unreachable.';
390-
} else if (e.toString().contains('network is unreachable')) {
391-
errorMessage = 'Network is unreachable. Please check your internet connection.';
392-
} else {
393-
// Include the actual error for debugging
394-
errorMessage = '$errorMessage: $e';
395-
}
396-
397-
_setError(errorMessage);
398-
return -1;
399-
}
400-
}
405+
// Removed testServerDelay method as requested
401406

402-
// Method to ping a server and display the result
403-
Future<void> pingServer(V2RayConfig? config) async {
404-
if (config == null) return;
405-
406-
_errorMessage = 'Pinging server...';
407-
notifyListeners();
408-
409-
try {
410-
int delay;
411-
if (_v2rayService.activeConfig != null && _v2rayService.activeConfig!.id == config.id) {
412-
// If this is the connected server, use getConnectedServerDelay
413-
delay = await _v2rayService.getConnectedServerDelay();
414-
} else {
415-
// Otherwise use regular getServerDelay
416-
delay = await _v2rayService.getServerDelay(config);
417-
}
418-
419-
if (delay >= 0) {
420-
_errorMessage = 'Ping: ${config.remark} - ${delay}ms';
421-
} else {
422-
_errorMessage = 'Failed to ping ${config.remark}';
423-
}
424-
notifyListeners();
425-
426-
// Clear the message after 2 seconds
427-
Future.delayed(const Duration(seconds: 2), () {
428-
_errorMessage = '';
429-
notifyListeners();
430-
});
431-
} catch (e) {
432-
_errorMessage = 'Error pinging server: $e';
433-
notifyListeners();
434-
435-
// Clear the error message after 2 seconds
436-
Future.delayed(const Duration(seconds: 2), () {
437-
_errorMessage = '';
438-
notifyListeners();
439-
});
440-
}
441-
}
442-
443-
// Method to ping all servers and display results
444-
Future<void> pingAllServers() async {
445-
if (_configs.isEmpty) {
446-
_errorMessage = 'No servers to ping';
447-
notifyListeners();
448-
return;
449-
}
450-
451-
_setLoading(true);
452-
_errorMessage = 'Pinging all servers...';
453-
notifyListeners();
454-
455-
try {
456-
// Create a map to store server delays
457-
final Map<String, int> delays = {};
458-
459-
// Ping each server
460-
for (var config in _configs) {
461-
int delay;
462-
if (_v2rayService.activeConfig != null && _v2rayService.activeConfig!.id == config.id) {
463-
// If this is the active config, use the connected server delay method
464-
delay = await _v2rayService.getConnectedServerDelay();
465-
} else {
466-
// Otherwise use the regular server delay method
467-
delay = await _v2rayService.getServerDelay(config);
468-
}
469-
470-
delays[config.remark] = delay;
471-
}
472-
473-
// Build a message with all delays
474-
final StringBuffer message = StringBuffer('Server Ping Results:\n');
475-
delays.forEach((server, delay) {
476-
message.write('$server: ${delay >= 0 ? "${delay}ms" : "Failed"}\n');
477-
});
478-
479-
_errorMessage = message.toString();
480-
notifyListeners();
481-
482-
// Clear the error message after 5 seconds
483-
Future.delayed(const Duration(seconds: 5), () {
484-
if (_errorMessage.contains('Server Ping Results')) {
485-
_errorMessage = '';
486-
notifyListeners();
487-
}
488-
});
489-
} catch (e) {
490-
_setError('Error pinging servers: $e');
491-
} finally {
492-
_setLoading(false);
493-
}
494-
}
407+
// Removed pingServer and pingAllServers methods as requested
495408

496409
Future<void> selectConfig(V2RayConfig config) async {
497410
_selectedConfig = config;
@@ -502,6 +415,7 @@ class V2RayProvider with ChangeNotifier, WidgetsBindingObserver {
502415

503416
void _setLoading(bool loading) {
504417
_isLoading = loading;
418+
_isLoadingServers = loading; // Update server loading state as well
505419
notifyListeners();
506420
}
507421

lib/screens/about_screen.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class AboutScreen extends StatelessWidget {
5151

5252
// App Version
5353
const Text(
54-
'Version 1.1.0',
54+
'Version 1.2.0',
5555
style: TextStyle(fontSize: 16, color: Colors.grey),
5656
),
5757

lib/screens/home_screen.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ class _HomeScreenState extends State<HomeScreen> {
124124
title: const Text('Proxy Cloud'),
125125
backgroundColor: Colors.transparent,
126126
elevation: 0,
127+
centerTitle: false,
127128
actions: [
128129
IconButton(
129130
icon: const Icon(Icons.refresh),

0 commit comments

Comments
 (0)