@ -23,6 +23,18 @@
# include "websockets.h"
QString MainWindow : : getZaddrForContact ( QString contact ) {
QList < QList < QString > > addressLabels = AddressBook : : getInstance ( ) - > getAllAddressLabels ( ) ;
for ( int i = 0 ; i < addressLabels . size ( ) ; + + i ) {
QList < QString > thisContact = addressLabels . at ( i ) ;
if ( thisContact [ 0 ] = = contact ) {
qDebug ( ) < < " Found contact " < < thisContact [ 0 ] < < " " < < thisContact [ 1 ] ;
return thisContact [ 1 ] ;
}
}
return " " ;
}
MainWindow : : MainWindow ( QWidget * parent ) :
QMainWindow ( parent ) ,
ui ( new Ui : : MainWindow )
@ -48,23 +60,15 @@ MainWindow::MainWindow(QWidget *parent) :
// Settings editor
setupSettingsModal ( ) ;
// Set up exit action
// Set up actions
QObject : : connect ( ui - > actionExit , & QAction : : triggered , this , & MainWindow : : close ) ;
// Set up feedback action
QObject : : connect ( ui - > actionDonate , & QAction : : triggered , this , & MainWindow : : donate ) ;
QObject : : connect ( ui - > actionDiscord , & QAction : : triggered , this , & MainWindow : : discord ) ;
QObject : : connect ( ui - > actionReportBug , & QAction : : triggered , this , & MainWindow : : reportbug ) ;
QObject : : connect ( ui - > actionWebsite , & QAction : : triggered , this , & MainWindow : : website ) ;
// Set up check for updates action
QObject : : connect ( ui - > actionCheck_for_Updates , & QAction : : triggered , [ = ] ( ) {
// Silent is false, so show notification even if no update was found
rpc - > checkForUpdate ( false ) ;
} ) ;
// Send button
QObject : : connect ( ui - > sendMemo , & QPushButton : : clicked , this , & MainWindow : : sendMemo ) ;
// Request hush
QObject : : connect ( ui - > actionRequest_zcash , & QAction : : triggered , [ = ] ( ) {
@ -118,29 +122,180 @@ MainWindow::MainWindow(QWidget *parent) :
// Initialize to the balances tab
ui - > tabWidget - > setCurrentIndex ( 0 ) ;
if ( AppDataServer : : getInstance ( ) - > isAppConnected ( ) ) {
auto ads = AppDataServer : : getInstance ( ) ;
QString wormholecode = " " ;
if ( ads - > getAllowInternetConnection ( ) )
wormholecode = ads - > getWormholeCode ( ads - > getSecretHex ( ) ) ;
qDebug ( ) < < " MainWindow: createWebsocket with wormholecode= " < < wormholecode ;
createWebsocket ( wormholecode ) ;
}
//TODO: allow user to set this
ui - > textEdit - > setTextColor ( QColor ( " red " ) ) ;
QItemSelectionModel * qsm = ui - > chatView - > selectionModel ( ) ;
QObject : : connect ( qsm , SIGNAL ( itemSelectionChanged ( const QItemSelection & , const QItemSelection & ) ) , this , SLOT ( itemSelectionChanged ( ) ) ) ;
// Contacts and chat views should not be editable
ui - > chatView - > setEditTriggers ( QAbstractItemView : : NoEditTriggers ) ;
ui - > contactsView - > setEditTriggers ( QAbstractItemView : : NoEditTriggers ) ;
ui - > contactsView - > setViewMode ( QListView : : ListMode ) ;
// This works but doesn't take into account dark theme and is unreadable
//ui->contactsView->setAlternatingRowColors(true);
setupSendTab ( ) ;
setupTransactionsTab ( ) ;
setupReceiveTab ( ) ;
setupBalancesTab ( ) ;
setupMarketTab ( ) ;
//setupChatTab();
setupChatTab ( ) ;
setupHushTab ( ) ;
// Set up check for updates action
QObject : : connect ( ui - > actionCheck_for_Updates , & QAction : : triggered , [ = ] ( ) {
// Silent is false, so show notification even if no update was found
rpc - > checkForUpdate ( false ) ;
} ) ;
rpc = new RPC ( this ) ;
qDebug ( ) < < " Created RPC " ;
restoreSavedStates ( ) ;
if ( AppDataServer : : getInstance ( ) - > isAppConnected ( ) ) {
auto ads = AppDataServer : : getInstance ( ) ;
}
QString wormholecode = " " ;
if ( ads - > getAllowInternetConnection ( ) )
wormholecode = ads - > getWormholeCode ( ads - > getSecretHex ( ) ) ;
QString MainWindow : : createHeaderMemo ( QString cid , QString zaddr , int version = 0 , int headerNumber = 1 )
{
QString header = " " ;
QJsonDocument j ;
QJsonObject h ;
version = - 1 ; // This is unstable v=-1 until we launch with v=0
// We use short keynames to use less space for metadata and so allow
// the user to send more actual data in memos
h [ " h " ] = headerNumber ; // header number
h [ " v " ] = version ; // HushChat version
h [ " z " ] = zaddr ; // zaddr to respond to
h [ " cid " ] = cid ; // conversation id
j . setObject ( h ) ;
//TODO: how do we remove newlines?
header = j . toJson ( ) ;
qDebug ( ) < < " made header= " < < header ;
return header ;
}
qDebug ( ) < < " MainWindow: createWebsocket with wormholecode= " < < wormholecode ;
createWebsocket ( wormholecode ) ;
QString MainWindow : : getZaddrForCurrentContact ( ) {
QString zaddr ;
QModelIndex qmi = ui - > contactsView - > currentIndex ( ) ;
if ( qmi . isValid ( ) ) {
qDebug ( ) < < " Current (row,col) index: " < < qmi . row ( ) < < " , " < < qmi . column ( ) ;
// we seem to get duplicates due to QT internals shenanigans, just pick the first
QMap < int , QVariant > currentContacts = ui - > contactsView - > model ( ) - > itemData ( qmi ) ;
QString contact = currentContacts [ 0 ] . toString ( ) ;
qDebug ( ) < < " Current HushContact: " < < contact ;
zaddr = getZaddrForContact ( contact ) ;
} else {
qDebug ( ) < < " Invalid current index, no contacts selected " ;
}
return zaddr ;
}
QString MainWindow : : getNameForCurrentContact ( ) {
QString name ;
QModelIndex qmi = ui - > contactsView - > currentIndex ( ) ;
if ( qmi . isValid ( ) ) {
qDebug ( ) < < " Current (row,col) index: " < < qmi . row ( ) < < " , " < < qmi . column ( ) ;
// we seem to get duplicates due to QT internals shenanigans, just pick the first
QMap < int , QVariant > currentContacts = ui - > contactsView - > model ( ) - > itemData ( qmi ) ;
QString name = currentContacts [ 0 ] . toString ( ) ;
} else {
qDebug ( ) < < " Invalid current index, no contacts selected " ;
}
return name ;
}
// Send button clicked
void MainWindow : : sendMemo ( ) {
HushChat thisChat = MainWindow : : getHushChat ( ) ;
// Either we made a custom zaddr for this contact in the past, or we make a new one now
if ( thisChat . getContact ( ) . getMyZaddr ( ) . isEmpty ( ) ) {
QString newzaddr ;
rpc - > newZaddr ( [ = ] ( QJsonValue reply ) {
Tx tx ;
tx . fee = Settings : : getMinerFee ( ) ;
//TODO: verify we currently own the private key to this zaddr via z_validateaddress
HushChat chat = MainWindow : : getHushChat ( ) ;
HushContact contact = chat . getContact ( ) ;
QString myZaddr = reply . toString ( ) ;
QString addr = getZaddrForCurrentContact ( ) ;
QString name = getNameForCurrentContact ( ) ;
qDebug ( ) < < " created new myZaddr= " < < myZaddr < < " for " < < name ;
contact . setName ( name ) ;
contact . setMyZaddr ( myZaddr ) ;
contact . setZaddr ( addr ) ;
AddressBook : : getInstance ( ) - > addAddressLabel ( contact . getName ( ) , contact . getZaddr ( ) , contact . getMyZaddr ( ) ) ;
qDebug ( ) < < " Wrote new myZaddr for " < < contact . getName ( ) < < " to storage " ;
qDebug ( ) < < " Using " < < myZaddr < < " as from address for " < < contact . getName ( ) ;
double amount = 0 ;
QString cid = QUuid : : createUuid ( ) . toString ( QUuid : : WithoutBraces ) ;
QString hmemo = createHeaderMemo ( cid , myZaddr ) ;
QString memo = ui - > textEdit - > toPlainText ( ) ;
// we send a header memo plus actual memo
tx . toAddrs . push_back ( ToFields { addr , amount , hmemo , hmemo . toUtf8 ( ) . toHex ( ) } ) ;
tx . toAddrs . push_back ( ToFields { addr , amount , memo , memo . toUtf8 ( ) . toHex ( ) } ) ;
tx . fromAddr = contact . getMyZaddr ( ) ;
qDebug ( ) < < " Sending " < < name < < " ( " < < addr < < " ) a memo: " < < memo ;
QString error = doSendTxValidations ( tx ) ;
if ( ! error . isEmpty ( ) ) {
// Something went wrong, so show an error and exit
QMessageBox msg ( QMessageBox : : Critical , tr ( " Transaction Error " ) , error ,
QMessageBox : : Ok , this ) ;
msg . exec ( ) ;
// abort the Tx
return ;
}
// Show a dialog to confirm the Tx
if ( confirmTx ( tx ) ) {
// And send the Tx
rpc - > executeTransaction ( tx ,
[ = ] ( QString opid ) {
ui - > statusBar - > showMessage ( tr ( " Computing transaction: " ) % opid ) ;
qDebug ( ) < < " Computing opid: " < < opid ;
} ,
[ = ] ( QString , QString txid ) {
ui - > statusBar - > showMessage ( Settings : : txidStatusMessage + " " + txid ) ;
} ,
[ = ] ( QString opid , QString errStr ) {
ui - > statusBar - > showMessage ( QObject : : tr ( " Transaction " ) % opid % QObject : : tr ( " failed " ) , 15 * 1000 ) ;
if ( ! opid . isEmpty ( ) )
errStr = QObject : : tr ( " The transaction with id " ) % opid % QObject : : tr ( " failed. The error was " ) + " : \n \n " + errStr ;
QMessageBox : : critical ( this , QObject : : tr ( " Transaction Error " ) , errStr , QMessageBox : : Ok ) ;
}
) ;
}
} ) ; // newZaddr
} else {
// this contact already has a myZaddr
}
}
void MainWindow : : createWebsocket ( QString wormholecode ) {
@ -705,14 +860,27 @@ void MainWindow::balancesReady() {
}
// Event filter for MacOS specific handling of payment URIs
bool MainWindow : : eventFilter ( QObject * object , QEvent * event ) {
// Event filter for MacOS specific handling of payment URIs
if ( event - > type ( ) = = QEvent : : FileOpen ) {
QFileOpenEvent * fileEvent = static_cast < QFileOpenEvent * > ( event ) ;
if ( ! fileEvent - > url ( ) . isEmpty ( ) )
payZcashURI ( fileEvent - > url ( ) . toString ( ) ) ;
return true ;
} else if ( event - > type ( ) = = QEvent : : MouseButtonPress ) {
qDebug ( ) < < __func__ < < " : " < < " mouse button event on " < < object - > objectName ( ) ;
QMouseEvent * ev = static_cast < QMouseEvent * > ( event ) ;
if ( ev - > buttons ( ) & Qt : : RightButton )
{
//qDebug()<< "RightButton clicked";
}
if ( ev - > buttons ( ) & Qt : : LeftButton )
{
//qDebug()<< "LeftButton clicked";
//TODO: if this was a HushContact object in chatView, update MainWindow::contact
}
//return false;
}
return QObject : : eventFilter ( object , event ) ;
@ -1136,26 +1304,31 @@ void MainWindow::setupBalancesTab() {
void MainWindow : : setupHushTab ( ) {
ui - > hushlogo - > setBasePixmap ( QPixmap ( " :/img/res/zcashdlogo.gif " ) ) ;
}
/*
void MainWindow : : setupChatTab ( ) {
qDebug ( ) < < __FUNCTION__ ;
QList < QPair < QString , QString > > addressLabels = AddressBook : : getInstance ( ) - > getAllAddressLabels ( ) ;
QList < QList < QString > > addressLabels = AddressBook : : getInstance ( ) - > getAllAddressLabels ( ) ;
QStringListModel * chatModel = new QStringListModel ( ) ;
QStringList contacts ;
//contacts << "Alice" << "Bob" << "Charlie" << "Eve";
for ( int i = 0 ; i < addressLabels . size ( ) ; + + i ) {
QPair < QString , QString > pair = addressLabels . at ( i ) ;
qDebug ( ) < < " Found contact " < < pair . first < < " " < < pair . second ;
contacts < < pair . first ;
QList < QString > thisContact = addressLabels . at ( i ) ;
qDebug ( ) < < " Found contact " < < thisContact [ 0 ] < < " " < < thisContact [ 1 ] ;
contacts < < thisContact [ 0 ] ;
}
chatModel - > setStringList ( contacts ) ;
QStringListModel * conversationModel = new QStringListModel ( ) ;
QStringList conversations ;
conversations < < " Bring home some milk " < < " Markets look rough " < < " How's the weather? " < < " Is this on? " ;
conversations < < " The Bitcoin network might actually reduce spam by diverting zombie farms to generating bitcoins instead. " ;
conversationModel - > setStringList ( conversations ) ;
//conversationModel[0].setItemAlignment(Qt::AlignRight);
// iterate on all elements in chat view and set alignment
// ui->chatView->
//Ui_addressBook ab;
//AddressBookModel model(ab.addresses);
@ -1166,8 +1339,9 @@ void MainWindow::setupChatTab() {
ui - > contactsView - > setModel ( chatModel ) ;
ui - > chatView - > setModel ( conversationModel ) ;
ui - > chatGridLayout - > setColumnStretch ( 1 , 1 ) ;
ui - > chatGridLayout - > setRowStretch ( 1 , 2 ) ;
}
*/
void MainWindow : : setupMarketTab ( ) {
qDebug ( ) < < " Setting up market tab " ;
@ -1486,14 +1660,12 @@ void MainWindow::setupReceiveTab() {
if ( ! curLabel . isEmpty ( ) & & label . isEmpty ( ) ) {
info = " Removed Label ' " % curLabel % " ' " ;
AddressBook : : getInstance ( ) - > removeAddressLabel ( curLabel , addr ) ;
}
else if ( ! curLabel . isEmpty ( ) & & ! label . isEmpty ( ) ) {
} else if ( ! curLabel . isEmpty ( ) & & ! label . isEmpty ( ) ) {
info = " Updated Label ' " % curLabel % " ' to ' " % label % " ' " ;
AddressBook : : getInstance ( ) - > updateLabel ( curLabel , addr , label ) ;
}
else if ( curLabel . isEmpty ( ) & & ! label . isEmpty ( ) ) {
} else if ( curLabel . isEmpty ( ) & & ! label . isEmpty ( ) ) {
info = " Added Label ' " % label % " ' " ;
AddressBook : : getInstance ( ) - > addAddressLabel ( label , addr ) ;
AddressBook : : getInstance ( ) - > addAddressLabel ( label , addr , " " ) ;
}
// Update labels everywhere on the UI
@ -1561,7 +1733,7 @@ void MainWindow::slot_change_currency(const QString& currency_name)
saved_currency_name = Settings : : getInstance ( ) - > get_currency_name ( ) ;
} catch ( const std : : exception & e ) {
qDebug ( ) < < QString ( " Ignoring currency change Exception! : " ) ;
saved_currency_name = " USD " ;
saved_currency_name = " BTC " ;
}
}