-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnewsGui.py
346 lines (280 loc) · 12.8 KB
/
newsGui.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
#!/bin/python3
######################################################################
# Developer : Ayush Bairagi
# E-mail: [email protected]
# Github profile: github.com/ayush3298
# project:
# ####################################################################
# Internal
import sys, os
import functools
# External
import requests
from PyQt5.QtWidgets import QMessageBox
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QFont
# UI Files
from mainUI import Ui_MainWindow
# Main GUI window, uses 'main.ui'
class MainWindow(Ui_MainWindow):
# UI init
def __init__(self, dialog):
Ui_MainWindow.__init__(self)
# try:
# requests.get('https://www.google.com')
# print('google')
# except:
# self.DisplayMessagebox(title='Cant Connect',text='please check your internet connection')
# exit()
self.setupUi(dialog)
# Article scroll area init
self.articleList = []
self.articleGBox, self.articleGLayout = self.InitArticleScrollarea()
# Sources scroll area init
self.sourceList = []
self.sourceGBox, self.sourceGLayout = self.InitSourceScrollarea()
self.currentSourceId = ""
# Following scroll area init
self.followingList = []
self.followingGBox, self.followingGLayout = self.InitFollowScrollarea()
self.LoadFollowed()
# Get the all avaliable sources
self.InsertSources(jsonRes=self.LoadSources(sourcesUrl="https://newsapi.org/v1/sources?language=en").json())
# Get apikey
self.apiKey = self.GetApiKey('api.txt')
# Event handler init
self.MainPage()
self.InputManager()
# Handles all GUI events on MainWindow static widget static widgetss
def InputManager(self):
# Refresh button
self.refreshBtn.clicked.connect(self.ReloadArticles)
# Changed category
self.categoryCombobox.currentIndexChanged.connect(self.SelectionChange)
# Follow button
self.followBtn.clicked.connect(self.FollowCurrent)
# Reload all articles from the current source
def MainPage(self):
self.InsertArticles(jsonRes=self.LoadArticlesBy(
apiUrl="https://newsapi.org/v2/top-headlines?country=in",
source='',
apiKey=self.apiKey
).json())
def ReloadArticles(self):
if (len(self.currentSourceId) > 0):
self.InsertArticles(jsonRes=self.LoadArticlesBy(
apiUrl="https://newsapi.org/v1/articles",
source=self.currentSourceId,
apiKey=self.apiKey
).json())
# Changed category from the combobox, display the sources from the selected category
def SelectionChange(self):
if (self.categoryCombobox.currentText() == "all"):
self.InsertSources(jsonRes=self.LoadSources(sourcesUrl="https://newsapi.org/v1/sources?language=en").json())
else:
self.InsertSources(jsonRes=self.LoadSources(sourcesUrl="https://newsapi.org/v1/sources?language=en&category=" + self.categoryCombobox.currentText()).json())
# Appends the currently selected source to the following list
def FollowCurrent(self):
if (len(self.currentSourceId) > 0):
if (self.currentSourceId not in self.followingList):
self.followingList.append(self.currentSourceId)
self.followBtn.setText("Unfollow")
self.UpdateFollowed()
elif (self.currentSourceId in self.followingList):
self.followingList.remove(self.currentSourceId)
self.followBtn.setText("Follow")
self.UpdateFollowedRemoved()
self.SaveFollowed() # Save each time
# Creates the elements needed to propperly append widgets to the articles scrollarea
def InitArticleScrollarea(self):
# Create groupbox container
gBox = QtWidgets.QGroupBox()
gLayout = QtWidgets.QFormLayout()
# Append articles scroll
gBox.setLayout(gLayout)
self.articleScroll.setWidget(gBox) # Append groupbox to scrollarea
return gBox, gLayout # Return them back out the global variables, so they can be used in the UpdateScrollarea function as well.
# Creates the elements needed to propperly append widgets to the sources scrollarea
def InitSourceScrollarea(self):
# Create groupbox container
gBox = QtWidgets.QGroupBox()
gLayout = QtWidgets.QFormLayout()
# Append to sources scroll
gBox.setLayout(gLayout)
self.sourcesScroll.setWidget(gBox)
return gBox, gLayout # Return back just like for the articles
# Creates the elements needed to propperly append widgets to the followed scrollarea
def InitFollowScrollarea(self):
# Create groupbox container
gBox = QtWidgets.QGroupBox()
gLayout = QtWidgets.QFormLayout()
# Append to followed scroll
gBox.setLayout(gLayout)
self.followScroll.setWidget(gBox)
return gBox, gLayout # Return references back out to global variables
# Loads all the followed sources from a file
def LoadFollowed(self):
try:
with open("followed.txt", "r") as loadFile:
for line in loadFile:
self.currentSourceId = line.replace("\n", "")
self.followingList.append(self.currentSourceId)
self.UpdateFollowed()
except Exception as e:
pass
# Saves the list of all followed sources to a file
def SaveFollowed(self):
with open("followed.txt", "w") as saveFile:
for source in self.followingList:
saveFile.write(source + "\n")
# Inserts the last followed source which was appended to the self.follwingList
def UpdateFollowed(self):
followLabel = QtWidgets.QLabel()
followLabel.mousePressEvent = functools.partial(self.SourceClicked, source_obj=followLabel)
followLabel.setText("<a href='#'>" + self.currentSourceId + "</a>")
horiLayout = QtWidgets.QHBoxLayout()
horiLayout.addWidget(followLabel)
self.followingGLayout.addRow(horiLayout)
# Finds and deletes the currentSourceId when the unfollow button is clicked
def UpdateFollowedRemoved(self):
for x in reversed(range(self.followingGLayout.count())):
# Get element to delete
currentElemText = self.followingGLayout.itemAt(x).itemAt(0).widget().text()
if (currentElemText[12:len(currentElemText) - 4] == self.currentSourceId):
# Remove QLabel from inner horiLayout
take = self.followingGLayout.itemAt(x).takeAt(0).widget()
take.deleteLater()
# Remove horiLayout form followingGLayout
takeLayout = self.followingGLayout.takeAt(x)
takeLayout.deleteLater()
# Break when found
break
# This can be done in a way better way, than to generate the entire formlay out each time and append each label
def UpdateScrollarea(self):
for item in self.articleList[len(self.articleList) - 1]:
horiLayout = QtWidgets.QHBoxLayout()
horiLayout.addWidget(item)
self.articleGLayout.addRow(horiLayout)
# Displays an information messagebox with the given title and text
def DisplayMessagebox(self, title, text):
msg = QtWidgets.QMessageBox()
msg.setIcon(QtWidgets.QMessageBox.Information)
msg.setText(text)
msg.setWindowTitle(title)
msg.setStandardButtons(QtWidgets.QMessageBox.Ok)
msg.exec_()
# Gets the apikey from the specifed file
# The key should be on the first line of the file
def GetApiKey(self, fileName):
try:
with open(fileName, "r") as keyFile:
return keyFile.read()
except Exception as e:
self.DisplayMessagebox("Warning", "This application requires an api key to function!\nPlease go to: https://www.newsapi.org/ to get your key.\nThis key needs to be placed in a file called 'apikey.txt'.")
return None
# Loads the articles using requests
def LoadArticlesBy(self, apiUrl, source, apiKey):
payload = {'source': source, 'apiKey': apiKey}
res = requests.get(apiUrl, params=payload)
# Check status code
if (res.status_code == 200):
return res
return None
# Opens the clicked on label link
def OpenLink(self, linkStr):
QtGui.QDesktopServices.openUrl(QtCore.QUrl(linkStr))
# Loads a given json object containing articles onto the GUI
def InsertArticles(self, jsonRes):
# Clear from previous
self.articleList = []
for idx in reversed(range(self.articleGLayout.rowCount())):
self.articleGLayout.removeRow(idx)
# Insert new articles
for article in jsonRes['articles']:
readmoreLabel = QtWidgets.QLabel("<a href='" + article['url'] + "'>Read more.</a>")
readmoreLabel.linkActivated.connect(self.OpenLink)
if article['author'] is not None:
try:
self.articleList.append([
# QtWidgets.QLabel('Source: ' + article['source']['name']),
])
except:pass
try:
# Create articleList, this is the list where all elements are loaded from
self.articleList.append([
#QtWidgets.QLabel('Source: ' + article['source']['name']),
QtWidgets.QLabel('Author: '+article['author']),
QtWidgets.QLabel('Title: '+article['title']).setFont(QFont('Arial', 20)),
QtWidgets.QLabel('Published At: '+article['publishedAt']),
QtWidgets.QLabel(article['description']),
readmoreLabel,
QtWidgets.QLabel('-'*160),
QtWidgets.QLabel()
])
self.UpdateScrollarea()
except:pass
# Insert sources using the sourceList
def UpdateSourcesScrollarea(self):
horiLayout = QtWidgets.QHBoxLayout()
horiLayout.addWidget(self.sourceList[len(self.sourceList) - 1])
self.sourceGLayout.addRow(horiLayout)
def GetImage(self,url):
d = requests.get(url).read()
return d
# Loads all sources from the given URL, returns a respons object (None if status_code != 200)
def LoadSources(self, sourcesUrl):
res = requests.get(sourcesUrl)
if (res.status_code == 200):
return res
return None
# Source link clicked event - load the latest articles from the source
def SourceClicked(self, event, source_obj=None):
# Get source name
sourceNameText = source_obj.text()
sourceName = sourceNameText[12:len(sourceNameText) - 4]
# Set label
self.articleByLabel.setText("Articles by: " + sourceName)
# Get and insert the articles from the clicked source
sourceId = sourceName.lower()
for ch in ['(', ')']:
sourceId = sourceId.replace(ch, "")
sourceId = sourceId.replace(" ", "-")
self.currentSourceId = sourceId
# Set follow button text based on current source
if (self.currentSourceId in self.followingList):
self.followBtn.setText("Unfollow")
else:
self.followBtn.setText("Follow")
self.InsertArticles(jsonRes=self.LoadArticlesBy(
apiUrl="https://newsapi.org/v1/articles",
source=sourceId,
apiKey=self.apiKey
).json())
# Inserts all sources from a given json object into the sources scroll area
def InsertSources(self, jsonRes):
# Clear from previous
for idx in reversed(range(self.sourceGLayout.rowCount())):
self.sourceGLayout.removeRow(idx)
for source in jsonRes['sources']:
label = QtWidgets.QLabel()
# Makes the labels clickable links
label.mousePressEvent = functools.partial(self.SourceClicked, source_obj=label)
label.setText("<a href='#'>" + source['name'] + "</a>")
self.sourceList.append(label)
self.UpdateSourcesScrollarea()
# Init
if (__name__ == '__main__'):
# Init main GUI
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
window.setWindowTitle('News')
window.setWindowIcon(QtGui.QIcon('logo.png'))
prog = MainWindow(window)
# try:
# requests.get('https://www.google.com')
# print('google')
# except:
# self.DisplayMessagebox(title='Cant Connect',text='please check your internet connection')
# exit()
window.show() # Actually show the window
sys.exit(app.exec_())