TODO na Mac App Store, usando a arquitetura PYQT5 ModelView para criar um aplicativo simples para TODO

A interface do tipo ModelView Architecture qt S MVC para exibir dados nas visualizações

O aplicativo em execução é mostrado abaixo.

TODO 4+

Por vários anos, usei este aplicativo no meu iPad, meu iPhone e meu MacBookPro. Se continuar funcionando perfeitamente no iOS, parece que não seguiu completamente a evolução do macOS.
Sem problemas para instalá -lo. Mas não é mais possível sincronizar com Toodledo no macOS, enquanto continua sendo possível no iOS: os mesmos identificadores não são reconhecidos.
Portanto, torna -se desnecessário para mim … e a assistência do Appigo não parece ter pressa em fornecer uma resposta ao meu pedido. É sempre desagradável notar que o conceito de cliente perde um pouco mais de seu valor todos os dias.

Pisa d

Desde esta atualização, perdi todas as minhas listas no número de 12 e com as quais trabalho diariamente de maneira profissional. Eu gerenciei aproximadamente 200 pontos permanentemente, esta atualização foi colocada no chão meses de provação ! Todas as tarefas organizadas na lista se viu agrupadas em uma única lista global. Certamente não é esse bug que me fará passar para a versão dizendo profissional deste software, de outra forma excelente. Eu nunca serei cativo. Resta apenas para mim esperar a resposta do suporte contatada esta noite por e -mail ou depois encontre a versão antiga deste magnífico software. Eu realmente espero que seja um juventude da nova versão e não uma estratégia para forçar a migrar para a versão Pro PAY para encontrar funcionalidades já adquiridas com a versão anterior. Para informações, minha sincronização é feita com o Dropbox

SurlePoint, 13/12/2011

O síncro agora é níquel

Peguei antes da sincronização que era lenta, caminhei mal, etc. Mas agora com o iCloud, ela me convém perfeitamente.

