Utilidad para dispositivos móviles Android para tomar notas y guardarlas localmente o en una base de datos externa.
En esta versión (v2.0.0.32) la utilidad/aplicación hace lo siguiente:
Permite crear notas y marcarlas con estos atributos/propiedades:
Indicar a qué grupo (tag/etiqueta) pertenece.
Se pueden crear tantos grupos como se deseen.
El programa recordará el último nombre de grupo utilizado al guardar una nota.
Se pueden ver los grupos que hay creados, mostrando la información de las notas que contiene.
Al mostrar los grupos se muestra la información de las notas que contiene.
Al seleccionar un grupo (clic o tap) te muestra la información de tallada de las notas que contiene, así como la lista de esas notas pertenecientes a ese grupo. Desde esa lista puedes editar las notas.
Atributos /Propiedades de cada nota:
Favorita, al mostrar las notas (de la base de datos externa) las notas favoritas se muestran al principio.
Notificar, las notas marcadas para notificar se pueden usar para que al hacer login se muestren automáticamente, ahí puedes anotar los recordatorios que necesites ver cada vez que inicias sesión.
Archivada, esto hará que la nota no se muestre al mostrar las notas activas.
Eliminada, es otra forma de ocultar las notas, ya que nunca se eliminan físicamente de la base de datos (tanto local como externa).
Sincronizada, esta propiedad indica si la nota está sincronizada entre las bases local y externa. Las notas siempre se sincronizan entre las dos bases de datos.
Para mostrar las notas hay varios apartados en el menú o pantalla principal, pudiendo mostrar las notas según el atributo o propiedad seleccionado.
En la lista de notas se muestra la siguiente información:
El título de la nota que consiste en los primeros 50 caracteres o si hay cambios de líneas en la nota, la primera línea.
El nombre del grupo, la fecha de modificación y una letra cn el nombre del atributo y si está marcado (True) o no lo está (False).
Las abreviaturas de los atributos son:
Favorita, Notificar, Archivada y Eliminada.
En una nueva actualización añadiré Sincronizada, aunque se supone que siempre deben estar sincronizadas.
Seguramente también añadiré una página (opción) para mostrar las notas sincronizadas y poder asegurarte que si no está sincronizada, lo haga.
En la configuración puedes indicar:
Recordar el usuario con el que se ha hecho Login.
Recordar el password usado.
Iniciar la aplicación con el último usuario.
Mantener las notas sincronizadas (siempre está activada esta opción).
Mostrar las notas a Notificar al iniciar el programa (o hacer Login).
Usar las notas locales (cuando se activa) o usar las notas de la base externa.
En la información del Perfil te muestra los datos de la cuenta con la que has hecho Login.
Ahí puedes cambiar la cuenta de correo y el password.
Si cambias la cuenta de correo, se enviarán 2 mensajes, uno a cada cuenta pidiendo confirmación.
Te muestra la inforamción de la fecha de alta, último acceso, cuántas notas de la base externa puedes escribir:
Para los primeros 90 usuarios que se registren tienen una cuota de 1.000 notas, a partir del usuario 100 (los otros 10 los tengo reservados para mí) tendrán 100 notas como máximo de forma totalmente gratuita.
En esa cantidad, se cuentan todas las notas, estén o no eliminadas (ya que nunca se eliminan las notas).
El importe por cada 1.000 notas será de una donación anual de 12$ USD (unos 10€).
En esa cuota no se cuentan las notas ofrecidas gratuitamente.
El importe indicado en Pagos será el importe que hayas ido pagando.
Ya te digo que solamente debes pagar si quieres más cantidad de notas. La aplicación es totalmente gratuita. Salvo que prefieras hacer un donativo voluntario.
Puedes realizar búsquedas en las notas (tanto en la base local como en la externa).
La búsqueda se realiza sin tener en cuenta el case (no diferencia entre mayúsculas y minúsculas).
Por ahora solo hace la búsqueda en el Texto de las notas.
En una nueva actualización incluiré que se pueda hacer tanbién (o solo) en los nombres de los grupos).
En el resultado de la búsqueda puedes pulsar (hacer clic o tap) en la nota para editarla.
Aunque estés usando las notas de la base de datos remota (de SQL Server) puedes mostrar las notas de la base de datos loca, en este caso las notas no son editables, solo se muestran en la lista y haciendo tap o clic en ellas no se muestran.
??? Si quieres editar una nota local, debes cambiarlo en la configuración seleccionando la opción Usar las notas locales.
En la pantalla principal además te encontrarás con estas opciones:
Validar Email. Esto tendrás que usarlo cuando te registres con un nuevo usuario. O al crear un nuevo usuario.
Sincronizar. Esta opción te sirve para comprobar si las notas están sincronizadas (deberían estarlo), pero en caso de que no lo estuvieran, puedes sincronizar las locales al romoto o al revés.
Comentarios. Por si quieres enviarme alguna sugerencia, bug o cualquier cosa que me quieras decir. Esta opción te permite indicar un comentario y al pulsar en el botón de ENVIAR… abrirá una cuenta de email que tengas configurada en tu dispositivo para poder enviar el mensaje. El texto que hayas escritor aparecerá en el cuerpo del mensaje.
Acerca de Abre una ventana con un poco de ayuda sobre la aplicación. Seguramente añadiré un enlace a esta página descriptiva, ya que tanto texto no se puede poner en ese tipo de páginas… o al menos no se vería bien.
Cambiar de usuario. Desde ahí puedes hacer login, si no lo has hecho ya, o bien poder registrar un nuevo usuario.
En todas (o casi todas) existe un botón POLÍTICA DE PRIVACIDAD que al pulsarlo te muestra (en el navegador) la política de privacidad, es decir, qué datos personales se recogen.
De todas formas, comentarte que con los datos que facilitas o las notas que escribe yo no hago nada, ni cambairé nada, salvo que tú me lo pidas expresamente, bien porque no tengas acceso o cualquier otra circunstancia que te impida acceder a las notas o tu cuenta de usuario.
Bueno y creo que esto es todo…
He escrito tanto con idea de crear una página en elguillemola.com y así poder usarla como ayuda de la aplicación.
También crearé un video explicativo con las cosas que debes saber sobre la aplicación.
Si has llegado leyendo hasta aquí… ¡muchas gracias! 🙂
Y como estamos en las fechas que estamos (30 de diciembre de 2020) te deseo ¡FELICES FIESTAS!
Galería de fotos / capturas de la versión 2.0.0.32 (al menos en las que hay cambios, el resto es de la v2.0.0.31)
Acerca de…
Comentarios
Configuración
Login
Menú 1
Menú 2
Notas de base local
Perfil
Validar
Buscar
Resultados de buscar
Grupos
Grupos – Detalles
gsNotasNET-v2.32
gsNotasNET-v2.32
Notificar
Puedes descargar el "paquete" de instalación desde GitHub:
Pues eso… que ayer (o anteayer) me puse a trastear con el Xamarin para crear aplicaciones para móviles (para Android, ya que no tengo conexión a un Mac y por tanto no puedo desarrollar para iPhone) y he creado una versión de gsNotasNET pero para dispositivos móviles de Android. Y ya lo tengo en funcionamiento en mi móvil 😉
Nota del 15-oct-2022: He creado el paquete de instalación para Android y aquí te dejo el enlace de la versión 2.3.0.
Ya estás en la segunda entrega de este Tutorial sobre el uso de las APIs de Google. Aquí te mostraré el código de Visual Basic y C# para acceder a los contactos de Google usando People API. Como te comenté en la priumera entrega sobre cómo crear un proyecto en Google Cloud, el API que usaremos es People API, no te confundas con Contacts API (como a mí me ocurrió) ya que parece que será la más adecuada, pero además de que Google no recomienda que se use Contacts API, la he probado y no he conseguido sacar prácticamente nada de información, y al que he sacado es de unos pocos contactos (que ni recordaba que los tenía creados).
Nota: Está uno acostumbrado a que te marquen los errores horrográficos que esto de que no te los marque es un Orror! 😛
Bueno vamos empezar con el código de C# que es lo que la gente suele ver en internet (de VB no he visto ni un ejemplo, así que… ya mismo lo verás en primicia).
Después de escribir el párrafo anterior he cambiado de opinión y te voy a enseñar conjuntamente el código de los dos lenguajes, para que vayas comparando.
Código de C# y VB para mostrar los contactos de una cuenta de Google usando People API
Nota: Debo decir que parte de este código lo he visto en algunos ejemplosencontrados tanto en la documentación de Google como en foros de C#. Pero principalmente de la documentación (escasa) de Google y en agunos casos, los ejemplos eran de java, ni siquiera de C#.
Como te comenté en el preámbulo del tutorial, debes añadir las referencias a los paquetes de NuGet que instalarán las APIs en tu proyecto. Yo he añadido todas las que te indiqué en esa primera página del tutorial. Por supuesto si quieres acceder, por ejemplo al calendario o a GMail, tendrás que añadir referencias a esas APIs, además de añadirlas al proyecto creado en Google Cloud Platform.
Veamos el código inicial (con las importaciones de los espacios de nombres) que será básicamente el mismo en todas las aplicaciones que hagas para acceder a las APIs de Google.
// Genéricasusing Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Util.Store;
// People APIusing Google.Apis.People.v1;
using Google.Apis.People.v1.Data;
// Docs APIusing Google.Apis.Docs.v1;
using Google.Apis.Docs.v1.Data;
// Drive APIusing Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data; // Para el tipo Fileusing System;
using System.Collections.Generic;
//using System.IO;using System.Threading;
using System.Text;
using System.Linq;
'// GenéricasImports Google.Apis.Auth.OAuth2
Imports Google.Apis.Services
Imports Google.Apis.Util.Store
'// People APIImports Google.Apis.People.v1
Imports Google.Apis.People.v1.Data
'// Docs APIImports Google.Apis.Docs.v1
Imports Google.Apis.Docs.v1.Data
'// Drive APIImports Google.Apis.Drive.v3
Imports Google.Apis.Drive.v3.Data '// Para el tipo FileImports System
Imports System.Collections.Generic
Imports System.Threading
Imports System.Text
Imports System.Linq
Ahora vamos a crear una serie de campos estáticos/compartidos (static en C#, shared en VB) que usaremos también de forma genérica en todos los proyectos de acceso a Google APIs.
classProgram
{
// If modifying these scopes, delete your previously saved credentials
// at ~/.credentials/docs.googleapis.com-dotnet-quickstart.json
staticstring[] Scopes = { DocsService.Scope.Documents,
DocsService.Scope.DriveFile,
PeopleService.Scope.ContactsReadonly };
staticstring ApplicationName = "Tutorial Google APIs VB";
// Los datos del proyecto creado para VB
staticClientSecrets secrets = newClientSecrets()
{
ClientId = "430211665266-t68vl99t2q40v3lbctgbph23j2644bpj.apps.googleusercontent.com",
ClientSecret = "Xqexl0FMPedNc1KYs0iJt22A"
};
staticDocsService docService;
staticDriveService driveService;
staticPeopleService peopleService;
staticUserCredential Credential;
Lo que ese primer comentario indica (es de un quickstart de Google) es que si cambias los valores del array Scopes debes eliminar el directorio creado en Documentos\.credentials (ahora verás porqué).
El array Scopes contiene los ámbitos de la aplicación, es a qué estamos pidiendo permiso para acceder. Ahí he añadido los tres ámbitos que usaré en este tutorial, pero si solo quieres acceder a los contactos con People API, añadiendo PeopleService.Scope.ContactsReadonly sería suficiente. Si te fijas, estás pidiendo autorización (a OAuth) para acceder de forma de solo lectura a los contactos. En realidad, estás pidiendo permisos para acceder a los Documentos y al Drive sin restricciones, pero a los contactos solo para leerlos. Estos dos últimos necesitan más permisos porque queremos crear ficheros, eliminarlos, lo mismo con los documentos.
Lo importante (también) es la asignación de ClientSecrets, ahí tendrás que poner los datos que te haya generado al configurar el OAuth de la aplicación. Eso que te muestro son los valores que en mi proyecto para este tutorial he pedido, el que se indique que la aplicación se llama Tutorial Google APis VB no significa que no se pueda usar para C#, ese título o nombre de aplicación no es restrictivo para nada.
Nota: Normalmente esos valores se recomiendan que no se hagan públicos… ¡vaya el caso que hago! jejejeje… pero para este caso, me fio de ti, y sé que no se lo dirás a nadie y así lo mantenemos en secreto… 😉
Las tres declaraciones después de asignar el valor a secrets son para acceder a los servicios de las tres APIs que usaré en estos tutoriales, las defino a nivel de clase para que se puedan usar en todos los métodos que sean necesarios y no tener que pasarlas como argumento de llamada al método que lo necesite.
La última declaración (Credential) es para crear las credenciales del usuario. La asignación la haré en el método Main, y como es un valor compartido, también se podrá usar en cualquier parte de la clase.
El siguiente código es el método Main, en el que llamaremos al método que accede a los contactos y los muestra.
Y como verás en las capturas el correo que he usado no tenía ningún contacto y he tenido que crear uno para comprobar que funciona… las cosas del Guille…
staticvoid Main(string[] args)
{
Console.WriteLine("Tutorial Google APIs con C#");
string credPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.Personal);
// Directorio donde se guardarán las credenciales
credPath = System.IO.Path.Combine(credPath, ".credentials/Tutorial-Google-APIs-VB");
Credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
secrets,
Scopes,
"user",
CancellationToken.None,
newFileDataStore(credPath, true)).Result;
//Console.WriteLine("Credential file saved to: " + credPath);
// Mostrar los contactos
MostrarContactos();
Console.WriteLine();
Console.WriteLine("Pulsa una tecla.");
Console.Read();
}
PublicSharedSub Main(ByVal args AsString())
Console.WriteLine("Tutorial Google APIs con Visual Basic")
Dim credPath AsString = System.Environment.GetFolderPath(
Environment.SpecialFolder.Personal)
'// Directorio donde se guardarán las credenciales
credPath = System.IO.Path.Combine(credPath, ".credentials/Tutorial-Google-APIs-VB")
Credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
secrets,
Scopes,
"user",
CancellationToken.None,
NewFileDataStore(credPath, True)).Result
'// Mostrar los contactos
MostrarContactos()
Console.WriteLine()
Console.WriteLine("Pulsa una tecla.")
Console.Read()
EndSub
El valor de credPath es el direcorio donde se crearán las credenciales que vamos a usar en este programa. Se guardará en los documentos del usuario en una carpeta llamada Tutorial-Google-APIs-VB que estará incluida en .credentials.
Si haces cambios en los permisos o te han faltado permisos en la configuración de OAuth y los modificas, debes eliminar la carpeta del tutorial, a de .credentials la puedes dejar, por si la usas para almacenar las credenciales de otros programas que use el usuario. También tendrás que borrarla si decides usar otra cuenta de Google (GMail) para acceder a esos contactos. Si solo tienes una cuenta de GMail, no hará falta que la borres salvo para los dos primeros casos.
Cuando ejecutemos la aplicación verás qué es lo que se guarda en esa carpeta.
A Credentials le asignamos las credenciales que queremos usar.
Aquí tengo que hacer una puntualización. El valor de secrets se asigna con los valores que hemos indicado (de forma llana y clara) antes, pero también se puede hacer accediendo a un fichero que contiene esos valores, al menos así no se mostrarán directamente en el código los valores secretos. Aunque seguirán estando al alcance del usuario de la aplicación.
La forma de hacerlo lo pondré en otro ejemplo de este tutorial.
Ahora solo nos falta ver qué código contiene el método MostrarContactos.
¡Vamos a ello!
privatestaticvoid MostrarContactos()
{
// Create Drive API service.
peopleService = newPeopleService(newBaseClientService.Initializer()
{
HttpClientInitializer = Credential,
ApplicationName = ApplicationName,
});
// Lista de los contactos (People)
Console.WriteLine("Contactos:");
// Este muestra todos los contactos
GetPeople(peopleService, null);
Console.WriteLine();
Console.WriteLine($"Hay {total} contactos / People");
Console.WriteLine();
}
Le asignamos el valor a peopleService para que pida esos permisos a Google, como ves se usa el protocolo HTTP. Eso lo que hará es abrir una página en el navegador pidiendo permiso para acceder a los datos de una cuenta de GMail (ver la figura 1)
Figura 1. Seleccionar la cunta que queremos usar para acceder a sus contactos.
Esa primera pantalla nos pide que indiquemos a qué contactos queremos acceder, es decir, solo accederá a los contactos de la cuenta que indiques, y para indicar esa cuenta debes tener el password, si no… no hay nada que hacer. Por tanto, esto que vamos a hacer es seguro, en el sentido de que yo no voy a acceder (ni puedo) a tus contactos… otra cosa es que mi aplicación se comunicara conmigo o guardara esa información en algún sitio… pero no te preocupes, no lo hace, además lo puedes comprobar por ti mismo viendo el código.
Una vez elegida la cuenta, te mostrará un aviso de que la aplicación no es segura o, en realidad, que no se ha verificado (ver la figura 2). Tendrás que autorizarla para que pueda seguir.
Figura 2. DEbes mostrar la información oculta para permitir ir a la aplicación
Una vez hecho esto, Google te pedirá confirmación para dejar que la aplicación haga lo que se ha indicado en Scopes. Así que… otras tres pantallitas más de autorización (ver figuras 3 a 5).
Figura 3. Permiso para ver los contactos.Figura 4. Acceder al Drive.Figura 5. Acceder a los documentos.
Y una vez permitido estas cosas, debes terminar de aceptarlo (ver la figura 6 en la que está el resumen de los permisos que le darás a la aplicación).
Figura 6. Confirmación final de los permisos.
Después de pulsar en Permitir, el navegador te mostrará un mensaje de que puedes cerrar la página.
Estos permisos no te los volverá a pedir para usar esta aplicación. Y, por tanto, siempre accederá a la cuenta de GMail que has indicado.
Si quieres usar otra cuenta diferente, borra la carpeta esa que te comenté antes (o el fichero que contiene) y eso hará que te vuelva a mostrar todas estas pantallas.
Antes de seguir, espera un poco que me estoy meando de la risa… ¡ay!
Es que te dije que definí la variable peopleService (y las otras dos) a nivel de clase para no tener que usarla como argumento a un método y voy y pongo como argumento el valor de esa variable compartida… en fin… la cabeza del Guille…
Bueno, ya.
Sigamos con el código que accede a los contactos.
privatestaticint total = 0;
staticvoid GetPeople(PeopleService service, string pageToken)
{
// Define parameters of request.
PeopleResource.ConnectionsResource.ListRequest peopleRequest =
service.People.Connections.List("people/me");
//
// Lista de campos a usar en RequestMaskIncludeField:
// https://developers.google.com/people/api/rest/v1/people/get
//
peopleRequest.RequestMaskIncludeField = newList<string>()
{"person.names", "person.phoneNumbers", "person.emailAddresses",
"person.birthdays", "person.Addresses"
};
if (pageToken != null)
{
peopleRequest.PageToken = pageToken;
}
ListConnectionsResponse people = peopleRequest.Execute();
if (people != null && people.Connections != null && people.Connections.Count > 0)
{
total += people.Connections.Count;
foreach (var person in people.Connections)
{
Console.Write(person.Names != null ? ($"{person.Names.FirstOrDefault().DisplayName} - ") : "");
Console.Write(person.PhoneNumbers != null ? ($"{person.PhoneNumbers.FirstOrDefault().Value} - ") : "");
Console.Write(person.EmailAddresses != null ? ($"{person.EmailAddresses.FirstOrDefault().Value} - ") : "");
Console.Write(person.Addresses != null ? ($"{person.Addresses.FirstOrDefault()?.City} - ") : "");
if (person.Birthdays != null)
{
var fecha = "";
var b = person.Birthdays.FirstOrDefault()?.Date;
if (b != null)
fecha = $"{b.Day}/{b.Month}/{b.Year}";
Console.Write($"{fecha}");
}
Console.WriteLine();
}
if (people.NextPageToken != null)
{
Console.WriteLine();
Console.WriteLine($"{total} contactos mostrados hasta ahora. Pulsa una tecla para seguir mostrando contactos.");
Console.WriteLine();
Console.ReadKey();
GetPeople(service, people.NextPageToken);
}
}
else
{
Console.WriteLine("No se han encontrado contactos.");
return;
}
}
PrivateShared total AsInteger = 0
PrivateSharedSub GetPeople(service AsPeopleService, pageToken AsString)
Dim peopleRequest AsPeopleResource.ConnectionsResource.ListRequest =
service.People.Connections.List("people/me")
peopleRequest.RequestMaskIncludeField = NewList(OfString)() From {
"person.names",
"person.phoneNumbers",
"person.emailAddresses",
"person.birthdays",
"person.Addresses"
}
If pageToken IsNotNothingThen
peopleRequest.PageToken = pageToken
EndIf
Dim people AsListConnectionsResponse = peopleRequest.Execute()
If people IsNotNothingAndAlso
people.Connections IsNotNothingAndAlso
people.Connections.Count > 0 Then
total += people.Connections.Count
ForEach person In people.Connections
Console.Write(If(person.Names IsNotNothing,
($"{person.Names.FirstOrDefault().DisplayName} - "), ""))
Console.Write(If(person.PhoneNumbers IsNotNothing,
($"{person.PhoneNumbers.FirstOrDefault().Value} - "), ""))
Console.Write(If(person.EmailAddresses IsNotNothing,
($"{person.EmailAddresses.FirstOrDefault().Value} - "), ""))
Console.Write(If(person.Addresses IsNotNothing,
($"{person.Addresses.FirstOrDefault()?.City} - "), ""))
If person.Birthdays IsNotNothingThen
Dim fecha = ""
Dim b = person.Birthdays.FirstOrDefault()?.Date
If b IsNotNothingThen fecha = $"{b.Day}/{b.Month}/{b.Year}"
Console.Write($"{fecha}")
EndIf
Console.WriteLine()
Next
If people.NextPageToken IsNotNothingThen
Console.WriteLine()
Console.WriteLine($"{total} contactos mostrados hasta ahora. " &
"Pulsa una tecla para seguir mostrando contactos.")
Console.WriteLine()
Console.ReadKey()
GetPeople(service, people.NextPageToken)
EndIf
Else
Console.WriteLine("No se han encontrado contactos.")
Return
EndIf
EndSub
El valor de peopleRequest debe ser siempre people/me o bien si te sabes el ID de otro usuario lo podrías indicar en lugar de «me«. Ese me significa que accedes a tus contactos. He buscado por todas partes, y no he averiguado como saber ese famoso ID, ni siquiera de una de mis cuentas para poder saber si se puede acceder a la cuenta de alguien que no seas tú. Cuando lo averigüe te lo cuento.
Los valores asignados a la lista RequestMaskIncludeField serán a los datos que queremos acceder y siempre deben empezar con person. seguido del campo al que queremos acceder. En este ejemplo estamos indicando que queremos acceder a: los nombres, teléfonos, emails, cumpleaños y domicilios.
Y como esos valores pueden ser nulos (y normalmente son una colección de valores), comprobamos si es nulo y en el caso de las colecciones accedemos al primero o al predeterminado, si hay algo lo mostramos y si no, se usa una cadena vacía.
Con el valor de Birtdays debemos hacer una comprobación más elaborada e incluso te recomendaría que usaras un try/catch si quieres acceder a los valores de la fecha, porque de las pruebas que he heco, en un caso me dio error al querer acceder al año… se ve que el contacto ese no quería dar su año de nacimiento y dio error al querer convertirlo a entero… en fin…
El NextPageToken nos indica que hay más páginas de datos, así que… si las hay volvemos a llamar a este método y seguimos mostrando los contactos que falten por acceder.
Y esto es todo lo que hay que hacer para mostrar los contactos usando People API. Otra cosa es que quieras crear contactos o modificarlos, en esos casos tendrás que modificar el valor del Scope de los contactos. Si hago pruebas de crear o modificar te los pondré por aquí.
Para terminar, la captura del programa en funcionamiento. Ver la figura 7.
Figura 7. La cuenta que he usado para acceder a los contactos, ¡no tiene contactos!
Pues la sorpresa que me llevé… pensé que lo mismo fallaba algo, así que… me fui a google, creé un contacto y volvía a probar… ¡Esta vez sí que sí! (ver la figura 8).
Figura 8. Un contacto tengo en la cuenta que he usado para esta prueba.