loading spaces
This commit is contained in:
parent
dca9ee1939
commit
65028a1231
14 changed files with 629 additions and 86 deletions
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -34,4 +34,7 @@ keystore.jks
|
||||||
key.properties
|
key.properties
|
||||||
|
|
||||||
# Generated Files
|
# Generated Files
|
||||||
*.g.dart
|
*.g.dart
|
||||||
|
|
||||||
|
# Devel Password
|
||||||
|
password.txt
|
||||||
3
devtools_options.yaml
Normal file
3
devtools_options.yaml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
||||||
|
|
@ -44,10 +44,13 @@
|
||||||
pkgs.mkShell {
|
pkgs.mkShell {
|
||||||
packages = with pkgs; [
|
packages = with pkgs; [
|
||||||
jdk17
|
jdk17
|
||||||
|
rustc
|
||||||
flutter
|
flutter
|
||||||
android.platform-tools
|
android.platform-tools
|
||||||
];
|
];
|
||||||
env = rec {
|
env = rec {
|
||||||
|
LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath (with pkgs; [ sqlite ])}:$LD_LIBRARY_PATH";
|
||||||
|
|
||||||
ANDROID_HOME = "${android.androidsdk}/libexec/android-sdk";
|
ANDROID_HOME = "${android.androidsdk}/libexec/android-sdk";
|
||||||
ANDROID_SDK_ROOT = ANDROID_HOME;
|
ANDROID_SDK_ROOT = ANDROID_HOME;
|
||||||
JAVA_HOME = pkgs.jdk17;
|
JAVA_HOME = pkgs.jdk17;
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,31 @@
|
||||||
// import "dart:io";
|
import "dart:io";
|
||||||
|
|
||||||
// import "package:matrix/matrix.dart";
|
import "package:matrix/matrix.dart";
|
||||||
// import "package:nexusbot/controllers/settings_controller.dart";
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
// import "package:riverpod/riverpod.dart";
|
import "package:sqflite_common_ffi/sqflite_ffi.dart";
|
||||||
// import "package:sqflite_common_ffi/sqflite_ffi.dart";
|
|
||||||
|
|
||||||
// class ClientController extends AsyncNotifier<Client> {
|
class ClientController extends AsyncNotifier<Client> {
|
||||||
// @override
|
@override
|
||||||
// Future<Client> build() async {
|
Future<Client> build() async {
|
||||||
// final settings = ref.watch(SettingsController.provider)!;
|
final client = Client(
|
||||||
// final client = Client(
|
"nexus",
|
||||||
// "nexusbot",
|
database: await MatrixSdkDatabase.init(
|
||||||
// database: await MatrixSdkDatabase.init(
|
"nexus",
|
||||||
// "NexusBot",
|
database: await databaseFactoryFfi.openDatabase("./test.db"),
|
||||||
// database: await databaseFactoryFfi.openDatabase(inMemoryDatabasePath),
|
),
|
||||||
// ),
|
);
|
||||||
// );
|
//mxc
|
||||||
|
await client.checkHomeserver(Uri.https("federated.nexus"));
|
||||||
|
await client.login(
|
||||||
|
LoginType.mLoginPassword,
|
||||||
|
identifier: AuthenticationUserIdentifier(user: "quadradical"),
|
||||||
|
password: File("./password.txt").readAsStringSync(),
|
||||||
|
);
|
||||||
|
|
||||||
// await client.checkHomeserver(settings.homeserver);
|
return client;
|
||||||
// await client.login(
|
}
|
||||||
// LoginType.mLoginPassword,
|
|
||||||
// identifier: AuthenticationUserIdentifier(user: settings.name),
|
|
||||||
// password: (await File(settings.botPasswordFile).readAsString()).trim(),
|
|
||||||
// );
|
|
||||||
|
|
||||||
// return client;
|
static final provider = AsyncNotifierProvider<ClientController, Client>(
|
||||||
// }
|
ClientController.new,
|
||||||
|
);
|
||||||
// static final provider = AsyncNotifierProvider<ClientController, Client>(
|
}
|
||||||
// ClientController.new,
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
36
lib/controllers/spaces_controller.dart
Normal file
36
lib/controllers/spaces_controller.dart
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import "package:flutter/widgets.dart";
|
||||||
|
import "package:matrix/matrix.dart";
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/client_controller.dart";
|
||||||
|
import "package:nexus/models/space.dart";
|
||||||
|
|
||||||
|
class SpacesController extends AsyncNotifier<List<Space>> {
|
||||||
|
@override
|
||||||
|
Future<List<Space>> build() async {
|
||||||
|
final client = await ref.watch(ClientController.provider.future);
|
||||||
|
|
||||||
|
return Future.wait(
|
||||||
|
client.rooms.where((room) => room.isSpace).map((data) async {
|
||||||
|
final thumb = await data.avatar?.getThumbnailUri(
|
||||||
|
client,
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
);
|
||||||
|
return Space(
|
||||||
|
roomData: data,
|
||||||
|
avatar: thumb == null
|
||||||
|
? null
|
||||||
|
: Image.network(
|
||||||
|
thumb.toString(),
|
||||||
|
width: 40,
|
||||||
|
headers: {"authorization": "Bearer ${client.accessToken}"},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static final provider = AsyncNotifierProvider<SpacesController, List<Space>>(
|
||||||
|
SpacesController.new,
|
||||||
|
);
|
||||||
|
}
|
||||||
17
lib/helpers/extension_helper.dart
Normal file
17
lib/helpers/extension_helper.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import "package:flutter/widgets.dart";
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:nexus/widgets/error_dialog.dart";
|
||||||
|
import "package:nexus/widgets/loading.dart";
|
||||||
|
|
||||||
|
extension BetterWhen<T> on AsyncValue<T> {
|
||||||
|
Widget betterWhen({
|
||||||
|
required Widget Function(T value) data,
|
||||||
|
Widget Function() loading = Loading.new,
|
||||||
|
bool skipLoadingOnRefresh = false,
|
||||||
|
}) => when(
|
||||||
|
data: data,
|
||||||
|
error: (error, stackTrace) => ErrorDialog(error, stackTrace),
|
||||||
|
loading: loading,
|
||||||
|
skipLoadingOnRefresh: skipLoadingOnRefresh,
|
||||||
|
);
|
||||||
|
}
|
||||||
10
lib/models/space.dart
Normal file
10
lib/models/space.dart
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import "package:flutter/widgets.dart";
|
||||||
|
import "package:freezed_annotation/freezed_annotation.dart";
|
||||||
|
import "package:matrix/matrix.dart";
|
||||||
|
part "space.freezed.dart";
|
||||||
|
|
||||||
|
@freezed
|
||||||
|
abstract class Space with _$Space {
|
||||||
|
const factory Space({required Room roomData, required Image? avatar}) =
|
||||||
|
_Space;
|
||||||
|
}
|
||||||
274
lib/models/space.freezed.dart
Normal file
274
lib/models/space.freezed.dart
Normal file
|
|
@ -0,0 +1,274 @@
|
||||||
|
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||||
|
// coverage:ignore-file
|
||||||
|
// ignore_for_file: type=lint
|
||||||
|
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark
|
||||||
|
|
||||||
|
part of 'space.dart';
|
||||||
|
|
||||||
|
// **************************************************************************
|
||||||
|
// FreezedGenerator
|
||||||
|
// **************************************************************************
|
||||||
|
|
||||||
|
// dart format off
|
||||||
|
T _$identity<T>(T value) => value;
|
||||||
|
/// @nodoc
|
||||||
|
mixin _$Space {
|
||||||
|
|
||||||
|
Room get roomData; Image? get avatar;
|
||||||
|
/// Create a copy of Space
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
$SpaceCopyWith<Space> get copyWith => _$SpaceCopyWithImpl<Space>(this as Space, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is Space&&(identical(other.roomData, roomData) || other.roomData == roomData)&&(identical(other.avatar, avatar) || other.avatar == avatar));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,roomData,avatar);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Space(roomData: $roomData, avatar: $avatar)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class $SpaceCopyWith<$Res> {
|
||||||
|
factory $SpaceCopyWith(Space value, $Res Function(Space) _then) = _$SpaceCopyWithImpl;
|
||||||
|
@useResult
|
||||||
|
$Res call({
|
||||||
|
Room roomData, Image? avatar
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class _$SpaceCopyWithImpl<$Res>
|
||||||
|
implements $SpaceCopyWith<$Res> {
|
||||||
|
_$SpaceCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final Space _self;
|
||||||
|
final $Res Function(Space) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Space
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@pragma('vm:prefer-inline') @override $Res call({Object? roomData = null,Object? avatar = freezed,}) {
|
||||||
|
return _then(_self.copyWith(
|
||||||
|
roomData: null == roomData ? _self.roomData : roomData // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Room,avatar: freezed == avatar ? _self.avatar : avatar // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Image?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Adds pattern-matching-related methods to [Space].
|
||||||
|
extension SpacePatterns on Space {
|
||||||
|
/// A variant of `map` that fallback to returning `orElse`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeMap<TResult extends Object?>(TResult Function( _Space value)? $default,{required TResult orElse(),}){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Space() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// Callbacks receives the raw object, upcasted.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case final Subclass2 value:
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult map<TResult extends Object?>(TResult Function( _Space value) $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Space():
|
||||||
|
return $default(_that);case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `map` that fallback to returning `null`.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case final Subclass value:
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? mapOrNull<TResult extends Object?>(TResult? Function( _Space value)? $default,){
|
||||||
|
final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Space() when $default != null:
|
||||||
|
return $default(_that);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to an `orElse` callback.
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return orElse();
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult maybeWhen<TResult extends Object?>(TResult Function( Room roomData, Image? avatar)? $default,{required TResult orElse(),}) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Space() when $default != null:
|
||||||
|
return $default(_that.roomData,_that.avatar);case _:
|
||||||
|
return orElse();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A `switch`-like method, using callbacks.
|
||||||
|
///
|
||||||
|
/// As opposed to `map`, this offers destructuring.
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case Subclass2(:final field2):
|
||||||
|
/// return ...;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult when<TResult extends Object?>(TResult Function( Room roomData, Image? avatar) $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Space():
|
||||||
|
return $default(_that.roomData,_that.avatar);case _:
|
||||||
|
throw StateError('Unexpected subclass');
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// A variant of `when` that fallback to returning `null`
|
||||||
|
///
|
||||||
|
/// It is equivalent to doing:
|
||||||
|
/// ```dart
|
||||||
|
/// switch (sealedClass) {
|
||||||
|
/// case Subclass(:final field):
|
||||||
|
/// return ...;
|
||||||
|
/// case _:
|
||||||
|
/// return null;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
|
||||||
|
@optionalTypeArgs TResult? whenOrNull<TResult extends Object?>(TResult? Function( Room roomData, Image? avatar)? $default,) {final _that = this;
|
||||||
|
switch (_that) {
|
||||||
|
case _Space() when $default != null:
|
||||||
|
return $default(_that.roomData,_that.avatar);case _:
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
|
||||||
|
|
||||||
|
class _Space implements Space {
|
||||||
|
const _Space({required this.roomData, required this.avatar});
|
||||||
|
|
||||||
|
|
||||||
|
@override final Room roomData;
|
||||||
|
@override final Image? avatar;
|
||||||
|
|
||||||
|
/// Create a copy of Space
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @JsonKey(includeFromJson: false, includeToJson: false)
|
||||||
|
@pragma('vm:prefer-inline')
|
||||||
|
_$SpaceCopyWith<_Space> get copyWith => __$SpaceCopyWithImpl<_Space>(this, _$identity);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(Object other) {
|
||||||
|
return identical(this, other) || (other.runtimeType == runtimeType&&other is _Space&&(identical(other.roomData, roomData) || other.roomData == roomData)&&(identical(other.avatar, avatar) || other.avatar == avatar));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => Object.hash(runtimeType,roomData,avatar);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'Space(roomData: $roomData, avatar: $avatar)';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// @nodoc
|
||||||
|
abstract mixin class _$SpaceCopyWith<$Res> implements $SpaceCopyWith<$Res> {
|
||||||
|
factory _$SpaceCopyWith(_Space value, $Res Function(_Space) _then) = __$SpaceCopyWithImpl;
|
||||||
|
@override @useResult
|
||||||
|
$Res call({
|
||||||
|
Room roomData, Image? avatar
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
/// @nodoc
|
||||||
|
class __$SpaceCopyWithImpl<$Res>
|
||||||
|
implements _$SpaceCopyWith<$Res> {
|
||||||
|
__$SpaceCopyWithImpl(this._self, this._then);
|
||||||
|
|
||||||
|
final _Space _self;
|
||||||
|
final $Res Function(_Space) _then;
|
||||||
|
|
||||||
|
/// Create a copy of Space
|
||||||
|
/// with the given fields replaced by the non-null parameter values.
|
||||||
|
@override @pragma('vm:prefer-inline') $Res call({Object? roomData = null,Object? avatar = freezed,}) {
|
||||||
|
return _then(_Space(
|
||||||
|
roomData: null == roomData ? _self.roomData : roomData // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Room,avatar: freezed == avatar ? _self.avatar : avatar // ignore: cast_nullable_to_non_nullable
|
||||||
|
as Image?,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// dart format on
|
||||||
32
lib/widgets/error_dialog.dart
Normal file
32
lib/widgets/error_dialog.dart
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_riverpod/flutter_riverpod.dart";
|
||||||
|
import "package:flutter_riverpod/misc.dart";
|
||||||
|
|
||||||
|
class ErrorDialog extends ConsumerWidget {
|
||||||
|
final Object error;
|
||||||
|
final StackTrace? stackTrace;
|
||||||
|
final ProviderOrFamily? provider;
|
||||||
|
const ErrorDialog(this.error, this.stackTrace, {this.provider, super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text("An Error Occurred"),
|
||||||
|
content: SingleChildScrollView(
|
||||||
|
child: SelectableText("$error\n\n$stackTrace"),
|
||||||
|
),
|
||||||
|
actions: [
|
||||||
|
if (provider != null)
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => ref.invalidate(provider!),
|
||||||
|
child: const Text("Try Again"),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () =>
|
||||||
|
Navigator.of(context).popUntil((route) => route.isFirst),
|
||||||
|
child: const Text("Go Back"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
13
lib/widgets/loading.dart
Normal file
13
lib/widgets/loading.dart
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
|
class Loading extends StatelessWidget {
|
||||||
|
const Loading({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) => const Center(
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(16),
|
||||||
|
child: CircularProgressIndicator(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -14,6 +14,7 @@ class RoomChat extends HookConsumerWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final urlRegex = RegExp(r"https?://[^\s\]\(\)]+");
|
||||||
final controller = RoomChatController.provider("1");
|
final controller = RoomChatController.provider("1");
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
return Chat(
|
return Chat(
|
||||||
|
|
@ -25,7 +26,10 @@ class RoomChat extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
builders: Builders(
|
builders: Builders(
|
||||||
composerBuilder: (_) => Composer(),
|
composerBuilder: (_) => Composer(
|
||||||
|
sendIconColor: theme.colorScheme.primary,
|
||||||
|
sendOnEnter: true,
|
||||||
|
),
|
||||||
textMessageBuilder:
|
textMessageBuilder:
|
||||||
(
|
(
|
||||||
context,
|
context,
|
||||||
|
|
@ -36,9 +40,7 @@ class RoomChat extends HookConsumerWidget {
|
||||||
}) => FlyerChatTextMessage(
|
}) => FlyerChatTextMessage(
|
||||||
message: message.copyWith(
|
message: message.copyWith(
|
||||||
text: message.text.replaceAllMapped(
|
text: message.text.replaceAllMapped(
|
||||||
RegExp(
|
urlRegex,
|
||||||
r"http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+",
|
|
||||||
),
|
|
||||||
(match) => "[${match.group(0)}](${match.group(0)})",
|
(match) => "[${match.group(0)}](${match.group(0)})",
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
@ -49,26 +51,22 @@ class RoomChat extends HookConsumerWidget {
|
||||||
sentLinksColor: Colors.blue,
|
sentLinksColor: Colors.blue,
|
||||||
receivedLinksColor: Colors.blue,
|
receivedLinksColor: Colors.blue,
|
||||||
),
|
),
|
||||||
linkPreviewBuilder: (_, message, isSentByMe) {
|
linkPreviewBuilder: (_, message, isSentByMe) => LinkPreview(
|
||||||
return LinkPreview(
|
text: urlRegex.firstMatch(message.text)?.group(0) ?? "",
|
||||||
text: message.text,
|
backgroundColor: isSentByMe
|
||||||
backgroundColor: isSentByMe
|
? theme.colorScheme.inversePrimary
|
||||||
? theme.colorScheme.inversePrimary
|
: theme.colorScheme.surfaceContainerLow,
|
||||||
: theme.colorScheme.surfaceContainerLow,
|
insidePadding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
||||||
insidePadding: EdgeInsets.symmetric(vertical: 8, horizontal: 16),
|
linkPreviewData: message.linkPreviewData,
|
||||||
linkPreviewData: message.linkPreviewData,
|
onLinkPreviewDataFetched: (linkPreviewData) {
|
||||||
onLinkPreviewDataFetched: (linkPreviewData) {
|
ref
|
||||||
ref
|
.watch(controller)
|
||||||
.watch(controller)
|
.updateMessage(
|
||||||
.updateMessage(
|
message,
|
||||||
message,
|
message.copyWith(linkPreviewData: linkPreviewData),
|
||||||
message.copyWith(linkPreviewData: linkPreviewData),
|
);
|
||||||
);
|
},
|
||||||
},
|
),
|
||||||
// You can still customize the appearance
|
|
||||||
parentContent: message.text,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
imageMessageBuilder:
|
imageMessageBuilder:
|
||||||
(
|
(
|
||||||
_,
|
_,
|
||||||
|
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
import "dart:io";
|
import "package:color_hash/color_hash.dart";
|
||||||
|
|
||||||
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:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:nexus/controllers/spaces_controller.dart";
|
||||||
|
|
||||||
class Sidebar extends HookWidget {
|
class Sidebar extends HookConsumerWidget {
|
||||||
const Sidebar({super.key});
|
const Sidebar({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final index = useState(0);
|
final index = useState(0);
|
||||||
return Drawer(
|
return Drawer(
|
||||||
shape: Border(),
|
shape: Border(),
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
NavigationRail(
|
NavigationRail(
|
||||||
|
scrollable: true,
|
||||||
useIndicator: false,
|
useIndicator: false,
|
||||||
labelType: NavigationRailLabelType.none,
|
|
||||||
onDestinationSelected: (value) => index.value = value,
|
onDestinationSelected: (value) => index.value = value,
|
||||||
destinations: [
|
destinations: [
|
||||||
NavigationRailDestination(
|
NavigationRailDestination(
|
||||||
|
|
@ -28,11 +29,39 @@ class Sidebar extends HookWidget {
|
||||||
label: Text("Messages"),
|
label: Text("Messages"),
|
||||||
padding: EdgeInsets.only(top: 12),
|
padding: EdgeInsets.only(top: 12),
|
||||||
),
|
),
|
||||||
NavigationRailDestination(
|
...ref
|
||||||
icon: Image.file(File("assets/icon.png"), width: 40),
|
.watch(SpacesController.provider)
|
||||||
label: Text("Space 1"),
|
.when(
|
||||||
padding: EdgeInsets.only(top: 12),
|
loading: () => [],
|
||||||
),
|
error: (error, stack) {
|
||||||
|
debugPrintStack(
|
||||||
|
label: error.toString(),
|
||||||
|
stackTrace: stack,
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
},
|
||||||
|
data: (spaces) => spaces.map(
|
||||||
|
(space) => NavigationRailDestination(
|
||||||
|
icon: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||||
|
child: SizedBox(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
child:
|
||||||
|
space.avatar ??
|
||||||
|
ColoredBox(
|
||||||
|
color: ColorHash(space.roomData.name).color,
|
||||||
|
child: Center(
|
||||||
|
child: Text(space.roomData.name[0]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
label: Text(space.roomData.name),
|
||||||
|
padding: EdgeInsets.only(top: 12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
selectedIndex: index.value,
|
selectedIndex: index.value,
|
||||||
),
|
),
|
||||||
|
|
@ -44,6 +73,7 @@ class Sidebar extends HookWidget {
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
),
|
),
|
||||||
body: NavigationRail(
|
body: NavigationRail(
|
||||||
|
scrollable: true,
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
extended: true,
|
extended: true,
|
||||||
destinations: [
|
destinations: [
|
||||||
|
|
|
||||||
161
pubspec.lock
161
pubspec.lock
|
|
@ -89,6 +89,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.13.0"
|
version: "2.13.0"
|
||||||
|
base58check:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: base58check
|
||||||
|
sha256: "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
blurhash_dart:
|
blurhash_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -113,6 +121,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.0"
|
version: "3.1.0"
|
||||||
|
build_cli_annotations:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: build_cli_annotations
|
||||||
|
sha256: e563c2e01de8974566a1998410d3f6f03521788160a02503b0b1f1a46c7b3d95
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.1.1"
|
||||||
build_config:
|
build_config:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -169,6 +185,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.12.0"
|
version: "8.12.0"
|
||||||
|
canonical_json:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: canonical_json
|
||||||
|
sha256: d6be1dd66b420c6ac9f42e3693e09edf4ff6edfee26cb4c28c1c019fdb8c0c15
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.1.2"
|
||||||
characters:
|
characters:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -233,6 +257,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.19.1"
|
version: "1.19.1"
|
||||||
|
color_hash:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: color_hash
|
||||||
|
sha256: caf944576d465b17f273d2bc14b50e37e9292f6f20975771edde4916301dde74
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.1"
|
||||||
convert:
|
convert:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -457,10 +489,11 @@ packages:
|
||||||
flutter_chat_ui:
|
flutter_chat_ui:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: flutter_chat_ui
|
path: "packages/flutter_chat_ui"
|
||||||
sha256: "08a13577ea943d7965e3b1766d3a2119b07b56aced5336900ab7fb4c377d4ca0"
|
ref: HEAD
|
||||||
url: "https://pub.dev"
|
resolved-ref: c1ef794e78e56308872ec377c91645a483204a02
|
||||||
source: hosted
|
url: "https://github.com/Henry-Hiles/flutter_chat_ui"
|
||||||
|
source: git
|
||||||
version: "2.9.1"
|
version: "2.9.1"
|
||||||
flutter_hooks:
|
flutter_hooks:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
|
|
@ -523,6 +556,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.0.3"
|
version: "3.0.3"
|
||||||
|
flutter_rust_bridge:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: flutter_rust_bridge
|
||||||
|
sha256: "37ef40bc6f863652e865f0b2563ea07f0d3c58d8efad803cc01933a4b2ee067e"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.11.1"
|
||||||
flutter_svg:
|
flutter_svg:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -645,6 +686,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.15.6"
|
version: "0.15.6"
|
||||||
|
html_unescape:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: html_unescape
|
||||||
|
sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
http:
|
http:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -781,14 +830,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.9.0"
|
version: "4.9.0"
|
||||||
json_serializable:
|
|
||||||
dependency: "direct dev"
|
|
||||||
description:
|
|
||||||
name: json_serializable
|
|
||||||
sha256: "33a040668b31b320aafa4822b7b1e177e163fc3c1e835c6750319d4ab23aa6fe"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.11.1"
|
|
||||||
leak_tracker:
|
leak_tracker:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -829,6 +870,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.3.0"
|
version: "1.3.0"
|
||||||
|
markdown:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: markdown
|
||||||
|
sha256: "935e23e1ff3bc02d390bad4d4be001208ee92cc217cb5b5a6c19bc14aaa318c1"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "7.3.0"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -845,6 +894,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.11.1"
|
version: "0.11.1"
|
||||||
|
matrix:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: matrix
|
||||||
|
sha256: "94f5284c4ee521ae9d61f30cbb7c299d02d820e35509c028090d3b1901f520a3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.2"
|
||||||
meta:
|
meta:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1069,6 +1126,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
random_string:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: random_string
|
||||||
|
sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.1"
|
||||||
riverpod:
|
riverpod:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1149,6 +1214,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.26.2"
|
version: "1.26.2"
|
||||||
|
sdp_transform:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sdp_transform
|
||||||
|
sha256: "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.3.2"
|
||||||
sembast:
|
sembast:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1250,6 +1323,14 @@ packages:
|
||||||
description: flutter
|
description: flutter
|
||||||
source: sdk
|
source: sdk
|
||||||
version: "0.0.0"
|
version: "0.0.0"
|
||||||
|
slugify:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: slugify
|
||||||
|
sha256: b272501565cb28050cac2d96b7bf28a2d24c8dae359280361d124f3093d337c3
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.0"
|
||||||
source_gen:
|
source_gen:
|
||||||
dependency: "direct overridden"
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1258,14 +1339,6 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.0.2"
|
version: "4.0.2"
|
||||||
source_helper:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: source_helper
|
|
||||||
sha256: "6a3c6cc82073a8797f8c4dc4572146114a39652851c157db37e964d9c7038723"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.3.8"
|
|
||||||
source_map_stack_trace:
|
source_map_stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1290,6 +1363,30 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.10.1"
|
version: "1.10.1"
|
||||||
|
sqflite_common:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqflite_common
|
||||||
|
sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.5.6"
|
||||||
|
sqflite_common_ffi:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: sqflite_common_ffi
|
||||||
|
sha256: "9faa2fedc5385ef238ce772589f7718c24cdddd27419b609bb9c6f703ea27988"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.3.6"
|
||||||
|
sqlite3:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: sqlite3
|
||||||
|
sha256: "3145bd74dcdb4fd6f5c6dda4d4e4490a8087d7f286a14dee5d37087290f0f8a2"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.9.4"
|
||||||
stack_trace:
|
stack_trace:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1402,6 +1499,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.4.0"
|
version: "1.4.0"
|
||||||
|
unorm_dart:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: unorm_dart
|
||||||
|
sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.2.0"
|
||||||
url_launcher:
|
url_launcher:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
|
@ -1514,6 +1619,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "15.0.2"
|
version: "15.0.2"
|
||||||
|
vodozemac:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: vodozemac
|
||||||
|
sha256: "39144e20740807731871c9248d811ed5a037b21d0aa9ffcfa630954de74139d9"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.4.0"
|
||||||
watcher:
|
watcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -1554,6 +1667,14 @@ packages:
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.2.1"
|
version: "1.2.1"
|
||||||
|
webrtc_interface:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: webrtc_interface
|
||||||
|
sha256: "2e604a31703ad26781782fb14fa8a4ee621154ee2c513d2b9938e486fa695233"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.3.0"
|
||||||
win32:
|
win32:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
|
|
@ -40,18 +40,23 @@ dependencies:
|
||||||
url: https://github.com/google/flutter-desktop-embedding
|
url: https://github.com/google/flutter-desktop-embedding
|
||||||
path: plugins/window_size
|
path: plugins/window_size
|
||||||
flutter_chat_core: ^2.0.0
|
flutter_chat_core: ^2.0.0
|
||||||
flutter_chat_ui: ^2.0.0
|
|
||||||
flyer_chat_image_message: ^2.0.0
|
flyer_chat_image_message: ^2.0.0
|
||||||
flyer_chat_system_message: ^2.0.0
|
flyer_chat_system_message: ^2.0.0
|
||||||
flutter_link_previewer: ^4.0.0
|
flutter_link_previewer: ^4.0.0
|
||||||
flyer_chat_text_message: ^2.0.0
|
flyer_chat_text_message: ^2.0.0
|
||||||
|
flutter_chat_ui:
|
||||||
|
git:
|
||||||
|
url: https://github.com/Henry-Hiles/flutter_chat_ui
|
||||||
|
path: packages/flutter_chat_ui
|
||||||
|
matrix: ^3.0.2
|
||||||
|
sqflite_common_ffi: ^2.3.6
|
||||||
|
color_hash: ^1.0.1
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.11
|
build_runner: ^2.4.11
|
||||||
custom_lint: ^0.8.0
|
custom_lint: ^0.8.0
|
||||||
flutter_lints: ^6.0.0
|
flutter_lints: ^6.0.0
|
||||||
freezed: ^3.2.3
|
freezed: ^3.2.3
|
||||||
json_serializable: ^6.8.0
|
|
||||||
riverpod_lint: ^3.0.3
|
riverpod_lint: ^3.0.3
|
||||||
flutter_launcher_icons: ^0.14.1
|
flutter_launcher_icons: ^0.14.1
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue