234 lines
8.1 KiB
Dart
Executable File
234 lines
8.1 KiB
Dart
Executable File
import 'dart:io';
|
|
|
|
import 'package:device_info_plus/device_info_plus.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter_sdk/starcloud_flutter_sdk.dart';
|
|
import '../global.dart';
|
|
import '../l10n.dart';
|
|
import '../widgets/common_widgets.dart';
|
|
|
|
class AuthTab extends StatefulWidget {
|
|
const AuthTab({super.key});
|
|
|
|
@override
|
|
State<AuthTab> createState() => _AuthTabState();
|
|
}
|
|
|
|
class _AuthTabState extends State<AuthTab> {
|
|
final _clientIdCtrl = TextEditingController();
|
|
final _clientSecretCtrl = TextEditingController();
|
|
static const _environmentUrl = 'https://cloud.skychip.top/sdk';
|
|
final _usernameCtrl = TextEditingController();
|
|
final _passwordCtrl = TextEditingController();
|
|
final List<String> _log = [];
|
|
bool _sdkReady = false;
|
|
bool _cloudUserReady = false;
|
|
bool _loggingIn = false;
|
|
|
|
void _log_(String msg) {
|
|
final ts = DateTime.now().toIso8601String().substring(11, 19);
|
|
setState(() => _log.add('[$ts] $msg'));
|
|
}
|
|
|
|
void _initSdk() {
|
|
final id = _clientIdCtrl.text.trim();
|
|
if (id.isEmpty) {
|
|
_log_(S.isEn ? 'Please fill Client ID' : '请先填写 Client ID');
|
|
return;
|
|
}
|
|
try {
|
|
StarCloudClient.instance.auth.init(
|
|
clientId: id,
|
|
clientSecret: _clientSecretCtrl.text.trim(),
|
|
environmentUrl: _environmentUrl,
|
|
);
|
|
setState(() => _sdkReady = true);
|
|
_log_(S.isEn ? 'SDK Init Success' : 'SDK 初始化成功');
|
|
} catch (e) {
|
|
_log_('${S.isEn ? "Failed" : "失败"}: $e');
|
|
}
|
|
}
|
|
|
|
Future<void> _createDemoCloudAccount() async {
|
|
setState(() => _loggingIn = true);
|
|
_log_(S.isEn ? 'Creating SDK cloud account...' : '正在创建 SDK 星云测试账户...');
|
|
try {
|
|
final cloudUser = await StarCloudClient.instance.auth.createCloudUser();
|
|
StarCloudClient.instance.auth.setCloudAccounts([cloudUser]);
|
|
sdkCloudAccountReady.value = true;
|
|
pairedLockId.value = null;
|
|
pairedLock.value = null;
|
|
setState(() => _cloudUserReady = true);
|
|
_log_(S.isEn
|
|
? 'SDK cloud account is ready. You can scan and pair.'
|
|
: 'SDK 星云账户已就绪。现在可扫描并绑定锁。');
|
|
} catch (e) {
|
|
_log_('${S.isEn ? "Failed" : "失败"}: $e');
|
|
} finally {
|
|
if (mounted) setState(() => _loggingIn = false);
|
|
}
|
|
}
|
|
|
|
Future<void> _loginLockService() async {
|
|
final username = _usernameCtrl.text.trim();
|
|
final password = _passwordCtrl.text;
|
|
if (username.isEmpty || password.isEmpty) {
|
|
_log_(S.isEn ? 'Please fill username and password' : '请填写用户名和密码');
|
|
return;
|
|
}
|
|
setState(() => _loggingIn = true);
|
|
_log_(S.isEn ? 'Signing in...' : '正在登录...');
|
|
try {
|
|
String deviceBrand = Platform.isAndroid ? 'android' : 'ios';
|
|
String deviceModel = 'unknown';
|
|
String deviceVersion = 'unknown';
|
|
try {
|
|
final deviceInfo = DeviceInfoPlugin();
|
|
if (Platform.isAndroid) {
|
|
final android = await deviceInfo.androidInfo;
|
|
deviceBrand = android.brand;
|
|
deviceModel = android.model;
|
|
deviceVersion = android.version.release;
|
|
} else if (Platform.isIOS) {
|
|
final ios = await deviceInfo.iosInfo;
|
|
deviceBrand = 'Apple';
|
|
deviceModel = ios.utsname.machine;
|
|
deviceVersion = ios.systemVersion;
|
|
}
|
|
} catch (_) {
|
|
// 设备信息只用于服务端风控,无法读取时使用默认值继续登录。
|
|
}
|
|
|
|
// lock.skychip.top token 只用于 WiFi 网关配置,不能替代 SDK 云账户。
|
|
final lockServiceToken =
|
|
await StarCloudClient.instance.auth.loginLockService(
|
|
username: username,
|
|
password: password,
|
|
deviceBrand: deviceBrand,
|
|
deviceModel: deviceModel,
|
|
deviceVersion: deviceVersion,
|
|
);
|
|
|
|
lockServiceAccessToken.value = lockServiceToken;
|
|
signedInAccount.value = username;
|
|
_log_(S.isEn ? 'WiFi authorization is ready.' : 'WiFi 网关授权登录成功。');
|
|
} catch (e) {
|
|
_log_('${S.isEn ? "Failed" : "失败"}: $e');
|
|
} finally {
|
|
if (mounted) setState(() => _loggingIn = false);
|
|
}
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
_clientIdCtrl.dispose();
|
|
_clientSecretCtrl.dispose();
|
|
_usernameCtrl.dispose();
|
|
_passwordCtrl.dispose();
|
|
super.dispose();
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return ValueListenableBuilder<bool>(
|
|
valueListenable: S.langNotifier,
|
|
builder: (context, isEn, _) {
|
|
return SingleChildScrollView(
|
|
padding: const EdgeInsets.all(16),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
children: [
|
|
Card(
|
|
child: Padding(
|
|
padding:
|
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
|
child: Wrap(
|
|
spacing: 8,
|
|
children: [
|
|
StatusChip(label: S.sdkStatus, ready: _sdkReady),
|
|
StatusChip(
|
|
label: S.cloudUserStatus, ready: _cloudUserReady),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextField(
|
|
controller: _clientIdCtrl,
|
|
decoration: InputDecoration(
|
|
labelText: S.clientId,
|
|
border: const OutlineInputBorder(),
|
|
prefixIcon: const Icon(Icons.badge_outlined)),
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextField(
|
|
controller: _clientSecretCtrl,
|
|
obscureText: true,
|
|
decoration: InputDecoration(
|
|
labelText: S.clientSecret,
|
|
border: const OutlineInputBorder(),
|
|
prefixIcon: const Icon(Icons.key_outlined)),
|
|
),
|
|
const SizedBox(height: 12),
|
|
const SizedBox(height: 16),
|
|
ElevatedButton.icon(
|
|
onPressed: _initSdk,
|
|
icon: const Icon(Icons.settings),
|
|
label: Text(S.step1Init)),
|
|
const SizedBox(height: 16),
|
|
ElevatedButton.icon(
|
|
onPressed:
|
|
_sdkReady && !_loggingIn ? _createDemoCloudAccount : null,
|
|
icon: const Icon(Icons.person_add_outlined),
|
|
label: Text(
|
|
_loggingIn ? S.btnProcessing : S.btnCreateTestCloudAccount,
|
|
),
|
|
),
|
|
const SizedBox(height: 16),
|
|
TextField(
|
|
controller: _usernameCtrl,
|
|
keyboardType: TextInputType.emailAddress,
|
|
decoration: InputDecoration(
|
|
labelText: S.accountLabel,
|
|
border: const OutlineInputBorder(),
|
|
prefixIcon: const Icon(Icons.person_outline),
|
|
),
|
|
),
|
|
const SizedBox(height: 12),
|
|
TextField(
|
|
controller: _passwordCtrl,
|
|
obscureText: true,
|
|
onSubmitted: (_) =>
|
|
_sdkReady && !_loggingIn ? _loginLockService() : null,
|
|
decoration: InputDecoration(
|
|
labelText: S.passwordLabel,
|
|
border: const OutlineInputBorder(),
|
|
prefixIcon: const Icon(Icons.password),
|
|
),
|
|
),
|
|
const SizedBox(height: 8),
|
|
ElevatedButton.icon(
|
|
onPressed:
|
|
_sdkReady && !_loggingIn ? _loginLockService : null,
|
|
icon: _loggingIn
|
|
? const SizedBox(
|
|
width: 18,
|
|
height: 18,
|
|
child: CircularProgressIndicator(strokeWidth: 2),
|
|
)
|
|
: const Icon(Icons.login),
|
|
label: Text(
|
|
_loggingIn
|
|
? S.btnProcessing
|
|
: S.btnLoginForWifiAuthorization,
|
|
)),
|
|
const SizedBox(height: 16),
|
|
LogArea(log: _log),
|
|
],
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|