class PlotItemViewModel: def __init__(self, strVariavel, strQuery, color, plotType): self.strVariavelBehavior = BehaviorSubject(strVariavel) self.strQueryBehavior = BehaviorSubject(strQuery) self.colorBehavior = BehaviorSubject(color) self.plotTypeBehavior = BehaviorSubject(plotType) def dispose(self): self.strVariavelBehavior.dispose() self.strQueryBehavior.dispose() self.colorBehavior.dispose() self.plotTypeBehavior.dispose() def _get_strVariavel_(self): return self.strVariavelBehavior.value def _set_strVariavel_(self, value): if value != self.strVariavelBehavior.value: self.strVariavelBehavior.on_next(value) strVariavel = property(_get_strVariavel_, _set_strVariavel_) def _get_strQuery_(self): return self.strQueryBehavior.value def _set_strQuery_(self, value): if value != self.strQueryBehavior.value: self.strQueryBehavior.on_next(value) strQuery = property(_get_strQuery_, _set_strQuery_) def _get_color_(self): return self.colorBehavior.value def _set_color_(self, value): if value[0] != self.colorBehavior.value[0] or value[ 1] != self.colorBehavior.value[1] or value[ 2] != self.colorBehavior.value[2]: self.colorBehavior.on_next(value) color = property(_get_color_, _set_color_) def _get_plotType_(self): return self.plotTypeBehavior.value def _set_plotType_(self, value): if value != self.plotTypeBehavior.value: self.plotTypeBehavior.on_next(value) plotType = property(_get_plotType_, _set_plotType_)
class TabViewModel: """Informação global da tab""" def __init__(self, share_x, max_plots, name): self.sharexBehavior = BehaviorSubject(share_x) self.maxPlotsBehavior = BehaviorSubject(max_plots) self.nameBehavior = BehaviorSubject(name) def dispose(self): self.sharexBehavior.dispose() self.maxPlotsBehavior.dispose() self.nameBehavior.dispose() def _get_sharex_(self): return self.sharexBehavior.value def _set_sharex_(self, s): self.sharexBehavior.on_next(s) sharex = property(_get_sharex_, _set_sharex_) def _get_maxPlots_(self): return self.maxPlotsBehavior.value def _set_maxPlots_(self, m): self.maxPlotsBehavior.on_next(m) maxPlots = property(_get_maxPlots_, _set_maxPlots_) def _get_name_(self): return self.nameBehavior.value def _set_name_(self, value): self.nameBehavior.on_next(value) name = property(_get_name_, _set_name_)
class PlotViewModel: def __init__(self, xVariavel, xQuery, grid): self.xVariavelBehavior = BehaviorSubject(xVariavel) self.xQueryBehavior = BehaviorSubject(xQuery) self.gridBehavior = BehaviorSubject(grid) # Fazer parte dos itens # self.plotItems = [ for pltItem in items] # Itens def dispose(self): self.xVariavelBehavior.dispose() self.xQueryBehavior.dispose() self.gridBehavior.dispose() def _get_xVariavel_(self): return self.xVariavelBehavior.value def _set_xVariavel_(self, value): if value != self.xVariavelBehavior.value: self.xVariavelBehavior.on_next(value) xVariavel = property(_get_xVariavel_, _set_xVariavel_) def _get_xQuery_(self): return self.xQueryBehavior.value def _set_xQuery_(self, value): if value != self.xQueryBehavior.value: self.xQueryBehavior.on_next(value) xQuery = property(_get_xQuery_, _set_xQuery_) def _get_grid_(self): return self.gridBehavior.value def _set_grid_(self, value): if value != self.gridBehavior.value: self.gridBehavior.on_next(value) grid = property(_get_grid_, _set_grid_)
class GenericRantList(urwid.WidgetWrap): def __init__(self, rants_subscriptable): self.widget = None self.rants_subscriptable = rants_subscriptable self.rants = [] self.update = BehaviorSubject(self) self._subscriptions = [] self.create() super().__init__(self.widget) def __del__(self): self.update.dispose() for subscription in self._subscritpions: subscription.unsubscribe() def create_list_box(self): elements = [] for i, rant in enumerate(self.rants): if i > 0: elements.append(urwid.Divider(u'\u2500')) element = RantListElementWidget(rant) elements.append(element) list_box = urwid.ListBox(urwid.SimpleListWalker(elements)) return list_box def create(self): self.widget = urwid.Frame(self.create_list_box()) self._subscribe_rant_list() def _subscribe_rant_list(self): def action(new_value): self.rants = new_value simple_list_walker = self.widget.contents['body'][0].body i = 0 j = 0 # update existent while i < len(simple_list_walker) and j < len(new_value): element = simple_list_walker[i] rant = new_value[j] if type(element) is not RantListElementWidget: i += 1 else: element.update_rant(rant) i += 1 j += 1 # append new ones while j < len(new_value): rant = new_value[j] if i > 0: simple_list_walker.append(urwid.Divider(u'\u2500')) i += 1 simple_list_walker.contents.append(RantListElementWidget(rant)) i += 1 j += 1 # delete excedent simple_list_walker.contents[:i] self.update.on_next(self) self._subscriptions.append(self.rants_subscriptable.subscribe(action))
class DevRantService(): def __init__(self, *args, **kwargs): self.base_url = "https://devrant.com/api" self.base_params = { 'app': 3, } self.rants = BehaviorSubject([]) self.error = Subject() self.me = BehaviorSubject(None) self.auth_token = BehaviorSubject(None) self.is_logged = BehaviorSubject(False) self._subscribe_to_auth_token() self._load_cache() def __del__(self): self.rants.dispose() self.error.dispose() self.me.dispose() self.auth_token.dispose() self.is_logged.dispose() def _get_params(self, **kwargs): params = dict(self.base_params, **kwargs) return urllib.parse.urlencode(params) def _load_cache(self, filename='.cache.json'): try: fh = open(filename, 'r') except FileNotFoundError: self._write_cache(filename) self._load_cache(filename) else: try: cache_data = json.load(fh) except json.decoder.JSONDecodeError: pass else: cached_auth_token = cache_data.get('auth_token') if cached_auth_token is not None: cached_auth_token = AuthToken(**cached_auth_token) self.auth_token.on_next(cached_auth_token) fh.close() def _write_cache(self, filename='.cache.json'): cache_data = {} try: fh = open(filename, 'r') cache_data = json.load(fh) except FileNotFoundError: pass except json.JSONDecodeError: pass else: fh.close() fh = open(filename, 'w') if self.auth_token.value is not None: cache_data['auth_token'] = self.auth_token.value.__dict__() json.dump(cache_data, fh) fh.close() def _delete_cache(self, filename='.cache.json'): fh = open(filename, 'w') json.dump({}, fh) fh.close() def _subscribe_to_auth_token(self): def action(value): # change is_logged value if self.is_logged.value and value.user_id is None: self.is_logged.on_next(False) elif not self.is_logged.value and value and value.user_id: self.is_logged.on_next(True) # save new auth_token self._write_cache() self._auth_token_subscription = self.auth_token.subscribe(action) return self async def get_rants(self, limit=10): param_url = self._get_params(sort='recent', limit=limit, skip=len(self.rants.value)) response = requests.get(self.base_url + '/devrant/rants' + '?' + param_url) if response.status_code == 200: new_rants = json.loads(response.text)['rants'] new_rants = [Rant(rant) for rant in new_rants] all_rants = list( merge(self.rants.value, new_rants, key=lambda x: x.id, reverse=True)) self.rants.on_next(all_rants) else: self.error.on_next({ 'code': 1, 'message': 'Unexpected status code', 'response': response }) return self async def get_new_rants(self, skip=0, limit=10): if len(self.rants.value) == 0: return await self.get_rants() newest_actual_rant = self.rants.value[0] param_url = self._get_params(sort='recent', limit=limit, skip=skip) response = requests.get(self.base_url + '/devrant/rants' + '?' + param_url) if response.status_code == 200: new_rants = json.loads(response.text)['rants'] new_rants = [Rant(rant) for rant in new_rants] new_rants.sort(key=lambda x: x.id, reverse=True) if new_rants[-1].id > newest_actual_rant.id: await self.get_new_rants(skip + limit, limit) newest_actual_rant = self.rants.value[0] new_rants = [ rant for rant in new_rants if rant.id > newest_actual_rant.id ] all_rants = list( merge(new_rants, self.rants.value, key=lambda x: x.id, reverse=True)) self.rants.on_next(all_rants) else: self.error.on_next({ 'code': 1, 'message': 'Unexpected status code', 'response': response }) return self async def post_rant(self, draft_rant): headers = { "Host": "devrant.com", "Connection": "keep-alive", "Accept": "application/json", "Origin": "https://devrant.com", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "https://devrant.com/feed", } form_data = { **self.base_params, 'rant': draft_rant.text, 'token_id': self.auth_token.value.id, 'token_key': self.auth_token.value.key, 'user_id': self.auth_token.value.user_id, 'tags': ', '.join(draft_rant.tags), 'type': 1 } draft_rant.response = requests.post(self.base_url + '/devrant/rants', headers=headers, data=form_data) draft_rant.state.on_next(DraftState.Sent) if draft_rant.response.status_code == 200: success = json.loads(draft_rant.response.text).get('success') if success: await self.get_new_rants() draft_rant.state.on_next(DraftState.Published) else: draft_rant.state.on_next(DraftState.Rejected) self.error.on_next({ 'code': 2, 'message': 'Posted rant error', 'response': draft_rant.response }) elif draft_rant.response.status_code == 400: draft_rant.state.on_next(DraftState.Rejected) self.error.on_next({ 'code': 2, 'message': 'Posted rant error', 'response': draft_rant.response }) else: draft_rant.state.on_next(DraftState.Rejected) self.error.on_next({ 'code': 1, 'message': 'Unexpected status code', 'response': draft_rant.response }) async def login(self, username, password): headers = { "Host": "devrant.com", "Connection": "keep-alive", "Accept": "application/json", "Origin": "https://devrant.com", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "https://devrant.com/", } response = requests.post(self.base_url + '/users/auth-token', headers=headers, data={ **self.base_params, "username": username, "password": password, }) if response.status_code == 200: data = response.json() if data.get('success'): auth_token = AuthToken(**data.get('auth_token')) self.auth_token.on_next(auth_token) # await self.get_about_me() else: self.error.on_next({'message': data.get('error')}) def logout(self): self._delete_cache() self.auth_token.on_next(AuthToken()) async def get_about_me(self): param_url = self._get_params(token_id=self.auth_token.value.id, token_key=self.auth_token.value.key) response = requests.get( self.base_url + '/users/{}'.format(self.auth_token.value.user_id) + '?' + param_url) return response