Algumas melhorias possíveis: mais configurações de exibição.
– Para exibir apenas o que o usuário usa. Por exemplo, não uso contextos ou etiquetas (em qualquer caso ainda não) e gostaria de não exibir mais essas opções que “poluem” meu TODO. Eu gostaria de ter apenas “data / prioridade / lista / tipo” para minhas anotações do dia a dia e clique com o botão direito do mouse para as opções que eu raramente uso
– E, por outro lado, gostaria de uma simples exibição do PLSU do que um menu de queda para escolher a data, prioridade, lista, … se eu tiver apenas três listas, então três botões seriam suficientes para serem exibidos e poderia escolher minha lista Com um clique em vez de clicar no menu Drop -Robown, encontre o nome e clique nele. (Idem por prioridade, especialmente que passamos de um desenho muito visual na lista de TODO para uma escolha de nome nas opções que não são muito naturais.

Estes são detalhes da ergonomia. Eu gosto da simplicidade e da eficiência do TODO, então gostaria que possa ser ainda mais configurável ser ainda mais simples.

App de privacidade

O desenvolvedor, Appigo, não forneceu detalhes sobre suas práticas privadas e manuseio de dados para a Apple. Para obter mais informações, consulte a Política de Privacidade do Desenvolvimento.

A arquitetura do ModelView
Interface do tipo MVC do QT para exibir dados em visualizações

Ao começar a criar aplicativos mais complexos com PYQT5, você provavelmente encontrará widgets de manutenção em sincronia com seus dados. Dados armazenados em widgets (e.g. um simples qlistwidget) não está prontamente disponível para manipular do Python – as alterações exigem que você obtenha um item, obtenha os dados e depois o defina de volta. A solução padrão para isso é manter uma representação externa de dados no Python e, em seguida, eith duplicar atualizações para os dados e o widget, ou simplesmente reescrever o widget Wihole a partir dos dados. Isso pode ficar feio rapidamente e resulta em muito boilerplate apenas para brincar com os dados.

Felizmente, o QT tem uma solução para isso – ModelViews. O ModelViews é uma alternativa poderosa aos widgets de exibição padrão, que usam uma interface de modelo regular para interagir com fontes de dados – desde estruturas de dados simples até bancos de dados externos. Isso isola seus dados, permitindo que sejam mantidos em qualquer estrutura que você quiser, enquanto a visão cuida da apresentação e atualizações.

Este tutorial apresenta os aspectos principais da arquitetura de ModelView do QT e o usa para criar um aplicativo simples para desktop no pyqt5.

Modelo Visualizar controlador

Modelo – Veja – Controlador (MVC) é um uso de padrões arquitetônicos para o desenvolvimento de interfaces de usuário que dividam um aplicativo em três partes interconectadas. Isso separa a representação interna dos dados de como as informações são apresentadas e aceitam do usuário.

O MVC Design Pattenn Fets três componentes principais –

  • Modelo Mantém a estrutura de dados com os quais o aplicativo está trabalhando.
  • Visualizar é qualquer representação de informações como mostrado ao usuário, onde gráfico ou tabela. Várias visualizações do mesmo modelo de dados são permitidas.
  • Ao controle Aceita a entrada do usuário, transformando -o em comandos para o modelo ou visualização.

QT TERMELHA A DISTINCIÇÃO ENTRE A VISTA E O CONTROLADOR fica um pouco obscura. O QT aceita eventos de entrada do usuário (através do sistema operacional) e os delega nos widgets (controlador) para lidar. No entanto, os widgets também lidam com a apresentação do estado atual ao usuário, colocando -os diretamente na visão. Em vez de agonizar sobre onde desenhar a linha, no QT-S-S-Speak, a visualização e o controlador são togd fundidos por um modelo/viewcontroller, chamado “Model View” por simplicidade.

Importante, a distinção entre o dados e Como é apresentado é preservado.

A visualização do modelo

O modelo atua como a interface entre o armazenamento de dados e o ViewController. O modelo mantém os dados (ou uma referência a ele) e apresenta esses dados através de uma API padronizada que as visualizações consomem e apresentam ao usuário. Várias visualizações podem compartilhar os mesmos dados, apresentando -os de maneiras completamente diferentes.

Você pode usar qualquer “armazenamento de dados” para o seu modelo, incluído, por exemplo, uma lista de python padrão ou dicionário, ou um banco de dados (via e.g. Sqlalchemy) – tem direito a você.

As duas partes são essencialmente responsáveis ​​por –

  1. Chá modelo Armazena os dados, ou uma referência a eles e retorna individuais ou faixas de registros, e metadados associados ou mostrar instruções.
  2. Chá visualizar Solicita dados do modelo e exibe o que é retornado no widget.

Há uma discussão aprofundada da arquitetura do QT na documentação.

O guia completo para embalar Aplicativos Python GUI com PyInstaller.

Embalagem Aplicativos Python com PyInstaller

[[desconto.Desconto_pc]]]% de desconto para o próximo [desconto.duração]] [desconto.Descrição]] com o código [desconto.Código do cupom]]

Paridade do poder de compra

Desenvolvedores em [[país]] recebem [[desconto.desconto_pc]].Código do cupom]]

Uma simples visualização de modelo – uma lista de TODO

Para demonstrar como usar as visualizações de modelos na prática, montamos uma implementação muito simples de uma lista de computadores de desktop. Isso consistirá em um QListView para a lista de itens, um Qlineedit para inserir novos itens e um conjunto de botões para adicionar, excluir ou marcar itens como feito.

A interface do usuário

A interface do usuário simples foi feia, criadora de QT e salva como Mainwindow.Ui . Chá .O arquivo da interface do usuário e todas as outras partes podem ser baixadas abaixo.

Projetando um aplicativo simples de TODO no QT Creator

Projetando um aplicativo simples de TODO no QT Creator

