Author: Todd

DBI Calendar Control

If you attended Southwest Fox 2016, a free copy of DBI’s Calendar Control was part of your goodies bag. I had a user request come in recently that the calendar control was a perfect fit for so had a chance to work with it.

My application has an “Appointment Book” form that shows all of the appointments, events, etc that the client has to deal with. It’s not terribly sophisticated, just listing all the items in date/time order, but it got the job done:

appointmentbook

The problem the client ran into was that the “Intro” items frequently move around when people call to reschedule. They needed a quicker and easier way to change them as well as seeing what is going on over multiple days. This is exactly what the DBI Calendar Control does and I ended up with the form below. Again, not terribly sophisticated, not using a lot of the color/graphic capabilities of the control, but it gets the job done:

schedule

The advantage here for the user is that they can see the days graphically now, can see multiple days at once, and they can drag & drop the appointments to change the day/time of the appointment.

I was impressed with how easily the control was to work with and how smoothly it works with VFP. In 4 hours or so I went through DBI’s samples (in VFP!), created my own form, and did all the code for adding the appointments, allowing for drag & drop, and double-clicking to open an appointment for editing.

Here’s the 1 line of code for adding an appointment to the calendar. The calendar control works on minutes past midnight rather than a time format so the first parameter is converting my VFP time into minutes. The second parameter is end time which I don’t have for my appointments so I default to start time + 30 minutes. The third parameter is the date while the fourth is whatever text you want to show up.

lIndex = thisform.ctxCalendar1.addAppointment(HOUR(ApDate) * 60 + MINUTE(apDate),;
 (HOUR(apDate) + 1) * 60 + MINUTE(apDate) - 30,;
 TTOD(apDate),;
 lText)

Here’s the code to update my data when an appointment is dragged & dropped to a new date/time. This goes into the control’s AfterAppointmentChange event. The control keeps an index number for every added appointment so I just have to take the nIndex that is passed in, find that entry in my data, and then update my data with all of the other passed in parameters for the new date/time:

SELECT CurAppt
LOCATE FOR ctIndex = nIndex
IF !apx("Seek", CurAppt.apID)
 zmsg("o", "Error! Could not locate appointment to update date/time.", "Error!", "!")
else
 * Update the time of the appointment
 SELECT apAll
 LOCAL lDateTime
 lDateTime = dtDate + (nStartTime * 60)
 replace apDate WITH lDateTime
endif

This code adds or removes day columns when the user changes the form width:

 LOCAL lCol
 lCol = INT((thisform.ctxCalendar1.Width - 60) / 150)
 thisform.ctxCalendar1.DayColumns = lCol

 

Really straight-forward code and the control works really smoothly. In the future I might get fancy and add some color-coding for different appointment types or add some graphics.

The ease of use from DBI has me wondering what other controls I might want to incorporate as well.

Amazon Web Service – Insufficient Capacity

Update 3/1/17: So it looks like Amazon was having trouble yesterday. Let’s assume my problems were related to that, not a problem in this service in general. Hopefully things go more smoothly moving forward.

———————————————————–

I tried to jump into Amazon Web Services today to explore the possibility of a hosted application. Pretty cool stuff, I setup an instance to test some things out and setup a second instance for a client to look at things.

Then things started going wonky – I couldn’t get the Windows Start menu to come up in one instance. Tried rebooting it – no help. “I’ll just stop it,” I thought. And, being cheap, I thought “let’s shut down the other down as well, don’t want to get a $3 bill from Amazon if I go over hours”.

Then the client calls and wants to test things out. “No problem,” I say. This stuff is like magic. I just go to my cloud interface and start that baby back up. When I try, I then get this:

awsinstance

It’s been three hours now and I can’t restart either instance. The client is not impressed. I’m not impressed.

Stripe Metadata

Stripe is obviously good for charging credit cards. Subscriptions & Plans work great for SAAS. A feature that is not so obvious but I’m finding really useful is Stripe’s ability to add metadata to a client entry. Metadata can be any name/value pair and looks like this in the Stripe web interface:

metadata

So what can you use it for?

I have a software program I sell that comes with a free 30 day demo period. I put the expire date of the demo period in the Stripe metadata. I could hide that in the data of the program in one way or another, but what happens when a potential customer calls and says they’d like a little more time to test out the software? With the data in Stripe, I can easily go into the Stripe web interface, change the date, and they’re good to go.

I also put the version number of my software in Stripe metadata. When a tech support email comes in, I can easily check for myself what version of my software they are using.

Since it is demo software, I also store the last time the software was used. This let’s me see demos that are no longer being used.

On a simpler level, I can store name/phone number/email information in the metadata. Again, when that tech support email comes in, I can figure out what company it is and can call them back if need be.

Updating Stripe metadata is straight-forward using the StripeX library in VFPX:

