mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-20 17:16:29 +08:00
feat: space setting
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -880,4 +880,8 @@ class Api {
|
|||||||
static const String coinArc = '${HttpString.appBaseUrl}/x/v2/space/coinarc';
|
static const String coinArc = '${HttpString.appBaseUrl}/x/v2/space/coinarc';
|
||||||
|
|
||||||
static const String likeArc = '${HttpString.appBaseUrl}/x/v2/space/likearc';
|
static const String likeArc = '${HttpString.appBaseUrl}/x/v2/space/likearc';
|
||||||
|
|
||||||
|
static const String spaceSetting = '/x/space/setting/app';
|
||||||
|
|
||||||
|
static const String spaceSettingMod = '/x/space/privacy/batch/modify';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:PiliPlus/models/user/stat.dart';
|
|||||||
import 'package:PiliPlus/models_new/history/data.dart';
|
import 'package:PiliPlus/models_new/history/data.dart';
|
||||||
import 'package:PiliPlus/models_new/later/data.dart';
|
import 'package:PiliPlus/models_new/later/data.dart';
|
||||||
import 'package:PiliPlus/models_new/media_list/data.dart';
|
import 'package:PiliPlus/models_new/media_list/data.dart';
|
||||||
|
import 'package:PiliPlus/models_new/space_setting/data.dart';
|
||||||
import 'package:PiliPlus/models_new/sub/sub/data.dart';
|
import 'package:PiliPlus/models_new/sub/sub/data.dart';
|
||||||
import 'package:PiliPlus/models_new/sub/sub/list.dart';
|
import 'package:PiliPlus/models_new/sub/sub/list.dart';
|
||||||
import 'package:PiliPlus/models_new/video/video_tag/data.dart';
|
import 'package:PiliPlus/models_new/video/video_tag/data.dart';
|
||||||
@@ -352,4 +353,34 @@ class UserHttp {
|
|||||||
);
|
);
|
||||||
return res.data as Map;
|
return res.data as Map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<SpaceSettingData>> spaceSetting() async {
|
||||||
|
final res = await Request().get(
|
||||||
|
Api.spaceSetting,
|
||||||
|
queryParameters: {
|
||||||
|
'mid': Accounts.main.mid,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return Success(SpaceSettingData.fromJson(res.data['data']));
|
||||||
|
} else {
|
||||||
|
return Error(res.data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future spaceSettingMod(data) async {
|
||||||
|
final res = await Request().post(
|
||||||
|
Api.spaceSettingMod,
|
||||||
|
queryParameters: {
|
||||||
|
'csrf': Accounts.main.csrf,
|
||||||
|
},
|
||||||
|
data: data,
|
||||||
|
options: Options(contentType: Headers.formUrlEncodedContentType),
|
||||||
|
);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
18
lib/models_new/space_setting/data.dart
Normal file
18
lib/models_new/space_setting/data.dart
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import 'package:PiliPlus/models_new/space_setting/privacy.dart';
|
||||||
|
|
||||||
|
class SpaceSettingData {
|
||||||
|
Privacy? privacy;
|
||||||
|
bool? showNftSwitch;
|
||||||
|
String? exclusiveUrl;
|
||||||
|
|
||||||
|
SpaceSettingData({this.privacy, this.showNftSwitch, this.exclusiveUrl});
|
||||||
|
|
||||||
|
factory SpaceSettingData.fromJson(Map<String, dynamic> json) =>
|
||||||
|
SpaceSettingData(
|
||||||
|
privacy: json['privacy'] == null
|
||||||
|
? null
|
||||||
|
: Privacy.fromJson(json['privacy'] as Map<String, dynamic>),
|
||||||
|
showNftSwitch: json['show_nft_switch'] as bool?,
|
||||||
|
exclusiveUrl: json['exclusive_url'] as String?,
|
||||||
|
);
|
||||||
|
}
|
||||||
102
lib/models_new/space_setting/privacy.dart
Normal file
102
lib/models_new/space_setting/privacy.dart
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
class SpaceSettingModel {
|
||||||
|
SpaceSettingModel({
|
||||||
|
required this.name,
|
||||||
|
required this.key,
|
||||||
|
required this.value,
|
||||||
|
this.isReverse = false,
|
||||||
|
});
|
||||||
|
|
||||||
|
String name;
|
||||||
|
String key;
|
||||||
|
int? value;
|
||||||
|
bool isReverse;
|
||||||
|
|
||||||
|
bool get boolVal => isReverse ? value == 0 : value == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Privacy {
|
||||||
|
List<SpaceSettingModel> list1;
|
||||||
|
List<SpaceSettingModel> list2;
|
||||||
|
List<SpaceSettingModel> list3;
|
||||||
|
|
||||||
|
Privacy({
|
||||||
|
required this.list1,
|
||||||
|
required this.list2,
|
||||||
|
required this.list3,
|
||||||
|
});
|
||||||
|
|
||||||
|
factory Privacy.fromJson(Map<String, dynamic> json) => Privacy(
|
||||||
|
list1: [
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开我的收藏', key: 'fav_video', value: json['fav_video']),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开我的追番追剧', key: 'bangumi', value: json['bangumi']),
|
||||||
|
SpaceSettingModel(name: '公开我的追漫', key: 'comic', value: json['comic']),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开最近投币的视频',
|
||||||
|
key: 'coins_video',
|
||||||
|
value: json['coins_video'],
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开最近点赞的视频',
|
||||||
|
key: 'likes_video',
|
||||||
|
value: json['likes_video'],
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开最近玩过的游戏',
|
||||||
|
key: 'played_game',
|
||||||
|
value: json['played_game'],
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开拥有的粉丝装扮', key: 'dress_up', value: json['dress_up']),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开我的关注列表',
|
||||||
|
key: 'disable_following',
|
||||||
|
value: json['disable_following'],
|
||||||
|
isReverse: true,
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开我的粉丝列表',
|
||||||
|
key: 'disable_show_fans',
|
||||||
|
value: json['disable_show_fans'],
|
||||||
|
isReverse: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
list2: [
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开佩戴的粉丝勋章',
|
||||||
|
key: 'close_space_medal',
|
||||||
|
value: json['close_space_medal'],
|
||||||
|
isReverse: true,
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '勋章墙公开显示所有粉丝勋章',
|
||||||
|
key: 'only_show_wearing',
|
||||||
|
value: json['only_show_wearing'],
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '公开学校信息',
|
||||||
|
key: 'disable_show_school',
|
||||||
|
value: json['disable_show_school'],
|
||||||
|
isReverse: true,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
list3: [
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '投稿视频列表中展现直播回放',
|
||||||
|
key: 'live_playback',
|
||||||
|
value: json['live_playback'],
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '投稿视频列表中展现包月充电专属视频',
|
||||||
|
key: 'charge_video',
|
||||||
|
value: json['charge_video'],
|
||||||
|
),
|
||||||
|
SpaceSettingModel(
|
||||||
|
name: '投稿视频列表中展现课堂视频',
|
||||||
|
key: 'lesson_video',
|
||||||
|
value: json['lesson_video'],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -135,41 +135,53 @@ class _MemberPageState extends State<MemberPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (_userController.ownerMid != null &&
|
if (_userController.ownerMid != 0)
|
||||||
_userController.mid != _userController.ownerMid) ...[
|
if (_userController.mid == _userController.ownerMid)
|
||||||
const PopupMenuDivider(),
|
PopupMenuItem(
|
||||||
PopupMenuItem(
|
onTap: () => Get.toNamed('/spaceSetting'),
|
||||||
onTap: () => showDialog(
|
child: const Row(
|
||||||
context: context,
|
mainAxisSize: MainAxisSize.min,
|
||||||
builder: (context) => AlertDialog(
|
children: [
|
||||||
clipBehavior: Clip.hardEdge,
|
Icon(Icons.settings_outlined, size: 19),
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
SizedBox(width: 10),
|
||||||
horizontal: 20,
|
Text('空间设置'),
|
||||||
vertical: 16,
|
],
|
||||||
),
|
),
|
||||||
content: MemberReportPanel(
|
)
|
||||||
name: _userController.username,
|
else ...[
|
||||||
mid: _mid,
|
const PopupMenuDivider(),
|
||||||
|
PopupMenuItem(
|
||||||
|
onTap: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => AlertDialog(
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
contentPadding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: 20,
|
||||||
|
vertical: 16,
|
||||||
|
),
|
||||||
|
content: MemberReportPanel(
|
||||||
|
name: _userController.username,
|
||||||
|
mid: _mid,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Icon(
|
||||||
|
Icons.error_outline,
|
||||||
|
size: 19,
|
||||||
|
color: theme.colorScheme.error,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
'举报',
|
||||||
|
style: TextStyle(color: theme.colorScheme.error),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
],
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
size: 19,
|
|
||||||
color: theme.colorScheme.error,
|
|
||||||
),
|
|
||||||
const SizedBox(width: 10),
|
|
||||||
Text(
|
|
||||||
'举报',
|
|
||||||
style: TextStyle(color: theme.colorScheme.error),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
|
|||||||
46
lib/pages/space_setting/controller.dart
Normal file
46
lib/pages/space_setting/controller.dart
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/http/user.dart';
|
||||||
|
import 'package:PiliPlus/models_new/space_setting/data.dart';
|
||||||
|
import 'package:PiliPlus/models_new/space_setting/privacy.dart';
|
||||||
|
import 'package:PiliPlus/pages/common/common_data_controller.dart';
|
||||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|
||||||
|
class SpaceSettingController
|
||||||
|
extends CommonDataController<SpaceSettingData, Privacy?> {
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
queryData();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool? hasMod;
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool customHandleResponse(
|
||||||
|
bool isRefresh, Success<SpaceSettingData> response) {
|
||||||
|
loadingState.value = Success(response.response.privacy);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<LoadingState<SpaceSettingData>> customGetData() =>
|
||||||
|
UserHttp.spaceSetting();
|
||||||
|
|
||||||
|
Future<void> onMod() async {
|
||||||
|
if (hasMod == true && loadingState.value.isSuccess) {
|
||||||
|
Privacy? data = loadingState.value.data;
|
||||||
|
if (data != null) {
|
||||||
|
var res = await UserHttp.spaceSettingMod(
|
||||||
|
{
|
||||||
|
for (var e in data.list1) ...{e.key: e.value},
|
||||||
|
for (var e in data.list2) ...{e.key: e.value},
|
||||||
|
for (var e in data.list3) ...{e.key: e.value},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if (!res['status']) {
|
||||||
|
SmartDialog.showToast(res['msg']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
143
lib/pages/space_setting/view.dart
Normal file
143
lib/pages/space_setting/view.dart
Normal file
@@ -0,0 +1,143 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart';
|
||||||
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
|
import 'package:PiliPlus/models_new/space_setting/privacy.dart';
|
||||||
|
import 'package:PiliPlus/pages/space_setting/controller.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
|
||||||
|
class SpaceSettingPage extends StatefulWidget {
|
||||||
|
const SpaceSettingPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SpaceSettingPage> createState() => _SpaceSettingPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SpaceSettingPageState extends State<SpaceSettingPage> {
|
||||||
|
final _controller = Get.put(SpaceSettingController());
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('空间设置'),
|
||||||
|
),
|
||||||
|
body: Obx(() => _buildBody(theme, _controller.loadingState.value)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.onMod();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildBody(ThemeData theme, LoadingState<Privacy?> loadingState) {
|
||||||
|
return switch (loadingState) {
|
||||||
|
Loading() => const SizedBox.shrink(),
|
||||||
|
Success<Privacy?>(:var response) => response == null
|
||||||
|
? scrollErrorWidget(onReload: _controller.onReload)
|
||||||
|
: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
final padding = MediaQuery.paddingOf(context);
|
||||||
|
final divider = Divider(
|
||||||
|
height: 1,
|
||||||
|
indent: max(16, padding.left),
|
||||||
|
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||||
|
);
|
||||||
|
final dividerL = SliverToBoxAdapter(
|
||||||
|
child: Divider(
|
||||||
|
height: 12,
|
||||||
|
thickness: 12,
|
||||||
|
color: theme.colorScheme.outline.withValues(alpha: 0.1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return CustomScrollView(
|
||||||
|
slivers: [
|
||||||
|
dividerL,
|
||||||
|
SliverList.separated(
|
||||||
|
itemCount: response.list1.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _item(response.list1[index]);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) => divider,
|
||||||
|
),
|
||||||
|
dividerL,
|
||||||
|
SliverList.separated(
|
||||||
|
itemCount: response.list2.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _item(response.list2[index]);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) => divider,
|
||||||
|
),
|
||||||
|
dividerL,
|
||||||
|
SliverList.separated(
|
||||||
|
itemCount: response.list3.length,
|
||||||
|
itemBuilder: (context, index) {
|
||||||
|
return _item(response.list3[index]);
|
||||||
|
},
|
||||||
|
separatorBuilder: (context, index) => divider,
|
||||||
|
),
|
||||||
|
dividerL,
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: SizedBox(
|
||||||
|
height: padding.bottom + 80,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Error(:var errMsg) => scrollErrorWidget(
|
||||||
|
errMsg: errMsg,
|
||||||
|
onReload: _controller.onReload,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _item(SpaceSettingModel item) {
|
||||||
|
return Builder(
|
||||||
|
builder: (context) {
|
||||||
|
void onChanged([bool? value]) {
|
||||||
|
_controller.hasMod ??= true;
|
||||||
|
|
||||||
|
value ??= !item.boolVal;
|
||||||
|
item.value = item.isReverse
|
||||||
|
? value
|
||||||
|
? 0
|
||||||
|
: 1
|
||||||
|
: value
|
||||||
|
? 1
|
||||||
|
: 0;
|
||||||
|
(context as Element).markNeedsBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: onChanged,
|
||||||
|
title: Text(
|
||||||
|
item.name,
|
||||||
|
style: const TextStyle(fontSize: 14),
|
||||||
|
),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
scale: 0.8,
|
||||||
|
child: Switch(
|
||||||
|
thumbIcon: WidgetStateProperty.resolveWith<Icon?>(
|
||||||
|
(Set<WidgetState> states) {
|
||||||
|
if (states.isNotEmpty && states.first == WidgetState.selected) {
|
||||||
|
return const Icon(Icons.done);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}),
|
||||||
|
value: item.boolVal,
|
||||||
|
onChanged: onChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -49,6 +49,7 @@ import 'package:PiliPlus/pages/setting/style_setting.dart';
|
|||||||
import 'package:PiliPlus/pages/setting/video_setting.dart';
|
import 'package:PiliPlus/pages/setting/video_setting.dart';
|
||||||
import 'package:PiliPlus/pages/setting/view.dart';
|
import 'package:PiliPlus/pages/setting/view.dart';
|
||||||
import 'package:PiliPlus/pages/settings_search/view.dart';
|
import 'package:PiliPlus/pages/settings_search/view.dart';
|
||||||
|
import 'package:PiliPlus/pages/space_setting/view.dart';
|
||||||
import 'package:PiliPlus/pages/sponsor_block/view.dart';
|
import 'package:PiliPlus/pages/sponsor_block/view.dart';
|
||||||
import 'package:PiliPlus/pages/subscription/view.dart';
|
import 'package:PiliPlus/pages/subscription/view.dart';
|
||||||
import 'package:PiliPlus/pages/subscription_detail/view.dart';
|
import 'package:PiliPlus/pages/subscription_detail/view.dart';
|
||||||
@@ -175,6 +176,7 @@ class Routes {
|
|||||||
CustomGetPage(name: '/articleList', page: () => const ArticleListPage()),
|
CustomGetPage(name: '/articleList', page: () => const ArticleListPage()),
|
||||||
CustomGetPage(name: '/barSetting', page: () => const BarSetPage()),
|
CustomGetPage(name: '/barSetting', page: () => const BarSetPage()),
|
||||||
CustomGetPage(name: '/upowerRank', page: () => const UpowerRankPage()),
|
CustomGetPage(name: '/upowerRank', page: () => const UpowerRankPage()),
|
||||||
|
CustomGetPage(name: '/spaceSetting', page: () => const SpaceSettingPage()),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user