matrix-js-sdk and login screen

master
f0x 5 years ago
parent b4baae8023
commit 720ccb2d2e

@ -3,6 +3,7 @@ const React = require('react')
const ReactDOM = require('react-dom')
const create = require('create-react-class')
const Promise = require('bluebird')
const urllib = require('url')
const Matrix = require('./backends/matrix.js')
@ -18,37 +19,87 @@ const Input = require('./components/input.js')
// incoming/outgoing message alignment (split)
let backend = new Matrix("user", "pass", "https://lain.haus")
backend.sync()
let App = create({
displayName: "App",
getInitialState: function() {
return this.checkBackend()
return {rooms: {}, events: {}}
},
checkBackend: function() {
let returnValue = null
if(backend.hasUpdates()) {
returnValue = {
rooms: backend.getRooms(),
events: backend.getEvents()
}
if(this.state.backend.hasUpdates()) {
console.log("RECEIVING UPDATES FROM BACKEND")
this.setState({
rooms: this.state.backend.getRooms(),
events: this.state.backend.getEvents()
})
}
setTimeout(() => {
this.setState(this.checkBackend())
this.checkBackend()
}, 100)
return returnValue
},
login: function() {
let user = document.getElementById("user").value
let pass = document.getElementById("pass").value
let hs = document.getElementById("hs").value
hs = urllib.parse(hs)
let data = {
user: user,
password: pass,
type: "m.login.password",
initial_device_display_name: "Neo v4",
};
let url = urllib.format(Object.assign(hs, {
pathname: "/_matrix/client/r0/login"
}));
fetch(url, {
body: JSON.stringify(data),
headers: {
'content-type': 'application/json'
},
method: 'POST',
}).then((response) => response.json())
.then((responseJson) => {
this.setState({json: responseJson});
if(responseJson.access_token != undefined) {
let backend = new Matrix(responseJson.user_id, responseJson.access_token, "https://"+responseJson.home_server)
this.setState({
backend: backend
})
this.checkBackend()
}
})
.catch((error) => {
console.error(error);
});
},
render: function() {
if (this.state.backend == undefined) {
//Login screen
return (
<div className="loginwrapper">
<img src="/neo.png"/>
<div className="login">
<label htmlFor="user">Username: </label><input type="text" id="user" placeholder="username"/>
<label htmlFor="pass">Password: </label><input type="password" id="pass"/>
<label htmlFor="hs">Homeserver: </label><input type="text" id="hs" placeholder="https://lain.haus"/>
<button onClick={()=>this.login()}>Log in</button>
</div>
</div>
)
}
return (
<>
<Sidebar rooms={this.state.rooms}/>
<Sidebar rooms={this.state.rooms} selectRoom={(roomId) => {this.setState({roomId: roomId})}}/>
<div className="main">
<Info />
<Chat events={this.state.events} backend={backend}/>
<Chat events={this.state.events} backend={this.state.backend} roomId={this.state.roomId}/>
<Input />
</div>
</>

@ -2,83 +2,53 @@
const React = require('react')
const ReactDOM = require('react-dom')
const defaultValue = require('default-value')
const sdk = require('matrix-js-sdk')
class Matrix {
constructor(user, password, homeserver) {
constructor(user, token, homeserver) {
this.user = user;
this.password = password;
this.homeserver = homeserver;
this.a = 0
this.events = {
"roomId": [
{
type: "m.room.message",
sender: "@f0x:lain.haus",
content: {
body: "Image caption",
info: {
size: 1331429,
mimetype: "image/png",
thumbnail_info: {
w: 600,
h: 600,
mimetype: "image/png",
size: 151911
},
w: 2000,
h: 2000,
thumbnail_url: "mxc://lain.haus/PnptnVmLprDNICfhCqIIurHZ"
},
msgtype: "m.image",
url: "mxc://lain.haus/MXtCRwxheuSEVsIyHfyUGJNz"
},
event_id: "$155317808164309EPnWP:lain.haus",
origin_server_ts: 1553178081145,
unsigned: {
age: 587,
transaction_id: "m1553178080798.12"
},
room_id: "!bghqZrxFTiDyEUzunK:disroot.org"
}
]
}
this.client = sdk.createClient({
baseUrl: homeserver,
accessToken: token,
userId: user
});
//this.rooms = ["Neo", "version 4", "Codename", "Iris", "Let's All Love Lain", "Very long room name abcdefghijklmnopqrstuvwxyz"]
this.rooms = {
"room0": {
name: "Neo",
lastEvent: 10
},
"room1": {
name: "v4: iris",
lastEvent: 10
},
"room2": {
name: "groups",
lastEvent: 10
},
"room3": {
name: "GUI Demo",
lastEvent: 0
}
}
this.events = {}
this.rooms = {}
this.startClient()
this.updates = true
}
startClient() {
this.client.on("Room.timeline", (event, room, toStartOfTimeline) => {
if (toStartOfTimeline) {
return
}
if (this.events[room.roomId] == undefined) {
this.events[room.roomId] = []
this.rooms[room.roomId] = {
name: room.name,
lastEvent: 0
}
}
this.events[room.roomId].push(event.event)
this.updates = true
console.log("NEW EVENTS")
})
this.client.startClient()
}
getHS() {
return this.homeserver
}
getEvents(roomId) {
return this.events["roomId"]
return this.events
}
getRooms() {
let orderList = Object.keys(this.rooms)
orderList.sort((a, b) => {
return this.rooms[b].lastEvent - this.rooms[a].lastEvent
})
return {rooms: this.rooms, order: orderList}
return this.rooms
}
hasUpdates() {
@ -89,36 +59,33 @@ class Matrix {
return false
}
addEvent(event) {
this.events["roomId"].push(event)
}
sync() {
let rand = this.lastRand
while(rand == this.lastRand) {
rand = Math.floor(Math.random()*Object.keys(this.rooms).length)
}
this.lastRand = rand
let roomId = `room${rand}`
let now = new Date().getMilliseconds()
this.rooms[roomId].lastEvent = now
this.updates = true
// let rand = this.lastRand
// while(rand == this.lastRand) {
// rand = Math.floor(Math.random()*Object.keys(this.rooms).length)
// }
// this.lastRand = rand
// let roomId = `room${rand}`
// let now = new Date().getMilliseconds()
// this.rooms[roomId].lastEvent = now
// this.updates = true
// let event = {
// content: {
// body: "New <code>m.text</code> Event",
// msgtype: "m.text"
// },
// event_id: this.fakeEventId(),
// origin_server_ts: 1432735824653,
// room_id: "!jEsUZKDJdhlrceRyVU:domain.com",
// sender: "@example:domain.com",
// type: "m.room.message",
// unsigned: {
// age: 1234
// }
// }
// this.events["roomId"].push(event)
let event = {
content: {
body: "Testing m.text",
msgtype: "m.text"
},
event_id: this.fakeEventId(),
origin_server_ts: 1432735824653,
room_id: "!jEsUZKDJdhlrceRyVU:domain.com",
sender: "@example:domain.com",
type: "m.room.message",
unsigned: {
age: 1234
}
}
this.events["roomId"].push(event)
setTimeout(() => {this.sync()}, 2000)
}

@ -27,8 +27,15 @@ jdenticon.config = {
let chat = create({
displayName: "Chat",
getInitialState: function() {
return {
ref: null
}
},
getSnapshotBeforeUpdate: function(oldProps, oldState) {
let ref = this.state.ref
if (ref == null) {return}
if ((ref.scrollHeight - ref.offsetHeight) - ref.scrollTop < 100) { // Less than 100px from bottom
return true
}
@ -37,6 +44,7 @@ let chat = create({
componentDidUpdate(prevProps, prevState, snapshot) {
let ref = this.state.ref
if (ref == null) {return}
if (snapshot) { // scroll to bottom
ref.scrollTop = (ref.scrollHeight - ref.offsetHeight)
}
@ -49,6 +57,14 @@ let chat = create({
},
render: function() {
if (this.props.roomId == undefined || this.props.events[this.props.roomId] == undefined) {
//empty screen
return <div className="chat" ref={this.setRef}>
<div className="events">
</div>
</div>
}
let messageGroups = {
current: [],
groups: [],
@ -58,7 +74,7 @@ let chat = create({
// if the sender is the same, add it to the 'current' messageGroup, if not,
// push the old one to 'groups' and start with a new array.
this.props.events.forEach((event, id) => {
this.props.events[this.props.roomId].forEach((event, id) => {
if (event.sender != messageGroups.sender) {
messageGroups.sender = event.sender
if (messageGroups.current.length != 0) {
@ -115,7 +131,7 @@ let EventGroup = create({
function getRenderedEvent(event, id, backend) {
if (event.type == "m.room.message") {
let msgtype = event.content.msgtype;
return React.createElement(elements[defaultValue(msgtype, "m.text")], {event: event, key: id, backend: backend})
return React.createElement(defaultValue(elements[msgtype], elements["m.text"]), {event: event, key: id, backend: backend})
}
}

@ -17,7 +17,7 @@ let FilterList = create({
select: function(id) {
this.setState({selection: id})
//this.props.callback(id)
this.props.callback(id)
},
inputRef: function(ref) {
@ -37,9 +37,9 @@ let FilterList = create({
},
render: function() {
let items = Object.keys(this.props.items).map((itemKey, id) => {
let keys = Object.keys(this.props.items)
let items = keys.map((itemKey, id) => {
let item = this.props.items[itemKey]
let props = {
selected: this.state.selection == itemKey,
filter: this.state.filter,

@ -4,6 +4,7 @@ const ReactDOM = require('react-dom')
const create = require('create-react-class')
const Promise = require('bluebird')
const debounce = require('debounce')
const jdenticon = require('jdenticon')
const FilterList = require('./filterList.js')
@ -17,6 +18,10 @@ let RoomListItem = create({
}
},
componentDidMount() {
jdenticon.update("svg")
},
setRef: function(ref) {
if (ref == null) {
return
@ -61,7 +66,7 @@ let Sidebar = create({
render: function() {
return <div className="sidebar">
<FilterList items={this.props.rooms.rooms} order={this.props.rooms.order} element={RoomListItem}/>
<FilterList items={this.props.rooms} element={RoomListItem} callback={(roomId) => {this.props.selectRoom(roomId)}}/>
</div>
}
})

@ -35,9 +35,11 @@
"gulp-util": "^3.0.8",
"jdenticon": "^2.1.1",
"livereactload": "^4.0.0-beta.2",
"matrix-js-sdk": "^1.0.2",
"react": "^16.6.3",
"react-dom": "^16.6.3",
"sanitize-html": "^1.20.0",
"sourceify": "^0.1.0",
"vinyl-buffer": "^1.0.1",
"vinyl-source-stream": "^2.0.0",
"webpack": "^4.27.1"

@ -48,6 +48,53 @@ body {
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
}
.loginwrapper {
margin-top: -15rem;
display: flex;
justify-content: center;
flex-direction: column;
img {
height: 15rem;
width: 15rem;
text-align: center;
align-self: center;
}
}
.login {
align-self: center;
display: inline-grid;
grid-template-columns: 1fr 1fr;
$blue: #5294e2;
label, input, button {
margin: 0.3rem;
padding: 0.3rem;
}
label {
background: $blue;
justify-self: left;
}
input {
border: 0.1rem solid $blue;
background: transparent;
color: white;
}
button {
grid-column-start: 2;
background: $blue;
color: white;
justify-self: right;
border: none;
}
}
.main {

@ -25,9 +25,11 @@ dependencies:
gulp-util: 3.0.8
jdenticon: 2.1.1
livereactload: 4.0.0-beta.2
matrix-js-sdk: 1.0.2
react: 16.6.3
react-dom: 16.6.3
sanitize-html: 1.20.0
sourceify: 0.1.0
vinyl-buffer: 1.0.1
vinyl-source-stream: 2.0.0
webpack: 4.27.1
@ -989,6 +991,15 @@ packages:
ajv: ^6.0.0
resolution:
integrity: sha1-6GuBnGAs+IIa1jdBNpjx3sAhhHo=
/ajv/6.10.0:
dependencies:
fast-deep-equal: 2.0.1
fast-json-stable-stringify: 2.0.0
json-schema-traverse: 0.4.1
uri-js: 4.2.2
dev: false
resolution:
integrity: sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
/ajv/6.6.2:
dependencies:
fast-deep-equal: 2.0.1
@ -1004,6 +1015,10 @@ packages:
node: '>=0.4.2'
resolution:
integrity: sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
/another-json/0.2.0:
dev: false
resolution:
integrity: sha1-tfQBnJc7bdXGUGotk0acttMq7tw=
/ansi-colors/1.1.0:
dependencies:
ansi-wrap: 0.1.0
@ -1393,6 +1408,13 @@ packages:
dev: false
resolution:
integrity: sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
/babel-runtime/6.26.0:
dependencies:
core-js: 2.6.5
regenerator-runtime: 0.11.1
dev: false
resolution:
integrity: sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
/babelify/10.0.0:
dev: false
engines:
@ -1421,6 +1443,18 @@ packages:
dev: false
resolution:
integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
/base-x/3.0.4:
dependencies:
safe-buffer: 5.1.2
dev: false
resolution:
integrity: sha512-UYOadoSIkEI/VrRGSG6qp93rp2WdokiAiNYDfGW5qURAY8GiAQkvMbwNNSDYiVJopqv4gCna7xqf4rrNGp+5AA==
/base-x/3.0.5:
dependencies:
safe-buffer: 5.1.2
dev: false
resolution:
integrity: sha512-C3picSgzPSLE+jW3tcBzJoGwitOtazb5B+5YmAxZm2ybmTi9LNgAtDO/jjVEBZwHoXmDBZ9m/IELj3elJVRBcA==
/base/0.11.2:
dependencies:
cache-base: 1.0.1
@ -1620,6 +1654,12 @@ packages:
hasBin: true
resolution:
integrity: sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==
/browser-request/0.3.3:
dev: false
engines:
'0': node
resolution:
integrity: sha1-ns5bWsqJopkyJC4Yv5M975h2zBc=
/browser-resolve/1.11.3:
dependencies:
resolve: 1.1.7
@ -1819,6 +1859,12 @@ packages:
hasBin: true
resolution:
integrity: sha512-kMGKs4BTzRWviZ8yru18xBpx+CyHG9eqgRbj9XbE3IMgtczf4aiA0Y1YCpVdvUieKGZ03kolSPXqTcscBCb9qw==
/bs58/4.0.1:
dependencies:
base-x: 3.0.5
dev: false
resolution:
integrity: sha1-vhYedsNU9veIrkBx9j806MTwpCo=
/budo/11.5.0:
dependencies:
bole: 2.0.0
@ -2405,6 +2451,12 @@ packages:
optional: true
resolution:
integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
/content-type/1.0.4:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
/convert-source-map/0.3.5:
dev: false
resolution:
@ -2451,6 +2503,10 @@ packages:
resolution:
integrity: sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=
tarball: 'http://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz'
/core-js/2.6.5:
dev: false
resolution:
integrity: sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
/core-util-is/1.0.2:
resolution:
integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
@ -3839,7 +3895,7 @@ packages:
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.7
mime-types: 2.1.21
mime-types: 2.1.22
dev: false
engines:
node: '>= 0.12'
@ -4491,7 +4547,7 @@ packages:
integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
/har-validator/5.1.3:
dependencies:
ajv: 6.6.2
ajv: 6.10.0
har-schema: 2.0.0
dev: false
engines:
@ -4675,7 +4731,7 @@ packages:
dependencies:
assert-plus: 1.0.0
jsprim: 1.4.1
sshpk: 1.16.0
sshpk: 1.16.1
dev: false
engines:
node: '>=0.8'
@ -5832,6 +5888,12 @@ packages:
optional: true
resolution:
integrity: sha1-X46MkNME7fElMJUaVVSruMXj9VI=
/loglevel/1.6.1:
dev: false
engines:
node: '>= 0.6.0'
resolution:
integrity: sha1-4PyVEztu8nbNyIh82vJKpvFW+Po=
/longest/1.0.1:
dev: false
engines:
@ -5953,6 +6015,22 @@ packages:
/math-random/1.0.1:
resolution:
integrity: sha1-izqsWIuKZuSXXjzepn97sylgH6w=
/matrix-js-sdk/1.0.2:
dependencies:
another-json: 0.2.0
babel-runtime: 6.26.0
base-x: 3.0.4
bluebird: 3.5.3
browser-request: 0.3.3
bs58: 4.0.1
content-type: 1.0.4
loglevel: 1.6.1
qs: 6.6.0
request: 2.88.0
unhomoglyph: 1.0.2
dev: false
resolution:
integrity: sha512-4WCBJFSoOLelHi7IUAcVxPQF+gTc/i9NUKZ77qwUfcZVED8VKTIyWZnwpeLgocK5gAOJV9fkAyO5mny9SkZaGg==
/md5.js/1.3.5:
dependencies:
hash-base: 3.0.4
@ -6085,16 +6163,23 @@ packages:
dev: false
engines:
node: '>= 0.6'
optional: true
resolution:
integrity: sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==
/mime-types/2.1.21:
/mime-db/1.38.0:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==
/mime-types/2.1.22:
dependencies:
mime-db: 1.37.0
mime-db: 1.38.0
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==
integrity: sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==
/mime/1.4.1:
dev: false
hasBin: true
@ -7321,6 +7406,12 @@ packages:
node: '>=0.6'
resolution:
integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
/qs/6.6.0:
dev: false
engines:
node: '>=0.6'
resolution:
integrity: sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA==
/query-string/4.3.4:
dependencies:
object-assign: 4.1.1
@ -7521,6 +7612,10 @@ packages:
dev: false
resolution:
integrity: sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
/regenerator-runtime/0.11.1:
dev: false
resolution:
integrity: sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
/regenerator-runtime/0.12.1:
dev: false
resolution:
@ -7650,7 +7745,7 @@ packages:
is-typedarray: 1.0.0
isstream: 0.1.2
json-stringify-safe: 5.0.1
mime-types: 2.1.21
mime-types: 2.1.22
oauth-sign: 0.9.0
performance-now: 2.1.0
qs: 6.5.2
@ -8161,6 +8256,13 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
/sourceify/0.1.0:
dependencies:
convert-source-map: 1.6.0
through2: 2.0.5
dev: false
resolution:
integrity: sha1-C1b+V/lFc1DZJliBCq/afA9EA0w=
/sparkles/1.0.1:
dev: false
engines:
@ -8228,7 +8330,7 @@ packages:
node: '>=0.10.0'
resolution:
integrity: sha1-pWad4StC87HV6D7QPHEEb8SPQe8=
/sshpk/1.16.0:
/sshpk/1.16.1:
dependencies:
asn1: 0.2.4
assert-plus: 1.0.0
@ -8244,7 +8346,7 @@ packages:
node: '>=0.10.0'
hasBin: true
resolution:
integrity: sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ==
integrity: sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
/ssri/6.0.1:
dependencies:
figgy-pudding: 3.5.1
@ -8987,6 +9089,10 @@ packages:
node: '>= 0.10'
resolution:
integrity: sha1-M52kZGJS0ILcN45wgGcpl1DhG0k=
/unhomoglyph/1.0.2:
dev: false
resolution:
integrity: sha1-1p5fWmocayEZQaCIm4HrqGWVwlM=
/unicode-canonical-property-names-ecmascript/1.0.4:
dev: false
engines:
@ -9546,9 +9652,11 @@ specifiers:
gulp-watch: ^5.0.1
jdenticon: ^2.1.1
livereactload: ^4.0.0-beta.2
matrix-js-sdk: ^1.0.2
react: ^16.6.3
react-dom: ^16.6.3
sanitize-html: ^1.20.0
sourceify: ^0.1.0
vinyl-buffer: ^1.0.1
vinyl-source-stream: ^2.0.0
webpack: ^4.27.1

Loading…
Cancel
Save