* Create/Update the Stripe customer record
oStripe.AddMetaData("Last Update", TTOC(DATETIME()))
oStripe.AddMetaData("Expire", DTOC(lExpire))
oStripe.AddMetaData("Version", oVar.zAppDate + ": " + oVar.zAppVersion)
oStripe.AddMetaData("Active Count", TRANSFORM(lActiveCnt))
oStripe.AddMetaData("School", lName)

lCustID = oStripe.Customer(zsysvar("CustID"), lName)

Canva for Quick Graphics

As a computer programmer, I’m legally barred from having any artistic ability whatsoever. That was fine back in the days of punch cards, but it’s super inconvenient today because computers today come with screens. Screens that frequently need graphics.

Canva.com has been a huge help for me when I need to create some simple graphics – a banner, a business card, a button image, a Facebook ad, whatever. It’s mostly free (you can pay a couple bucks for graphics and such), easy to use and flexible.

Here’s a quick graphic I did for a business card for my local PTSA. I stole the graphic from the school website (thanks Snagit!) and combined it with some text using Canva:

canva1

And a banner I could slap into my Teamviewer client:

canva2

A skilled graphic artist would certainly do better, but for all my quick & free needs, Canva has been great.

Teamviewer – Two Places at Once

Last week I bit the bullet and bought the full version of Teamviewer and I already loving it. Having clients do Help > Start Remote Control from my app’s menu (and then my code is simply run / TeamView—-) is worlds easier than directing them to a website to download an EXE.

Today I had a client trying to move my app from one computer to another. They were having trouble as clients sometimes do. I was on the new computer, but needed files from the old computer. So I had the client start remote support on the old computer, while I was still connected to the new computer…. and it worked. I had two sessions of Teamviewer running connecting me to both computers at the same time.

I had them up and running in 10 minutes with no hassle. Pretty slick.

TeamViewer – Customize Remote Control

After a couple successful months with the free Teamviewer, I finally bit the ($800) bullet and bought the full version. Yeah, that feels expensive,  but I figure it will eventually be cheaper than the monthly or the pay-as-you-go services.  :: crosses-fingers ::

One of the nice features of TeamViewer is that it’s a simply EXE that the client runs to start a remote control session (Teamviewer calls it Quick Support). I can distribute this EXE to my clients with my app and call it directly from my VFP app — no walking them through a download from a website, trying to find their download folder, and then getting them to run it. Very easy.

When a user wants support, their name shows up in my TeamViewer admin panel. I just click on that to start the support. Here’s a user named Administrator wanting support:

admin

Another nice touch is that you can customize the program on the client to look how you want. You can add your logo, change the text around, and change the colors. So my clients see this customized version rather than some confusing screen with some other company’s name on it:

client

And, you can have multiple quick support screens. So one group of clients get the one above, while other clients have this one:

remote2

Easy to use, easy to implement to the client, customizable so it looks like my product, and – hopefully – a price tag that breaks even in not too long.

Gotcha: One gotcha to look out for. The EXE you’re sending to your client has a got an ugly name like “TeamViewerQS-en-idXXXXXX.EXE”. If you change that name, it will still work but it won’t show your customized screen. You have to use that file name to get your customized screen.

Google Keep – Not There Yet

I’ve pretty much given over everything to Google at this point with two hold outs remaining: OneNote for notes (thanks to the Eric Selje presentation at Southwest Fox) and gQueues for managing tasks/to-dos.

I keep hoping that Google Keep might be able to replace those two things – giving me a little more integration and giving Goole a little more of my soul – but the app is missing a couple key things:

  • No text formatting. I could probably live without bold/italics, but Keep’s inability to – for example – let me  copy a table from a web page and paste it in is kind of a killer.
  • Keep can’t order your notes within a label. Sure, Keep will let you rearrange/order your notes on the main page – where I have a couple hundred personal and business notes – Not convenient. OneNote and gQueues (more importantly for GTD) let me order things within a category. This is a deal breaker.
  • gQueues has really smart recurring task settings. The one I use all the time is “repeat this task X days after I complete it” (doing the laundry for example, I need to do that every 7 days or so. I don’t need to do it every Wednesday). Because sometimes I don’t always GTD when I’m supposed to GTD. Keep only has the very dumb “repeat every X days”. I could create a non-recurring task and just continually move it when I’m done, but that’s annoying and doesn’t give you the little dopamine rush of marking it done.
  • OneNote has a great web clipper that lets you grab the whole web page, part of the page, can recognize if it’s a recipe and cleans it up, and then ultimately stores the web page all nice and pretty in a note. Keep can only put the link in a note for you. I suppose that’s better than nothing, but it is frequently worthless when I’m trying to search for a recipe and the recipe name isn’t in the link.

So until Keep gets an upgrade (and I have little hope of that. Google seems to release stuff and then be done with it) I’ll keep using OneNote (which is slow, clunky, and doesn’t integrate with my other Google apps) and gQueues (which I actually really kind of love and don’t mind paying the $25 a year for and does integrate nicely with my Google calendar).