1
0
Fork 0
forked from Nexus/nexus

Compare commits

...

8 commits

10 changed files with 134 additions and 75 deletions

View file

@ -108,8 +108,8 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
- [x] Events
- [ ] Rooms
- [x] Member list
- [x] Sort by power level
- [ ] Colors based off of power level
- [ ] Sort by power level
- [ ] Notifications using UnifiedPush ([#35](https://git.federated.nexus/Nexus/nexus/issues/35))
- [ ] Group calls using [MSC4195](https://github.com/matrix-org/matrix-spec-proposals/pull/4195)
- [ ] Invites

Binary file not shown.

Before

Width:  |  Height:  |  Size: 466 KiB

After

Width:  |  Height:  |  Size: 616 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 462 KiB

After

Width:  |  Height:  |  Size: 616 KiB

Before After
Before After

View file

@ -2,5 +2,5 @@ import "package:color_hash/color_hash.dart";
import "package:flutter/material.dart";
extension ToColor on String {
Color get colorHash => ColorHash(this, lightness: .7, saturation: .7).color;
Color get colorHash => ColorHash(this, lightness: .5, saturation: .7).color;
}

View file

@ -1,4 +1,5 @@
import "package:flutter/material.dart";
import "package:nexus/widgets/divider_widget.dart";
class DividerText extends StatelessWidget {
final String text;
@ -6,24 +7,6 @@ class DividerText extends StatelessWidget {
const DividerText(this.text, {super.key});
@override
Widget build(BuildContext context) => LayoutBuilder(
builder: (context, constraints) => Row(
children: [
SizedBox(
width: 16,
child: Divider(color: Theme.of(context).colorScheme.onSurface),
),
ConstrainedBox(
constraints: .new(maxWidth: constraints.maxWidth - 32),
child: Padding(
padding: const .all(8),
child: Text(text, style: Theme.of(context).textTheme.labelLarge),
),
),
Expanded(
child: Divider(color: Theme.of(context).colorScheme.onSurface),
),
],
),
);
Widget build(BuildContext context) =>
DividerWidget(Text(text, style: Theme.of(context).textTheme.labelLarge));
}

View file

@ -0,0 +1,25 @@
import "package:flutter/material.dart";
class DividerWidget extends StatelessWidget {
final Widget widget;
const DividerWidget(this.widget, {super.key});
@override
Widget build(BuildContext context) => LayoutBuilder(
builder: (_, constraints) => Row(
children: [
SizedBox(
width: 16,
child: Divider(color: Theme.of(context).colorScheme.onSurface),
),
ConstrainedBox(
constraints: .new(maxWidth: constraints.maxWidth - 32),
child: Padding(padding: const .all(8), child: widget),
),
Expanded(
child: Divider(color: Theme.of(context).colorScheme.onSurface),
),
],
),
);
}

View file

@ -21,11 +21,12 @@ class ErrorDialog extends ConsumerWidget {
onPressed: () => ref.invalidate(provider!),
child: const Text("Try Again"),
),
TextButton(
onPressed: () =>
Navigator.of(context).popUntil((route) => route.isFirst),
child: const Text("Go Back"),
),
if (Navigator.of(context).canPop())
TextButton(
onPressed: () =>
Navigator.of(context).popUntil((route) => route.isFirst),
child: const Text("Go Back"),
),
],
);
}

View file

@ -18,36 +18,37 @@ class MessageImage extends ConsumerWidget {
url.toString(),
child: ClipRRect(
borderRadius: .all(.circular(8)),
child: Image(
image: CachedNetworkImage(
url.toString(),
ref.watch(CrossCacheController.provider),
headers: ref.headers,
),
width: info?.width,
loadingBuilder: (_, child, loadingProgress) => loadingProgress == null
? child
: switch (info?.blurHash) {
final blurHash? =>
info?.width == null || info?.height == null
? SizedBox(
width: 200,
height: 200,
child: BlurHash(hash: blurHash),
)
: AspectRatio(
aspectRatio: info!.width! / info!.height!,
child: SizedBox(
child: AspectRatio(
aspectRatio: info!.width! / info!.height!,
child: Image(
image: CachedNetworkImage(
url.toString(),
ref.watch(CrossCacheController.provider),
headers: ref.headers,
),
width: info?.width,
fit: BoxFit.fitWidth,
loadingBuilder: (_, child, loadingProgress) => loadingProgress == null
? child
: switch (info?.blurHash) {
final blurHash? =>
info?.width == null || info?.height == null
? SizedBox(
width: 200,
height: 200,
child: BlurHash(hash: blurHash),
)
: SizedBox(
width: info!.width,
child: BlurHash(hash: blurHash),
),
),
_ => Loading(),
},
errorBuilder: (context, error, stackTrace) => Center(
child: Text(
"Image Failed to Load",
style: .new(color: Theme.of(context).colorScheme.error),
_ => Loading(),
},
errorBuilder: (context, error, stackTrace) => Center(
child: Text(
"Image Failed to Load",
style: .new(color: Theme.of(context).colorScheme.error),
),
),
),
),

View file

@ -17,6 +17,7 @@ import "package:nexus/models/content/server_acl.dart";
import "package:nexus/models/content/sticker.dart";
import "package:nexus/models/content/topic.dart";
import "package:nexus/models/event.dart";
import "package:nexus/widgets/error_dialog.dart";
import "package:nexus/widgets/lazy_loading/message_displayname.dart";
import "package:nexus/widgets/renderers/message.dart";
import "package:nexus/widgets/reaction_row.dart";
@ -49,9 +50,13 @@ class EventRenderer extends ConsumerWidget {
final child = event.redactedBy != null || event.relationType == "m.replace"
? null
: switch (event.content) {
Content(:final parseError?) => SelectableText(
"An error occurred while parsing this event:\n$parseError\n${parseError.stackTrace}",
style: errorStyle,
Content(:final parseError?) => Row(
children: [
ErrorDialog(
"An error occurred while parsing event ${event.eventId}:\n$parseError",
parseError.stackTrace,
),
],
),
MessageContent() ||

View file

@ -7,6 +7,7 @@ import "package:nexus/controllers/key_controller.dart";
import "package:nexus/controllers/spaces_controller.dart";
import "package:nexus/models/room.dart";
import "package:nexus/widgets/avatar_or_hash.dart";
import "package:nexus/widgets/divider_widget.dart";
import "package:nexus/widgets/join_dialog.dart";
import "package:nexus/widgets/room_menu.dart";
@ -38,9 +39,11 @@ class Sidebar extends HookConsumerWidget {
spaces.firstWhereOrNull((space) => space.id == selectedSpaceId) ??
spaces.first;
final indexOfSelectedRoom = selectedSpace.children.indexWhere(
(room) => room.metadata?.id == selectedRoomId,
);
final indexOfSelectedRoom = selectedSpace.children
.addAll(
selectedSpace.subSpaces.map((element) => element.children).flattened,
)
.indexWhere((room) => room.metadata?.id == selectedRoomId);
final selectedRoomIndex = indexOfSelectedRoom == -1
? null
: indexOfSelectedRoom;
@ -60,7 +63,6 @@ class Sidebar extends HookConsumerWidget {
fallback: selectedSpaceId == "dms"
? null
: Icon(Icons.numbers),
// space.client.headers,
),
),
)
@ -98,17 +100,32 @@ class Sidebar extends HookConsumerWidget {
destinations: spaces
.map(
(space) => NavigationRailM3EDestination(
badgeCount: switch (space.children.fold(
0,
(previousValue, room) =>
previousValue +
(room.metadata?.unreadNotifications ?? 0),
)) {
badgeCount: switch (space.children
.addAll(
space.subSpaces
.map((element) => element.children)
.flattened,
)
.fold(
0,
(previousValue, room) =>
previousValue +
(room.metadata?.unreadNotifications ?? 0),
)) {
0 =>
space.children.any(
(room) =>
room.metadata?.unreadMessages != 0,
)
space.children
.addAll(
space.subSpaces
.map(
(element) => element.children,
)
.flattened,
)
.any(
(room) =>
room.metadata?.unreadMessages !=
0,
)
? 0
: null,
int badgeCount => badgeCount,
@ -213,20 +230,47 @@ class Sidebar extends HookConsumerWidget {
selectedIndex: selectedRoomIndex ?? 0,
sections: [
.new(
header: selectedSpace.room == null ? null : Text("Rooms"),
header: selectedSpace.room == null
? null
: DividerWidget(Text("Rooms")),
destinations: roomsToDestinations(selectedSpace.children),
),
for (final subSpace in selectedSpace.subSpaces)
.new(
header: Text(
subSpace.room.metadata?.name ?? "Unnamed Space",
header: DividerWidget(
Row(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
if (subSpace.room.metadata?.avatar != null)
AvatarOrHash(
subSpace.room.metadata?.avatar,
subSpace.room.metadata?.name ??
"Unnamed Room",
height: 16,
),
Flexible(
child: Text(
subSpace.room.metadata?.name ??
"Unnamed Space",
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
destinations: roomsToDestinations(subSpace.children),
),
],
onDestinationSelected: (value) {
final children = selectedSpace.children.addAll(
selectedSpace.subSpaces
.map((element) => element.children)
.flattened,
);
selectedRoomIdNotifier.set(
selectedSpace.children[value].metadata?.id,
children[value].metadata?.id, //
);
if (!isDesktop) Navigator.of(context).pop();
},