forked from Henry-Hiles/nexus
working login
This commit is contained in:
parent
7c6ddab6a3
commit
e447540062
7 changed files with 162 additions and 32 deletions
|
|
@ -2,6 +2,7 @@ import "dart:ffi";
|
||||||
import "dart:isolate";
|
import "dart:isolate";
|
||||||
import "package:ffi/ffi.dart";
|
import "package:ffi/ffi.dart";
|
||||||
import "package:flutter/foundation.dart";
|
import "package:flutter/foundation.dart";
|
||||||
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
import "package:nexus/controllers/sync_status_controller.dart";
|
import "package:nexus/controllers/sync_status_controller.dart";
|
||||||
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
import "package:nexus/helpers/extensions/gomuks_buffer.dart";
|
||||||
import "package:nexus/models/client_state.dart";
|
import "package:nexus/models/client_state.dart";
|
||||||
|
|
@ -31,18 +32,22 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
|
|
||||||
switch (muksEventType) {
|
switch (muksEventType) {
|
||||||
case "client_state":
|
case "client_state":
|
||||||
final clientState = ClientState.fromJson(decodedMuksEvent);
|
ref
|
||||||
debugPrint("Received event: $clientState");
|
.watch(ClientStateController.provider.notifier)
|
||||||
|
.set(ClientState.fromJson(decodedMuksEvent));
|
||||||
break;
|
break;
|
||||||
case "sync_status":
|
case "sync_status":
|
||||||
ref
|
ref
|
||||||
.watch(SyncStatusController.provider.notifier)
|
.watch(SyncStatusController.provider.notifier)
|
||||||
.set(SyncStatus.fromJson(decodedMuksEvent));
|
.set(SyncStatus.fromJson(decodedMuksEvent));
|
||||||
break;
|
break;
|
||||||
|
case "sync_complete":
|
||||||
|
// ref
|
||||||
|
// .watch(SyncStatusController.provider.notifier)
|
||||||
|
// .set(SyncStatus.fromJson(decodedMuksEvent));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
debugPrint(
|
debugPrint("Unhandled event: $muksEventType");
|
||||||
"Unhandled event: $muksEventType: $decodedMuksEvent",
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
} catch (error, stackTrace) {
|
} catch (error, stackTrace) {
|
||||||
debugPrintStack(stackTrace: stackTrace, label: error.toString());
|
debugPrintStack(stackTrace: stackTrace, label: error.toString());
|
||||||
|
|
@ -73,6 +78,15 @@ class ClientController extends AsyncNotifier<int> {
|
||||||
return response.buf.toJson();
|
return response.buf.toJson();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> verify(String recoveryKey) async {
|
||||||
|
try {
|
||||||
|
await sendCommand("verify", {"recovery_key": recoveryKey});
|
||||||
|
return true;
|
||||||
|
} catch (_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Future<bool> login(Login login) async {
|
Future<bool> login(Login login) async {
|
||||||
try {
|
try {
|
||||||
await sendCommand("login", login.toJson());
|
await sendCommand("login", login.toJson());
|
||||||
|
|
|
||||||
15
lib/controllers/client_state_controller.dart
Normal file
15
lib/controllers/client_state_controller.dart
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:nexus/models/client_state.dart";
|
||||||
|
|
||||||
|
class ClientStateController extends Notifier<ClientState?> {
|
||||||
|
@override
|
||||||
|
Null build() => null;
|
||||||
|
|
||||||
|
void set(ClientState newState) {
|
||||||
|
state = newState;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final provider = NotifierProvider<ClientStateController, ClientState?>(
|
||||||
|
ClientStateController.new,
|
||||||
|
);
|
||||||
|
}
|
||||||
20
lib/controllers/multi_provider_controller.dart
Normal file
20
lib/controllers/multi_provider_controller.dart
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import "dart:async";
|
||||||
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
|
||||||
|
class MultiProviderController extends AsyncNotifier<void> {
|
||||||
|
MultiProviderController(this.providers);
|
||||||
|
final IList<AsyncNotifierProvider> providers;
|
||||||
|
|
||||||
|
@override
|
||||||
|
FutureOr<void> build() async => await Future.wait(
|
||||||
|
providers.map((provider) => ref.watch(provider.future)),
|
||||||
|
);
|
||||||
|
|
||||||
|
static final provider =
|
||||||
|
AsyncNotifierProvider.family<
|
||||||
|
MultiProviderController,
|
||||||
|
void,
|
||||||
|
IList<AsyncNotifierProvider>
|
||||||
|
>(MultiProviderController.new);
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,18 @@
|
||||||
import "dart:io";
|
import "dart:io";
|
||||||
|
import "package:fast_immutable_collections/fast_immutable_collections.dart";
|
||||||
import "package:flutter/foundation.dart";
|
import "package:flutter/foundation.dart";
|
||||||
import "package:flutter_riverpod/flutter_riverpod.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
import "package:nexus/controllers/client_controller.dart";
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
|
import "package:nexus/controllers/client_state_controller.dart";
|
||||||
|
import "package:nexus/controllers/multi_provider_controller.dart";
|
||||||
import "package:nexus/controllers/shared_prefs_controller.dart";
|
import "package:nexus/controllers/shared_prefs_controller.dart";
|
||||||
import "package:nexus/controllers/sync_status_controller.dart";
|
|
||||||
import "package:nexus/helpers/extensions/better_when.dart";
|
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/models/sync_status.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/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:window_manager/window_manager.dart";
|
import "package:window_manager/window_manager.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:dynamic_system_colors/dynamic_system_colors.dart";
|
import "package:dynamic_system_colors/dynamic_system_colors.dart";
|
||||||
|
|
@ -78,11 +82,11 @@ void main() async {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class App extends ConsumerWidget {
|
class App extends StatelessWidget {
|
||||||
const App({super.key});
|
const App({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) => DynamicColorBuilder(
|
Widget build(BuildContext context) => DynamicColorBuilder(
|
||||||
builder: (lightDynamic, darkDynamic) => MaterialApp(
|
builder: (lightDynamic, darkDynamic) => MaterialApp(
|
||||||
navigatorKey: navigatorKey,
|
navigatorKey: navigatorKey,
|
||||||
debugShowCheckedModeBanner: false,
|
debugShowCheckedModeBanner: false,
|
||||||
|
|
@ -96,10 +100,38 @@ class App extends ConsumerWidget {
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
))
|
))
|
||||||
.theme,
|
.theme,
|
||||||
home: Builder(
|
home: Scaffold(
|
||||||
builder: (context) => ref
|
body: Consumer(
|
||||||
.watch(SharedPrefsController.provider)
|
builder: (_, ref, _) => ref
|
||||||
.betterWhen(data: (_) => LoginPage()),
|
.watch(
|
||||||
|
MultiProviderController.provider(
|
||||||
|
IListConst([
|
||||||
|
SharedPrefsController.provider,
|
||||||
|
ClientController.provider,
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.betterWhen(
|
||||||
|
data: (_) => Consumer(
|
||||||
|
builder: (_, ref, _) {
|
||||||
|
final clientState = ref.watch(
|
||||||
|
ClientStateController.provider,
|
||||||
|
);
|
||||||
|
if (clientState == null || !clientState.isInitialized) {
|
||||||
|
return Loading();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clientState.isLoggedIn) {
|
||||||
|
return LoginPage();
|
||||||
|
} else if (!clientState.isVerified) {
|
||||||
|
return VerifyPage();
|
||||||
|
} else {
|
||||||
|
return ChatPage();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:nexus/widgets/chat_page/room_chat.dart";
|
// import "package:nexus/widgets/chat_page/room_chat.dart";
|
||||||
import "package:nexus/widgets/chat_page/sidebar.dart";
|
// import "package:nexus/widgets/chat_page/sidebar.dart";
|
||||||
|
|
||||||
class ChatPage extends StatelessWidget {
|
class ChatPage extends StatelessWidget {
|
||||||
const ChatPage({super.key});
|
const ChatPage({super.key});
|
||||||
|
|
@ -10,23 +10,23 @@ class ChatPage extends StatelessWidget {
|
||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final isDesktop = constraints.maxWidth > 650;
|
final isDesktop = constraints.maxWidth > 650;
|
||||||
final showMembersByDefault = constraints.maxWidth > 1000;
|
final showMembersByDefault = constraints.maxWidth > 1000;
|
||||||
|
return Placeholder();
|
||||||
return Scaffold(
|
// return Scaffold(
|
||||||
body: Builder(
|
// body: Builder(
|
||||||
builder: (context) => Row(
|
// builder: (context) => Row(
|
||||||
children: [
|
// children: [
|
||||||
if (isDesktop) Sidebar(),
|
// if (isDesktop) Sidebar(),
|
||||||
Expanded(
|
// Expanded(
|
||||||
child: RoomChat(
|
// child: RoomChat(
|
||||||
isDesktop: isDesktop,
|
// isDesktop: isDesktop,
|
||||||
showMembersByDefault: showMembersByDefault,
|
// showMembersByDefault: showMembersByDefault,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
],
|
// ],
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
drawer: isDesktop ? null : Sidebar(),
|
// drawer: isDesktop ? null : Sidebar(),
|
||||||
);
|
// );
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
46
lib/pages/verify_page.dart
Normal file
46
lib/pages/verify_page.dart
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
|
import "package:nexus/widgets/form_text_input.dart";
|
||||||
|
|
||||||
|
class VerifyPage extends HookConsumerWidget {
|
||||||
|
const VerifyPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final passphraseController = useTextEditingController();
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text("Verify"),
|
||||||
|
content: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Enter your recovery key or passphrase below to unlock encrypted messages.\nYour passphrase is usually not the same as your password.",
|
||||||
|
),
|
||||||
|
SizedBox(height: 12),
|
||||||
|
FormTextInput(
|
||||||
|
required: false,
|
||||||
|
autofocus: true,
|
||||||
|
capitalize: true,
|
||||||
|
controller: passphraseController,
|
||||||
|
obscure: true,
|
||||||
|
title: "Recovery Key or Passphrase",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () async {
|
||||||
|
ref
|
||||||
|
.watch(ClientController.provider.notifier)
|
||||||
|
.verify(passphraseController.text);
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
child: Text("Verify"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -20,11 +20,13 @@ class FormTextInput extends StatelessWidget {
|
||||||
final Widget? trailing;
|
final Widget? trailing;
|
||||||
final InputBorder? border;
|
final InputBorder? border;
|
||||||
final List<TextInputFormatter>? formatters;
|
final List<TextInputFormatter>? formatters;
|
||||||
|
final bool autofocus;
|
||||||
|
|
||||||
const FormTextInput({
|
const FormTextInput({
|
||||||
super.key,
|
super.key,
|
||||||
this.border,
|
this.border,
|
||||||
this.controller,
|
this.controller,
|
||||||
|
this.autofocus = false,
|
||||||
this.title,
|
this.title,
|
||||||
this.obscure = false,
|
this.obscure = false,
|
||||||
this.readOnly = false,
|
this.readOnly = false,
|
||||||
|
|
@ -45,6 +47,7 @@ class FormTextInput extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) => TextFormField(
|
Widget build(BuildContext context) => TextFormField(
|
||||||
|
autofocus: autofocus,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
keyboardType: keyboardType,
|
keyboardType: keyboardType,
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue