Skip to content

Commit

Permalink
Merge pull request #45 from hood-chat/chat-list
Browse files Browse the repository at this point in the history
Chat list
  • Loading branch information
farhoud authored Jan 18, 2023
2 parents a289d0b + a68a5c2 commit 1d424cf
Show file tree
Hide file tree
Showing 19 changed files with 270 additions and 125 deletions.
18 changes: 16 additions & 2 deletions android/app/src/main/java/com/helloworld/CoreModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -370,12 +370,12 @@ public void run() {
}

@ReactMethod
public void addContact(String id, String name, Promise promise) {
public void putContact(String id, String name, Promise promise) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Boolean res = cService.addContact(id, name);
Boolean res = cService.putContact(id, name);
promise.resolve(res);
} catch (Exception e) {
promise.reject(e);
Expand All @@ -385,6 +385,20 @@ public void run() {

}

@ReactMethod
public void seen(String id) {
new Thread(new Runnable() {
@Override
public void run() {
try {
cService.seen(id);
} catch (Exception e) {}
}
}).start();

}


@Override
public void onHostResume() {
// Activity `onResume`
Expand Down
6 changes: 5 additions & 1 deletion android/core/src/main/aidl/fx/android/core/ICoreService.aidl
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ interface ICoreService {
/**
* add new contact
*/
boolean addContact(String id, String name);
boolean putContact(String id, String name);
/**
* get contact info
*/
Expand Down Expand Up @@ -62,6 +62,10 @@ interface ICoreService {
*/
String sendMessage(String chatID, String text);
/**
* seen recived messages
*/
oneway void seen(String chatID);
/**
* Often you want to allow a service to call back to its clients.
* This shows how to do so, by registering a callback interface with
* the service.
Expand Down
16 changes: 12 additions & 4 deletions android/core/src/main/java/fx/android/core/CoreService.java
Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,9 @@ public String getChats(int skip, int limit) throws RemoteException {
}
}

public boolean addContact(String id, String name) throws RemoteException {
public boolean putContact(String id, String name) throws RemoteException {
try {
core.addContact(id, name);
core.putContact(id, name);
return true;
} catch (Exception e) {
return handleCoreException(false, e, "can not add contact");
Expand Down Expand Up @@ -308,7 +308,9 @@ public String getIdentity() throws RemoteException {

public String newIdentity(String name) throws RemoteException {
try {
return core.newIdentity(name);
String identity = core.newIdentity(name);
core.start();
return identity;
} catch (Exception e) {
return handleCoreException(null, e, "failed to retrieve create identity");
}
Expand Down Expand Up @@ -356,13 +358,19 @@ public String getPMChat(String contactID) throws RemoteException {
}

public String sendMessage(String chatID, String text) throws RemoteException {
Log.d(NAME, "send called");
Log.d(NAME, "send called with: "+chatID +", " +text );
try {
return core.sendMessage(chatID, text);
} catch (Exception e) {
return handleCoreException(null, e, "failed to send private message");
}
}

public void seen(String chatID) throws RemoteException {
try {
core.seen(chatID);
} catch (Exception e) { }
}
};

}
2 changes: 1 addition & 1 deletion app/components/chat/MessageStatus.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ interface Props {
id : string
}
export const MessageStatus: FC<Props>= observer((props: Props) => {
const { chatStore: { messages } } = useStores()
const { messageStore: { messages } } = useStores()
const msg = messages.get(props.id)
return(
<View style={$tickView}>
Expand Down
4 changes: 3 additions & 1 deletion app/models/Chat.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { Instance, SnapshotIn, SnapshotOut, types } from "mobx-state-tree"
import { ContactModel } from "./Contact"
import { MessageModel } from "./Message"

/**
* Model description here for TypeScript hints.
Expand All @@ -11,6 +10,9 @@ export const ChatModel = types
_id: types.identifier,
name: types.string,
members: types.array(types.reference(ContactModel)),
type: types.integer,
unread: types.integer,
latestText: types.string
})
.views((self) => ({})) // eslint-disable-line @typescript-eslint/no-unused-vars
.actions((self) => ({})) // eslint-disable-line @typescript-eslint/no-unused-vars
Expand Down
62 changes: 11 additions & 51 deletions app/models/ChatStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,10 @@ export const ChatStoreModel = types
.props({
chats: types.map(ChatModel),
selected: types.maybeNull(types.reference(ChatModel)),
messages: types.map(MessageModel),
hasEarlierMessages: types.maybe(types.boolean)
})
.views((self) => ({
get chatList() {
return self.chats.values()
},
get sortedMessages() {
return [...self.messages.values()].sort((a, b) => b.createdAt - a.createdAt)
}
})) // eslint-disable-line @typescript-eslint/no-unused-vars
.actions((self) => {
Expand All @@ -36,47 +31,25 @@ export const ChatStoreModel = types
self.chats.put(chat)

}
selectChat(chat._id)

select(chat._id)
})
const loadChatList = flow(function* loadChatList() {
const list = yield api.beeCore.chat.list(0, 50)
const load = flow(function* loadChatList() {
const list = yield api.beeCore.chat.list(0, 0)
const root = getRootStore(self)
const members = list.flatMap(item => item.members).filter((i)=>i !== root.identityStore.user._id)
root.contactStore.load(members)
list.forEach(chat => {
self.chats.put(chat)
});
})
const selectChat = flow(function* selectChat(chatId: string) {
const select = flow(function* selectChat(chatId: string) {
const selected = self.chats.get(chatId)
if (self.selected == null || self.selected._id !== selected._id) {
self.selected = selected
self.hasEarlierMessages = true
self.messages.clear()
}

})
const loadMessages = flow(function* loadMessages() {
const messages: Message[] = yield api.beeCore.messages.list(self.selected._id, self.messages.size, self.messages.size + 20)
self.hasEarlierMessages = !(messages.length < 20);
messages.forEach(msg => {
self.messages.put(msg)
});
})
const send = flow(function* send(msg: Message) {
let rmsg: Message = yield api.beeCore.chat.send(self.selected._id, {
_id: msg._id,
chatId: "",
createdAt: msg.createdAt,
user: msg.user._id,
text: msg.text
})
self.messages.put(rmsg)
})
const clear = () => {
self.selected = null
self.messages.clear()
}
const onMessageChange = flow(function* onMessageChange(id: string, action: string) {
//Todo: to much if and else need to clean it up
Expand All @@ -85,38 +58,25 @@ export const ChatStoreModel = types
switch (action) {
case "received":
let rmsg: Message = yield api.beeCore.messages.get(id)
// Chat if chat open put message
if (self.selected && self.selected._id === rmsg.chatId) {
self.messages.put(rmsg)
}
// Add chat to list if not exist
if (!self.chats.has(rmsg.chatId)) {
const root = getRootStore(self)
let newCH = yield api.beeCore.chat.get(rmsg.chatId)
root.contactStore.load(newCH.members)
self.chats.put(newCH);
} else {
const chat = self.chats.get(rmsg.chatId)
chat.latestText = rmsg.text
chat.unread += 1

}
break;
case "sent":
let smsg = self.messages.get(id)
if (self.selected && smsg && self.selected._id === smsg.chatId ) {
smsg.onSent()
}
break;
case "failed":
let nmsg = self.messages.get(id)
if (self.selected && nmsg && self.selected._id === nmsg.chatId) {
nmsg.onFailed()
}
break;
}
})
return {
loadMessages,
openPMChat,
selectChat,
loadChatList,
send,
select,
load,
clear,
onMessageChange
}
Expand Down
2 changes: 1 addition & 1 deletion app/models/ContactStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export const ContactStoreModel = types
self.form.saving = true;
const newContact = { _id:self.form._id, name:self.form.name }
try {
const res = yield api.beeCore.contact.add(newContact)
const res = yield api.beeCore.contact.put(newContact)
if(res){
self.contacts.put(newContact)
}else{
Expand Down
1 change: 1 addition & 0 deletions app/models/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const MessageModel = types
chatId: types.string,
user: types.reference(ContactModel),
sent: types.maybe(types.boolean),
seen: types.maybe(types.boolean),
received: types.maybe(types.boolean),
pending: types.maybe(types.boolean),
failed: types.maybe(types.boolean),
Expand Down
113 changes: 113 additions & 0 deletions app/models/MessageStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { flow, Instance, SnapshotIn, SnapshotOut, types } from "mobx-state-tree"
import { api } from "../services/core"
import { Message, MessageModel } from "./Message"
import { getRootStore } from "./helpers/getRootStore"
import { getUnixTime } from "date-fns"

const PAGINATION_SIZE = 20
const REFRESH_SIZE = 5

/**
* Model description here for TypeScript hints.
*/
export const MessageStoreModel = types
.model("MessageStore")
.props({
messages: types.map(MessageModel),
hasEarlierMessages: types.maybe(types.boolean),
chatId: types.maybeNull(types.string),
block: types.maybeNull(types.number)
})
.views((self) => ({
get sortedMessages() {
return [...self.messages.values()].sort((a, b) => b.createdAt - a.createdAt)
}
})) // eslint-disable-line @typescript-eslint/no-unused-vars
.actions((self) => {
const onFocus = flow(function* onFocus() {
if(self.block+1000< getUnixTime(new Date())){
refresh()
self.block=getUnixTime(new Date())
}
// check chat is selected
api.beeCore.chat.seen(self.chatId)
})
const open = flow(function* open(chatId) {
if(self.chatId !== chatId){
self.chatId = chatId
self.block = getUnixTime(new Date())
clear()
load()
}
})
const refresh = flow(function* refresh() {
let skip = 0
let limit = self.messages.size > 0 ? PAGINATION_SIZE : REFRESH_SIZE
const messages: Message[] = yield api.beeCore.messages.list(self.chatId, skip, limit)
self.hasEarlierMessages = !(messages.length < 20);
messages.forEach(msg => {
self.messages.put(msg)
});
})
const load = flow(function* load() {
const messages: Message[] = yield api.beeCore.messages.list(self.chatId, self.messages.size, self.messages.size + PAGINATION_SIZE)
self.hasEarlierMessages = !(messages.length < 20);
messages.forEach(msg => {
self.messages.put(msg)
});
})
const send = flow(function* send(msg: Message) {
let rmsg: Message = yield api.beeCore.chat.send(self.chatId, {
_id: msg._id,
chatId: "",
createdAt: msg.createdAt,
user: msg.user._id,
text: msg.text
})
self.messages.put(rmsg)
})
const clear = () => {
self.messages.clear()
self.hasEarlierMessages = false
}
const onMessageChange = flow(function* onMessageChange(id: string, action: string) {
//Todo: to much if and else need to clean it up
console.log("update message called with ", id, action)
// New Received Message
switch (action) {
case "received":
let rmsg: Message = yield api.beeCore.messages.get(id)
// Chat if chat open put message
if (self.chatId && self.chatId === rmsg.chatId) {
self.messages.put(rmsg)
}
break;
case "sent":
let smsg = self.messages.get(id)
if (self.chatId && smsg && self.chatId === smsg.chatId) {
smsg.onSent()
}
break;
case "failed":
let nmsg = self.messages.get(id)
if (self.chatId && nmsg && self.chatId === nmsg.chatId) {
nmsg.onFailed()
}
break;
}
})
return {
onFocus,
refresh,
load,
send,
clear,
open,
onMessageChange
}
}) // eslint-disable-line @typescript-eslint/no-unused-vars

export interface MessageStore extends Instance<typeof MessageStoreModel> { }
export interface MessageStoreSnapshotOut extends SnapshotOut<typeof MessageStoreModel> { }
export interface MessageStoreSnapshotIn extends SnapshotIn<typeof MessageStoreModel> { }
export const createMessageStoreDefaultModel = () => types.optional(MessageStoreModel, {})
4 changes: 3 additions & 1 deletion app/models/RootStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { createContactStoreDefaultModel } from "./ContactStore"
import { createChatListDefaultModel } from "./ChatStore"
import { createIdentityDefaultModel } from "./Identity"
import { createPermissionsDefaultModel } from "./Permissions"
import { createMessageStoreDefaultModel } from "./MessageStore"

/**
* A RootStore model.
Expand All @@ -11,7 +12,8 @@ export const RootStoreModel = types.model("RootStore").props({
contactStore: createContactStoreDefaultModel(),
identityStore: createIdentityDefaultModel(),
chatStore: createChatListDefaultModel(),
permissionStore: createPermissionsDefaultModel()
permissionStore: createPermissionsDefaultModel(),
messageStore: createMessageStoreDefaultModel(),
})

/**
Expand Down
1 change: 1 addition & 0 deletions app/models/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export * from "./Chat"
export * from "./Contact"
export * from "./Message"
export * from "./ChatStore"
export * from "./MessageStore"
export * from "./NewContact"
export * from "./ContactStore"
export * from "./Permissions"
Loading

0 comments on commit 1d424cf

Please sign in to comment.