1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import 'package:flutter/material.dart';
import '../app_settings.dart';
import '../core/core_controller.dart';
import '../l10n/app_localizations.dart';
import 'zed_home_common.dart';
/// The Old design (the phone's "Classic"), ported from FoxyVPN's
/// Android app: the traditional VPN-app layout — the state as a plain
/// headline, the connect core, the session's length, and divided rows
/// for the server, the accounts and the speed.
class ZedOldHome extends StatelessWidget {
const ZedOldHome({
super.key,
required this.core,
required this.settings,
this.onOpenServers,
this.onOpenAccounts,
});
final CoreController core;
final AppSettings settings;
final VoidCallback? onOpenServers;
final VoidCallback? onOpenAccounts;
@override
Widget build(BuildContext context) {
final l = AppLocalizations.of(context);
final theme = Theme.of(context);
final scheme = theme.colorScheme;
final status = core.status!;
final d = ZedHomeData(core, status, l);
final title = d.live
? l.zedVpnOn
: d.busy
? l.stateConnecting
: l.zedVpnOff;
final proxy = status.proxy;
return ZedHomeScaffold(
children: [
const SizedBox(height: 24),
AnimatedSwitcher(
duration: const Duration(milliseconds: 250),
reverseDuration: const Duration(milliseconds: 150),
child: Text(
title,
key: ValueKey(title),
textAlign: TextAlign.center,
style: theme.textTheme.headlineMedium?.copyWith(
color: d.live ? scheme.primary : scheme.onSurfaceVariant,
),
),
),
const SizedBox(height: 18),
Center(
child: ZedConnectCore(
live: d.live,
busy: d.busy,
since: d.since,
size: 208,
onToggle: () => d.toggle(context, onOpenAccounts),
),
),
if (d.live) ...[
const SizedBox(height: 10),
Center(
child: ZedElapsedText(
since: d.since,
prefix: '${l.zedConnectedFor} ',
style: theme.textTheme.bodyMedium,
color: scheme.onSurfaceVariant,
),
),
],
const SizedBox(height: 24),
if (d.hasError) ...[
ZedErrorCard(text: d.errorText),
const SizedBox(height: 12),
],
_ClassicRow(
title: l.navServers,
subtitle: d.live
? [
d.place.name,
if (proxy != null && proxy.cityName.isNotEmpty)
proxy.cityName,
].join(' · ')
: l.zedRecommendedTapChoose,
onTap: () => onOpenServers?.call(),
),
Divider(color: scheme.outlineVariant.withValues(alpha: 0.6)),
_ClassicRow(
title: l.navAccounts,
subtitle: l.zedAccountsOfConnected(d.live ? d.ready : 0, d.total),
onTap: () => d.openAccounts(context, onOpenAccounts),
),
Divider(color: scheme.outlineVariant.withValues(alpha: 0.6)),
_ClassicRow(
title: l.zedSpeed,
subtitle: d.live ? l.zedSpeedLive : l.zedIdle,
onTap: () {},
),
const SizedBox(height: 16),
],
);
}
}
/// One divided row of the Old design: a title, a subtitle, a chevron.
class _ClassicRow extends StatelessWidget {
const _ClassicRow({
required this.title,
required this.subtitle,
required this.onTap,
});
final String title;
final String subtitle;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final scheme = theme.colorScheme;
return InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 14),
child: Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: theme.textTheme.titleMedium),
Text(
subtitle,
style: theme.textTheme.bodySmall?.copyWith(
color: scheme.onSurfaceVariant,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
],
),
),
Icon(Icons.chevron_right_rounded, color: scheme.onSurfaceVariant),
],
),
),
);
}
}