✨ About page
This commit is contained in:
parent
3f0a7a2227
commit
3c621187a7
@ -2,6 +2,7 @@
|
||||
"nextVersionAlert": "Heavy Development Alert",
|
||||
"nextVersionNotice": "You are using Solian 2.0 Preview, which is the first version of Solian 2.0. The current stable branch (sn.solsynth.dev) is 1.4. This version is still under heavy development, some features may not be stable, and not all features are supported. You can roll back to 1.4.X version via TestFlight, or continue to experience the new version (sn-next.solsynth.dev).",
|
||||
"screen": "Screen",
|
||||
"screenAbout": "About",
|
||||
"screenHome": "Home",
|
||||
"screenExplore": "Explore",
|
||||
"screenAccount": "Account",
|
||||
@ -188,6 +189,9 @@
|
||||
"settingsNetworkServerPreset": "Present HyperNet Server",
|
||||
"settingsNetworkServerPresetDescription": "You can choose one of our preset HyperNet server addresses from the list on the right.",
|
||||
"settingsNetworkServerSaved": "Server address saved.",
|
||||
"settingsMisc": "Misc",
|
||||
"settingsMiscAbout": "About",
|
||||
"settingsMiscAboutDescription": "View the version information of Solian.",
|
||||
"sensitiveContent": "Sensitive Content",
|
||||
"sensitiveContentCollapsed": "Sensitive content has been collapsed.",
|
||||
"sensitiveContentDescription": "This content has been marked as sensitive, and may not be suitable for all viewers.",
|
||||
@ -417,5 +421,8 @@
|
||||
"termAcceptLink": "View terms",
|
||||
"termAcceptNextWithAgree": "By clicking the \"Next\", it means you agree to our terms and its updates.",
|
||||
"unauthorized": "Unauthorized",
|
||||
"unauthorizedDescription": "Login to explore the entire Solar Network."
|
||||
"unauthorizedDescription": "Login to explore the entire Solar Network.",
|
||||
"serviceStatus": "Service Status",
|
||||
"termRelated": "Related Terms",
|
||||
"appDetails": "App Details"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
"nextVersionAlert": "高强度开发提示",
|
||||
"nextVersionNotice": "您正在使用的是 Solian 2.0 的抢先体验版本,目前稳定分支(sn.solsynth.dev)版本为 1.4。该版本还在持续的开发中,部分功能可能不稳定,也并非所有功能都支持了。您可以通过 TestFlight 回滚到 1.4.X 或者继续体验新版本(sn-next.solsynth.dev)。",
|
||||
"screen": "页面",
|
||||
"screenAbout": "关于",
|
||||
"screenHome": "首页",
|
||||
"screenExplore": "探索",
|
||||
"screenAccount": "您",
|
||||
@ -188,6 +189,9 @@
|
||||
"settingsNetworkServerPreset": "预设的 HyperNet 服务器",
|
||||
"settingsNetworkServerPresetDescription": "你可以在旁边的列表中选择我们提供的预设 HyperNet 服务器地址。",
|
||||
"settingsNetworkServerSaved": "服务器地址已保存。",
|
||||
"settingsMisc": "杂项",
|
||||
"settingsMiscAbout": "关于",
|
||||
"settingsMiscAboutDescription": "查看 Solian 的版本信息。",
|
||||
"sensitiveContent": "敏感内容",
|
||||
"sensitiveContentCollapsed": "敏感内容已折叠。",
|
||||
"sensitiveContentDescription": "此内容已被标记,可能不适合所有人查看。",
|
||||
@ -417,5 +421,8 @@
|
||||
"termAcceptLink": "浏览条款",
|
||||
"termAcceptNextWithAgree": "点击 “下一步”,即表示你同意我们的各项条款,包括其之后的更新。",
|
||||
"unauthorized": "未登陆",
|
||||
"unauthorizedDescription": "登陆以探索整个 Solar Network。"
|
||||
"unauthorizedDescription": "登陆以探索整个 Solar Network。",
|
||||
"serviceStatus": "服务状态",
|
||||
"termRelated": "相关条款",
|
||||
"appDetails": "应用程序详情"
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ import 'package:surface/screens/realm/manage.dart';
|
||||
import 'package:surface/screens/realm/realm_detail.dart';
|
||||
import 'package:surface/screens/settings.dart';
|
||||
import 'package:surface/types/post.dart';
|
||||
import 'package:surface/widgets/about.dart';
|
||||
import 'package:surface/widgets/navigation/app_background.dart';
|
||||
import 'package:surface/widgets/navigation/app_scaffold.dart';
|
||||
|
||||
@ -301,6 +302,18 @@ final _appRoutes = [
|
||||
),
|
||||
],
|
||||
),
|
||||
ShellRoute(
|
||||
builder: (context, state, child) => AppPageScaffold(body: child),
|
||||
routes: [
|
||||
GoRoute(
|
||||
path: '/about',
|
||||
name: 'about',
|
||||
builder: (context, state) => const AppBackground(
|
||||
child: AboutScreen(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
final appRouter = GoRouter(
|
||||
|
@ -5,6 +5,7 @@ import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:image_picker/image_picker.dart';
|
||||
import 'package:material_symbols_icons/symbols.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
@ -41,8 +42,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
SharedPreferences.getInstance().then((prefs) {
|
||||
setState(() {
|
||||
_prefs = prefs;
|
||||
_serverUrlController.text =
|
||||
prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||
_serverUrlController.text = prefs.getString(kNetworkServerStoreKey) ?? kNetworkServerDefault;
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -65,11 +65,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('settingsAppearance')
|
||||
.bold()
|
||||
.fontSize(17)
|
||||
.tr()
|
||||
.padding(horizontal: 20, bottom: 4),
|
||||
Text('settingsAppearance').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
||||
if (!kIsWeb)
|
||||
ListTile(
|
||||
title: Text('settingsBackgroundImage').tr(),
|
||||
@ -78,20 +74,17 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
leading: const Icon(Symbols.image),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
onTap: () async {
|
||||
final image = await ImagePicker()
|
||||
.pickImage(source: ImageSource.gallery);
|
||||
final image = await ImagePicker().pickImage(source: ImageSource.gallery);
|
||||
if (image == null) return;
|
||||
|
||||
await File(image.path)
|
||||
.copy('$_docBasepath/app_background_image');
|
||||
await File(image.path).copy('$_docBasepath/app_background_image');
|
||||
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
if (!kIsWeb)
|
||||
FutureBuilder<bool>(
|
||||
future:
|
||||
File('$_docBasepath/app_background_image').exists(),
|
||||
future: File('$_docBasepath/app_background_image').exists(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData || !snapshot.data!) {
|
||||
return const SizedBox.shrink();
|
||||
@ -99,16 +92,12 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
|
||||
return ListTile(
|
||||
title: Text('settingsBackgroundImageClear').tr(),
|
||||
subtitle:
|
||||
Text('settingsBackgroundImageClearDescription')
|
||||
.tr(),
|
||||
contentPadding:
|
||||
const EdgeInsets.symmetric(horizontal: 24),
|
||||
subtitle: Text('settingsBackgroundImageClearDescription').tr(),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
leading: const Icon(Symbols.texture),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
onTap: () {
|
||||
File('$_docBasepath/app_background_image')
|
||||
.deleteSync();
|
||||
File('$_docBasepath/app_background_image').deleteSync();
|
||||
setState(() {});
|
||||
},
|
||||
);
|
||||
@ -136,11 +125,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('settingsNetwork')
|
||||
.bold()
|
||||
.fontSize(17)
|
||||
.tr()
|
||||
.padding(horizontal: 20, bottom: 4),
|
||||
Text('settingsNetwork').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
||||
TextField(
|
||||
controller: _serverUrlController,
|
||||
decoration: InputDecoration(
|
||||
@ -161,8 +146,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
},
|
||||
),
|
||||
),
|
||||
onTapOutside: (_) =>
|
||||
FocusManager.instance.primaryFocus?.unfocus(),
|
||||
onTapOutside: (_) => FocusManager.instance.primaryFocus?.unfocus(),
|
||||
).padding(horizontal: 16, top: 8, bottom: 4),
|
||||
ListTile(
|
||||
title: Text('settingsNetworkServerPreset').tr(),
|
||||
@ -174,9 +158,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
isExpanded: true,
|
||||
items: [
|
||||
...kNetworkServerDirectory,
|
||||
if (!kNetworkServerDirectory
|
||||
.map((ele) => ele.$2)
|
||||
.contains(_serverUrlController.text))
|
||||
if (!kNetworkServerDirectory.map((ele) => ele.$2).contains(_serverUrlController.text))
|
||||
('Custom', _serverUrlController.text),
|
||||
]
|
||||
.map(
|
||||
@ -188,8 +170,7 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(item.$1).fontSize(14),
|
||||
Text(item.$2, overflow: TextOverflow.ellipsis)
|
||||
.fontSize(11)
|
||||
Text(item.$2, overflow: TextOverflow.ellipsis).fontSize(11)
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -232,6 +213,22 @@ class _SettingsScreenState extends State<SettingsScreen> {
|
||||
),
|
||||
],
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('settingsMisc').bold().fontSize(17).tr().padding(horizontal: 20, bottom: 4),
|
||||
ListTile(
|
||||
title: Text('settingsMiscAbout').tr(),
|
||||
subtitle: Text('settingsMiscAboutDescription').tr(),
|
||||
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
leading: const Icon(Symbols.info),
|
||||
trailing: const Icon(Symbols.chevron_right),
|
||||
onTap: () async {
|
||||
GoRouter.of(context).pushNamed('about');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
].expand((ele) => [ele, const Gap(16)]).toList(),
|
||||
).padding(vertical: 20),
|
||||
),
|
||||
|
109
lib/widgets/about.dart
Normal file
109
lib/widgets/about.dart
Normal file
@ -0,0 +1,109 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:gap/gap.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
import 'package:url_launcher/url_launcher_string.dart';
|
||||
|
||||
class AboutScreen extends StatelessWidget {
|
||||
const AboutScreen({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
const denseButtonStyle = ButtonStyle(visualDensity: VisualDensity(vertical: -4));
|
||||
|
||||
return SizedBox(
|
||||
width: double.infinity,
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
child: Image.asset('assets/icon/icon-light-radius.png', width: 120, height: 120),
|
||||
),
|
||||
const Gap(8),
|
||||
Text(
|
||||
'Solian',
|
||||
style: Theme.of(context).textTheme.titleLarge!.copyWith(fontSize: 36),
|
||||
),
|
||||
const Text(
|
||||
'The Solar Network',
|
||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
|
||||
),
|
||||
const Gap(8),
|
||||
FutureBuilder(
|
||||
future: PackageInfo.fromPlatform(),
|
||||
builder: (context, snapshot) {
|
||||
if (!snapshot.hasData) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
|
||||
return Text(
|
||||
'v${snapshot.data!.version} · ${snapshot.data!.buildNumber}',
|
||||
style: const TextStyle(fontFamily: 'monospace'),
|
||||
);
|
||||
},
|
||||
),
|
||||
Text('Copyright © ${DateTime.now().year} Solsynth LLC'),
|
||||
const Gap(16),
|
||||
Container(
|
||||
constraints: const BoxConstraints(maxWidth: 280),
|
||||
child: Wrap(
|
||||
spacing: 4,
|
||||
runSpacing: 4,
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
TextButton(
|
||||
style: denseButtonStyle,
|
||||
child: Text('appDetails').tr(),
|
||||
onPressed: () async {
|
||||
final info = await PackageInfo.fromPlatform();
|
||||
|
||||
if (!context.mounted) return;
|
||||
showAboutDialog(
|
||||
context: context,
|
||||
applicationName: 'Solian',
|
||||
applicationVersion: '${info.version}+${info.buildNumber}',
|
||||
applicationLegalese:
|
||||
'The Solar Network App is an intuitive and open-source social network and computing platform. Experience the freedom of a user-friendly design that empowers you to create and connect with communities on your own terms. Embrace the future of social networking with a platform that prioritizes your independence and privacy.',
|
||||
applicationIcon: ClipRRect(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
||||
child: Image.asset(
|
||||
'assets/icon/icon-light-radius.png',
|
||||
width: 60,
|
||||
height: 60,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
style: denseButtonStyle,
|
||||
child: Text('termRelated').tr(),
|
||||
onPressed: () {
|
||||
launchUrlString('https://solsynth.dev/terms');
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
style: denseButtonStyle,
|
||||
child: Text('serviceStatus').tr(),
|
||||
onPressed: () {
|
||||
launchUrlString('https://status.solsynth.dev');
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
).center(),
|
||||
const Gap(16),
|
||||
const Text(
|
||||
'Open-sourced under AGPLv3',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w300,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:responsive_framework/responsive_framework.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
@ -48,9 +49,14 @@ class _AppNavigationDrawerState extends State<AppNavigationDrawer> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Solar Network').bold(),
|
||||
Text('Canary Preview 2.0α')
|
||||
.fontSize(12)
|
||||
.textColor(Theme.of(context).colorScheme.onSurface.withOpacity(0.5)),
|
||||
FutureBuilder<String>(
|
||||
future: PackageInfo.fromPlatform().then((value) => 'Stable ${value.version}+${value.buildNumber}'),
|
||||
builder: (context, snapshot) {
|
||||
return Text(!snapshot.hasData ? 'Stable 2.0' : snapshot.data!)
|
||||
.fontSize(12)
|
||||
.textColor(Theme.of(context).colorScheme.onSurface.withOpacity(0.5));
|
||||
},
|
||||
),
|
||||
],
|
||||
).padding(
|
||||
horizontal: 32,
|
||||
|
@ -955,7 +955,7 @@ packages:
|
||||
source: hosted
|
||||
version: "0.2.1+1"
|
||||
intl:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl
|
||||
sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
|
||||
@ -1227,7 +1227,7 @@ packages:
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
package_info_plus:
|
||||
dependency: transitive
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: package_info_plus
|
||||
sha256: da8d9ac8c4b1df253d1a328b7bf01ae77ef132833479ab40763334db13b91cce
|
||||
|
@ -98,6 +98,8 @@ dependencies:
|
||||
gal: ^2.3.0
|
||||
share_plus: ^10.1.2
|
||||
email_validator: ^3.0.0
|
||||
package_info_plus: ^8.1.1
|
||||
intl: ^0.19.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -130,6 +132,7 @@ flutter:
|
||||
# To add assets to your application, add an assets section, like this:
|
||||
assets:
|
||||
- assets/icon/icon.png
|
||||
- assets/icon/icon-light-radius.png
|
||||
- assets/translations/
|
||||
|
||||
# An image asset can refer to one or more resolution-specific "variants", see
|
||||
|
Loading…
Reference in New Issue
Block a user