Stupid complications questions

Hello,

Before I head down the path of complications, please verify:

1) It's not that drastic to convert/publish my Glance as an app 

2) I can open my own app using a long press on an area of my compatible watch face

It looks a bit daunting from my amateur programmer seat.

Thanks

  • So...this worked:

    Complications.registerComplicationChangeCallback(stepsDisp());
    If I understand correctly, this will only run the stepsDisp function when the Complication detects a change in steps, versus every onUpdate.  Am I close?
  • So...this worked:

    Complications.registerComplicationChangeCallback(stepsDisp());
    If I understand correctly, this will only run the stepsDisp function when the Complication detects a change in steps, versus every onUpdate.  Am I close?

    How exactly did that "work"? Do you mean it compiled and it didn't crash when you tried to run it? You must not have type-checking enabled, as this will at best do nothing and at worst crash at runtime.

    Let me try to explain how registerComplicationChangeCallback() actually works. It takes a method reference to a single callback function, not a complication ID and not the name, symbol or result of calling a function (unless that function returns a method reference to a single callback function.) If you call it multiple times, only the last call will count.

    Let's break down what a statement like Complications.registerComplicationChangeCallback(stepsDisp()); actually does:

    1) stepsDisp() is called, and the return value is temporarily saved

    2) The saved value from 1. is passed into Complications.registerComplicationChangeCallback()

    So no, that code will not call stepsDisp() when the Complication detects a change in steps. It calls stepsDisp() immediately and tries to register the result as a callback.

    Once again, what needs to be passed to Complications.registerComplicationChangeCallback() is a method reference to a callback function. If the callback is a function in the current class called myAwesomeFunction, then that reference is obtained using method(:myAwesomeFunction)

    Here's some code which seems to be in spirit of what you're trying to do:

    - There's separate functions to update the battery, steps or calendar complications *value*, either from the complication or "legacy" source

    - These functions are called either by onUpdate() (if complications are not available) or by the complication change callback

    I don't claim this is the best approach, just the one that matches your stated approach.

    Sorry for the screenshot and link to pastebin, but Insert Code is giving me a fun forum error, and trying to manually format code in the forums is a huge waste of time.

    https://pastebin.com/Gayzma2C

    EDIT "RandomWatchFaceViewClass" should probably be "RandomWatchFaceView" but I'm not going to update the screenshot and pastebin.)

    EDIT: I'm aware that this code won't work properly if somehow some, but not all, of the desired native complications exist. The code can be adapted to handle that situation, although I don't think it's realistic.

    EDIT: "if (id == calComp)" should be "if (id == calId)"

  • First, thank you.  I think...I've got it.  it at least it now makes sense why there is often a return true or false with a complication.  My hangup is that a Method seems unnecessarily complicated (no pun intended) and needlessly adds a layer. The second Toybox sample still makes zero sense to me, btw.

    Side note: Yes, by working, I mean it compiles and runs.  After a while, this is a huge victory.  Yes, usually the results are often amusing and routinely frustrating, but it at least gives me a starting point. Let's face it, the instructional materials for Monkey C are limited and those of us non-pro programmers are left to a lot of trial and error.  That's why the help from programmers on message boards is so critical. Thanks again!

  • My hangup is that a Method seems unnecessarily complicated (no pun intended) and needlessly adds a layer.

    If you mean that it's unnecessarily complicated to have to type "method(:myAwesomeCallback)" as opposed to "myAwesomeCallback", I agree. In some popular languages (like Javascript and Python), functions are first class objects, and you can just pass them around / refer to them by name. In other languages (like Java), it's not as simple.

    There's a lot of things in Monkey C that are unnecessarily complicated, which is annoying for a new(ish) language. For example, ES6 (a version of javascript) and Monkey C both came out around 2015, but ES6 has a ton of modern language features which Monkey C will apparently never have. I realize that Garmin isn't the type of company to be on the bleeding edge of anything though.

    I've definitely seen this sentiment echoed in reddit comments circa 2015, about how interested devs wished that Monkey C was more modern.

    Let's face it, the instructional materials for Monkey C are limited and those of us non-pro programmers are left to a lot of trial and error.

    Yeah, while I appreciate that Garmin has the only 3rd party app framework out of all the "legacy sportswatches", it doesn't seem like they care about it a whole lot (as a company.) I don't blame em as users don't care a lot either. Kind of a chicken and egg thing tho, imo. The situation is further complicated by the fact that garmin will never allow sports-focused apps to have the same functionality as native apps (because they wouldn't want a CIQ dev to re-implement a Garmin premium feature, but better.) That's why I was happy to have "navigation for free" with a CIQ app on an old Garmin watch, but as soon as I got a Garmin with native navigation, I never looked back. The dev and app were great, but the app could never be as good as the native feature.

    Thanks again!

    No worries!

  • Back to one of my initial issues. 

    To make 

    Complications.registerComplicationChangeCallback(self.method(:onComplicationChanged))
    work with 
    function onComplicationChanged(compId as Complications.Id) as Void {...
    I needed to first assign "compId" as a variable in the class. (insert face palm here)
  • To make 

    Complications.registerComplicationChangeCallback(self.method(:onComplicationChanged))
    work with 
    function onComplicationChanged(compId as Complications.Id) as Void {...
    I needed to first assign "compId" as a variable in the class. (insert face palm here)

    That doesn't sound right to me. compId is the name of a function parameter, so it shouldn't also have to exist as a class member variable.

    Can you share a snippet of code and/or the error message that you're seeing?

  • You're killing me smalls!  Yup.  just took it out.  Works fine now.  In my defense, I have re-started my computer since last try.

    Now I'm on to why 

    batteryDisplay.setText(batString) works if I define batString not using complications, but crashes if I do use it. 
    if (hasComps) {
    batLoad = Complications.getComplication(batId).value;

    batType = Complications.getComplication(batId).ranges;
    System.println("batLoad Units: "+batType);

    System.println("batLoad Comps: "+batLoad);
    } else {
    batLoad = ((System.getSystemStats().battery) + 0.5).toNumber();
    System.println("batLoad no Comps: "+batLoad);
    }
    batString = Lang.format("$1$", [batLoad])+"%";
    I get a "Details: Failed invoking <symbol>" at the line where I setText is and not where it evaluates the number.  Maybe I'll reboot a few more times and see if that fixes it.
  • Hi Jim, going back to this topic again. I'm looking to add a background service to my widget/"super app" to publish some data. I need to fire off the background service without the user having to start the widget. Is that possible? and if so, is there a specific place where I should register the background event? Today I usually do that from my app class (extends App.AppBase) inside getInitialView() 

  • Understand that you don't need to be in the background service to publish.  In fact, Some apps may only publish from the main app.  For my publishers, I do both.  So in getInitialView and getGlance view (neither uses getSettingView but it should work there too).  I publish and registerforTemporalEvents.  Your app needs to run in some way to publish, and that can be as simple as scrolling through the glance loop.

    Depending on how you write your background service you can also do what you need from the main app too. Unlike watch faces where there's stuff you can only do in a background service, widgets/super apps don't have those restrictions.

    I'd say, first you want to get publishing working in the main app, then look at adding publishing logic in a background service.

  • I see, but if I want to publish data to a watch face from my widget, without the user having to open the widget or go into the glances carousel, is there a way I can do that?