Server selection and login are on different pages. #33
5 changed files with 247 additions and 173 deletions
Login is on seperated page and for the server selection only the cards instead of the entire page are scrollable.
commit
5ad85d3f62
|
|
@ -9,6 +9,14 @@ class ClientStateController extends Notifier<ClientState?> {
|
||||||
state = newState;
|
state = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setHomeServer(String homeserver){
|
||||||
|
Henry-Hiles marked this conversation as resolved
Outdated
|
|||||||
|
state = .new(isInitialized: state?.isInitialized ?? false,
|
||||||
|
isLoggedIn: state?.isLoggedIn ?? false,
|
||||||
|
isVerified: state?.isVerified ?? false,
|
||||||
|
userId: state?.userId,
|
||||||
|
homeserverUrl: homeserver);
|
||||||
|
}
|
||||||
|
|
||||||
static final provider = NotifierProvider<ClientStateController, ClientState?>(
|
static final provider = NotifierProvider<ClientStateController, ClientState?>(
|
||||||
ClientStateController.new,
|
ClientStateController.new,
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import "package:nexus/helpers/extensions/better_when.dart";
|
||||||
import "package:nexus/helpers/extensions/scheme_to_theme.dart";
|
import "package:nexus/helpers/extensions/scheme_to_theme.dart";
|
||||||
import "package:nexus/pages/chat_page.dart";
|
import "package:nexus/pages/chat_page.dart";
|
||||||
import "package:nexus/pages/login_page.dart";
|
import "package:nexus/pages/login_page.dart";
|
||||||
|
import "package:nexus/pages/select_server_page.dart";
|
||||||
import "package:nexus/pages/verify_page.dart";
|
import "package:nexus/pages/verify_page.dart";
|
||||||
import "package:nexus/widgets/error_dialog.dart";
|
import "package:nexus/widgets/error_dialog.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
@ -123,7 +124,9 @@ class App extends StatelessWidget {
|
||||||
return Loading();
|
return Loading();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!clientState.isLoggedIn) {
|
if ((!clientState.isLoggedIn) && (clientState.homeserverUrl == null || clientState.homeserverUrl?.isEmpty == true)) {
|
||||||
|
return SelectServerPage();
|
||||||
|
Henry-Hiles marked this conversation as resolved
Outdated
Henry-Hiles
commented
I don't think this logic needs to be changed this much. If you can keep the previous logic, but instead show ServerSelectPage instead of login, we can take a different approach to push the login. I don't think this logic needs to be changed this much. If you can keep the previous logic, but instead show ServerSelectPage instead of login, we can take a different approach to push the login.
|
|||||||
|
} else if(!clientState.isLoggedIn) {
|
||||||
return LoginPage();
|
return LoginPage();
|
||||||
} else if (!clientState.isVerified) {
|
} else if (!clientState.isVerified) {
|
||||||
return VerifyPage();
|
return VerifyPage();
|
||||||
|
|
|
||||||
|
|
@ -1,185 +1,64 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:flutter_svg/flutter_svg.dart";
|
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
import "package:nexus/helpers/launch_helper.dart";
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
import "package:nexus/models/homeserver.dart";
|
|
||||||
import "package:nexus/models/requests/login_request.dart";
|
import "package:nexus/models/requests/login_request.dart";
|
||||||
import "package:nexus/widgets/appbar.dart";
|
import "package:nexus/widgets/appbar.dart";
|
||||||
import "package:nexus/widgets/divider_text.dart";
|
|
||||||
import "package:nexus/widgets/loading.dart";
|
|
||||||
|
|
||||||
class LoginPage extends HookConsumerWidget {
|
class LoginPage extends HookConsumerWidget {
|
||||||
const LoginPage({super.key});
|
const LoginPage({super.key});
|
||||||
|
Henry-Hiles marked this conversation as resolved
Henry-Hiles
commented
Lets take in Lets take in `final Uri homeserver` as an argument here, instead of using `ClientStateController`.
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final theme = Theme.of(context);
|
|
||||||
final client = ref.watch(ClientController.provider.notifier);
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
|
final isLoggingIn = useState(false);
|
||||||
|
final homeserverUrl = ref.watch(ClientStateController.provider)?.homeserverUrl;
|
||||||
|
|
||||||
final isLoading = useState(false);
|
if(homeserverUrl == null || homeserverUrl.trim().isEmpty) {
|
||||||
|
Henry-Hiles marked this conversation as resolved
Outdated
Henry-Hiles
commented
This will be redundant when it takes in a URI. This will be redundant when it takes in a URI.
|
|||||||
final homeserver = useState<String?>(null);
|
throw Exception("Homeserver URL must be set for login.");
|
||||||
|
|
||||||
final launch = ref.watch(LaunchHelper.provider).launchUrl;
|
|
||||||
|
|
||||||
Future<void> setHomeserver(Uri? newHomeserver) async {
|
|
||||||
isLoading.value = true;
|
|
||||||
|
|
||||||
homeserver.value = newHomeserver == null
|
|
||||||
? null
|
|
||||||
: await client.discoverHomeserver(
|
|
||||||
newHomeserver.hasScheme
|
|
||||||
? newHomeserver
|
|
||||||
: Uri.https(newHomeserver.path),
|
|
||||||
);
|
|
||||||
|
|
||||||
if (homeserver.value == null && context.mounted) {
|
|
||||||
ScaffoldMessenger.of(context).showSnackBar(
|
|
||||||
SnackBar(
|
|
||||||
content: Text(
|
|
||||||
"Homeserver verification failed. Is your homeserver down?",
|
|
||||||
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
|
||||||
),
|
|
||||||
backgroundColor: theme.colorScheme.errorContainer,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
isLoading.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final homeserverUrl = useTextEditingController();
|
final theme = Theme.of(context);
|
||||||
|
|
||||||
final username = useTextEditingController();
|
final username = useTextEditingController();
|
||||||
final password = useTextEditingController();
|
final password = useTextEditingController();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: Appbar(),
|
appBar: Appbar(),
|
||||||
body: Center(
|
body: AlertDialog(
|
||||||
child: ConstrainedBox(
|
title: Text("Login"),
|
||||||
constraints: BoxConstraints(maxWidth: 600),
|
content: Column(
|
||||||
child: ListView(
|
mainAxisSize: MainAxisSize.min,
|
||||||
padding: EdgeInsets.symmetric(horizontal: 16, vertical: 64),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Text(
|
||||||
children: [
|
"Enter your login credentials:",
|
||||||
SvgPicture.asset("assets/icon.svg", width: 128),
|
),
|
||||||
SizedBox(width: 12),
|
SizedBox(height: 12),
|
||||||
Expanded(
|
TextField(
|
||||||
child: Column(
|
decoration: InputDecoration(label: Text("Username")),
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
controller: username,
|
||||||
children: [
|
),
|
||||||
Text("Nexus", style: theme.textTheme.displayMedium),
|
SizedBox(height: 12),
|
||||||
Text(
|
TextField(
|
||||||
"A Simple Matrix Client",
|
decoration: InputDecoration(label: Text("Password")),
|
||||||
style: theme.textTheme.headlineMedium,
|
controller: password,
|
||||||
overflow: TextOverflow.ellipsis,
|
obscureText: true,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
actions: [
|
||||||
],
|
TextButton(
|
||||||
),
|
onPressed: isLoggingIn.value
|
||||||
Padding(
|
? null
|
||||||
padding: EdgeInsetsGeometry.symmetric(vertical: 12),
|
: () async {
|
||||||
child: Divider(),
|
isLoggingIn.value = true;
|
||||||
),
|
|
||||||
|
|
||||||
DividerText("Enter a homeserver domain:"),
|
|
||||||
Row(
|
|
||||||
spacing: 8,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
child: TextField(
|
|
||||||
controller: homeserverUrl,
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: "Homeserver URL (e.g. matrix.org)",
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
IconButton.filled(
|
|
||||||
tooltip: "Confirm homeserver choice",
|
|
||||||
onPressed: isLoading.value
|
|
||||||
? null
|
|
||||||
: () => setHomeserver(Uri.tryParse(homeserverUrl.text)),
|
|
||||||
icon: Icon(Icons.check),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
|
|
||||||
DividerText("Or, choose from some popular homeservers:"),
|
|
||||||
...(<Homeserver>[
|
|
||||||
Homeserver(
|
|
||||||
name: "Matrix.org",
|
|
||||||
description:
|
|
||||||
"The Matrix.org Foundation offers the matrix.org homeserver as an easy entry point for anyone wanting to try out Matrix.",
|
|
||||||
url: Uri.https("matrix.org"),
|
|
||||||
iconUrl:
|
|
||||||
"https://raw.githubusercontent.com/element-hq/logos/refs/heads/master/matrix/matrix-favicon${Theme.brightnessOf(context) == Brightness.dark ? "-white" : ""}.png",
|
|
||||||
),
|
|
||||||
Homeserver(
|
|
||||||
name: "Federated Nexus",
|
|
||||||
description:
|
|
||||||
"Federated Nexus is a community resource hosting multiple FOSS (especially federated) services, including Matrix and Forgejo. By the same developers who made Nexus client.",
|
|
||||||
url: Uri.https("federated.nexus"),
|
|
||||||
iconUrl: "https://federated.nexus/images/icon.png",
|
|
||||||
),
|
|
||||||
Homeserver(
|
|
||||||
name: "Unredacted",
|
|
||||||
description:
|
|
||||||
"Unredacted is a 501(c)(3) non-profit organization that builds Internet infrastructure and services to help people evade censorship and protect their right to privacy.",
|
|
||||||
url: Uri.https("unredacted.org", "services/si/matrix"),
|
|
||||||
iconUrl: "https://unredacted.org/favicon.ico",
|
|
||||||
),
|
|
||||||
].map(
|
|
||||||
(homeserver) => Card(
|
|
||||||
child: ListTile(
|
|
||||||
title: Text(homeserver.name),
|
|
||||||
leading: Image.network(
|
|
||||||
homeserver.iconUrl,
|
|
||||||
errorBuilder: (_, _, _) => SizedBox.shrink(),
|
|
||||||
height: 32,
|
|
||||||
),
|
|
||||||
subtitle: Text(homeserver.description),
|
|
||||||
onTap: isLoading.value
|
|
||||||
? null
|
|
||||||
: () => setHomeserver(homeserver.url),
|
|
||||||
trailing: IconButton(
|
|
||||||
tooltip: "Launch homeserver info page",
|
|
||||||
onPressed: () => launch(homeserver.url),
|
|
||||||
icon: Icon(Icons.info_outline),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)),
|
|
||||||
SizedBox(height: 8),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => launch(Uri.https("servers.joinmatrix.org")),
|
|
||||||
child: Text("See more homeservers..."),
|
|
||||||
),
|
|
||||||
if (isLoading.value)
|
|
||||||
Padding(padding: EdgeInsets.only(top: 32), child: Loading())
|
|
||||||
else if (homeserver.value != null) ...[
|
|
||||||
DividerText("Then, sign in:"),
|
|
||||||
SizedBox(height: 4),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(label: Text("Username")),
|
|
||||||
controller: username,
|
|
||||||
),
|
|
||||||
SizedBox(height: 12),
|
|
||||||
TextField(
|
|
||||||
decoration: InputDecoration(label: Text("Password")),
|
|
||||||
controller: password,
|
|
||||||
obscureText: true,
|
|
||||||
),
|
|
||||||
SizedBox(height: 12),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () async {
|
|
||||||
isLoading.value = true;
|
|
||||||
final error = await client.login(
|
final error = await client.login(
|
||||||
LoginRequest(
|
LoginRequest(
|
||||||
username: username.text,
|
username: username.text,
|
||||||
password: password.text,
|
password: password.text,
|
||||||
homeserverUrl: homeserver.value!,
|
homeserverUrl: homeserverUrl,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -195,15 +74,12 @@ class LoginPage extends HookConsumerWidget {
|
||||||
backgroundColor: theme.colorScheme.errorContainer,
|
backgroundColor: theme.colorScheme.errorContainer,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
isLoading.value = false;
|
isLoggingIn.value = false;
|
||||||
}
|
}
|
||||||
|
Henry-Hiles marked this conversation as resolved
Outdated
Henry-Hiles
commented
Else: pop page Else: pop page
|
|||||||
},
|
},
|
||||||
child: Text("Sign In"),
|
child: Text("Sign In"),
|
||||||
),
|
|
||||||
],
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
187
lib/pages/select_server_page.dart
Normal file
187
lib/pages/select_server_page.dart
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
import "package:flutter_svg/flutter_svg.dart";
|
||||||
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
|
import "package:nexus/helpers/launch_helper.dart";
|
||||||
|
import "package:nexus/models/homeserver.dart";
|
||||||
|
import "package:nexus/widgets/appbar.dart";
|
||||||
|
import "package:nexus/widgets/divider_text.dart";
|
||||||
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
||||||
|
class SelectServerPage extends HookConsumerWidget {
|
||||||
|
const SelectServerPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final theme = Theme.of(context);
|
||||||
|
final client = ref.watch(ClientController.provider.notifier);
|
||||||
|
|
||||||
|
final isLoading = useState(false);
|
||||||
|
|
||||||
|
final launch = ref.watch(LaunchHelper.provider).launchUrl;
|
||||||
|
|
||||||
|
final homeserverUrl = useTextEditingController();
|
||||||
|
|
||||||
|
Future<void> setHomeserver(Uri? newHomeserver) async {
|
||||||
|
isLoading.value = true;
|
||||||
|
|
||||||
|
if(newHomeserver?.hasScheme == false){
|
||||||
|
newHomeserver = Uri.https(newHomeserver!.path);
|
||||||
|
}
|
||||||
|
|
||||||
|
final newUrl = newHomeserver == null
|
||||||
|
? null
|
||||||
|
: await client.discoverHomeserver(newHomeserver);
|
||||||
|
|
||||||
|
if (context.mounted) {
|
||||||
|
if (newUrl == null) {
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text(
|
||||||
|
"Homeserver verification failed. Is your homeserver down?",
|
||||||
|
style: TextStyle(color: theme.colorScheme.onErrorContainer),
|
||||||
|
),
|
||||||
|
backgroundColor: theme.colorScheme.errorContainer,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
homeserverUrl.text = newHomeserver!.origin;
|
||||||
|
ref.watch(ClientStateController.provider.notifier).setHomeServer(newUrl);
|
||||||
|
Henry-Hiles marked this conversation as resolved
Henry-Hiles
commented
Instead of setting homeserver in client state controller, can we just Instead of setting homeserver in client state controller, can we just `Navigator.of(context).push` the `LoginPage`, passing in a `homeserver` as an argument?
|
|||||||
|
}
|
||||||
|
}
|
||||||
|
isLoading.value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Scaffold(
|
||||||
|
appBar: Appbar(),
|
||||||
|
body: Center(
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(maxWidth: 600),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset("assets/icon.svg", width: 128),
|
||||||
|
SizedBox(width: 12),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text("Nexus", style: theme.textTheme.displayMedium),
|
||||||
|
Text(
|
||||||
|
"A Simple Matrix Client",
|
||||||
|
style: theme.textTheme.headlineMedium,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsetsGeometry.symmetric(vertical: 12),
|
||||||
|
child: Divider(),
|
||||||
|
),
|
||||||
|
DividerText("Enter a homeserver domain:"),
|
||||||
|
Row(
|
||||||
|
spacing: 8,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: TextField(
|
||||||
|
controller: homeserverUrl,
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Homeserver URL (e.g. matrix.org)",
|
||||||
|
hintText: "e.g. matrix.org",
|
||||||
|
enabledBorder: OutlineInputBorder(
|
||||||
|
borderSide: BorderSide(color: (homeserverUrl.text.trim().isEmpty)
|
||||||
|
? theme.colorScheme.error
|
||||||
|
: theme.colorScheme.primary)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
IconButton.filled(
|
||||||
|
tooltip: "Confirm homeserver choice",
|
||||||
|
onPressed: isLoading.value
|
||||||
|
? null
|
||||||
|
: () => setHomeserver(Uri.tryParse(homeserverUrl.text)),
|
||||||
|
icon: Icon(Icons.check),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
padding: EdgeInsets.only(top: 12),
|
||||||
|
children: [
|
||||||
|
DividerText("Or, choose from some popular homeservers:"),
|
||||||
|
...(<Homeserver>[
|
||||||
|
Homeserver(
|
||||||
|
name: "Matrix.org",
|
||||||
|
description:
|
||||||
|
"The Matrix.org Foundation offers the matrix.org homeserver as an easy entry point for anyone wanting to try out Matrix.",
|
||||||
|
url: Uri.https("matrix.org"),
|
||||||
|
iconUrl:
|
||||||
|
"https://raw.githubusercontent.com/element-hq/logos/refs/heads/master/matrix/matrix-favicon${Theme.brightnessOf(context) == Brightness.dark ? "-white" : ""}.png",
|
||||||
|
),
|
||||||
|
Homeserver(
|
||||||
|
name: "Federated Nexus",
|
||||||
|
description:
|
||||||
|
"Federated Nexus is a community resource hosting multiple FOSS (especially federated) services, including Matrix and Forgejo. By the same developers who made Nexus client.",
|
||||||
|
url: Uri.https("federated.nexus"),
|
||||||
|
iconUrl: "https://federated.nexus/images/icon.png",
|
||||||
|
),
|
||||||
|
Homeserver(
|
||||||
|
name: "Unredacted",
|
||||||
|
description:
|
||||||
|
"Unredacted is a 501(c)(3) non-profit organization that builds Internet infrastructure and services to help people evade censorship and protect their right to privacy.",
|
||||||
|
url: Uri.https("unredacted.org", "services/si/matrix"),
|
||||||
|
iconUrl: "https://unredacted.org/favicon.ico",
|
||||||
|
),
|
||||||
|
Homeserver(
|
||||||
|
name: "Lorem ipsum",
|
||||||
|
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
|
||||||
|
url: Uri.https("loremipsum.io"),
|
||||||
|
iconUrl: "https://loremipsum.io/favicon.ico"
|
||||||
|
),
|
||||||
|
].map(
|
||||||
|
(homeserver) => Card(
|
||||||
|
child: ListTile(
|
||||||
|
title: Text(homeserver.name),
|
||||||
|
leading: Image.network(
|
||||||
|
homeserver.iconUrl,
|
||||||
|
errorBuilder: (_, _, _) => SizedBox.shrink(),
|
||||||
|
height: 32,
|
||||||
|
),
|
||||||
|
subtitle: Text(homeserver.description),
|
||||||
|
onTap: isLoading.value
|
||||||
|
? null
|
||||||
|
: () => setHomeserver(homeserver.url),
|
||||||
|
trailing: IconButton(
|
||||||
|
tooltip: "Launch homeserver info page",
|
||||||
|
onPressed: () => launch(homeserver.url),
|
||||||
|
icon: Icon(Icons.info_outline),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(height: 5),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => launch(Uri.https("servers.joinmatrix.org")),
|
||||||
|
child: Text("See more homeservers..."),
|
||||||
|
),
|
||||||
|
if (isLoading.value)
|
||||||
|
Henry-Hiles marked this conversation as resolved
Outdated
Henry-Hiles
commented
This padding should be removed entirely now theres nothing below it. When loading, the whole page should be replaced by a loading indicator, not just at the bottom. This padding should be removed entirely now theres nothing below it. When loading, the whole page should be replaced by a loading indicator, not just at the bottom.
|
|||||||
|
Padding(padding: EdgeInsets.only(top: 32), child: Loading())
|
||||||
|
else
|
||||||
|
Padding(padding: EdgeInsets.only(top: 12))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
16
pubspec.lock
16
pubspec.lock
|
|
@ -836,10 +836,10 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
|
Henry-Hiles
commented
I'd appreciate if you didn't commit these changes. I'd appreciate if you didn't commit these changes.
|
|||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
mime:
|
mime:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1321,26 +1321,26 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test
|
name: test
|
||||||
sha256: "280d6d890011ca966ad08df7e8a4ddfab0fb3aa49f96ed6de56e3521347a9ae7"
|
sha256: "8d9ceddbab833f180fbefed08afa76d7c03513dfdba87ffcec2718b02bbcbf20"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.30.0"
|
version: "1.31.0"
|
||||||
test_api:
|
test_api:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "8161c84903fd860b26bfdefb7963b3f0b68fee7adea0f59ef805ecca346f0c7a"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.10"
|
version: "0.7.11"
|
||||||
test_core:
|
test_core:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_core
|
name: test_core
|
||||||
sha256: "0381bd1585d1a924763c308100f2138205252fb90c9d4eeaf28489ee65ccde51"
|
sha256: "1991d4cfe85d5043241acac92962c3977c8d2f2add1ee73130c7b286417d1d34"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.6.16"
|
version: "0.6.17"
|
||||||
timeago:
|
timeago:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue
Given this won't be persistent anyways, I think we can go for a simpler approach and not touch client state controller.