Menu2 a lot of questions.

Hello!

I'm a beginner in garmin developing APP.. I have a Fenix 5x plus and I want to make a Windsurf APP.

the ideia is have an app with all my information about windsurf equipment.

when going windsurf, I will run the app, choose what sail I will use, what board and what fin, then it will only track me and record how many jibes, jumps and shows live time and speed.

I already search on this forum about my doubts but I still have ones.

To create a Menu 2, what I'm doing wrong?

what is the best way to create a menu like:

the menu is pre defined by me, will be like.

Sails
- 11 m2
- 9.4 m2
- 7.8 m2
- 7.1 m2
- 6 m2 
etc...

Boards
- Formula 161l
- Isonic 127l
- Simmer 116l
etc...

Fins
- 70 boss
- 70 Zfins
- 44 Vmax
-39 SMAX
etc...

I know it will be very hard to make this kind of app, but lets give a try... 

maybe 10 years a go on my free times I used to be "web developer", using javascript, php, Ajax, ASP, mySQL, HTML :D

Thanks!!!

menu.xml

<menu id="mainMenu_Windsurf">
    <menu-item id="item_sail" label="@Strings.menu_sail" />
    <menu-item id="item_board" label="@Strings.menu_board" />
</menu>

strings.xml

<strings>
    <string id="AppName">teste4</string>
    <string id="prompt">Windsurf APP</string>
    <string id="menu_sail">Sail</string>
    <string id="menu_board">Board</string>
</strings>

teste4App.mc

import Toybox.Application;
import Toybox.Lang;
import Toybox.WatchUi;

class teste4App extends Application.AppBase {

    function initialize() {
        AppBase.initialize();
    }

    // onStart() is called on application start up
    function onStart(state as Dictionary?) as Void {
    }

    // onStop() is called when your application is exiting
    function onStop(state as Dictionary?) as Void {
    }

    // Return the initial view of your application here
    function getInitialView() as Array<Views or InputDelegates>? {
        return [ new teste4View(), new teste4Delegate() ] as Array<Views or InputDelegates>;
    }

}

function getApp() as teste4App {
    return Application.getApp() as teste4App;
}

teste4Delegate.mc

import Toybox.Lang;
import Toybox.WatchUi;

class teste4Delegate extends WatchUi.BehaviorDelegate {

    function initialize() {
        BehaviorDelegate.initialize();
    }


    function onMenu() as Boolean {

        var menu = new WatchUi.Menu2({:title=>"Wind Surf"});

            menu.addItem(new WatchUi.MenuItem("Sails",null,"item_sail",{}));
            menu.addItem(new WatchUi.MenuItem("Boards", null,"item_board", null));

            WatchUi.pushView(menu, new teste4MenuDelegate(), WatchUi.SLIDE_IMMEDIATE);

        return true;
    }
    

}

teste4MenuDelegate.mc

import Toybox.Lang;
import Toybox.System;
import Toybox.WatchUi;

class teste4MenuDelegate extends WatchUi.MenuInputDelegate {

    function initialize() {
        MenuInputDelegate.initialize();
    }

    


    function onMenuItem(item as Symbol) as Void {

        // quando carrega no bortao "vermelho"
        if (item == :item_sail) {

            System.println("VELAS");

            //CREATE SUB MENU
            var menu_sub = new WatchUi.Menu2({:title=>"Sails Size"});

            menu_sub.addItem(new WatchUi.MenuItem("7.8",null,"sail1",null));
            menu_sub.addItem(new WatchUi.MenuItem("7.1", null,"sail2", null));
            menu_sub.addItem(new WatchUi.MenuItem("6", null,"sail3", null));

            WatchUi.pushView(menu_sub, new teste4MenuDelegate(), WatchUi.SLIDE_IMMEDIATE);

        } 
        else if (item == :sail1) { System.println("you chose sail 7.8"); }
        else if (item == :sail2) { System.println("you chose sail 7.1"); }
        else if (item == :item_board) { System.println("PRANCHAS"); }
    }

}

teste4View.mc

import Toybox.Graphics;
import Toybox.WatchUi;

class teste4View extends WatchUi.View {

    function initialize() {
        View.initialize();
    }

    // Load your resources here
    function onLayout(dc as Dc) as Void {
        setLayout(Rez.Layouts.MainLayout(dc));
    }

    // Called when this View is brought to the foreground. Restore
    // the state of this View and prepare it to be shown. This includes
    // loading resources into memory.
    function onShow() as Void {
    }

    // Update the view
    function onUpdate(dc as Dc) as Void {
        // Call the parent onUpdate function to redraw the layout
        View.onUpdate(dc);
    }

    // Called when this View is removed from the screen. Save the
    // state of this View here. This includes freeing resources from
    // memory.
    function onHide() as Void {
    }

}

so... the only error is when I push the select button on "Sails", instead of open a new menu with new options (sail sizes), it doesn't do nothing...

Error: Symbol Not Found Error
Details: Failed invoking <symbol>
Stack: 

