1
0
mirror of https://github.com/fazo96/telecommander.git synced 2025-01-10 11:34:20 +01:00

improved interface, implemented marking messages as read

This commit is contained in:
Enrico Fasoli 2015-09-01 15:30:51 +02:00
parent d6ff917688
commit 66d9667c88
4 changed files with 163 additions and 188 deletions

View File

@ -14,14 +14,13 @@ As of __now__, __Telecommander lets you__:
- Chat in groups and in private (it also marks messages as read when you read them)
- Know when you have unread messages
- Do everything __completely in the terminal, even via ssh__ using only the keyboard
- Do everything (except writing, duh) using only the mouse!
- Do everything (except writing messages, duh) using only the mouse, in the terminal!
- Navigate your contact and chat list
- Scroll back to view old messages
Waht's missing for version _0.1.0_ (__Almost done!__):
- View who's online and when was the last time they logged in
- Testing and tying up loose ends in user interface and code quality
What's missing (for future versions up to 1.0)
@ -35,7 +34,6 @@ What's missing (for future versions up to 1.0)
- Sign out (without having to manually delete files)
- Delete account
- Reply to and Forward message support
- Cool interface (it's already ok, just not as cool as I want it to be)
- Search, Tab completion, chatbox history
- Send multiline messages
- Themes and configurability! Basic scripting!

161
lib/ui.js
View File

@ -8,31 +8,37 @@ module.exports = function(data){
// Get msgBox for given group/user NAME, create if not exists
data.getMsgBox = function(chat){
if(chat === undefined){
log('ERROR: asked for box for "undefined"!!')
data.log('ERROR: asked for box for "undefined"!!')
return data.msgBox[statusWindow]
}
if(!data.msgBox[chat]){
//log('Generating window: "'+chat+'"')
data.msgBox[chat] = data.mkBox(chat)
data.screen.append(data.msgBox[chat])
data.screen.insertBefore(data.msgBox[chat],data.loader)
//data.getMessages(chat,data.msgBox[chat])
} // else log('Getting window','"'+chat+'"')
return data.msgBox[chat]
}
data.switchToBox = function(boxname){
// Hide current window
if(data.selectedWindow && data.msgBox[data.selectedWindow])
data.msgBox[data.selectedWindow].hide()
data.selectedWindow = boxname;
if(data.selectedWindow != data.statusWindow){
data.cmdline.setLabel('to '+data.selectedWindow)
data.markAsRead(data.selectedWindow)
if(boxname === undefined){
// Leave the clear
} else {
data.cmdline.setLabel('Command for Telecommander')
// Switch window
data.selectedWindow = boxname;
if(data.selectedWindow != data.statusWindow){
data.cmdline.setLabel('to '+data.selectedWindow)
data.markAsRead(data.selectedWindow)
} else {
data.cmdline.setLabel('Command for Telecommander')
}
var newb = data.getMsgBox(data.selectedWindow)
newb.show()
newb.emit('scroll')
}
var newb = data.getMsgBox(data.selectedWindow)
newb.show()
newb.emit('scroll')
data.screen.render()
}
@ -88,6 +94,20 @@ module.exports = function(data){
})
data.screen.append(data.chats)
// Command line prompt
data.cmdline = blessed.textbox({
keys: false,
mouse: true,
label: 'Command for Telecommander',
bottom: 0,
left: 'center',
width: '100%',
height: 3,
border: { type: 'line' },
style: data.getDefaultStyle()
})
data.screen.append(data.cmdline);
// Function to create a log box
data.mkBox = function(txt){
var b = ChatBox({
@ -125,40 +145,44 @@ module.exports = function(data){
return b
}
// Command line prompt
data.cmdline = blessed.textbox({
keys: false,
mouse: true,
label: 'Command for Telecommander',
bottom: 0,
left: 'center',
width: '100%',
height: 3,
border: { type: 'line' },
style: data.getDefaultStyle()
})
data.screen.append(data.cmdline);
data.getDefaultPopupStyle = function(){
return {
width: '30%',
key: true,
height: 'shrink',
left: 'center',
top: 'center',
align: 'center',
valign: 'center',
border: { type: 'line' },
style: data.getDefaultStyle()
}
}
// Widget used to show loading windows
data.loader = blessed.loading({
width: '30%',
height: 5,
left: 'center',
top: 'center',
align: 'center',
valign: 'center',
border: { type: 'line' },
style: data.getDefaultStyle()
})
data.loader = blessed.Loading(data.getDefaultPopupStyle())
data.screen.append(data.loader)
data.load = function(msg){
data.loader.stop()
data.loader.load(msg)
}
// Widget used to ask for phone number and code
data.promptBox = blessed.Prompt(data.getDefaultPopupStyle())
data.screen.append(data.promptBox)
// Widget used to show pop up read only messages
data.popup = blessed.Message(data.getDefaultPopupStyle())
data.screen.append(data.popup)
data.popup.hide()
// mgsBox holds the chat window instance for every chat
data.msgBox = { }
// Add the status window and switch to it
// Add the status window but don't show it
data.msgBox[data.statusWindow] = data.mkBox(data.statusWindow)
data.screen.append(data.msgBox[data.statusWindow])
data.switchToBox(data.statusWindow)
data.switchToBox()
data.screen.on('resize',function(){
for(i in data.msgBox){
@ -175,72 +199,7 @@ module.exports = function(data){
data.switchToBox(data.statusWindow)
})
data.command = function(cmd){
cmdl = cmd.split(' ')
cmdname = cmdl[0]
if(cmdname === 'phone'){ // So the user can provide his phone numbah
if(data.connected){
return log("Silly user, you're already connected! We don't need that phone number")
}
data.user.phone = cmd.split(' ')[1]
var mindate = moment()
log('Checking your phone number with Telegram...')
data.client.auth.sendCode(user.phone,5,'en',function(result){
if(result.err_code){
return log('Errors:',result.error_code,result.error_message)
}
//log('Res:',JSON.stringify(result))
data.user.registered = result.phone_registered
data.user.phoneCodeHash = result.phone_code_hash
function gmd(){
var m = moment()
m = m.subtract(m.diff(mindate))
return 'Please use a telegram code not older than '+m.fromNow(true)
}
if(!data.user.registered){
data.log("Your number is not registered. Telecommander will register your account with the Telegram service")
data.log(gmd())
data.log('Ready for phone code, use command: "code <code> <name> <lastname>" to register')
data.log("If you don't want to sign up, just don't enter the code and press ESC to exit. No data was saved to the file system")
} else {
data.log("Your number is already assigned to a Telegram account. Telecommander will log you in.")
data.log(gmd())
data.log("If you don't want to sign in, just don't enter the code and press ESC to exit. No data was saved to the file system")
}
})
} else if(cmdname === 'code'){ // So the user can provide his phone code
if(data.connected){
return log("Silly user, you're already connected! We don't need that phone code")
}
code = cmdl[1]
name = cmdl[2]
lastname = cmdl[3]
if(((!name || !lastname) && !data.user.registered) || !code)
return log('insufficient arguments:',cmd)
cb = function(result){
data.user.id = ''+result.user.id
data.user.phone = result.user.phone
data.user.phoneCodeHash = result.phone_code_hash
data.user.username = result.user.username
data.user.first_name = result.user.first_name
data.user.last_name = result.user.last_name
// Done, write user data and key to disk
log('Writing Log In token and user data to',cfgDir)
fs.writeFile(cfgDir+'key',authKey,function(err){
if(err) log('FATAL: Could not write key to disk:',err)
})
fs.writeFile(cfgDir+'user_data.json',JSON.stringify(user),function(err){
if(err) log("FATAL: couldn't write user_data.json:",err)
})
whenReady()
}
// Log in finally
if(user.registered) client.auth.signIn(user.phone,user.phoneCodeHash,code,cb)
else client.auth.signUp(user.phone,user.phoneCodeHash,code,name,lastname,cb)
} else {
data.log('Command not found.')
}
data.log('Commands are not implemented... sorry!')
}
// What happens when a different window is selected

View File

@ -127,18 +127,15 @@ module.exports = function(data){
toread = data.contacts[id].toread
} else data.log('Failed to find name for',type,id)
if(obj === undefined){
throw new Error("Can't find name for",type,id)
return
}
if(type === 'user'){
name = 'Unknown '+type+' '+id
} else if(type === 'user'){
// User
if(obj.first_name === undefined && obj.last_name === undefined && obj.username === undefined){
data.log('Zombie User: '+obj)
return 'undefined'
}
name = obj.first_name + (obj.last_name?' '+obj.last_name:'') + (obj.username?' (@'+obj.username+')':'')
} else {
// Group
} else { // Group
name = obj.title
}
if(forChatList && toread > 0) return '* '+name

View File

@ -57,70 +57,13 @@ data.command = function(cmd){
if(data.connected){
return log("Silly user, you're already connected! We don't need that phone number")
}
data.user.phone = cmd.split(' ')[1]
var mindate = moment()
data.log('Checking your phone number with Telegram...')
data.client.auth.sendCode(data.user.phone,5,'en',function(result){
if(result.err_code){
return data.log('Errors:',result.error_code,result.error_message)
}
//data.log('Res:',JSON.stringify(result))
data.user.registered = result.phone_registered
data.user.phoneCodeHash = result.phone_code_hash
function gmd(){
var m = moment()
m = m.subtract(m.diff(mindate))
return 'Please use a telegram code not older than '+m.fromNow(true)
}
if(!data.user.registered){
data.log("Your number is not registered. Telecommander will register your account with the Telegram service")
data.log(gmd())
data.log('Ready for phone code, use command: "code <code> <name> <lastname>" to register')
data.log("If you don't want to sign up, just don't enter the code and press ESC to exit. No data was saved to the file system")
} else {
data.log("Your number is already assigned to a Telegram account. Telecommander will log you in.")
data.log(gmd())
data.log("If you don't want to sign in, just don't enter the code and press ESC to exit. No data was saved to the file system")
}
})
} else if(cmdname === 'code'){ // So the user can provide his phone code
if(data.connected){
return data.log("Silly user, you're already connected! We don't need that phone code")
}
code = cmdl[1]
name = cmdl[2]
lastname = cmdl[3]
if(((!name || !lastname) && !data.user.registered) || !code)
return log('insufficient arguments:',cmd)
var cb = function(result){
data.user.id = ''+result.user.id
data.user.phone = result.user.phone
data.user.phoneCodeHash = result.phone_code_hash
data.user.username = result.user.username
data.user.first_name = result.user.first_name
data.user.last_name = result.user.last_name
// Done, write user data and key to disk
try {
fs.mkdirSync(data.cfgDir,'0770')
} catch (e) {
if(e.code != 'EEXIST'){
console.error("FATAL: couldn't create configuration directory",data.cfgDir,e)
process.exit(-1)
}
}
data.log('Writing Log In token and user data to',data.cfgDir)
fs.writeFile(data.cfgDir+'key',data.app.authKey,function(err){
if(err) data.log('FATAL: Could not write key to disk:',err)
})
fs.writeFile(data.cfgDir+'user_data.json',JSON.stringify(data.user),function(err){
if(err) data.log("FATAL: couldn't write user_data.json:",err)
})
data.whenReady()
}
// Log in finally
if(data.user.registered) data.client.auth.signIn(data.user.phone,data.user.phoneCodeHash,code,cb)
else data.client.auth.signUp(data.user.phone,data.user.phoneCodeHash,code,name,lastname,cb)
} else {
data.log('Command not found.')
}
@ -142,15 +85,86 @@ data.sendMsg = function(name,str){
})
}
data.onPhoneCode = function(something,s){
if(s === null){ // User cancelled
process.exit(0)
}
var cmdl = s.split(' ')
code = cmdl[0]
name = cmdl[1]
lastname = cmdl[2]
if(((!name || !lastname) && !data.user.registered) || !code)
return log('insufficient arguments:',cmd) // TODO: handle this better!
var cb = function(result){
data.user.id = ''+result.user.id
data.user.phone = result.user.phone
data.user.phoneCodeHash = result.phone_code_hash
data.user.username = result.user.username
data.user.first_name = result.user.first_name
data.user.last_name = result.user.last_name
// Done, write user data and key to disk
try {
fs.mkdirSync(data.cfgDir,'0770')
} catch (e) {
if(e.code != 'EEXIST'){
console.error("FATAL: couldn't create configuration directory",data.cfgDir,e)
process.exit(-1)
}
}
data.log('Writing Log In token and user data to',data.cfgDir)
fs.writeFile(data.cfgDir+'key',data.app.authKey,function(err){
if(err) data.log('FATAL: Could not write key to disk:',err)
})
fs.writeFile(data.cfgDir+'user_data.json',JSON.stringify(data.user),function(err){
if(err) data.log("FATAL: couldn't write user_data.json:",err)
})
data.whenReady()
}
// Log in finally
if(data.user.registered) data.client.auth.signIn(data.user.phone,data.user.phoneCodeHash,code,cb)
else data.client.auth.signUp(data.user.phone,data.user.phoneCodeHash,code,name,lastname,cb)
}
data.onPhoneNumber = function(something,s){
if(s === null){ // User cancelled
process.exit(0)
}
data.user.phone = s.trim()
var mindate = moment()
data.log('Checking your phone number with Telegram...')
data.client.auth.sendCode(data.user.phone,5,'en',function(result){
if(result.err_code){
return data.log('Errors:',result.error_code,result.error_message)
}
//data.log('Res:',JSON.stringify(result))
data.user.registered = result.phone_registered
data.user.phoneCodeHash = result.phone_code_hash
var msg
if(!data.user.registered){
msg = "Your number ("+data.user.phone+") is not registered.\nTelecommander will register your account with the Telegram service."
} else {
msg = "Your number ("+data.user.phone+") is already assigned to a Telegram account.\nTelecommander will log you in."
}
msg += "\nPress ESC to exit now, or enter to continue"
data.popup.display(msg,0,function(){
data.popup.hide()
data.promptBox.input('Your telegram code:','',data.onPhoneCode)
})
})
}
// Connects to telegram
data.connect = function(){
data.load('Connecting...')
data.client = data.telegramLink.createClient(data.app, data.dataCenter, function(){
if(!data.app.authKey){
data.log('Downloading Authorization Key...')
data.client.createAuthKey(function(auth){
data.app.authKey = auth.key.encrypt('password') // Will add security later, I promise
// Writes the new encrypted key to disk
data.log('Ready for phone number, use command: phone <number>')
data.loader.stop()
//data.log('Ready for phone number, use command: phone <number>')
data.promptBox.input('Phone number (international format):','+',data.onPhoneNumber)
})
} else {
data.whenReady()
@ -164,7 +178,7 @@ data.connect = function(){
// Executed when connected and logged in
data.whenReady = function(){
data.log('Connected')
data.load('Connected')
data.connected = true
data.downloadData()
data.chats.focus()
@ -172,8 +186,7 @@ data.whenReady = function(){
// Downloads stuff
data.downloadData = function(){
data.loader.load('Downloading data')
data.screen.render()
data.load('Downloading data')
data.client.contacts.getContacts('',function(cont){
//data.chats.clearItems()
//data.chats.add(data.statusWindow)
@ -184,6 +197,7 @@ data.downloadData = function(){
data.client.messages.getDialogs(0,0,10,function(dialogs){
if(dialogs && dialogs.chats && dialogs.chats.list)
dialogs.chats.list.forEach(data.addGroup)
data.loader.stop()
})
data.client.updates.getState(function(astate){
@ -236,6 +250,7 @@ data.getMessages = function(name,box){
if(!peer) return log('Could not find peer:',name)
data.downloadingMessages = true
var oldnlines = box.getLines().length
if(data.selectedWindow === name) data.load('Downloading history...')
data.client.messages.getHistory(peer,0,obj.oldest_message||0,10,function(res){
//log(res.toPrintable())
//log('Got history for: '+getName(peer.user_id||peer.chat_id,peer.chat_id?'group':'user'))
@ -251,6 +266,7 @@ data.getMessages = function(name,box){
})
if(oldnlines == 0) box.setScrollPerc(100)
//box.add(obj.oldest_message)
data.loader.stop()
data.downloadingMessages = false
})
}
@ -308,20 +324,25 @@ data.appendMsg = function(msg,toBoxId,bare,prepend){
box.add(msg)
else {
var id = msg.from_id
var date = moment.unix(msg.date).format('DD-MM-YYYY H:mm')
name = data.getName(id,'user')
var txt = (name || id)+' {|} {grey-fg}'+date+'{/grey-fg}\n'
if(msg.media){
if(msg.media.photo)
txt += '{grey-fg}>>>{/grey-fg} (Photo)'
else if(msg.media.audio)
txt += "{grey-fg}>>>{/grey-fg} (Audio Message) "+msg.media.audio.duration+" seconds"
else if(!msg.message)
txt += "{grey-fg}>>>{/grey-fg} (Unsupported Message)"
if(!id){ // Weird zombie message!
data.log('Zombie Message:',msg.toPrintable())
return box
} else { // Regular message
var date = moment.unix(msg.date).format('DD-MM-YYYY H:mm')
name = data.getName(id,'user')
var txt = (name || id)+' {|} {grey-fg}'+date+'{/grey-fg}\n'
if(msg.media){
if(msg.media.photo)
txt += '{grey-fg}>>>{/grey-fg} (Photo)'
else if(msg.media.audio)
txt += "{grey-fg}>>>{/grey-fg} (Audio Message) "+msg.media.audio.duration+" seconds"
else if(!msg.message)
txt += "{grey-fg}>>>{/grey-fg} (Unsupported Message)"
}
if(msg.message) txt += '{grey-fg}>{/grey-fg} '+msg.message
if(prepend) box.prepend(txt)
else box.add(txt)
}
if(msg.message) txt += '{grey-fg}>{/grey-fg} '+msg.message
if(prepend) box.prepend(txt)
else box.add(txt)
}
// Mark messages as read if needed
if(param === data.selectedWindow) data.markAsRead(param)
@ -330,8 +351,8 @@ data.appendMsg = function(msg,toBoxId,bare,prepend){
// - Entry Point -
// Load authKey and userdata from disk, then act depending on outcome
data.load('Starting up...')
data.screen.render()
data.log('Loading files...')
fs.exists(data.keyFile,function(exists){
if(exists){
//log('Authorization Key found')