Skip to content
This repository has been archived by the owner on Sep 27, 2024. It is now read-only.

Commit

Permalink
feat: load user profiles faster
Browse files Browse the repository at this point in the history
  • Loading branch information
RossComputerGuy committed May 3, 2024
1 parent 9fb9f59 commit ba9fd9d
Show file tree
Hide file tree
Showing 8 changed files with 179 additions and 72 deletions.
88 changes: 88 additions & 0 deletions lib/logic/account.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import 'dart:collection';

import 'package:provider/provider.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';

class AccountManager extends ChangeNotifier {
static const channel = MethodChannel('com.expidusos.genesis.shell/account');

AccountManager() {
channel.setMethodCallHandler((call) async {
switch (call.method) {
case 'loaded':
_sync();
break;
default:
throw MissingPluginException();
}
});

_sync();
}

final List<Account> _accounts = [];
UnmodifiableListView<Account> get account => UnmodifiableListView(_accounts);

Account? find({
int? uid,
String? name,
}) {
for (final account in _accounts) {
if (account.uid == uid || account.name == name) return account;
}
return null;
}

Account? findByUid(int uid) {
for (final account in _accounts) {
if (account.uid == uid) return account;
}
return null;
}

Account? findByName(String name) {
for (final account in _accounts) {
if (account.name == name) return account;
}
return null;
}

void _sync() {
channel.invokeListMethod('list').then((list) {
_accounts.clear();
_accounts.addAll(list!.map(
(account) =>
Account(
name: account['name'],
uid: account['uid'],
icon: account['icon'],
displayName: account['displayName'],
home: account['home'],
passwordHint: account['passwordHint'],
)
));
notifyListeners();
}).catchError((err) {
print(err);
});
}
}

class Account {
const Account({
this.name = null,
this.uid = null,
this.icon = null,
this.displayName = null,
this.home = null,
this.passwordHint = null,
});

final String? name;
final int? uid;
final String? icon;
final String? displayName;
final String? home;
final String? passwordHint;
}
4 changes: 4 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:system_theme/system_theme.dart';

import 'logic/account.dart';
import 'logic/outputs.dart';
import 'logic/route_args.dart';
import 'logic/theme.dart' show buildThemeData;
Expand Down Expand Up @@ -62,12 +63,14 @@ class GenesisShellApp extends StatefulWidget {
}