Encountered app crash.

  • That is where I use the workout for.

    I use workouts when I train alone, but for group workouts it's easier for me just to turn off auto-lap and take manual laps. Reason being that in a group, you're probably not going to run exactly 800 metres or rest for exactly 2 minutes. (Yeah, you can change every step to "until lap press" or insert extra steps with "until lap press", but it's very tedious and almost defeats the purpose.)

  • Although I use https://github.com/cpfair/tapiriik to sync stuff between Garmin and Strava. So it might be that all my history is already at Strava.

    I'm curious why you don't use the standard garmin to strava sync (i.e. go to strava app/site and link with your Garmin account)? Personally I wouldn't rely on Strava to archive all my data because it's not accessible in the original FIT format anymore, and Strava does a few things to modify your run data from the original. For example, if you have GPS issues due to running past tall buildings downtown, Strava often extrapolates the data so you have insane splits / instant paces in a way that Garmin Connect does not.

    I do like https://www.runalyze.com which syncs with Garmin, shows additional information (such as recovery HR* and VO2 Max to 2 decimal places), and makes the original FIT file available for export. Even that site messes with your cadence and stride length numbers when displaying data.

    (* this is saved to FIT files but isn't available in Garmin Connect for all watches, not even fairly new ones like 945 LTE.)

    You can also use this python script to download your history locally:

    [https://github.com/pe-st/garmin-connect-export]

  • And truthfully, I don't really see a need to change - Garmin gives me hardware wise everything I need.

    The other very common user opinion I've seen is that Garmin is great for hardware, and not so great for software.

  • I'm not making the switch because all my data in in Garmin.

    This goes back to the question of whether people use Garmin because they like Garmin or because they're already in the ecosystem.

    And whether a new or casual runner would want an AW or a Garmin-like device.

    Most runners don't run 50-100 km per week (or more) or try to run a sub-3 marathon (which ofc is nothing special). Most runners run for likes, socialization, exercise or the lifestyle.

    I'm currently running 25 km per week (which is very low for me) and I still run more than ~95% of Garmin users. Do casual runners really need a Garmin?

  • I use it because when I set it up there wasnt a native Garmin thing and it just works and don't need to worry about it. I came from Endomondo, where I did the Dutch translation of the app for btw. So when I switched to Garmin I wanted Garmin and Endo to sync. This is years ago and no incentive to migrate away. It works, its foss and vendor independent.

  • No runner requires a Garmin. Not even the pros. You don't need one. But it is fun to have one to keep track of things. I don't need a smart phone. But I like to have one. It is a luxery item.

  • just another example.. how can I do this?? where it is explained?? 

    is made the XML ? made by cod ?

    how can I do this on monkey c???

    many thanks!

  • just another example.. how can I do this?? where it is explained?? 

    is made the XML ? made by cod ?

    how can I do this on monkey c???

    many thanks!

    https://ibb.co/ysYCJLr

    Just for anyone else reading this thread, that image is

    and it can be found here: developer.garmin.com/.../

    To answer your question, it's not something you're supposed to implement, it's one of the data field layouts supported by Garmin watches (looks like one of the 240 x 240 watches.)

    The UX guide is simply telling you what to expect, as the author of a CIQ data field which could be installed in any one of a watch's data field layouts. Other layouts include 1 field, 3 fields and 6 fields (for certain watches.)

    If you want to test how your app looks with a given layout, you can select a data field layout in the simulator.

    Having said that, some developers actually do implement full-screen CIQ fields which are only meant for the 1-field layout, and replicate their own multilple field layout within the app itself. (One reason to do this is because watches only support 2 CIQ fields, and people often want a screen full of data in exchange for using up one of their precious slots).

    If you do that, you don't have to mimic any of the layouts built into the watch. Some devs provide layouts which aren't available on watches, like a 6-field layout for watches which only support up to 4 fields.

    On the flip side, there's nothing in CIQ which will help you mimic a built-in layout, either. You could use an xml layout, or you could draw things programmatically, but either way, you have to reinvent the wheel on your own. (I wrote my own "layout system" using custom JSON resources and drawing code, because the garmin layout system uses a lot of memory, and so does other approaches like writing code to calculate the layout at runtime.)

  • hello. thanks for your answer.

    can you share your example with JSON ?

    I'm seeing the sdk example "JSONDataResource"

    thanks!

  • can you share your example with JSON ?

    Sorry, the code is too complex and messy for the forum. (It's not straightforward at all, because of the various hacks I used to save memory. I also encoded binary layout data by hand instead of writing a code generator :/) Just imagine that each layout is represented by an array of numbers (32-bit integers), where each bit is meaningful (so there's no wasted space), and layouts are stored in JSON resources. At runtime, my full-screen data field app reads the layout data from the JSON resource, decodes it and uses the information to draw text and lines to the DC. Using this system, the app also allows the user to select from multiple layouts with barely any impact to the runtime memory usage of the app. (The app only ever has to load one layout at a time.)

    The TL;DR is you can use Garmin layouts or you can code your own system. As a starting point you could use Garmin layouts, or you could look at this open-source data field:

    https://github.com/gcormier9/GRun

    This app calculates its layout at runtime based on the shape and size of the screen, which is fairly elegant, but unfortunately the code takes up a lot of memory, so the app isn't even available on older devices like FR230. This may not be a problem for you if you don't care about really old devices. (Anecdotally, I find most Garmin users keep their old devices for a very long time tho. But that kind of user probably doesn't care about CIQ at all.)

    It doesn't mimic Garmin layouts, but it has its own 8/9 field layout which appeals to a lot of users.