Skip to content

Commit

Permalink
feat(thraed): polish operation log style
Browse files Browse the repository at this point in the history
  • Loading branch information
realth000 committed Feb 22, 2025
1 parent 7380cd1 commit 70f3270
Show file tree
Hide file tree
Showing 7 changed files with 84 additions and 73 deletions.
1 change: 1 addition & 0 deletions lib/features/thread/v1/models/models.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import 'package:dart_mappable/dart_mappable.dart';
import 'package:tsdm_client/extensions/string.dart';
import 'package:tsdm_client/extensions/universal_html.dart';
import 'package:universal_html/html.dart' as uh;

part 'models.mapper.dart';
Expand Down
4 changes: 3 additions & 1 deletion lib/features/thread/v1/models/operation_log_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ final class OperationLogItem with OperationLogItemMappable {
}

final username = element.querySelector('a')?.innerText;
final time = tds[1].innerText.parseToDateTimeUtc8();
final time =
tds[1].querySelector('span')?.attributes['title']?.parseToDateTimeUtc8() ??
tds[1].firstEndDeepText()?.parseToDateTimeUtc8();
final action = tds[2].innerText;
String? duration = tds[3].innerText;
if (duration.isEmpty) {
Expand Down
93 changes: 46 additions & 47 deletions lib/features/thread/v1/repository/thread_repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class ThreadRepository {

String _buildOperationUrl(String tid) =>
'$baseUrl/forum.php?mod=misc&action=viewthreadmod&tid=$tid'
'&infloat=yes&handlekey=viewthreadmod&inajax=1&ajaxtarget=fwin_content_viewthreadmod';
'&infloat=yes&handlekey=viewthreadmod&inajax=1&ajaxtarget=fwin_content_viewthreadmod';

/// Fetch the thread page with [tid] on page [pageNumber].
///
Expand All @@ -38,57 +38,56 @@ class ThreadRepository {
String? onlyVisibleUid,
bool? reverseOrder,
int? exactOrder,
}) =>
AsyncEither(() async {
assert(tid != null || pid != null, 'tid and pid MUST not be null at the same time');
}) => AsyncEither(() async {
assert(tid != null || pid != null, 'tid and pid MUST not be null at the same time');

/// Only visible uid.
final visibleUid = onlyVisibleUid == null ? '' : '&authorid=$onlyVisibleUid';
// ordertype: Control sort of post floors.
// 1: desc (latest post first)
// 2: asc (oldest post first)
//
// Some threads defined reverse order (latest post first) as default
// post order, it's hard to detect the default order of a thread.
//
// Instead, always set `ordertype` query parameter to ensure all threads
// are in the same default order.
//
// And in some situation, do NOT force reverse order, like user is going
// to find a post in a certain page number, in this use case a manually
// other override may going into different page that does NOT contain
// the target post.
final orderType = switch ((exactOrder, reverseOrder)) {
(final int i, _) => '&ordertype=$i',
(null, true) => '&ordertype=1',
(null, false) => '&ordertype=2',
(null, null) => '',
};
/// Only visible uid.
final visibleUid = onlyVisibleUid == null ? '' : '&authorid=$onlyVisibleUid';
// ordertype: Control sort of post floors.
// 1: desc (latest post first)
// 2: asc (oldest post first)
//
// Some threads defined reverse order (latest post first) as default
// post order, it's hard to detect the default order of a thread.
//
// Instead, always set `ordertype` query parameter to ensure all threads
// are in the same default order.
//
// And in some situation, do NOT force reverse order, like user is going
// to find a post in a certain page number, in this use case a manually
// other override may going into different page that does NOT contain
// the target post.
final orderType = switch ((exactOrder, reverseOrder)) {
(final int i, _) => '&ordertype=$i',
(null, true) => '&ordertype=1',
(null, false) => '&ordertype=2',
(null, null) => '',
};

_pageNumber = pageNumber;
if (tid != null) {
_threadUrl =
_pageNumber = pageNumber;
if (tid != null) {
_threadUrl =
'$baseUrl/forum.php?mod=viewthread&tid=$tid&extra=page%3D1'
'$orderType$visibleUid'
'&page=$pageNumber';
} else {
// The page came from where we redirect by finding a post.
_threadUrl = '$baseUrl/forum.php?mod=redirect&goto=findpost&pid=$pid';
}
'$orderType$visibleUid'
'&page=$pageNumber';
} else {
// The page came from where we redirect by finding a post.
_threadUrl = '$baseUrl/forum.php?mod=redirect&goto=findpost&pid=$pid';
}

final respEither = await getIt.get<NetClientProvider>().get(_threadUrl!).run();
if (respEither.isLeft()) {
return left(respEither.unwrapErr());
}
final respEither = await getIt.get<NetClientProvider>().get(_threadUrl!).run();
if (respEither.isLeft()) {
return left(respEither.unwrapErr());
}

final resp = respEither.unwrap();
if (resp.statusCode != HttpStatus.ok) {
return left(HttpRequestFailedException(resp.statusCode));
}
final resp = respEither.unwrap();
if (resp.statusCode != HttpStatus.ok) {
return left(HttpRequestFailedException(resp.statusCode));
}

final document = parseHtmlDocument(resp.data as String);
return right(document);
});
final document = parseHtmlDocument(resp.data as String);
return right(document);
});