O aplicativo em execução é mostrado abaixo.

A GUI de corrida (nada ainda funciona)

A GUI de corrida (nada ainda funciona)

Os widgets disponíveis na interface que fornecemos os IDs mostrados na tabela abaixo.

Objeuch Tipo Descrição
TodView QLISTVIEL A lista de Todos atuais
Tododit QLINEEDIT A entrada de texto para criar um novo item de TODO
AddButton Qpushbutton Crie o novo TODO, adicionando -o à lista de Todos
Deletebutton Qpushbutton Exclua o atual TODO selecionado, removendo -o da lista de Todos
CompleteButton Qpushbutton Marque o atual TODO selecionado como feito

Usaremos esses identificadores para conectar a lógica do aplicativo mais tarde.

O modelo

Definimos nosso modelo personalizado subclassificando da implementação, permitindo -nos focar nas peças exclusivas do nosso modelo. O QT fornece uma série de bases de modelos diferentes, incluindo listas, árvores e mesas (ideais para planilhas).

Para este exemplo, estamos exibindo o resultado para um QLISTVIEW . O modelo base correspondente para isso é QabstractListModel . A definição de esboço para o nosso modelo é mostrada abaixo.

Classe ToDomodel (qtcore.QabstractListModel): def __init __ (self, *args, Todos = nenhum, ** kwargs): super (tomomodel, eu).__init __ (*args, ** kwargs).Todos = Todos ou [] Def Data (self, índice, função): se função == qt.DisplayRole: # Veja abaixo a estrutura de dados. status, texto = self.Todos [índice.Linha ()] # Retorne o texto TODO SOMENTE. Retornar Texto Def Rowcount (self, índice): retornar Len (self.Todos) 

Chá .A variável Todos é o nosso armazenamento de dados e os dois métodos RowCount () e Data () são métodos de modelo padrão que devemos para um modelo de lista. Vamos passar por isso por sua vez abaixo.

.Lista de Todos

O armazenamento de dados para o nosso modelo é .Todos, uma lista simples de Python na qual armazenaremos uma tupla de valores no formato [(bool, str), (bool, str), (bool, str)] onde bool é o portanto estado de uma determinada entrada, e str é o texto do TODO.

Inicializamos a si mesmo.TODO para uma lista vazia na startup, a menos que uma lista seja transmitida pelo argumento da palavra -chave Todos.

auto.Todos = Todos ou [] se preparará.Todos para o valor de Todos fornecido se for truty (eu.e. Qualquer coisa que não seja uma lista vazia, o booleano falso ou nenhum do valor padrão), caso contrário, será definido para a lista vazia [] .

Para criar uma insutação deste modelo, podemos simples –

Model = toDomodel () # Crie uma lista de Todo vazio 

Ou passar em uma lista existente –

Todos = [(false, 'um item'), (false, 'outro item')] Modelo = ToDomodel (Todos) 

.Contagem de linhas ()

Chá .O método RowCount () é chamado pela visualização para obter o número de linhas nos dados atuais. Isso é necessário para que a visualização agora seja o índice máximo que ele pode refazer o armazenamento de dados (contagem de linhas-1). Venda Estamos usando uma lista Python como nosso armazenamento de dados, o valor de retorno para isso é simplesmente o len () da lista.

.Dados ()

Este é o núcleo do seu modelo, que lida com solicitações de dados da visualização e retorna o resultado apropriado. Recebe dois parâmetros e função.

Índice é a posição/coordenadas dos dados que a visualização está solicitando, acessível por dois métodos .Linha () e .coluna () que dá a posição em cada dimensão.

Para o nosso QListView, a coluna é sempre 0 e pode ser ignorada, mas você precisaria usar isso para dados 2D em uma visualização de planilha.

