Skip to content

Commit

Permalink
fix(rn): conversation
Browse files Browse the repository at this point in the history
Signed-off-by: Godefroy Ponsinet <godefroy.ponsinet@outlook.com>
  • Loading branch information
90dy committed Jul 3, 2019
1 parent 10faa25 commit 795a6d1
Show file tree
Hide file tree
Showing 37 changed files with 749 additions and 511 deletions.
3 changes: 1 addition & 2 deletions client/react-native/.eslintrc
Expand Up @@ -35,8 +35,7 @@
"dependencies/no-cycles": 1,
"dependencies/no-unresolved": 1,
"semi": ["error", "never"],
"padded-blocks": ["error", "never"],
"lines-between-class-members": ["error", "always"]
"padded-blocks": ["error", "never"]
},
"parserOptions": {
"ecmaFeatures": {
Expand Down
6 changes: 6 additions & 0 deletions client/react-native/app/bridge/service/entity/message.js
@@ -0,0 +1,6 @@
import pbjs from 'protobufjs/light'
import jsonDescriptor from './message.pb.json'

const root = pbjs.Root.fromJSON(jsonDescriptor)
export const Message = root.lookup('berty.entity.Message')
export default Message
47 changes: 47 additions & 0 deletions client/react-native/app/common/helpers/entity/conversation.js
@@ -0,0 +1,47 @@
import { BertyEntityContactInputStatus } from '../../enums.gen'
import tDate from '../timestampDate'

export const getTitle = ({ title, members }) =>
(title && title !== '' && title) ||
(members &&
members
.filter(m => m.contact && m.contact.status !== 42)
.map((m, index) => {
const displayName =
m.contact &&
(m.contact.overrideDisplayName || m.contact.displayName || '?????')
const before =
index === 0 ? '' : index === members.length - 1 ? ' and ' : ', '
return `${before}${displayName}`
})
.join('')) ||
'No name'

export const isReadByMe = ({ wroteAt, members }) => {
const myself = members.find(
_ => _.contact && _.contact.status === BertyEntityContactInputStatus.Myself
)
if (myself == null) {
return true
}
return tDate(myself.readAt).getTime() >= tDate(wroteAt).getTime()
}

export const isMessageReadByMe = ({ members }, { createdAt }) => {
const myself = members.find(
_ => _.contact && _.contact.status === BertyEntityContactInputStatus.Myself
)
if (myself == null) {
return true
}
return tDate(myself.readAt).getTime() >= tDate(createdAt).getTime()
}

export const isReadByOthers = message =>
message.dispatches &&
message.dispatches.some(_ => tDate(_.ackedAt).getTime() > 0)

export const messageHasError = message =>
message.dispatches.some(
_ => _.sendErrorMessage != null && _.sendErrorMessage !== ''
)
1 change: 1 addition & 0 deletions client/react-native/app/common/helpers/entity/index.js
@@ -0,0 +1 @@
export * as conversation from './conversation'
3 changes: 1 addition & 2 deletions client/react-native/app/common/helpers/json.js
Expand Up @@ -8,5 +8,4 @@ if (TextDecoder === undefined) {

const decoder = new TextDecoder('utf-8')

export const parseEmbedded = serialized =>
JSON.parse(decoder.decode(new Uint8Array(serialized)))
export const parseEmbedded = serialized => decoder.decode(serialized)
10 changes: 10 additions & 0 deletions client/react-native/app/common/helpers/timestampDate.js
@@ -0,0 +1,10 @@
export const timestampDate = timestamp => {
return new Date(
timestamp
? timestamp.seconds * 1000 +
(timestamp.nanos ? Math.round(timestamp.nanos / 1000000) : 0)
: 0
)
}

export default timestampDate
2 changes: 1 addition & 1 deletion client/react-native/app/container/entity.js
Expand Up @@ -22,7 +22,7 @@ export class Entity extends Component {
}
for (const [, data] of this.store) {
if (deepFilterEqual(filter, data)) {
return data
return this.store.get(data.id)
}
}
return null
Expand Down
21 changes: 21 additions & 0 deletions client/react-native/app/container/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions client/react-native/app/container/package.json
Expand Up @@ -9,6 +9,7 @@
"@berty/component": "^0.0.1",
"@berty/store": "^0.0.1",
"async-mutex": "^0.1.3",
"await-mutex": "^1.0.2",
"mobx": "^5.10.0",
"mobx-react": "^5.4.3",
"throttle-debounce": "^2.1.0"
Expand Down
87 changes: 72 additions & 15 deletions client/react-native/app/container/stream.js
Expand Up @@ -3,14 +3,17 @@ import { debounce, throttle } from 'throttle-debounce'
import { Component } from 'react'
import objectHash from 'object-hash'
import { deepFilterEqual, deepEqual } from './helper'
import Case from 'case'

export class Stream extends Component {
get method () {
return this.props.method || function () {}
}

get request () {
return this.props.request
}

get response () {
return this.props.response
}
Expand All @@ -32,6 +35,7 @@ export class Stream extends Component {
componentDidMount () {
this.invoke()
}

componentWillUnmount () {}

invoke = async () => {
Expand All @@ -45,6 +49,7 @@ export class Stream extends Component {
}

setStateDebounce = debounce(50, this.setState)

setStateDebounce = throttle(50, this.setState)

render () {
Expand All @@ -57,8 +62,11 @@ export class Stream extends Component {

export class StreamPagination extends Stream {
queue = []

cursor = ''

count = 0

loading = true

componentWillReceiveProps (props) {
Expand All @@ -75,6 +83,15 @@ export class StreamPagination extends Stream {
this.forceUpdate(this.invoke)
}

cursorExtractor = item =>
this.props.cursorExtractor
? this.props.cursorExtractor(item)
: item[Case.camel(this.paginate.orderBy || 'id')]

compareInf = (a, b) => (this.paginate.orderDesc ? a >= b : a <= b)

compareSup = (a, b) => (this.paginate.orderDesc ? a < b : a > b)

add = change => {
const { newValue } = change

Expand All @@ -84,38 +101,69 @@ export class StreamPagination extends Stream {
return
}

// find where to put the new item
const cursor = this.cursorExtractor(newValue)

// if item exist, update it
const index = this.queue.findIndex(item => newValue.id === item.id)
if (index !== -1) {
this.queue.splice(index, 1, newValue)
return
// if cursor has not changed, just update item
if (cursor === this.cursorExtractor(this.queue[index])) {
this.queue.splice(index, 1, newValue)
return
} else {
// else, update his position
}
}

// else find where to put the new item
const cursorField = this.paginate.sortedBy || 'id'
const cursor = newValue[cursorField]

for (let topIndex in this.queue) {
let itemTop = this.queue[topIndex]
let infTop = cursor <= itemTop[cursorField]
let infTop = this.compareInf(cursor, this.cursorExtractor(itemTop))
if (infTop) {
this.queue.splice(topIndex, 0, newValue)
// if item exist, update his position
if (index !== -1) {
this.queue.splice(
// remove all items from top
topIndex,
// delete items from top to index (included)
index + 1 - topIndex,
// replace first by index updated
newValue,
// add the all items from top to index (not included)
...this.queue.slice(topIndex, index)
)
} else {
this.queue.splice(topIndex, 0, newValue)
}
return
}
let bottomIndex = this.queue.length - topIndex - 1
let itemBottom = this.queue[bottomIndex]
let supBottom = cursor > itemBottom[cursorField]
let supBottom = this.compareSup(cursor, this.cursorExtractor(itemBottom))
if (supBottom) {
if (bottomIndex + 1 !== this.queue.length || change.force) {
this.queue.splice(bottomIndex + 1, 0, newValue)
return
// if item exist, update his position
if (index !== -1) {
this.queue.splice(
// remove all items from index
index,
// delete items from index (included) to bottom
bottomIndex - (index + 1),
// add all items from index (not included) to bottom
...this.queue.slice(index + 1, bottomIndex + 1),
// replace last by index updated
newValue
)
} else {
if (bottomIndex + 1 < this.queue.length || change.force) {
this.queue.splice(bottomIndex + 1, 0, newValue)
}
}
return
}
}

// if forced to add, push it
if (change.force) {
if (this.queue.length === 0 && change.force) {
this.queue.push(newValue)
return
}
Expand All @@ -139,19 +187,25 @@ export class StreamPagination extends Stream {
this.queue.splice(index, 1)
}

observeMutex = new Mutex()
observe = async change => {
this[change.type](change)
this.observeMutex.acquire().then(unlock => {
this[change.type](change)
unlock()
})
this.smartForceUpdate()
}

smartForceUpdateMutex = new Mutex()

smartForceUpdate = async () => {
if (this.smartForceUpdateMutex.isLocked()) {
return
}
const release = await this.smartForceUpdateMutex.acquire()
this.forceUpdateDebounced(release)
}

forceUpdateDebounced = debounce(16, this.forceUpdate)

get request () {
Expand Down Expand Up @@ -189,6 +243,7 @@ export class StreamPagination extends Stream {
}

invokeHashTable = {}

invoke = async () => {
const queue = []

Expand Down Expand Up @@ -216,7 +271,8 @@ export class StreamPagination extends Stream {
this.loading = false

if (queue.length !== 0) {
this.cursor = queue[queue.length - 1][this.paginate.sortedBy || 'id']
this.cursor =
queue[queue.length - 1][Case.camel(this.paginate.orderBy || 'id')]
}

this.smartForceUpdate()
Expand All @@ -233,6 +289,7 @@ export class StreamPagination extends Stream {
queue: this.queue,
paginate: this.invoke,
count: this.queue.length,
cursor: this.cursor,
loading: this.loading,
retry: this.retry,
})
Expand Down
24 changes: 20 additions & 4 deletions client/react-native/app/store/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions client/react-native/app/store/service.js
Expand Up @@ -2,7 +2,9 @@ import { action } from 'mobx'

export class ServiceStore {
type = ''

store = null

bridge = null

constructor (store, bridge) {
Expand Down

0 comments on commit 795a6d1

Please sign in to comment.