Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feature] Note To Self #569

Open
wants to merge 20 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@
"label-new-password": "New Password",
"label-confirm-new-password": "Confirm New Password",
"label-default-room-notification": "Default (Argon)",
"label-note-to-self": "Note to Self",
"label-note-to-self-topic": "A place to leave yourself notes",
"button-login": "log in",
"button-login-sso": "single sign on",
"button-save": "save",
Expand Down
2 changes: 2 additions & 0 deletions lib/global/strings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,8 @@ class Strings {
static final labelAbout = tr('label-about');
static final labelChatSettings = tr('label-chat-settings');
static final labelColor = tr('label-color');
static final labelNoteToSelf = tr('label-note-to-self');
static final labelNoteToSelfTopic = tr('label-note-to-self-topic');
static final labelTimestamp = tr('label-timestamp');
static final labelNone = tr('label-none');
static final labelSyncing = tr('label-syncing');
Expand Down
21 changes: 17 additions & 4 deletions lib/store/rooms/actions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import 'package:syphon/global/libs/matrix/encryption.dart';
import 'package:syphon/global/libs/matrix/errors.dart';
import 'package:syphon/global/libs/matrix/index.dart';
import 'package:syphon/global/print.dart';
import 'package:syphon/global/strings.dart';
import 'package:syphon/storage/constants.dart';
import 'package:syphon/store/alerts/actions.dart';
import 'package:syphon/store/events/actions.dart';
Expand Down Expand Up @@ -325,6 +326,16 @@ ThunkAction<AppState> createRoom({

final currentUser = store.state.authStore.user;
final inviteIds = invites.map((user) => user.userId).toList();
final inviteIdsFiltered =
inviteIds.whereNot((userId) => userId == currentUser.userId).toList();

final isNoteToSelf =
inviteIds.length == 1 && inviteIds.single == currentUser.userId;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good form on this line. It's a one liner, but it's easy to read


if (isNoteToSelf) {
name = Strings.labelNoteToSelf;
topic = Strings.labelNoteToSelfTopic;
}

final data = await MatrixApi.createRoom(
protocol: store.state.authStore.protocol,
Expand All @@ -333,7 +344,7 @@ ThunkAction<AppState> createRoom({
name: name,
topic: topic,
alias: alias,
invites: inviteIds,
invites: inviteIdsFiltered, //Don't invite ourself
isDirect: isDirect,
chatTypePreset: preset,
);
Expand All @@ -356,7 +367,7 @@ ThunkAction<AppState> createRoom({
room = room.copyWith(usersTEMP: userInviteMap);

if (isDirect) {
final User directUser = invites[0];
final User directUser = currentUser;
room = room.copyWith(
direct: true,
name: directUser.displayName ?? directUser.userId,
Expand Down Expand Up @@ -674,7 +685,8 @@ ThunkAction<AppState> joinRoom({Room? room}) {

final rooms = store.state.roomStore.rooms;

final Room joinedRoom = rooms.containsKey(room.id) ? rooms[room.id]! : Room(id: room.id);
final Room joinedRoom =
rooms.containsKey(room.id) ? rooms[room.id]! : Room(id: room.id);

store.dispatch(SetRoom(room: joinedRoom.copyWith(invite: false)));

Expand Down Expand Up @@ -742,7 +754,8 @@ ThunkAction<AppState> acceptRoom({required Room room}) {

final rooms = store.state.roomStore.rooms;

final Room joinedRoom = rooms.containsKey(room.id) ? rooms[room.id]! : Room(id: room.id);
final Room joinedRoom =
rooms.containsKey(room.id) ? rooms[room.id]! : Room(id: room.id);
store.dispatch(SetRoom(room: joinedRoom.copyWith(invite: false)));

store.dispatch(SetLoading(loading: true));
Expand Down
12 changes: 9 additions & 3 deletions lib/store/user/selectors.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,17 @@ List<User> selectFriendlyUsers(AppState state) {
return List.from(roomsDirectUsers);
}

// Users the authed user has dm'ed
// Users the authed user has encountered
List<User> selectKnownUsers(AppState state) {
final currentUser = state.authStore.currentUser;
final users = state.userStore.users;
final latestUsers = users.values.take(25);
return List.from(latestUsers);
final List<User> latestUsers = List.from(users.values.take(25));

if (!latestUsers.any((user) => user.userId == currentUser.userId)) {
latestUsers.insert(0, currentUser);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's picky, but you could use a .sort() here instead to just move the current user to the front without the if

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That only works if the user's in the list to begin with though, right?

}

return latestUsers;
}

List<User?> roomUsers(AppState state, String? roomId) {
Expand Down
5 changes: 5 additions & 0 deletions lib/views/home/groups/invite-users-screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,7 @@ class InviteUsersState extends State<InviteUsersScreen> with Lifecycle<InviteUse
props: props, context: context, user: attemptableUser),
type: ListItemUserType.Selectable,
user: attemptableUser,
currentUser: props.currentUser,
enabled: creatingRoomDisplayName != searchable,
loading: props.loading,
real: false,
Expand All @@ -358,6 +359,7 @@ class InviteUsersState extends State<InviteUsersScreen> with Lifecycle<InviteUse
return ListItemUser(
type: ListItemUserType.Selectable,
user: user,
currentUser: props.currentUser,
enabled: creatingRoomDisplayName != user.displayName,
selected: invites.contains(user),
loading: props.loading,
Expand Down Expand Up @@ -388,6 +390,7 @@ class _Props extends Equatable {
final bool loading;
final ThemeType themeType;
final bool creatingRoom;
final User currentUser;
final List<User> usersRecent;
final List<dynamic> searchResults;

Expand All @@ -398,6 +401,7 @@ class _Props extends Equatable {
const _Props({
required this.themeType,
required this.loading,
required this.currentUser,
required this.usersRecent,
required this.creatingRoom,
required this.searchResults,
Expand All @@ -414,6 +418,7 @@ class _Props extends Equatable {
];

static _Props mapStateToProps(Store<AppState> store) => _Props(
currentUser: store.state.authStore.currentUser,
usersRecent: selectFriendlyUsers(store.state),
themeType: store.state.settingsStore.themeSettings.themeType,
loading: store.state.searchStore.loading,
Expand Down
45 changes: 43 additions & 2 deletions lib/views/home/search/search-users-screen.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'package:equatable/equatable.dart';

import 'package:file/memory.dart';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'package:screenshot/screenshot.dart';
import 'package:syphon/global/dimensions.dart';
import 'package:syphon/global/formatters.dart';
import 'package:syphon/global/strings.dart';
import 'package:syphon/store/index.dart';
Expand All @@ -15,6 +18,7 @@ import 'package:syphon/store/user/selectors.dart';
import 'package:syphon/views/home/chat/chat-screen.dart';
import 'package:syphon/views/navigation.dart';
import 'package:syphon/views/widgets/appbars/appbar-search.dart';
import 'package:syphon/views/widgets/avatars/avatar.dart';
import 'package:syphon/views/widgets/dialogs/dialog-start-chat.dart';
import 'package:syphon/views/widgets/lists/list-item-user.dart';
import 'package:syphon/views/widgets/loader/index.dart';
Expand Down Expand Up @@ -158,7 +162,8 @@ class SearchUserState extends State<SearchUserScreen> {
setState(() {
creatingRoomDisplayName = user.displayName;
});
final newRoomId = await props!.onCreateChatDirect(user: user);
final newRoomId =
await props!.onCreateChatDirect(user: user, context: context);

Navigator.pop(dialogContext);

Expand Down Expand Up @@ -212,6 +217,7 @@ class SearchUserState extends State<SearchUserScreen> {
onTap: () => onAttemptChat(props: props, context: context, user: attemptableUser),
child: ListItemUser(
user: attemptableUser,
currentUser: props.currentUser,
enabled: creatingRoomDisplayName != searchable,
loading: props.loading,
real: false,
Expand All @@ -230,6 +236,7 @@ class SearchUserState extends State<SearchUserScreen> {
onTap: () => onShowUserDetails(context: context, user: user),
child: ListItemUser(
user: user,
currentUser: props.currentUser,
enabled: creatingRoomDisplayName != user.displayName,
loading: props.loading,
onPress: () => onCreateChat(
Expand Down Expand Up @@ -279,6 +286,7 @@ class SearchUserState extends State<SearchUserScreen> {
onTap: () => onShowUserDetails(context: context, user: user),
child: ListItemUser(
user: user,
currentUser: props.currentUser,
enabled: creatingRoomDisplayName != user.displayName,
loading: props.loading,
onPress: () => onCreateChat(
Expand Down Expand Up @@ -314,6 +322,7 @@ class SearchUserState extends State<SearchUserScreen> {
onTap: () => onShowUserDetails(context: context, user: user),
child: ListItemUser(
user: user,
currentUser: props.currentUser,
enabled: creatingRoomDisplayName != user.displayName,
loading: props.loading,
onPress: () => onCreateChat(
Expand Down Expand Up @@ -377,6 +386,7 @@ class _Props extends Equatable {
final bool loading;
final ThemeType themeType;
final bool creatingRoom;
final User currentUser;
final List<User> usersRecent;
final List<User> usersKnown;
final List<dynamic> searchResults;
Expand All @@ -389,6 +399,7 @@ class _Props extends Equatable {
required this.loading,
required this.creatingRoom,
required this.searchResults,
required this.currentUser,
required this.usersRecent,
required this.usersKnown,
required this.onSearch,
Expand All @@ -407,6 +418,7 @@ class _Props extends Equatable {
themeType: store.state.settingsStore.themeSettings.themeType,
loading: store.state.searchStore.loading,
creatingRoom: store.state.roomStore.loading,
currentUser: store.state.authStore.currentUser,
usersKnown: selectKnownUsers(store.state),
usersRecent: selectFriendlyUsers(store.state),
searchResults: store.state.searchStore.searchResults,
Expand All @@ -421,7 +433,36 @@ class _Props extends Equatable {

store.dispatch(searchUsers(searchText: text));
},
onCreateChatDirect: ({required User user}) async {
onCreateChatDirect: (
{required User user, required BuildContext context}) async {
if (user.userId == store.state.authStore.currentUser.userId) {
//Note to self, create our Avatar
final store = StoreProvider.of<AppState>(context);
final screenshotController = ScreenshotController();
final avatar = MemoryFileSystem().file('avatar.png');

await screenshotController
Copy link
Member

@ereio ereio Apr 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore the previous message, I just realized the Icon is an asset. You should be able to convert this to a bytestream without taking a screenshot. I can push something in a branch to help with this

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you. It has been driving me nuts how to get it out of its SVG

.captureFromWidget(
Avatar(
alt: Strings.labelNoteToSelf,
icon: Icons.sticky_note_2_outlined,
size: Dimensions.avatarSizeMax,
background: Theme.of(context).primaryColor,
).build(context),
EdGeraghty marked this conversation as resolved.
Show resolved Hide resolved
context: context)
.then((capturedAvatar) {
avatar.writeAsBytesSync(capturedAvatar);
});

return store.dispatch(
createRoom(
isDirect: true,
invites: <User>[user],
avatarFile: avatar,
),
);
}

return store.dispatch(
createRoom(
isDirect: true,
Expand Down
Loading