class _GenesisShellAppState extends State<GenesisShellApp> {
late AccountManager _accountManager;
late OutputManager _outputManager;

@override
void initState() {
super.initState();

_accountManager = AccountManager();
_outputManager = OutputManager();
}

Expand All @@ -77,6 +80,7 @@ class _GenesisShellAppState extends State<GenesisShellApp> {
builder: (context, accent) =>
MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => _accountManager),
ChangeNotifierProvider(create: (_) => _outputManager),
],
child: MaterialApp(
Expand Down
85 changes: 37 additions & 48 deletions lib/widgets/account_profile.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:provider/provider.dart';

import '../logic/account.dart';

class AccountProfile extends StatefulWidget {
class AccountProfile extends StatelessWidget {
const AccountProfile({
super.key,
this.direction = Axis.horizontal,
Expand Down Expand Up @@ -33,56 +37,41 @@ class AccountProfile extends StatefulWidget {
final TextStyle? textStyle;

@override
State<AccountProfile> createState() => _AccountProfileState();
}

class _AccountProfileState extends State<AccountProfile> {
static const platform = MethodChannel('com.expidusos.genesis.shell/account');

String? displayName = null;
String? icon = null;

dynamic _getData() {
if (widget.uid != null) return widget.uid;
if (widget.name != null) return widget.name;
return null;
}

@override
void initState() {
super.initState();
Widget build(BuildContext context) =>
Consumer<AccountManager>(
builder: (context, mngr, _) {
final account = mngr.find(
uid: uid,
name: name,
);

platform.invokeMethod('get', _getData()).then((user) => setState(() {
displayName = user['displayName'];
icon = user['icon'];
})).catchError((err) {
print(err);
});
}
final icon = account == null ? null : account.icon;
final displayName = account == null ? null : account.displayName;

Widget build(BuildContext context) =>
Flex(
direction: widget.direction,
children: [
icon == null
? Icon(Icons.account_circle, size: widget.iconSize)
: ClipRRect(
borderRadius: BorderRadius.circular(360.0),
child: Image.file(
File(icon!),
width: widget.iconSize,
height: widget.iconSize,
errorBuilder: (context, err, stackTrace) =>
Icon(Icons.account_circle, size: widget.iconSize),
return Flex(
direction: direction,
children: [
icon == null
? Icon(Icons.account_circle, size: iconSize)
: ClipRRect(
borderRadius: BorderRadius.circular(360.0),
child: Image.file(
File(icon!),
width: iconSize,
height: iconSize,
errorBuilder: (context, err, stackTrace) =>
Icon(Icons.account_circle, size: iconSize),
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Text(
displayName ?? '',
style: textStyle ?? Theme.of(context).textTheme.titleLarge,
),
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: Text(
displayName ?? '',
style: widget.textStyle ?? Theme.of(context).textTheme.titleLarge,
),
),
],
],
);
},
);
}
3 changes: 2 additions & 1 deletion linux/application-priv.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "channels/account.h"
#include "channels/auth.h"
#include "channels/display.h"
#include "channels/outputs.h"
Expand All @@ -10,7 +11,7 @@ struct _GenesisShellApplication {
char** dart_entrypoint_arguments;
GtkWindow* win;

FlMethodChannel* account;
AccountChannel account;
AuthChannel auth;
DisplayChannel display;
OutputsChannel outputs;
Expand Down
12 changes: 3 additions & 9 deletions linux/application.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

#include "application.h"
#include "application-priv.h"
#include "channels/account.h"
#include "channels/outputs.h"

#include <flutter_linux/flutter_linux.h>
#ifdef GDK_WINDOWING_X11
Expand Down Expand Up @@ -33,16 +31,12 @@ static void genesis_shell_application_activate(GApplication* application) {

fl_register_plugins(FL_PLUGIN_REGISTRY(view));

{
g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
self->account = fl_method_channel_new(fl_engine_get_binary_messenger(fl_view_get_engine(view)), "com.expidusos.genesis.shell/account", FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(self->account, account_method_call_handler, self, nullptr);
}

account_channel_init(&self->account, view);
auth_channel_init(&self->auth, view);
display_channel_init(&self->display, view);
outputs_channel_init(&self->outputs, view);
session_channel_init(&self->session, view);

gtk_widget_grab_focus(GTK_WIDGET(view));
}

Expand Down Expand Up @@ -87,8 +81,8 @@ static void genesis_shell_application_shutdown(GApplication* application) {
static void genesis_shell_application_dispose(GObject* object) {
GenesisShellApplication* self = GENESIS_SHELL_APPLICATION(object);
g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev);
g_clear_object(&self->account);

account_channel_deinit(&self->account);
auth_channel_deinit(&self->auth);
display_channel_deinit(&self->display);
outputs_channel_deinit(&self->outputs);
Expand Down
39 changes: 28 additions & 11 deletions linux/channels/account.cc
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
#include <flutter_linux/flutter_linux.h>

extern "C" {
#include <act/act.h>
}

#include <sys/types.h>
#include <unistd.h>

Expand All @@ -27,11 +23,11 @@ static FlValue* from_user(ActUser* usr) {
return value;
}

void account_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) {
static void method_call_handler(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data) {
AccountChannel* self = (AccountChannel*)user_data;
g_autoptr(FlMethodResponse) response = nullptr;

ActUserManager* mngr = act_user_manager_get_default();
if (act_user_manager_no_service(mngr)) {
if (act_user_manager_no_service(self->mngr)) {
fl_method_call_respond_error(method_call, "AccountsService", "Service has not started.", nullptr, nullptr);
return;
}
Expand All @@ -40,13 +36,13 @@ void account_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_
FlValue* args = fl_method_call_get_args(method_call);
switch (fl_value_get_type(args)) {
case FL_VALUE_TYPE_NULL:
response = FL_METHOD_RESPONSE(fl_method_success_response_new(from_user(act_user_manager_get_user_by_id(mngr, geteuid()))));
response = FL_METHOD_RESPONSE(fl_method_success_response_new(from_user(act_user_manager_get_user_by_id(self->mngr, geteuid()))));
break;
case FL_VALUE_TYPE_INT:
response = FL_METHOD_RESPONSE(fl_method_success_response_new(from_user(act_user_manager_get_user_by_id(mngr, fl_value_get_int(args)))));
response = FL_METHOD_RESPONSE(fl_method_success_response_new(from_user(act_user_manager_get_user_by_id(self->mngr, fl_value_get_int(args)))));
break;
case FL_VALUE_TYPE_STRING:
response = FL_METHOD_RESPONSE(fl_method_success_response_new(from_user(act_user_manager_get_user(mngr, fl_value_get_string(args)))));
response = FL_METHOD_RESPONSE(fl_method_success_response_new(from_user(act_user_manager_get_user(self->mngr, fl_value_get_string(args)))));
break;
default:
fl_method_call_respond_error(method_call, "AccountsService", "Unknown type", args, nullptr);
Expand All @@ -55,7 +51,7 @@ void account_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_
} else if (strcmp(fl_method_call_get_name(method_call), "list") == 0) {
g_autoptr(FlValue) value = fl_value_new_list();

GSList* list = act_user_manager_list_users(mngr);
GSList* list = act_user_manager_list_users(self->mngr);
while (list != nullptr) {
fl_value_append(value, from_user(ACT_USER(list->data)));
list = list->next;
Expand All @@ -71,3 +67,24 @@ void account_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_
g_warning("Failed to send response: %s", error->message);
}
}

static void is_loaded(ActUserManager* mngr, GParamSpec* pspec, AccountChannel* self) {
(void)mngr;
(void)pspec;

fl_method_channel_invoke_method(self->channel, "loaded", nullptr, nullptr, nullptr, nullptr);
}

void account_channel_init(AccountChannel* self, FlView* view) {
self->mngr = g_object_ref(act_user_manager_get_default());
self->is_loaded = g_signal_connect(self->mngr, "notify::is-loaded", G_CALLBACK(is_loaded), self);

g_autoptr(FlStandardMethodCodec) codec = fl_standard_method_codec_new();
self->channel = fl_method_channel_new(fl_engine_get_binary_messenger(fl_view_get_engine(view)), "com.expidusos.genesis.shell/account", FL_METHOD_CODEC(codec));
fl_method_channel_set_method_call_handler(self->channel, method_call_handler, self, nullptr);
}

void account_channel_deinit(AccountChannel* self) {
g_clear_object(&self->mngr);
g_clear_object(&self->channel);
}
18 changes: 17 additions & 1 deletion linux/channels/account.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,22 @@

#include <flutter_linux/flutter_linux.h>

#ifdef __cplusplus
extern "C" {
#endif
#include <act/act.h>
#ifdef __cplusplus
}
#endif

#include "../application.h"

void account_method_call_handler(FlMethodChannel* channel, FlMethodCall* method_call, gpointer user_data);
typedef struct _AccountChannel {
guint is_loaded;

ActUserManager* mngr;
FlMethodChannel* channel;
} AccountChannel;

void account_channel_init(AccountChannel* self, FlView* view);
void account_channel_deinit(AccountChannel* self);
2 changes: 0 additions & 2 deletions linux/channels/display.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,6 @@ static void method_call_handler(FlMethodChannel* channel, FlMethodCall* method_c
FlValue* item = fl_value_get_list_value(list, i);
FlValue* item_geom = fl_value_lookup_string(item, "geometry");

g_message("%s", fl_value_to_string(item));

int64_t width = fl_value_get_int(fl_value_lookup_string(item_geom, "width"));
int64_t height = fl_value_get_int(fl_value_lookup_string(item_geom, "height"));

Expand Down

0 comments on commit ba9fd9d

Please sign in to comment.