Papel é uma bandeira indicando o tipo de dados que a visualização está solicitando. Isso é porque o .Data () Método realmente tem mais responsabilidade do que apenas os dados principais. Ele também lida com solicitações de informações de estilo, dicas de ferramentas, barras de status etc. – basal qualquer coisa que possa ser informada pelos próprios dados.

A nomeação do QT.DisplayRole é um pouco estranho, mas isso indica que o visualizar está nos perguntando “por favor me dê dados para exibição”. Ha outro papéis Que os dados podem receber por solicitações de estilo ou solicitar dados em formato “Editar prontos”.

Papel Valor Descrição
Qt.Mostrar 0 Os principais dados a serem rendidos na forma de texto. (QString)
Qt.DecorationRole 1 Os dados a serem renderizados como uma decoração na forma de um ícone. (Qcolor, Qicon ou Qpixmap)
Qt.Editorial 2 Os dados em um seguimento formal para editar em um editor. (QString)
Qt.ToolTipRole 3 Os dados exibidos na dica de ferramenta do item. (QString)
Qt.Statustiprole 4 Os dados exibidos na barra de status. (QString)
Qt.O que é isso 5 Os dados exibidos para o item em “O que é isso?” moda. (QString)
Qt.Sizehintrole 13 A dica de tamanho para o item que será fornecido às visualizações. (QSIZE)

Para uma lista completa de disponível papéis que você pode receber, consulte a documentação Qt Itmdatarole. Nossa lista de tarefas estará usando o QT.DisplayRole e Qt.DecorationRole .

Implementação básica

Abaixo está o aplicativo básico de stub necessário para carregar a interface do usuário e exibi -lo. Adicionaremos nosso código de modelo e lógica de aplicativo a esta base.

Importar sistemas de pyqt5 importar qtcore, qtgui, qtwidgets, uic de pyqt5.Qtcore importar qt_creator_file = "mainwindow.ui "ui_mainwindow, qtbaseClass = uic.Loaduduype (qt_creator_file) classe TODOMODEL (qtcore.QabstractListModel): def __init __ (self, *args, Todos = nenhum, ** kwargs): super (tomomodel, eu).__init __ (*args, ** kwargs).Todos = Todos ou [] Def Data (self, índice, função): se função == qt.DisplayRole: status, texto = self.Todos [índice.Linha ()] Retornar Texto Def Rowcount (self, índice): retornar Len (self.Todos) Classe MainWindow (Qtwidgets.Qmainwindow, ui_mainwindow): def __init __ (self): qtwidgets.QUMAINWindow.__init __ (self) ui_mainwindow.__init __ (eu) eu.Setupui (eu) eu.Modelo = ToDomodel () self.TodView.SetModel (self.Modelo) app = qtwidgets.Qapplication (sys.Argv) janela = janela mainwindow ().App Show ().Exec_ () 

Definimos nosso toDomodel como antes e inicializamos o objeto Mainwindow. No __init__ para o MainWindow, criamos uma instância do nosso modelo TODO e definimos esse modelo no TODO_VIEW . Salve este arquivo como TODO.Py e execute -o com –

python3 TODO.ritmo 

Embora ainda não haja muito o que ver, o QLISTVIEW e nosso modelo estão realmente funcionando – se você adicionar alguns dados padrão, você verá que aparecem na lista.

auto.Model = ToDomodel (Todos = [(false, 'meu primeiro TODO')]))))))))))))) 

QLISTVIEW mostrando um item de TODO com código duro

QLISTVIEW mostrando um item de TODO com código duro

Você pode continuar adicionando itens manualmente assim e eles aparecerão em ordem no QLISTVIEW . Em seguida, vamos possibilitar adicionar ITMs de dentro do aplicativo.

Primeiro, crie um novo método no MainWindow chamado Add Add . Este é o nosso retorno de chamada que cuidará de adicionar o texto atual da entrada como um novo TODO. Conecte este método ao addButton.Sinal pressionado no final do bloco __init__.

