forked from Nexus/nexus
Compare commits
No commits in common. "309d0df5819dbec341cc1f4778e4b35df8f0c86d" and "e1d7a30a0649f5856c3fcd8ed2567c7451bb0c39" have entirely different histories.
309d0df581
...
e1d7a30a06
10 changed files with 75 additions and 134 deletions
|
|
@ -108,8 +108,8 @@ A simple and user-friendly Matrix client made with Flutter and a Gomuks backend.
|
||||||
- [x] Events
|
- [x] Events
|
||||||
- [ ] Rooms
|
- [ ] Rooms
|
||||||
- [x] Member list
|
- [x] Member list
|
||||||
- [x] Sort by power level
|
|
||||||
- [ ] Colors based off of power level
|
- [ ] Colors based off of power level
|
||||||
|
- [ ] Sort by power level
|
||||||
- [ ] Notifications using UnifiedPush ([#35](https://git.federated.nexus/Nexus/nexus/issues/35))
|
- [ ] 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)
|
- [ ] Group calls using [MSC4195](https://github.com/matrix-org/matrix-spec-proposals/pull/4195)
|
||||||
- [ ] Invites
|
- [ ] Invites
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 616 KiB After Width: | Height: | Size: 466 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 616 KiB After Width: | Height: | Size: 462 KiB |
|
|
@ -2,5 +2,5 @@ import "package:color_hash/color_hash.dart";
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
|
|
||||||
extension ToColor on String {
|
extension ToColor on String {
|
||||||
Color get colorHash => ColorHash(this, lightness: .5, saturation: .7).color;
|
Color get colorHash => ColorHash(this, lightness: .7, saturation: .7).color;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
import "package:flutter/material.dart";
|
import "package:flutter/material.dart";
|
||||||
import "package:nexus/widgets/divider_widget.dart";
|
|
||||||
|
|
||||||
class DividerText extends StatelessWidget {
|
class DividerText extends StatelessWidget {
|
||||||
final String text;
|
final String text;
|
||||||
|
|
@ -7,6 +6,24 @@ class DividerText extends StatelessWidget {
|
||||||
const DividerText(this.text, {super.key});
|
const DividerText(this.text, {super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) =>
|
Widget build(BuildContext context) => LayoutBuilder(
|
||||||
DividerWidget(Text(text, style: Theme.of(context).textTheme.labelLarge));
|
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),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
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),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -21,12 +21,11 @@ class ErrorDialog extends ConsumerWidget {
|
||||||
onPressed: () => ref.invalidate(provider!),
|
onPressed: () => ref.invalidate(provider!),
|
||||||
child: const Text("Try Again"),
|
child: const Text("Try Again"),
|
||||||
),
|
),
|
||||||
if (Navigator.of(context).canPop())
|
TextButton(
|
||||||
TextButton(
|
onPressed: () =>
|
||||||
onPressed: () =>
|
Navigator.of(context).popUntil((route) => route.isFirst),
|
||||||
Navigator.of(context).popUntil((route) => route.isFirst),
|
child: const Text("Go Back"),
|
||||||
child: const Text("Go Back"),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,37 +18,36 @@ class MessageImage extends ConsumerWidget {
|
||||||
url.toString(),
|
url.toString(),
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius: .all(.circular(8)),
|
borderRadius: .all(.circular(8)),
|
||||||
child: AspectRatio(
|
child: Image(
|
||||||
aspectRatio: info!.width! / info!.height!,
|
image: CachedNetworkImage(
|
||||||
child: Image(
|
url.toString(),
|
||||||
image: CachedNetworkImage(
|
ref.watch(CrossCacheController.provider),
|
||||||
url.toString(),
|
headers: ref.headers,
|
||||||
ref.watch(CrossCacheController.provider),
|
),
|
||||||
headers: ref.headers,
|
width: info?.width,
|
||||||
),
|
loadingBuilder: (_, child, loadingProgress) => loadingProgress == null
|
||||||
width: info?.width,
|
? child
|
||||||
fit: BoxFit.fitWidth,
|
: switch (info?.blurHash) {
|
||||||
loadingBuilder: (_, child, loadingProgress) => loadingProgress == null
|
final blurHash? =>
|
||||||
? child
|
info?.width == null || info?.height == null
|
||||||
: switch (info?.blurHash) {
|
? SizedBox(
|
||||||
final blurHash? =>
|
width: 200,
|
||||||
info?.width == null || info?.height == null
|
height: 200,
|
||||||
? SizedBox(
|
child: BlurHash(hash: blurHash),
|
||||||
width: 200,
|
)
|
||||||
height: 200,
|
: AspectRatio(
|
||||||
child: BlurHash(hash: blurHash),
|
aspectRatio: info!.width! / info!.height!,
|
||||||
)
|
child: SizedBox(
|
||||||
: SizedBox(
|
|
||||||
width: info!.width,
|
width: info!.width,
|
||||||
child: BlurHash(hash: blurHash),
|
child: BlurHash(hash: blurHash),
|
||||||
),
|
),
|
||||||
_ => Loading(),
|
),
|
||||||
},
|
_ => Loading(),
|
||||||
errorBuilder: (context, error, stackTrace) => Center(
|
},
|
||||||
child: Text(
|
errorBuilder: (context, error, stackTrace) => Center(
|
||||||
"Image Failed to Load",
|
child: Text(
|
||||||
style: .new(color: Theme.of(context).colorScheme.error),
|
"Image Failed to Load",
|
||||||
),
|
style: .new(color: Theme.of(context).colorScheme.error),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ import "package:nexus/models/content/server_acl.dart";
|
||||||
import "package:nexus/models/content/sticker.dart";
|
import "package:nexus/models/content/sticker.dart";
|
||||||
import "package:nexus/models/content/topic.dart";
|
import "package:nexus/models/content/topic.dart";
|
||||||
import "package:nexus/models/event.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/lazy_loading/message_displayname.dart";
|
||||||
import "package:nexus/widgets/renderers/message.dart";
|
import "package:nexus/widgets/renderers/message.dart";
|
||||||
import "package:nexus/widgets/reaction_row.dart";
|
import "package:nexus/widgets/reaction_row.dart";
|
||||||
|
|
@ -50,13 +49,9 @@ class EventRenderer extends ConsumerWidget {
|
||||||
final child = event.redactedBy != null || event.relationType == "m.replace"
|
final child = event.redactedBy != null || event.relationType == "m.replace"
|
||||||
? null
|
? null
|
||||||
: switch (event.content) {
|
: switch (event.content) {
|
||||||
Content(:final parseError?) => Row(
|
Content(:final parseError?) => SelectableText(
|
||||||
children: [
|
"An error occurred while parsing this event:\n$parseError\n${parseError.stackTrace}",
|
||||||
ErrorDialog(
|
style: errorStyle,
|
||||||
"An error occurred while parsing event ${event.eventId}:\n$parseError",
|
|
||||||
parseError.stackTrace,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
|
|
||||||
MessageContent() ||
|
MessageContent() ||
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import "package:nexus/controllers/key_controller.dart";
|
||||||
import "package:nexus/controllers/spaces_controller.dart";
|
import "package:nexus/controllers/spaces_controller.dart";
|
||||||
import "package:nexus/models/room.dart";
|
import "package:nexus/models/room.dart";
|
||||||
import "package:nexus/widgets/avatar_or_hash.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/join_dialog.dart";
|
||||||
import "package:nexus/widgets/room_menu.dart";
|
import "package:nexus/widgets/room_menu.dart";
|
||||||
|
|
||||||
|
|
@ -39,11 +38,9 @@ class Sidebar extends HookConsumerWidget {
|
||||||
spaces.firstWhereOrNull((space) => space.id == selectedSpaceId) ??
|
spaces.firstWhereOrNull((space) => space.id == selectedSpaceId) ??
|
||||||
spaces.first;
|
spaces.first;
|
||||||
|
|
||||||
final indexOfSelectedRoom = selectedSpace.children
|
final indexOfSelectedRoom = selectedSpace.children.indexWhere(
|
||||||
.addAll(
|
(room) => room.metadata?.id == selectedRoomId,
|
||||||
selectedSpace.subSpaces.map((element) => element.children).flattened,
|
);
|
||||||
)
|
|
||||||
.indexWhere((room) => room.metadata?.id == selectedRoomId);
|
|
||||||
final selectedRoomIndex = indexOfSelectedRoom == -1
|
final selectedRoomIndex = indexOfSelectedRoom == -1
|
||||||
? null
|
? null
|
||||||
: indexOfSelectedRoom;
|
: indexOfSelectedRoom;
|
||||||
|
|
@ -63,6 +60,7 @@ class Sidebar extends HookConsumerWidget {
|
||||||
fallback: selectedSpaceId == "dms"
|
fallback: selectedSpaceId == "dms"
|
||||||
? null
|
? null
|
||||||
: Icon(Icons.numbers),
|
: Icon(Icons.numbers),
|
||||||
|
// space.client.headers,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
@ -100,32 +98,17 @@ class Sidebar extends HookConsumerWidget {
|
||||||
destinations: spaces
|
destinations: spaces
|
||||||
.map(
|
.map(
|
||||||
(space) => NavigationRailM3EDestination(
|
(space) => NavigationRailM3EDestination(
|
||||||
badgeCount: switch (space.children
|
badgeCount: switch (space.children.fold(
|
||||||
.addAll(
|
0,
|
||||||
space.subSpaces
|
(previousValue, room) =>
|
||||||
.map((element) => element.children)
|
previousValue +
|
||||||
.flattened,
|
(room.metadata?.unreadNotifications ?? 0),
|
||||||
)
|
)) {
|
||||||
.fold(
|
|
||||||
0,
|
|
||||||
(previousValue, room) =>
|
|
||||||
previousValue +
|
|
||||||
(room.metadata?.unreadNotifications ?? 0),
|
|
||||||
)) {
|
|
||||||
0 =>
|
0 =>
|
||||||
space.children
|
space.children.any(
|
||||||
.addAll(
|
(room) =>
|
||||||
space.subSpaces
|
room.metadata?.unreadMessages != 0,
|
||||||
.map(
|
)
|
||||||
(element) => element.children,
|
|
||||||
)
|
|
||||||
.flattened,
|
|
||||||
)
|
|
||||||
.any(
|
|
||||||
(room) =>
|
|
||||||
room.metadata?.unreadMessages !=
|
|
||||||
0,
|
|
||||||
)
|
|
||||||
? 0
|
? 0
|
||||||
: null,
|
: null,
|
||||||
int badgeCount => badgeCount,
|
int badgeCount => badgeCount,
|
||||||
|
|
@ -230,47 +213,20 @@ class Sidebar extends HookConsumerWidget {
|
||||||
selectedIndex: selectedRoomIndex ?? 0,
|
selectedIndex: selectedRoomIndex ?? 0,
|
||||||
sections: [
|
sections: [
|
||||||
.new(
|
.new(
|
||||||
header: selectedSpace.room == null
|
header: selectedSpace.room == null ? null : Text("Rooms"),
|
||||||
? null
|
|
||||||
: DividerWidget(Text("Rooms")),
|
|
||||||
destinations: roomsToDestinations(selectedSpace.children),
|
destinations: roomsToDestinations(selectedSpace.children),
|
||||||
),
|
),
|
||||||
for (final subSpace in selectedSpace.subSpaces)
|
for (final subSpace in selectedSpace.subSpaces)
|
||||||
.new(
|
.new(
|
||||||
header: DividerWidget(
|
header: Text(
|
||||||
Row(
|
subSpace.room.metadata?.name ?? "Unnamed Space",
|
||||||
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),
|
destinations: roomsToDestinations(subSpace.children),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
onDestinationSelected: (value) {
|
onDestinationSelected: (value) {
|
||||||
final children = selectedSpace.children.addAll(
|
|
||||||
selectedSpace.subSpaces
|
|
||||||
.map((element) => element.children)
|
|
||||||
.flattened,
|
|
||||||
);
|
|
||||||
selectedRoomIdNotifier.set(
|
selectedRoomIdNotifier.set(
|
||||||
children[value].metadata?.id, //
|
selectedSpace.children[value].metadata?.id,
|
||||||
);
|
);
|
||||||
if (!isDesktop) Navigator.of(context).pop();
|
if (!isDesktop) Navigator.of(context).pop();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue