Compare commits
9 Commits
1.2.1+41
...
befc647b03
| Author | SHA1 | Date | |
|---|---|---|---|
| befc647b03 | |||
| 16b2e3a0c7 | |||
| 0cc842c030 | |||
| fb370a484d | |||
| 153c15e5c9 | |||
| 6a0f42cdc9 | |||
| 01aaa5455e | |||
| f3ceb5f967 | |||
| b5e2fa4c25 |
@@ -428,9 +428,17 @@
|
|||||||
"preferencesApplied": "Preferences has been applied.",
|
"preferencesApplied": "Preferences has been applied.",
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"updateAvailable": "Update available",
|
"updateAvailable": "Update available",
|
||||||
"updateAvailableDesc": "There is an update available (@version). Do you want to download and install it now? You can still use the app normally while waiting for the download to complete.",
|
"updateAvailableDesc": "There is an update available (@from to @to). Do you want to download and install it now? You can still use the app normally while waiting for the download to complete.",
|
||||||
"update": "Update",
|
"update": "Update",
|
||||||
"updateCheckStrictly": "Strict mode",
|
"updateCheckStrictly": "Strict mode",
|
||||||
"updateCheckStrictlyDesc": "If enabled, the app will ask for updating once the local version is different from remote one.",
|
"updateCheckStrictlyDesc": "If enabled, the app will ask for updating once the local version is different from remote one.",
|
||||||
"updateMayAvailable": "App version @version is available, you can update from app store or our website."
|
"updateMayAvailable": "App version @version is available, you can update from app store or our website.",
|
||||||
|
"termAccept": "I've read and agree to Solar Network's Terms",
|
||||||
|
"termAcceptDesc": "Including but not limited to \"User Agreement\" and \"Privacy Policy\"",
|
||||||
|
"termAcceptLink": "View terms",
|
||||||
|
"termAcceptNextWithAgree": "By clicking the \"Next\", it means you agree to our terms and its updates. You should already agreed with them while you sign up.",
|
||||||
|
"termRelated": "Related Terms",
|
||||||
|
"appDetails": "App Details",
|
||||||
|
"projectWebsite": "Project Website",
|
||||||
|
"iAmNotRobot": "I'm not a Robot"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -428,5 +428,13 @@
|
|||||||
"update": "更新",
|
"update": "更新",
|
||||||
"updateCheckStrictly": "严格模式",
|
"updateCheckStrictly": "严格模式",
|
||||||
"updateCheckStrictlyDesc": "如果启用,应用程序将会在本地版本与远程版本不同时询问更新,而不会检查版本号大小。",
|
"updateCheckStrictlyDesc": "如果启用,应用程序将会在本地版本与远程版本不同时询问更新,而不会检查版本号大小。",
|
||||||
"updateMayAvailable": "版本 @version 现已可用,你可以前往应用商店或是我们的官网下载更新。"
|
"updateMayAvailable": "版本 @version 现已可用,你可以前往应用商店或是我们的官网下载更新。",
|
||||||
|
"termAccept": "我已阅读并同意 Solar Network 各项条款",
|
||||||
|
"termAcceptDesc": "包括但不限于《用户守则》和《隐私政策》",
|
||||||
|
"termAcceptLink": "浏览条款",
|
||||||
|
"termAcceptNextWithAgree": "点击 “下一步”,即表示你同意我们的各项条款,包括其之后的更新。你应该在注册时已经同意过了。",
|
||||||
|
"termRelated": "相关条款",
|
||||||
|
"projectWebsite": "项目网站",
|
||||||
|
"appDetails": "应用详情",
|
||||||
|
"iAmNotRobot": "我不是机器人"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,12 +60,19 @@ class _BootstrapperShellState extends State<BootstrapperShell> {
|
|||||||
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?page=1&limit=1',
|
'https://git.solsynth.dev/api/v1/repos/hydrogen/solian/tags?page=1&limit=1',
|
||||||
);
|
);
|
||||||
final remoteVersionString =
|
final remoteVersionString =
|
||||||
(resp.body as List).firstOrNull?['name'] ?? '0.0.0';
|
(resp.body as List).firstOrNull?['name'] ?? '0.0.0+0';
|
||||||
final remoteVersion = Version.parse(remoteVersionString ?? '0.0.0');
|
final remoteVersion =
|
||||||
|
Version.parse(remoteVersionString.split('+').first);
|
||||||
final localVersion =
|
final localVersion =
|
||||||
Version.parse(localVersionString.split('+').first);
|
Version.parse(localVersionString.split('+').first);
|
||||||
|
final remoteBuildNumber =
|
||||||
|
int.tryParse(remoteVersionString.split('+').last) ?? 0;
|
||||||
|
final localBuildNumber =
|
||||||
|
int.tryParse(localVersionString.split('+').last) ?? 0;
|
||||||
final strictUpdate = prefs.getBool('check_update_strictly') ?? false;
|
final strictUpdate = prefs.getBool('check_update_strictly') ?? false;
|
||||||
if (remoteVersion > localVersion ||
|
if (remoteVersion > localVersion ||
|
||||||
|
(remoteVersion == localVersion &&
|
||||||
|
remoteBuildNumber > localBuildNumber) ||
|
||||||
(remoteVersionString != localVersionString && strictUpdate)) {
|
(remoteVersionString != localVersionString && strictUpdate)) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_isErrored = true;
|
_isErrored = true;
|
||||||
|
|||||||
@@ -89,13 +89,13 @@ class ChannelProvider extends GetxController {
|
|||||||
return resp;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Response> listAvailableChannel({String realm = 'global'}) async {
|
Future<Response> listAvailableChannel({String scope = 'global'}) async {
|
||||||
final AuthProvider auth = Get.find();
|
final AuthProvider auth = Get.find();
|
||||||
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
if (auth.isAuthorized.isFalse) throw const UnauthorizedException();
|
||||||
|
|
||||||
final client = await auth.configureClient('messaging');
|
final client = await auth.configureClient('messaging');
|
||||||
|
|
||||||
final resp = await client.get('/channels/$realm/me/available');
|
final resp = await client.get('/channels/$scope/me/available');
|
||||||
if (resp.statusCode != 200) {
|
if (resp.statusCode != 200) {
|
||||||
throw RequestException(resp);
|
throw RequestException(resp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:gap/gap.dart';
|
import 'package:gap/gap.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:package_info_plus/package_info_plus.dart';
|
import 'package:package_info_plus/package_info_plus.dart';
|
||||||
|
import 'package:solian/widgets/sized_container.dart';
|
||||||
import 'package:url_launcher/url_launcher_string.dart';
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class AboutScreen extends StatelessWidget {
|
class AboutScreen extends StatelessWidget {
|
||||||
@@ -47,32 +49,51 @@ class AboutScreen extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
Text('Copyright © ${DateTime.now().year} Solsynth LLC'),
|
Text('Copyright © ${DateTime.now().year} Solsynth LLC'),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
|
CenteredContainer(
|
||||||
|
maxWidth: 280,
|
||||||
|
child: Wrap(
|
||||||
|
spacing: 8,
|
||||||
|
runSpacing: 8,
|
||||||
|
children: [
|
||||||
TextButton(
|
TextButton(
|
||||||
style: denseButtonStyle,
|
style: denseButtonStyle,
|
||||||
child: const Text('App Details'),
|
child: Text('appDetails'.tr),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final info = await PackageInfo.fromPlatform();
|
final info = await PackageInfo.fromPlatform();
|
||||||
|
|
||||||
showAboutDialog(
|
showAboutDialog(
|
||||||
context: context,
|
context: context,
|
||||||
applicationVersion: '${info.version} (${info.buildNumber})',
|
applicationVersion:
|
||||||
|
'${info.version} (${info.buildNumber})',
|
||||||
applicationLegalese:
|
applicationLegalese:
|
||||||
'The Solar Network App is an intuitive and self-hostable 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.',
|
'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(
|
applicationIcon: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(16)),
|
borderRadius:
|
||||||
child:
|
const BorderRadius.all(Radius.circular(16)),
|
||||||
Image.asset('assets/logo.png', width: 60, height: 60),
|
child: Image.asset('assets/logo.png',
|
||||||
|
width: 60, height: 60),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
style: denseButtonStyle,
|
style: denseButtonStyle,
|
||||||
child: const Text('Project Website'),
|
child: Text('projectWebsite'.tr),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
launchUrlString('https://solsynth.dev/products/solar-network');
|
launchUrlString(
|
||||||
|
'https://solsynth.dev/products/solar-network');
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
TextButton(
|
||||||
|
style: denseButtonStyle,
|
||||||
|
child: Text('termRelated'.tr),
|
||||||
|
onPressed: () {
|
||||||
|
launchUrlString('https://solsynth.dev/terms');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
const Text(
|
const Text(
|
||||||
'Open-sourced under AGPLv3',
|
'Open-sourced under AGPLv3',
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import 'package:solian/providers/relation.dart';
|
|||||||
import 'package:solian/providers/websocket.dart';
|
import 'package:solian/providers/websocket.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
import 'package:solian/widgets/sized_container.dart';
|
import 'package:solian/widgets/sized_container.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class SignInScreen extends StatefulWidget {
|
class SignInScreen extends StatefulWidget {
|
||||||
const SignInScreen({super.key});
|
const SignInScreen({super.key});
|
||||||
@@ -167,7 +168,6 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
|
|
||||||
final result = AuthResult.fromJson(resp.body);
|
final result = AuthResult.fromJson(resp.body);
|
||||||
_currentTicket = result.ticket;
|
_currentTicket = result.ticket;
|
||||||
_passwordController.clear();
|
|
||||||
|
|
||||||
// Finish sign in if possible
|
// Finish sign in if possible
|
||||||
if (result.isFinished) {
|
if (result.isFinished) {
|
||||||
@@ -185,11 +185,13 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
autoStartBackgroundNotificationService();
|
autoStartBackgroundNotificationService();
|
||||||
|
|
||||||
Navigator.pop(context, true);
|
Navigator.pop(context, true);
|
||||||
|
_passwordController.clear();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Skip the first step
|
// Skip the first step
|
||||||
_factorPicked = null;
|
_factorPicked = null;
|
||||||
_factorPickedType = null;
|
_factorPickedType = null;
|
||||||
|
_passwordController.clear();
|
||||||
setState(() => _period += 2);
|
setState(() => _period += 2);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -210,9 +212,8 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
case 2:
|
case 2:
|
||||||
_passwordController.clear();
|
_passwordController.clear();
|
||||||
_factorPickedType = null;
|
_factorPickedType = null;
|
||||||
default:
|
|
||||||
setState(() => _period--);
|
|
||||||
}
|
}
|
||||||
|
setState(() => _period--);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -235,16 +236,18 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: switch (_period % 3) {
|
child: switch (_period % 3) {
|
||||||
1 => Column(
|
1 => ListView(
|
||||||
|
shrinkWrap: true,
|
||||||
key: const ValueKey<int>(1),
|
key: const ValueKey<int>(1),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
child:
|
child:
|
||||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||||
).paddingOnly(bottom: 8, left: 4),
|
).paddingOnly(bottom: 8, left: 4),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
'signinPickFactor'.tr,
|
'signinPickFactor'.tr,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -323,16 +326,18 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
2 => Column(
|
2 => ListView(
|
||||||
key: const ValueKey<int>(2),
|
key: const ValueKey<int>(2),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
shrinkWrap: true,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
child:
|
child:
|
||||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||||
).paddingOnly(bottom: 8, left: 4),
|
).paddingOnly(bottom: 8, left: 4),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
'signinEnterPassword'.tr,
|
'signinEnterPassword'.tr,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -396,16 +401,18 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
_ => Column(
|
_ => ListView(
|
||||||
key: const ValueKey<int>(0),
|
key: const ValueKey<int>(0),
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
shrinkWrap: true,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
child:
|
child:
|
||||||
Image.asset('assets/logo.png', width: 64, height: 64),
|
Image.asset('assets/logo.png', width: 64, height: 64),
|
||||||
).paddingOnly(bottom: 8, left: 4),
|
).paddingOnly(bottom: 8, left: 4),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
'signinGreeting'.tr,
|
'signinGreeting'.tr,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -451,11 +458,50 @@ class _SignInScreenState extends State<SignInScreen> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
const Gap(12),
|
||||||
|
Align(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
child: Container(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 290),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'termAcceptNextWithAgree'.tr,
|
||||||
|
textAlign: TextAlign.end,
|
||||||
|
style:
|
||||||
|
Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withOpacity(0.75),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text('termAcceptLink'.tr),
|
||||||
|
const Gap(4),
|
||||||
|
const Icon(Icons.launch, size: 14),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
launchUrlString('https://solsynth.dev/terms');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
).paddingSymmetric(horizontal: 16),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
).paddingAll(24),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import 'package:get/get.dart';
|
|||||||
import 'package:solian/exts.dart';
|
import 'package:solian/exts.dart';
|
||||||
import 'package:solian/services.dart';
|
import 'package:solian/services.dart';
|
||||||
import 'package:solian/widgets/sized_container.dart';
|
import 'package:solian/widgets/sized_container.dart';
|
||||||
|
import 'package:url_launcher/url_launcher_string.dart';
|
||||||
|
|
||||||
class SignUpScreen extends StatefulWidget {
|
class SignUpScreen extends StatefulWidget {
|
||||||
const SignUpScreen({super.key});
|
const SignUpScreen({super.key});
|
||||||
@@ -18,7 +19,7 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
final _nicknameController = TextEditingController();
|
final _nicknameController = TextEditingController();
|
||||||
final _passwordController = TextEditingController();
|
final _passwordController = TextEditingController();
|
||||||
|
|
||||||
void performAction(BuildContext context) async {
|
void _performAction(BuildContext context) async {
|
||||||
final email = _emailController.value.text;
|
final email = _emailController.value.text;
|
||||||
final username = _usernameController.value.text;
|
final username = _usernameController.value.text;
|
||||||
final nickname = _nicknameController.value.text;
|
final nickname = _nicknameController.value.text;
|
||||||
@@ -60,20 +61,24 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool _isTermAccepted = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Material(
|
return Material(
|
||||||
color: Theme.of(context).colorScheme.surface,
|
color: Theme.of(context).colorScheme.surface,
|
||||||
child: CenteredContainer(
|
child: CenteredContainer(
|
||||||
maxWidth: 360,
|
maxWidth: 360,
|
||||||
child: Column(
|
child: ListView(
|
||||||
mainAxisSize: MainAxisSize.min,
|
shrinkWrap: true,
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
children: [
|
||||||
ClipRRect(
|
Align(
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
child: ClipRRect(
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
||||||
child: Image.asset('assets/logo.png', width: 64, height: 64),
|
child: Image.asset('assets/logo.png', width: 64, height: 64),
|
||||||
).paddingOnly(bottom: 8, left: 4),
|
).paddingOnly(bottom: 8, left: 4),
|
||||||
|
),
|
||||||
Text(
|
Text(
|
||||||
'signupGreeting'.tr,
|
'signupGreeting'.tr,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
@@ -136,12 +141,58 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
),
|
),
|
||||||
onTapOutside: (_) =>
|
onTapOutside: (_) =>
|
||||||
FocusManager.instance.primaryFocus?.unfocus(),
|
FocusManager.instance.primaryFocus?.unfocus(),
|
||||||
onSubmitted: (_) => performAction(context),
|
onSubmitted: (_) => _performAction(context),
|
||||||
|
),
|
||||||
|
const Gap(8),
|
||||||
|
CheckboxListTile(
|
||||||
|
value: _isTermAccepted,
|
||||||
|
title: Text('termAccept'.tr),
|
||||||
|
shape: const RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.all(
|
||||||
|
Radius.circular(8),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
subtitle: RichText(
|
||||||
|
text: TextSpan(
|
||||||
|
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSurface
|
||||||
|
.withOpacity(0.75),
|
||||||
|
),
|
||||||
|
children: [
|
||||||
|
TextSpan(text: 'termAcceptDesc'.tr),
|
||||||
|
WidgetSpan(
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: InkWell(
|
||||||
|
child: Row(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text('termAcceptLink'.tr),
|
||||||
|
const Gap(4),
|
||||||
|
const Icon(Icons.launch, size: 14),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () {
|
||||||
|
launchUrlString('https://solsynth.dev/terms');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onChanged: (value) {
|
||||||
|
setState(() => _isTermAccepted = value ?? false);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
const Gap(16),
|
const Gap(16),
|
||||||
Align(
|
Align(
|
||||||
alignment: Alignment.centerRight,
|
alignment: Alignment.centerRight,
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
|
onPressed:
|
||||||
|
!_isTermAccepted ? null : () => _performAction(context),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
@@ -149,12 +200,11 @@ class _SignUpScreenState extends State<SignUpScreen> {
|
|||||||
const Icon(Icons.chevron_right),
|
const Icon(Icons.chevron_right),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
onPressed: () => performAction(context),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
).paddingAll(24),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,6 +115,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
leading: const Icon(Icons.settings),
|
leading: const Icon(Icons.settings),
|
||||||
trailing: const Icon(Icons.chevron_right),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
title: Text('channelSettings'.tr),
|
title: Text('channelSettings'.tr),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
AppRouter.instance
|
AppRouter.instance
|
||||||
.pushNamed(
|
.pushNamed(
|
||||||
@@ -174,6 +175,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
leading: const Icon(Icons.notifications_active),
|
leading: const Icon(Icons.notifications_active),
|
||||||
title: Text('channelNotifyLevel'.tr),
|
title: Text('channelNotifyLevel'.tr),
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
trailing: DropdownButtonHideUnderline(
|
trailing: DropdownButtonHideUnderline(
|
||||||
child: DropdownButton2<int>(
|
child: DropdownButton2<int>(
|
||||||
isExpanded: true,
|
isExpanded: true,
|
||||||
@@ -206,6 +208,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
leading: const Icon(Icons.supervisor_account),
|
leading: const Icon(Icons.supervisor_account),
|
||||||
trailing: const Icon(Icons.chevron_right),
|
trailing: const Icon(Icons.chevron_right),
|
||||||
title: Text('channelMembers'.tr),
|
title: Text('channelMembers'.tr),
|
||||||
@@ -214,6 +217,7 @@ class _ChannelDetailScreenState extends State<ChannelDetailScreen> {
|
|||||||
...(_isOwned ? ownerActions : List.empty()),
|
...(_isOwned ? ownerActions : List.empty()),
|
||||||
const Divider(thickness: 0.3),
|
const Divider(thickness: 0.3),
|
||||||
ListTile(
|
ListTile(
|
||||||
|
contentPadding: const EdgeInsets.symmetric(horizontal: 24),
|
||||||
leading: _isOwned
|
leading: _isOwned
|
||||||
? const Icon(Icons.delete)
|
? const Icon(Icons.delete)
|
||||||
: const Icon(Icons.exit_to_app),
|
: const Icon(Icons.exit_to_app),
|
||||||
|
|||||||
@@ -183,18 +183,18 @@ class _PostPublishScreenState extends State<PostPublishScreen> {
|
|||||||
children: [
|
children: [
|
||||||
ListTile(
|
ListTile(
|
||||||
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
tileColor: Theme.of(context).colorScheme.surfaceContainerLow,
|
||||||
title: Row(
|
title: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
_editorController.title ?? 'title'.tr,
|
_editorController.title ?? 'title'.tr,
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
const Gap(6),
|
|
||||||
if (_editorController.aliasController.text.isNotEmpty)
|
if (_editorController.aliasController.text.isNotEmpty)
|
||||||
Badge(
|
Badge(
|
||||||
label: Text('#${_editorController.aliasController.text}'),
|
label: Text('#${_editorController.aliasController.text}'),
|
||||||
),
|
).paddingOnly(bottom: 2),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
|
|||||||
final List<Channel> _channels = List.empty(growable: true);
|
final List<Channel> _channels = List.empty(growable: true);
|
||||||
|
|
||||||
getRealm({String? overrideAlias}) async {
|
getRealm({String? overrideAlias}) async {
|
||||||
final RealmProvider provider = Get.find();
|
final RealmProvider realm = Get.find();
|
||||||
|
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final resp = await provider.getRealm(_overrideAlias ?? widget.alias);
|
final resp = await realm.getRealm(_overrideAlias ?? widget.alias);
|
||||||
setState(() => _realm = Realm.fromJson(resp.body));
|
setState(() => _realm = Realm.fromJson(resp.body));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
context.showErrorDialog(e);
|
context.showErrorDialog(e);
|
||||||
@@ -55,14 +55,26 @@ class _RealmViewScreenState extends State<RealmViewScreen> {
|
|||||||
getChannels() async {
|
getChannels() async {
|
||||||
setState(() => _isBusy = true);
|
setState(() => _isBusy = true);
|
||||||
|
|
||||||
final ChannelProvider provider = Get.find();
|
final ChannelProvider channel = Get.find();
|
||||||
final resp = await provider.listChannel(scope: _realm!.alias);
|
final resp = await channel.listChannel(scope: _realm!.alias);
|
||||||
|
final availableResp = await channel.listAvailableChannel(
|
||||||
|
scope: _realm!.alias,
|
||||||
|
);
|
||||||
|
|
||||||
|
final Set<int> channelIdx = {};
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_channels.clear();
|
_channels.clear();
|
||||||
_channels.addAll(
|
_channels.addAll(
|
||||||
resp.body.map((e) => Channel.fromJson(e)).toList().cast<Channel>(),
|
resp.body.map((e) => Channel.fromJson(e)).toList().cast<Channel>(),
|
||||||
);
|
);
|
||||||
|
_channels.addAll(
|
||||||
|
availableResp.body
|
||||||
|
.map((e) => Channel.fromJson(e))
|
||||||
|
.toList()
|
||||||
|
.cast<Channel>(),
|
||||||
|
);
|
||||||
|
_channels.retainWhere((x) => channelIdx.add(x.id));
|
||||||
});
|
});
|
||||||
|
|
||||||
setState(() => _isBusy = false);
|
setState(() => _isBusy = false);
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ abstract class AppTheme {
|
|||||||
brightness: brightness,
|
brightness: brightness,
|
||||||
seedColor: seedColor ?? const Color.fromRGBO(154, 98, 91, 1),
|
seedColor: seedColor ?? const Color.fromRGBO(154, 98, 91, 1),
|
||||||
),
|
),
|
||||||
|
snackBarTheme: const SnackBarThemeData(
|
||||||
|
behavior: SnackBarBehavior.floating,
|
||||||
|
),
|
||||||
fontFamily: 'Comfortaa',
|
fontFamily: 'Comfortaa',
|
||||||
fontFamilyFallback: [
|
fontFamilyFallback: [
|
||||||
'NotoSansSC',
|
'NotoSansSC',
|
||||||
|
|||||||
@@ -341,7 +341,9 @@ class _PostItemState extends State<PostItem> {
|
|||||||
if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
if (!snapshot.hasData || snapshot.data!.isEmpty) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
return Card(
|
return Container(
|
||||||
|
constraints: const BoxConstraints(maxWidth: 480),
|
||||||
|
child: Card(
|
||||||
margin: EdgeInsets.zero,
|
margin: EdgeInsets.zero,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: snapshot.data!
|
children: snapshot.data!
|
||||||
@@ -400,6 +402,7 @@ class _PostItemState extends State<PostItem> {
|
|||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.animate()
|
.animate()
|
||||||
.fadeIn(
|
.fadeIn(
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ name: solian
|
|||||||
description: "The Solar Network App"
|
description: "The Solar Network App"
|
||||||
publish_to: "none"
|
publish_to: "none"
|
||||||
|
|
||||||
version: 1.2.1+41
|
version: 1.2.2+3
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=3.3.4 <4.0.0"
|
sdk: ">=3.3.4 <4.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user