mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-29 12:38:34 +00:00
feat: login devices
Closes #1140 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
23
lib/pages/login_devices/controller.dart
Normal file
23
lib/pages/login_devices/controller.dart
Normal file
@@ -0,0 +1,23 @@
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/http/login.dart';
|
||||
import 'package:PiliPlus/models_new/login_devices/data.dart';
|
||||
import 'package:PiliPlus/models_new/login_devices/device.dart';
|
||||
import 'package:PiliPlus/pages/common/common_list_controller.dart';
|
||||
|
||||
class LoginDevicesController
|
||||
extends CommonListController<LoginDevicesData, LoginDevice> {
|
||||
@override
|
||||
void onInit() {
|
||||
super.onInit();
|
||||
queryData();
|
||||
}
|
||||
|
||||
@override
|
||||
List<LoginDevice>? getDataList(LoginDevicesData response) {
|
||||
return response.devices;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<LoadingState<LoginDevicesData>> customGetData() =>
|
||||
LoginHttp.loginDevices();
|
||||
}
|
||||
97
lib/pages/login_devices/view.dart
Normal file
97
lib/pages/login_devices/view.dart
Normal file
@@ -0,0 +1,97 @@
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||
import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart';
|
||||
import 'package:PiliPlus/http/loading_state.dart';
|
||||
import 'package:PiliPlus/models_new/login_devices/device.dart';
|
||||
import 'package:PiliPlus/pages/login_devices/controller.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class LoginDevicesPage extends StatefulWidget {
|
||||
const LoginDevicesPage({super.key});
|
||||
|
||||
@override
|
||||
State<LoginDevicesPage> createState() => LloginDevicesPageState();
|
||||
}
|
||||
|
||||
class LloginDevicesPageState extends State<LoginDevicesPage> {
|
||||
final _controller = Get.put(LoginDevicesController());
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final colorScheme = Theme.of(context).colorScheme;
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('登录设备')),
|
||||
body: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 650),
|
||||
child: refreshIndicator(
|
||||
onRefresh: _controller.onRefresh,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
ViewSliverSafeArea(
|
||||
sliver: MediaQuery.removeViewPadding(
|
||||
context: context,
|
||||
removeLeft: true,
|
||||
removeRight: true,
|
||||
child: Obx(
|
||||
() => _buildBody(
|
||||
colorScheme,
|
||||
_controller.loadingState.value,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(
|
||||
ColorScheme colorScheme,
|
||||
LoadingState<List<LoginDevice>?> loadingState,
|
||||
) {
|
||||
late final divider = Divider(
|
||||
height: 1,
|
||||
color: colorScheme.outline.withValues(alpha: 0.1),
|
||||
);
|
||||
return switch (loadingState) {
|
||||
Loading() => const SliverToBoxAdapter(),
|
||||
Success<List<LoginDevice>?>(:var response) =>
|
||||
response?.isNotEmpty == true
|
||||
? SliverList.separated(
|
||||
itemBuilder: (context, index) {
|
||||
return _buildItem(colorScheme, response[index]);
|
||||
},
|
||||
itemCount: response!.length,
|
||||
separatorBuilder: (_, _) => divider,
|
||||
)
|
||||
: HttpError(onReload: _controller.onReload),
|
||||
Error(:var errMsg) => HttpError(
|
||||
errMsg: errMsg,
|
||||
onReload: _controller.onReload,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
Widget _buildItem(ColorScheme colorScheme, LoginDevice item) {
|
||||
final style = TextStyle(fontSize: 13, color: colorScheme.outline);
|
||||
return ListTile(
|
||||
dense: true,
|
||||
title: Text(
|
||||
item.deviceName ?? '',
|
||||
style: const TextStyle(fontSize: 14),
|
||||
),
|
||||
subtitle: Text(
|
||||
'${item.latestLoginAt} ${item.source}',
|
||||
style: style,
|
||||
),
|
||||
trailing: item.isCurrentDevice == true
|
||||
? Text('(本机)', style: style)
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import 'package:PiliPlus/models_new/space/space/data.dart';
|
||||
import 'package:PiliPlus/pages/coin_log/controller.dart';
|
||||
import 'package:PiliPlus/pages/exp_log/controller.dart';
|
||||
import 'package:PiliPlus/pages/log_table/view.dart';
|
||||
import 'package:PiliPlus/pages/login_devices/view.dart';
|
||||
import 'package:PiliPlus/pages/login_log/controller.dart';
|
||||
import 'package:PiliPlus/pages/member/controller.dart';
|
||||
import 'package:PiliPlus/pages/member/widget/user_info_card.dart';
|
||||
@@ -190,6 +191,17 @@ class _MemberPageState extends State<MemberPage> {
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () => Get.to(const LoginDevicesPage()),
|
||||
child: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(Icons.devices, size: 18),
|
||||
SizedBox(width: 10),
|
||||
Text('登录设备'),
|
||||
],
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () => Get.to(
|
||||
const LogPage(),
|
||||
|
||||
Reference in New Issue
Block a user