Classe MainWindow (qtwidgets.Qmainwindow, ui_mainwindow): def __init __ (self): qtwidgets.QUMAINWindow.__init __ (self) ui_mainwindow.__init __ (eu) eu.Setupui (eu) eu.Modelo = ToDomodel () self.TodView.SetModel (self.Modelo) # conecte o botão. auto.AddButton.imprensa.Conecte -se (self.Add) def add (self): "" Adicione um item à nossa lista de Todo, recebendo o texto do Qlineedit .TODOEDIT e Lá limpando. "" "texto = eu.Tododit.Text () se texto: # não adicione strings vazios. # Acesse a lista através do modelo. auto.modelo.Todos.Anexar ((false, texto)) # Atualização de gatilho. auto.modelo.layoutchanged.Emit () # esvazie o eu de entrada.Tododit.SetText ("") 

No bloco add block.modelo.layoutchanged.Emitir () . Aqui emitimos um sinal de modelo .LayoutChanged para avisar que o forma dos dados foram alterados. Isso desencadeia uma atualização da entidade da visão. Se você omitir esta linha, o TODO ainda será adicionado, mas o QLISTVIEW não será atualizado.

Se apenas os dados forem alterados, mas o número de linhas/colunas não for afetado, você pode usar o .Sinal de dados (em vez disso. Isso também define uma região alterada nos dados usando um aluguel superior e inferior direito para evitar redesenhar toda a visualização de visualização.

Com as outras ações

Agora podemos conectar o restante dos sinais do botão e adicionar cutções de ajuda para desempenho excluir e completo operações. Adicionamos o botão sinais ao bloco __init__ como antes.

 auto.AddButton.imprensa.Conecte -se (self.Adicione) self.Deletebutton.imprensa.Conecte -se (self.Excluir) eu.CompleteButton.imprensa.Conecte -se (self.Completo) 

Em seguida, defina um novo método de exclusão da seguinte forma –

 DEL DELETE (self): índices = self.TodView.SelectedDindexes () se índices: # Indexes é uma lista de um único item em seleção única. Índice = índices [0] # Remova o item e atualize. Del self.modelo.Todos [índice.Linha ()] self.modelo.layoutchanged.Emit () # limpe a seleção (como não é válida). auto.TodView.ClarSelection () 

Nós usamos eu.TodView.SelectedDindexes para obter os índices (na verdade uma lista de um único item, como nós no modo de seleção única) e depois o .Linha () como um índice em nossa lista de Todos em nosso modelo. Excluímos o item indexado usando o operador Del do Python e, em seguida, acionamos um sinal LayoutChanged porque a forma dos dados foi modificada.

Finalmente, limpamos a seleção ativa, pois o item com que se refere pode agora fora dos limites (se você tivesse selecionado o último item).

Você pode tentar tornar este inteligente e selecionar o último item na lista

O método completo gosta como este –

 Def completo (self): índices = self.TodView.SELECTREDINDIDEXES () IF INDEXES: ÍNDICE = ÍNDICES [0] linha = índice.Row () Status, texto = self.modelo.Todos [Row] eu.modelo.Todos [linha] = (true, texto) # .DataChanged leva o canto superior esquerdo e inferior direito, que são iguais # para uma única seleção. auto.modelo.DataChanged.Emit (índice, índice) # limpe a seleção (pois não é válida). auto.TodView.ClarSelection () 

Isso usa a mesma indexação que para excluir, mas desta vez buscamos o item do modelo .Todos List e depois substitua o status por verdadeiro .

Temos que fazer essa busca e substituição, pois nossos dados são armazenados como tuplas python que não podem ser modificadas.

A chave diferente aqui vs. Widgets QT padrão é que fazemos alterações diretamente em nossos dados e precisamos simplificar o QT que muda o Haasurd – atualizando o estado do widget é tratado automaticamente.

Usando Qt.DecorationRole

Se você executar o aplicativo agora, você deve achar que adicionar e excluir o trabalho, mas enquanto conclui itens está funcionando, não há indicação dele na visão. Precisamos atualizar nosso modelo para fornecer à exibição um indicador para exibir quando um item é concluído. O modelo atualizado é mostrado abaixo.

Tick ​​= Qtgui.Qimage ('tick.PNG ') CLASS TODOMODEL (QTCORE.QabstractListModel): def __init __ (self, *args, Todos = nenhum, ** kwargs): super (tomomodel, eu).__init __ (*args, ** kwargs).Todos = Todos ou [] Def Data (self, índice, função): se função == qt.DisplayRole: _, texto = self.Todos [índice.Linha ()] retornar texto se função == qt.DecorationRole: Status, _ = self.Todos [índice.Linha ()] se status: retornar tick def rowcount (self, índice): retornar len (self.Todos) 

Estavam usando um carrapato de ícone de carrapato.PNG para indicar itens completos, que carregamos em um objeto Qimage chamado Tick . No modelo, implementamos um manipulador para o QT.DecorationRole, que retorna o ícone do carrapato para linhas cujo status é verdadeiro (para completo).

O ícone que estou usando é retirado da fuga definida por P.Yusukekamiyamane

INTOSTAD de um ícone I você também pode voltar à cor, e.g. Qtgui.Qcolor (‘verde’) que será desenhado como quadrado sólido.

Executando o aplicativo, agora você poderá marcar itens como completo.

Todos marcados completos

Todos marcados completos

Uma loja de dados persistente

Nosso aplicativo TODO funciona bem, mas tem uma falha fatal-esquece seu TODOS assim que você fecha o aplicativo enquanto pensa que não tem nada para fazer quando faz pode contribuir para sentimentos de curto prazo de zen, a longo prazo é provavelmente um péssima ideia.

A solução é implementar algum passeio de Data Persist Data Store. A abordagem mais simples é uma loja de arquivos simples, onde carregamos itens de um arquivo JSON ou Pickle na inicialização e escrevemos de volta à alteração.

Para fazer isso, definimos dois novos métodos em nossas mãos . Esses dados de carregamento de um JSON NOME NOME DADOS.JSON (se existe, ignorando o erro, se não for) para si mesmo.modelo.Todos e escreva o eu atual.modelo.Todos para o mesmo arquivo, respectivamente.

 Def carre (self): tente: com o aberto ('dados.json ',' r ') como f: self.modelo.Todos = JSON.Carregar (f) Exceção de exceção: PASS def Save (self): com open ('dados.json ',' w ') como f: dados = json.Despejo (eu.modelo.Todos, f) 

Para persistir as mudanças nos dados necessários para adicionar o .Salvador save () até o final de qualquer método que modifique os dados e o .Carregamento () manipulador para o bloco __init__ após o modelo criar.

O código final se parece com isso –

Importar sistemas importantes json de pyqt5 importar qtcore, qtgui, qtwidgets, uic de pyqt5.Qtcore importar qt_creator_file = "mainwindow.ui "ui_mainwindow, qtbaseClass = uic.LoadUDuseyype (qt_creator_file) tick = qtgui.Qimage ('tick.PNG ') CLASS TODOMODEL (QTCORE.QabstractListModel): def __init __ (self, *args, Todos = nenhum, ** kwargs): super (tomomodel, eu).__init __ (*args, ** kwargs).Todos = Todos ou [] Def Data (self, índice, função): se função == qt.DisplayRole: _, texto = self.Todos [índice.Linha ()] retornar texto se função == qt.DecorationRole: Status, _ = self.Todos [índice.Linha ()] se status: retornar tick def rowcount (self, índice): retornar len (self.Todos) Classe MainWindow (Qtwidgets.Qmainwindow, ui_mainwindow): def __init __ (self): super (mainwindow, eu).__Nele mesmo.Setupui (eu) eu.Modelo = ToDomodel () self.Carregamento () self.TodView.SetModel (self.Modelo) self.AddButton.imprensa.Conecte -se (self.Adicione) self.Deletebutton.imprensa.Conecte -se (self.Excluir) eu.CompleteButton.imprensa.Conecte -se (self.Completo) def add (self): "" "Adicione um item à nossa lista de todo, obtendo o texto do Qlineedit .TODOEDIT e Lá limpando. "" "texto = eu.Tododit.Text () se texto: # não adicione strings vazios. # Acesse a lista através do modelo. auto.modelo.Todos.Anexar ((false, texto)) # Atualização de gatilho. auto.modelo.layoutchanged.Emit () # esvazie o eu de entrada.Tododit.SetText ("") eu.Save () DEF delete (self): índices = self.TodView.SelectedDindexes () se índices: # Indexes é uma lista de um único item em seleção única. Índice = índices [0] # Remova o item e atualize. Del self.modelo.Todos [índice.Linha ()] self.modelo.layoutchanged.Emit () # limpe a seleção (como não é válida). auto.TodView.ClarSelection () self.Salvar () def completo (self): índices = self.TodView.SELECTREDINDIDEXES () IF INDEXES: ÍNDICE = ÍNDICES [0] linha = índice.Row () Status, texto = self.modelo.Todos [Row] eu.modelo.Todos [linha] = (true, texto) # .DataChanged leva o canto superior esquerdo e inferior direito, que são iguais # para uma única seleção. auto.modelo.DataChanged.Emit (índice, índice) # limpe a seleção (pois não é válida). auto.TodView.ClarSelection () self.Salvar () def carreg (self): tente: com open ('dados.db ',' r ') como f: self.modelo.Todos = JSON.Carregar (f) Exceção de exceção: PASS def Save (self): com open ('dados.db ',' w ') como f: dados = json.Despejo (eu.modelo.Todos, f) App = Qtwidgets.Qapplication (sys.Argv) janela = janela mainwindow ().App Show ().Exec_ () 

Se os dados em seu aplicativo têm o potencial de ficar grandes ou mais complexos, você poderá preferir usar um banco de dados real para armazená -lo. Nesse caso, o modelo embrulhará a interface no banco de dados e consulte -o diretamente para que os dados sejam exibidos. A capa de L’ll como fazer isso em um próximo tutorial.

Para outro exemplo interessante de um QLISTVIEW, veja este exemplo de aplicativo de mídia player. Ele usa o QT Building QMediaPlayList como o armazenamento de dados, com o conteúdo exibido em um QLISTVIEL .

Sobre BCR.CX:

Bcr.O CX é uma startup de tecnologia brasileira, especializada em processos de terceirização de negócios (BPO) e terceirização de ambiente de negócios (BEO), focados principalmente na geração de demanda, experiência do cliente, comunicação, suporte ao usuário e satisfação.

Descrição:

O aplicativo TODO foi desenvolvido como uma maneira rápida, segura e amigável de armazenar as notas do agente durante os dias úteis.

Ser capaz de criar e gerenciar suas próprias tarefas, com base em cada passagem individual ou cliente.

Crie trilhas e personalize seu fluxo de trabalho

Produtividade aprimorada! Usando o aplicativo TODO, você pode criar fluxos de trabalho personalizados para padronizar processos repetidos. Tente agora e comece a controlar seu progresso, como seus gostos e dones.

Recursos:

  1. Crie tarefas para cada ingresso
  2. Barra de progresso para acompanhar a entrega
  3. Crie fluxos de trabalho padronizados para melhorar a produtividade.
  4. Gerencie sua lista de tarefas, para mantê -la com sua rotina diária.
  1. Empilhe TODO e Zendesk Sunshine para obter acesso total sobre os recursos do aplicativo
  2. Melhore a produtividade criando ou editando tarefas de automações e salve suas predefinições personalizadas.