1 /*
2     Copyright (C) 2014 Aseman
3     http://aseman.co
4 
5     This project is free software: you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation, either version 3 of the License, or
8     (at your option) any later version.
9 
10     This project is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14 
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #include "telegramdialogsmodel.h"
20 #include "telegramqml.h"
21 #include "objects/types.h"
22 #include "userdata.h"
23 #include "database.h"
24 
25 #include <telegram.h>
26 #include <QPointer>
27 
28 class TelegramDialogsModelPrivate
29 {
30 public:
31     QPointer<TelegramQml> telegram;
32     bool initializing;
33     bool stopUpdating;
34 
35     int refresh_timer;
36 
37     QList<qint64> dialogs;
38 };
39 
TelegramDialogsModel(QObject * parent)40 TelegramDialogsModel::TelegramDialogsModel(QObject *parent) :
41     TgAbstractListModel(parent)
42 {
43     p = new TelegramDialogsModelPrivate;
44     p->telegram = 0;
45     p->initializing = false;
46     p->stopUpdating = false;
47     p->refresh_timer = 0;
48 }
49 
telegram() const50 TelegramQml *TelegramDialogsModel::telegram() const
51 {
52     return p->telegram;
53 }
54 
setTelegram(TelegramQml * tgo)55 void TelegramDialogsModel::setTelegram(TelegramQml *tgo)
56 {
57     if( p->telegram == tgo )
58         return;
59 
60     if( p->telegram )
61     {
62         disconnect( p->telegram, SIGNAL(dialogsChanged(bool)), this, SLOT(dialogsChanged(bool)) );
63         disconnect( p->telegram, SIGNAL(phoneNumberChanged()), this, SLOT(refreshDatabase()) );
64 
65         disconnect( p->telegram->userData(), SIGNAL(favoriteChanged(int)) , this, SLOT(userDataChanged()) );
66         disconnect( p->telegram->userData(), SIGNAL(valueChanged(QString)), this, SLOT(userDataChanged()) );
67 
68         disconnect(p->telegram, SIGNAL(authLoggedInChanged()), this, SLOT(recheck()));
69     }
70 
71     p->telegram = tgo;
72     p->initializing = tgo;
73     if( p->telegram )
74     {
75         connect( p->telegram, SIGNAL(dialogsChanged(bool)), SLOT(dialogsChanged(bool)) );
76         connect( p->telegram, SIGNAL(phoneNumberChanged()), SLOT(refreshDatabase()), Qt::QueuedConnection );
77 
78         connect( p->telegram->userData(), SIGNAL(favoriteChanged(int)) , this, SLOT(userDataChanged()) );
79         connect( p->telegram->userData(), SIGNAL(valueChanged(QString)), this, SLOT(userDataChanged()) );
80 
81         connect(p->telegram, SIGNAL(authLoggedInChanged()), this, SLOT(recheck()), Qt::QueuedConnection);
82     }
83 
84     recheck();
85 
86     Q_EMIT telegramChanged();
87     Q_EMIT initializingChanged();
88 }
89 
stopUpdating() const90 bool TelegramDialogsModel::stopUpdating() const
91 {
92     return p->stopUpdating;
93 }
94 
setStopUpdating(bool stt)95 void TelegramDialogsModel::setStopUpdating(bool stt)
96 {
97     if(p->stopUpdating == stt)
98         return;
99 
100     p->stopUpdating = stt;
101     if(!p->stopUpdating)
102         dialogsChanged(true);
103 
104     Q_EMIT stopUpdatingChanged();
105 }
106 
id(const QModelIndex & index) const107 qint64 TelegramDialogsModel::id(const QModelIndex &index) const
108 {
109     int row = index.row();
110     return p->dialogs.at(row);
111 }
112 
rowCount(const QModelIndex & parent) const113 int TelegramDialogsModel::rowCount(const QModelIndex &parent) const
114 {
115     Q_UNUSED(parent)
116     return p->dialogs.count();
117 }
118 
data(const QModelIndex & index,int role) const119 QVariant TelegramDialogsModel::data(const QModelIndex &index, int role) const
120 {
121     QVariant res;
122     const qint64 key = id(index);
123     switch( role )
124     {
125     case ItemRole:
126         res = QVariant::fromValue<DialogObject*>(p->telegram->dialog(key));
127         break;
128 
129     case SectionRole:
130         res = p->telegram->userData()->value("love").toLongLong()==key? 2 : (p->telegram->userData()->isFavorited(key)? 1 : 0);
131         break;
132     }
133 
134     return res;
135 }
136 
roleNames() const137 QHash<qint32, QByteArray> TelegramDialogsModel::roleNames() const
138 {
139     static QHash<qint32, QByteArray> *res = 0;
140     if( res )
141         return *res;
142 
143     res = new QHash<qint32, QByteArray>();
144     res->insert( ItemRole, "item");
145     res->insert( SectionRole, "section");
146     return *res;
147 }
148 
count() const149 int TelegramDialogsModel::count() const
150 {
151     return p->dialogs.count();
152 }
153 
initializing() const154 bool TelegramDialogsModel::initializing() const
155 {
156     return p->initializing;
157 }
158 
indexOf(DialogObject * dialog)159 int TelegramDialogsModel::indexOf(DialogObject *dialog)
160 {
161     if(!dialog)
162         return -1;
163 
164     qint64 dId = dialog->peer()->chatId();
165     if(!dId)
166         dId = dialog->peer()->userId();
167 
168     return p->dialogs.indexOf(dId);
169 }
170 
at(int row)171 DialogObject *TelegramDialogsModel::at(int row)
172 {
173     if(row < 0 || row >= p->dialogs.count())
174         return 0;
175 
176     return p->telegram->dialog( p->dialogs.at(row) );
177 }
178 
refreshDatabase()179 void TelegramDialogsModel::refreshDatabase()
180 {
181     if(!p->telegram)
182         return;
183 
184     p->telegram->database()->readFullDialogs();
185 }
186 
recheck()187 void TelegramDialogsModel::recheck()
188 {
189     if(!p->telegram)
190         return;
191 
192     refreshDatabase();
193     dialogsChanged(true);
194 
195     if(!p->telegram->authLoggedIn())
196         return;
197 
198     Telegram *tgObject = p->telegram->telegram();
199     if(tgObject)
200         tgObject->messagesGetDialogs(0,0,1000);
201 }
202 
dialogsChanged(bool cachedData)203 void TelegramDialogsModel::dialogsChanged(bool cachedData)
204 {
205     Q_UNUSED(cachedData)
206     if(p->initializing)
207     {
208         p->initializing = false;
209         Q_EMIT initializingChanged();
210     }
211 
212     if(p->refresh_timer)
213         killTimer(p->refresh_timer);
214 
215     p->refresh_timer = startTimer(100);
216 }
217 
dialogsChanged_priv()218 void TelegramDialogsModel::dialogsChanged_priv()
219 {
220     if(!p->telegram)
221         return;
222     if(p->stopUpdating)
223         return;
224 
225     const QList<qint64> & dialogs = fixDialogs(p->telegram->dialogs());
226 
227     for( int i=0 ; i<p->dialogs.count() ; i++ )
228     {
229         const qint64 dId = p->dialogs.at(i);
230         if( dialogs.contains(dId) )
231             continue;
232 
233         beginRemoveRows(QModelIndex(), i, i);
234         p->dialogs.removeAt(i);
235         i--;
236         endRemoveRows();
237     }
238 
239 
240     QList<qint64> temp_msgs = dialogs;
241     for( int i=0 ; i<temp_msgs.count() ; i++ )
242     {
243         const qint64 dId = temp_msgs.at(i);
244         if( p->dialogs.contains(dId) )
245             continue;
246 
247         temp_msgs.removeAt(i);
248         i--;
249     }
250     while( p->dialogs != temp_msgs )
251         for( int i=0 ; i<p->dialogs.count() ; i++ )
252         {
253             const qint64 dId = p->dialogs.at(i);
254             int nw = temp_msgs.indexOf(dId);
255             if( i == nw )
256                 continue;
257 
258             beginMoveRows( QModelIndex(), i, i, QModelIndex(), nw>i?nw+1:nw );
259             p->dialogs.move( i, nw );
260             endMoveRows();
261         }
262 
263 
264     for( int i=0 ; i<dialogs.count() ; i++ )
265     {
266         const qint64 dId = dialogs.at(i);
267         if( p->dialogs.contains(dId) )
268             continue;
269 
270         beginInsertRows(QModelIndex(), i, i );
271         p->dialogs.insert( i, dId );
272         endInsertRows();
273     }
274 
275     Q_EMIT countChanged();
276 }
277 
userDataChanged()278 void TelegramDialogsModel::userDataChanged()
279 {
280     const QList<qint64> & dialogs = fixDialogs(p->telegram->dialogs());
281 
282     beginResetModel();
283     p->dialogs.clear();
284     endResetModel();
285 
286     for( int i=0 ; i<dialogs.count() ; i++ )
287     {
288         const qint64 dId = dialogs.at(i);
289         if( p->dialogs.contains(dId) )
290             continue;
291 
292         beginInsertRows(QModelIndex(), i, i );
293         p->dialogs.insert( i, dId );
294         endInsertRows();
295     }
296 }
297 
fixDialogs(QList<qint64> dialogs)298 QList<qint64> TelegramDialogsModel::fixDialogs(QList<qint64> dialogs)
299 {
300     int fav_counts = 0;
301     for( int i=0; i<dialogs.count(); i++ )
302     {
303         qint64 dId = dialogs.at(i);
304         if( p->telegram->userData()->isFavorited(dId) )
305         {
306             dialogs.move(i, fav_counts);
307             fav_counts++;
308         }
309     }
310 
311     qint64 love_id = p->telegram->userData()->value("love").toLongLong();
312     int love_idx = dialogs.indexOf(love_id);
313     if( love_idx != -1 )
314         dialogs.move(love_idx, 0);
315 
316     return dialogs;
317 }
318 
timerEvent(QTimerEvent * e)319 void TelegramDialogsModel::timerEvent(QTimerEvent *e)
320 {
321     if(e->timerId() == p->refresh_timer)
322     {
323         killTimer(p->refresh_timer);
324         p->refresh_timer = 0;
325 
326         dialogsChanged_priv();
327     }
328 
329     TgAbstractListModel::timerEvent(e);
330 }
331 
~TelegramDialogsModel()332 TelegramDialogsModel::~TelegramDialogsModel()
333 {
334     delete p;
335 }
336