/// Fetch the operation log for thread [tid].
AsyncEither<List<OperationLogItem>> fetchOperationLog(String tid) =>
Expand All @@ -101,7 +100,7 @@ class ThreadRepository {

final doc = parseHtmlDocument(htmlData);
final items =
doc.querySelectorAll('table tr').map(OperationLogItem.fromTr).whereType<OperationLogItem>().toList();
doc.querySelectorAll('table tr').map(OperationLogItem.fromTr).whereType<OperationLogItem>().toList();
return items;
});
}
44 changes: 22 additions & 22 deletions lib/features/thread/v1/widgets/operation_log_card.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ import 'package:tsdm_client/extensions/date_time.dart';
import 'package:tsdm_client/extensions/fp.dart';
import 'package:tsdm_client/features/thread/v1/repository/thread_repository.dart';
import 'package:tsdm_client/i18n/strings.g.dart';
import 'package:tsdm_client/widgets/heroes.dart';
import 'package:tsdm_client/widgets/single_line_text.dart';

Future<void> _showOperationLogDialog(BuildContext context, String tid) async {
final tr = context.t.threadPage.operationLog;
await showDialog<void>(
context: context,
builder: (_) {
return AlertDialog(
title: const Text('Operation log'),
scrollable: true,
title: Text(tr.title),
content: FutureBuilder(
future: context.read<ThreadRepository>().fetchOperationLog(tid).run(),
builder: (context, snapshot) {
Expand All @@ -23,33 +24,32 @@ Future<void> _showOperationLogDialog(BuildContext context, String tid) async {
}

if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
return const SizedBox(width: 50, height: 50, child: Align(child: CircularProgressIndicator()));
}

final actions = snapshot.data!;
if (actions.isLeft()) {
return Text(context.t.general.failedToLoad);
}

final content =
actions
.unwrap()
.map(
(e) => [
ListTile(
title: Text(e.username),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleLineText(e.time.yyyyMMDDHHMMSS()),
if (e.duration != null) Text(e.action) else Text('${e.action} ? ${e.duration}'),
],
),
),
],
)
.flattenedToList;
return Column(children: content);
final content = actions.unwrap().map(
(e) => ListTile(
isThreeLine: true,
leading: HeroUserAvatar(username: e.username, avatarUrl: null, disableHero: true),
title: Text(e.username),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SingleLineText(e.time.yyyyMMDDHHMMSS()),
SingleLineText(
'${e.action}${e.duration != null ? "(${e.duration})" : ""}',
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
);
return SingleChildScrollView(child: Column(children: content.toList()));
},
),
);
Expand Down
5 changes: 4 additions & 1 deletion lib/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,10 @@
"needLogin": "Need login",
"replySuccess": "Reply success",
"replyFailed": "Failed to reply: $err",
"draft": "Draft"
"draft": "Draft",
"operationLog": {
"title": "Operation Log"
}
},
"noticePage": {
"title": "Notifications",
Expand Down
5 changes: 4 additions & 1 deletion lib/i18n/zh-CN.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,10 @@
"needLogin": "需要登录",
"replySuccess": "回复成功",
"replyFailed": "回复失败:$err",
"draft": "草稿"
"draft": "草稿",
"operationLog": {
"title": "操作记录"
}
},
"noticePage": {
"title": "通知",
Expand Down
5 changes: 4 additions & 1 deletion lib/i18n/zh-TW.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,10 @@
"needLogin": "需要登入",
"replySuccess": "回覆成功",
"replyFailed": "回覆失敗:$err",
"draft": "草稿"
"draft": "草稿",
"operationLog": {
"title": "操作記錄"
}
},
"noticePage": {
"title": "通知",
Expand Down

0 comments on commit 70f3270

Please sign in to comment.