增加设置项自动布局

main
落雨楓 3 years ago
parent 23264dfd7e
commit 622a775699

@ -49,9 +49,11 @@ class PageInfo {
int? watchers;
int? visitingwatchers;
MWPageProtectionInfo? protection;
List<MWPageProtectionInfo>? protection;
List<String>? restrictiontypes;
Map<DateTime, int?>? pageviews;
PageInfo({
required this.pageid,
required this.ns,
@ -74,6 +76,7 @@ class PageInfo {
this.visitingwatchers,
this.protection,
this.restrictiontypes,
this.pageviews,
});
String get mainTitle {
@ -84,8 +87,7 @@ class PageInfo {
return null;
}
factory PageInfo.fromJson(Map<String, dynamic> json) =>
_$PageInfoFromJson(json);
factory PageInfo.fromJson(Map<String, dynamic> json) => _$PageInfoFromJson(json);
Map<String, dynamic> toJson() => _$PageInfoToJson(this);
@ -110,15 +112,12 @@ class PageInfo {
class PagesResponse with _$PagesResponse {
factory PagesResponse({required List<PageInfo> pages}) = _PageResponse;
factory PagesResponse.fromJson(Map<String, dynamic> json) =>
_$PagesResponseFromJson(json);
factory PagesResponse.fromJson(Map<String, dynamic> json) => _$PagesResponseFromJson(json);
}
@Freezed(copyWith: false)
class PageImageInfo with _$PageImageInfo {
factory PageImageInfo({required String source, int? width, int? height}) =
_PageImageInfo;
factory PageImageInfo({required String source, int? width, int? height}) = _PageImageInfo;
factory PageImageInfo.fromJson(Map<String, dynamic> json) =>
_$PageImageInfoFromJson(json);
factory PageImageInfo.fromJson(Map<String, dynamic> json) => _$PageImageInfoFromJson(json);
}

@ -27,10 +27,10 @@ class _IsekaiWikiAppWrapperState extends State<IsekaiWikiAppWrapper> {
if (GetPlatform.isAndroid) {
//
SystemChrome.setPreferredOrientations([
/*SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
]);*/
if (GetPlatform.isAndroid) {
SystemChrome.setSystemUIOverlayStyle(
@ -97,9 +97,7 @@ class IsekaiWikiApp extends StatelessWidget {
? Styles.materialLightTheme
: Styles.materialDarkTheme,
child: CupertinoTheme(
data:
Styles.cupertinoTheme.copyWith(brightness: brightness),
child: child),
data: Styles.cupertinoTheme.copyWith(brightness: brightness), child: child),
),
);
}

@ -1,42 +1,72 @@
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
class AutoWrap extends StatefulWidget {
class ResponsivePair extends StatefulWidget {
final List<Widget> children;
final MainAxisAlignment rowMainAxisAlignment;
final CrossAxisAlignment rowCrossAxisAlignment;
const AutoWrap({super.key, required this.children});
final MainAxisAlignment colMainAxisAlignment;
final CrossAxisAlignment colCrossAxisAlignment;
const ResponsivePair({
super.key,
required this.children,
this.rowMainAxisAlignment = MainAxisAlignment.spaceBetween,
this.rowCrossAxisAlignment = CrossAxisAlignment.center,
this.colMainAxisAlignment = MainAxisAlignment.spaceBetween,
this.colCrossAxisAlignment = CrossAxisAlignment.start,
});
@override
State<StatefulWidget> createState() => _AutoWrapState();
State<StatefulWidget> createState() => _ResponsivePairState();
}
class _AutoWrapState extends State<AutoWrap> {
class _ResponsivePairState extends State<ResponsivePair> {
var _computed = false;
var _isFirstBuild = true;
final Map<int, double> _childWidth = {};
var _isRow = true;
void handleSizeChange(Size size, int id) {
_childWidth[id] = size.width;
@override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((_) {
refreshSize();
});
}
@override
void didUpdateWidget(covariant AutoWrap oldWidget) {
super.didUpdateWidget(oldWidget);
if (_isFirstBuild) {
_isFirstBuild = false;
var sum = _childWidth.values.reduce((value, element) => value + element);
var width = context.size?.width ?? 0;
void refreshSize() {
if (_childWidth.length != widget.children.length) return;
setState(() {
_computed = true;
_isRow = sum < width;
});
var sum = _childWidth.values.reduce((value, element) => value + element);
var width = context.size?.width ?? 0;
setState(() {
_computed = true;
_isRow = sum < width;
});
}
void handleSizeChange(Size size, int id) {
_childWidth[id] = size.width;
if (_childWidth.length == widget.children.length) {
refreshSize();
}
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
setState(() {
_computed = false;
});
}
@override
Widget build(BuildContext context) {
Widget inner;
if (!_computed) {
List<Widget> stackChildren = [];
for (var i = 0; i < widget.children.length; i++) {
@ -52,16 +82,29 @@ class _AutoWrapState extends State<AutoWrap> {
),
);
}
return Stack(
inner = Stack(
children: stackChildren,
);
} else {
if (_isRow) {
return Row(children: widget.children);
inner = Row(
mainAxisAlignment: widget.rowMainAxisAlignment,
crossAxisAlignment: widget.rowCrossAxisAlignment,
children: widget.children,
);
} else {
return Column(children: widget.children);
inner = Column(
mainAxisAlignment: widget.colMainAxisAlignment,
crossAxisAlignment: widget.colCrossAxisAlignment,
children: widget.children,
);
}
}
return AnimatedSize(
duration: const Duration(milliseconds: 150),
curve: Curves.linear,
child: inner,
);
}
}
@ -87,8 +130,8 @@ class WidgetSizeRenderObject extends RenderProxyBox {
onSizeChange(newSize, id);
});
}
} catch (e) {
print(e);
} catch (e, stack) {
debugPrint("$e $stack");
}
}
}

@ -33,10 +33,13 @@ class _OpacityGestureDetectorState extends State<OpacityGestureDetector> {
enum PointerActiveMode { none, hover, active }
class ClickableBuilder extends StatefulWidget {
final int minActiveDuration;
final Widget Function(BuildContext context, PointerActiveMode mode, Widget child) builder;
final Widget? child;
const ClickableBuilder({super.key, required this.builder, this.child});
const ClickableBuilder(
{super.key, required this.builder, this.child, this.minActiveDuration = 150});
@override
State<StatefulWidget> createState() => _ClickableBuilder();
@ -67,7 +70,7 @@ class _ClickableBuilder extends State<ClickableBuilder> {
setState(() {
isActive = true;
});
Future.delayed(const Duration(milliseconds: 150)).then((value) {
Future.delayed(Duration(milliseconds: widget.minActiveDuration)).then((value) {
if (isPointerDown) {
isPersistActive = true;
} else {

@ -271,6 +271,13 @@ class _WikiParserState extends ReactiveState<WikiPageParser> {
c = Get.put(c);
}
@override
void dispose() {
super.dispose();
c.loading.value = true;
}
@override
void receiveProps() {
c.pageInfo.value = widget.pageInfo;

@ -38,17 +38,14 @@ class WikiInfoPageController extends GetxController {
pageInfoRes = await MWApiList.getPageInfoList(pageids: [
pageId.value
], prop: [
"extracts",
"info",
"pageimages",
"pageviews"
], extraParams: {
"inprop":
"url|protection|watched|watchers|visitingwatchers|displaytitle",
"inprop": "url|protection|watched|watchers|visitingwatchers|displaytitle",
});
} else {
pageInfoRes =
await MWApiList.getPageInfoList(titles: [pageTitle.value]);
pageInfoRes = await MWApiList.getPageInfoList(titles: [pageTitle.value]);
}
if (pageInfoRes.data.isEmpty) {
throw MWApiErrorException(code: 'no-page', info: "页面信息丢失");
@ -58,8 +55,7 @@ class WikiInfoPageController extends GetxController {
pageId.value = pageInfo.value!.pageid;
pageTitle.value = pageInfo.value!.title;
} catch (err, stack) {
alert(Get.overlayContext!, ErrorUtils.getErrorMessage(err),
title: "错误");
alert(Get.overlayContext!, ErrorUtils.getErrorMessage(err), title: "错误");
if (kDebugMode) {
print("Exception in page: $err");
stack.printError();
@ -90,13 +86,14 @@ class _WikiInfoPageState extends ReactiveState<WikiInfoPage> {
void initState() {
super.initState();
c = Get.put(c);
Get.put(c);
}
@override
void dispose() {
c.dispose();
super.dispose();
Get.delete<WikiInfoPageController>();
}
@override
@ -112,16 +109,14 @@ class _WikiInfoPageState extends ReactiveState<WikiInfoPage> {
children: <CupertinoListTile>[
CupertinoListTile.notched(
title: Center(
child: CupertinoActivityIndicator(
radius: 10 * MediaQuery.of(context).textScaleFactor),
child: CupertinoActivityIndicator(radius: 10 * MediaQuery.of(context).textScaleFactor),
),
),
],
);
}
CupertinoListTile buildPageInfo(
BuildContext context, String label, dynamic value,
CupertinoListTile buildPageInfo(BuildContext context, String label, dynamic value,
{VoidFutureCallback? onTap}) {
final Locale appLocale = Localizations.localeOf(context);
var valueStr = "未知";
@ -129,8 +124,7 @@ class _WikiInfoPageState extends ReactiveState<WikiInfoPage> {
valueStr = value;
}
if (value is int) {
valueStr =
NumberFormat.decimalPattern(appLocale.toLanguageTag()).format(value);
valueStr = NumberFormat.decimalPattern(appLocale.toLanguageTag()).format(value);
} else if (value is double) {
var pattern = NumberFormat.decimalPattern(appLocale.toLanguageTag());
pattern.maximumFractionDigits = 2;
@ -146,48 +140,62 @@ class _WikiInfoPageState extends ReactiveState<WikiInfoPage> {
padding: const EdgeInsetsDirectional.fromSTEB(20.0, 10.0, 14.0, 10.0),
title: Container(
width: MediaQuery.of(context).size.width,
child: AutoWrap(
child: ResponsivePair(
children: [
Text(label),
Text(
valueStr,
style: TextStyle(
color: CupertinoColors.systemGrey2.resolveFrom(context)),
style: TextStyle(color: CupertinoColors.systemGrey2.resolveFrom(context)),
),
],
),
),
trailing: onTap != null ? const CupertinoListTileChevron() : null,
trailing: onTap != null
? const Padding(
padding: EdgeInsets.only(left: 8),
child: CupertinoListTileChevron(),
)
: null,
onTap: onTap,
);
}
int? getPageViews(Map<DateTime, int?>? pageViews) {
if (pageViews == null) return null;
int validData = 0;
int visitSum = 0;
pageViews.forEach((key, value) {
if (value != null) {
validData++;
visitSum += value;
}
});
return validData != 0 ? visitSum : null;
}
Widget buildPageInfoList(BuildContext context) {
var pageInfo = c.pageInfo.value;
return Column(
children: [
Obx(
() => CupertinoListSection.insetGrouped(
additionalDividerMargin: 6,
header: const Text("基本信息"),
backgroundColor: CupertinoTheme.of(context).scaffoldBackgroundColor,
children: <CupertinoListTile>[
buildPageInfo(
context,
"显示标题",
pageInfo?.mainTitle,
onTap: () async {},
),
buildPageInfo(context, "页面长度(字节)", pageInfo?.length),
buildPageInfo(context, "页面ID", pageInfo?.pageid),
buildPageInfo(context, "页面内容语言", pageInfo?.pagelanguage),
buildPageInfo(context, "页面内容类型", pageInfo?.contentmodel),
buildPageInfo(context, "收藏者数", pageInfo?.watchers),
buildPageInfo(context, "最后修改于", pageInfo?.updatedTime),
buildPageInfo(context, "该页面的子页面数", null),
buildPageInfo(context, "过去30天的页面访问量", null),
],
),
CupertinoListSection.insetGrouped(
additionalDividerMargin: 6,
header: const Text("基本信息"),
backgroundColor: CupertinoTheme.of(context).scaffoldBackgroundColor,
children: <CupertinoListTile>[
buildPageInfo(context, "页面标题", pageInfo?.title),
buildPageInfo(context, "显示标题", pageInfo?.mainTitle),
buildPageInfo(context, "页面长度(字节)", pageInfo?.length),
buildPageInfo(context, "页面ID", pageInfo?.pageid),
buildPageInfo(context, "页面内容语言", pageInfo?.pagelanguage),
buildPageInfo(context, "页面内容类型", pageInfo?.contentmodel),
buildPageInfo(context, "收藏者数", pageInfo?.watchers),
buildPageInfo(context, "更新后已查看的收藏者", pageInfo?.visitingwatchers),
buildPageInfo(context, "最后修改于", pageInfo?.updatedTime),
buildPageInfo(context, "该页面的子页面数", null),
buildPageInfo(context, "过去30天的页面访问量", getPageViews(pageInfo?.pageviews)),
],
),
],
);
@ -202,9 +210,7 @@ class _WikiInfoPageState extends ReactiveState<WikiInfoPage> {
child: SafeArea(
child: ListView(
children: [
Obx(() => c.loadingPageInfo.value
? buildLoading(context)
: buildPageInfoList(context))
Obx(() => c.loadingPageInfo.value ? buildLoading(context) : buildPageInfoList(context))
],
),
),

@ -28,11 +28,7 @@ class MinimumArticleData {
final String? mainCategory;
final DateTime? updateTime;
MinimumArticleData(
{required this.title,
this.description,
this.mainCategory,
this.updateTime});
MinimumArticleData({required this.title, this.description, this.mainCategory, this.updateTime});
}
class ArticleCategoryData {
@ -77,11 +73,9 @@ class WikiViewPageController extends GetxController {
loading.value = true;
MWResponse<List<PageInfo>> pageInfoRes;
if (pageId.value != 0) {
pageInfoRes =
await MWApiList.getPageInfoList(pageids: [pageId.value]);
pageInfoRes = await MWApiList.getPageInfoList(pageids: [pageId.value]);
} else {
pageInfoRes =
await MWApiList.getPageInfoList(titles: [pageTitle.value]);
pageInfoRes = await MWApiList.getPageInfoList(titles: [pageTitle.value]);
}
if (pageInfoRes.data.isEmpty) {
throw MWApiErrorException(code: 'no-page', info: "页面信息丢失");
@ -96,13 +90,11 @@ class WikiViewPageController extends GetxController {
var parseRes = await MWApiParse.parse(pageId: pageId.value);
parseInfo.value = parseRes.data;
} catch (err, stack) {
alert(Get.overlayContext!, ErrorUtils.getErrorMessage(err),
title: "错误");
alert(Get.overlayContext!, ErrorUtils.getErrorMessage(err), title: "错误");
if (kDebugMode) {
print("Exception in page: $err");
stack.printError();
}
} finally {
loading.value = false;
}
}
@ -114,8 +106,7 @@ class WikiViewPageController extends GetxController {
void handleShareButtonClick() {
if (pageInfo.value != null) {
var pageUrl =
pageInfo.value!.fullurl ?? getPageUrl(pageInfo.value!.title);
var pageUrl = pageInfo.value!.fullurl ?? getPageUrl(pageInfo.value!.title);
var shareTitle = "${pageInfo.value!.title} - ${Global.siteTitle}";
var shareText = "$shareTitle\n$pageUrl";
@ -150,8 +141,7 @@ class WikiViewPage extends StatefulWidget {
final String? targetPage;
final int? targetPageId;
const WikiViewPage(
{super.key, this.targetPage, this.targetPageId, this.initialArticleData});
const WikiViewPage({super.key, this.targetPage, this.targetPageId, this.initialArticleData});
@override
State<StatefulWidget> createState() => _WikiViewPageState();
@ -173,7 +163,7 @@ class _WikiViewPageState extends ReactiveState<WikiViewPage> {
void dispose() {
super.dispose();
c.dispose();
Get.delete<WikiViewPageController>();
}
@override
@ -223,8 +213,7 @@ class _WikiViewPageState extends ReactiveState<WikiViewPage> {
semanticLabel: "讨论",
),
Obx(() {
if (c.pageInfo.value != null &&
flc.isFavorite(c.pageInfo.value!)) {
if (c.pageInfo.value != null && flc.isFavorite(c.pageInfo.value!)) {
return NavBarButton(
icon: CupertinoIcons.heart_fill,
onPressed: () {},

Loading…
Cancel
Save