Starting an app in a menu

Former Member
Former Member
Playing around in the menu test sample. I want to be able to go from choosing an app straight into showing the top level menu. The menu test app shows a splash screen and only when the user presses the menu button does the menu get displayed.

I have tried several modifications but none of them work.

1.
Change the apps getInitialView from:

function getInitialView() {
return [ new MenuTestView(), new MenuTestDelegate() ];
}

to :

function getInitialView() {
return [new Rez.Menus.MainMenu(), new MenuTestMenuDelegate() ];
}

on the assumption that Ui.pushView can take either new MenuTestView() or new Rez.Menus.MainMenu() so the getInitialView should probably do the same. This change compiles OK but exits immediately in the simulator.

2.
Added onShow() to MenuTestView class

function onShow() {
Ui.switchToView(new Rez.Menus.MainMenu(), new MenuTestMenuDelegate(), Ui.SLIDE_UP);
}

but the simulator gives:
Failed invoking <symbol>
Symbol Not Found Error

error on startup. Not very helpful.

3.

Added onShow() to MenuTestView class

function onShow() {
Ui.pushView(new Rez.Menus.MainMenu(), new MenuTestMenuDelegate(), Ui.SLIDE_UP);
}

and adding to MenuTestDelegate

function onBack() {
Ui.popView(Ui.SLIDE_DOWN);
}

shows the menu immediately but pushing the back button to exit the app does nothing.



How do I start an app by showing a menu and then exit the app immediately by hitting the back button? I obviously want to do more than this (and I have successfully), but getting this seemingly trivial behaviour is defeating me. The docs don't make it clear the relationship between a view and a menu. On a watch where the menu takes over the whole screen it seams like it is just a specialised view.

Dave.
  • The top view in a widget doesn't allow up/down keys or up/down swipes by default You can get around it in glance view, but that isn't available on all devices and on others it's configurable.  You'd have to push a view to navigate your menu, and you'd be in the exact same state as with Menu2.

  • for example like Spotify widget :-)

  • That's not a widget.  It's a music provider app.

  • Here's some simple code that show you two options (controlled by useDelegate).  If false, it's similar to what you are doing, but instead of trying to do the pop, it puts up a screen.  That screen can be used for something like a summary based on what your widget does.

    If true, the widget starts with a screen, instructing the user to press menu or back and uses a delegate for this.  Menu brings up the menu.  But there, when you leave the menu, instead of just exiting, the user has the option to go back to the menu.  Again, might be useful depending on what your widget does. Again, it could also be used for something like a summary.

    using Toybox.WatchUi;
    using Toybox.Graphics as Gfx;
    using Toybox.System;
    using Toybox.Application;
    
    //use delegate or not
    var useDelegate=false;
    
    class M2WApp extends Application.AppBase {
    
        function initialize() {
            AppBase.initialize();
        }
    
        function onStart(state) {
    	}
    	
        function onStop(state) {
        }
    
        function getInitialView() {
        	//use this if you want to allow returning to the menu
        	if(useDelegate) {return [new M2WView(),new M2WDelegate()];}
            else {return [new M2WView()];}
        }
    
    }
    
    class M2WView extends WatchUi.View {
    	var width,height;
    	var shown=false;
    	
        function initialize() {
           View.initialize();
    	}
    	
    	function onShow() {
    		if(!shown && !useDelegate) {
    	   		var myMenu=new WatchUi.Menu2({:title=>"Items"});
    			myMenu.addItem(new WatchUi.MenuItem("item 1","","i1",{}));
    			myMenu.addItem(new WatchUi.MenuItem("item 2","","i2",{}));	 		
    	 		WatchUi.pushView(myMenu, new M2WMenuDelegate(),WatchUi.SLIDE_IMMEDIATE);
    	 		shown=true;			
    		}
    	}
    	
    	function onLayout(dc) {
    		width=dc.getWidth();
    		height=dc.getHeight();
    	}
    	
    	function onUpdate(dc) {
    		dc.setColor(Gfx.COLOR_BLACK,Gfx.COLOR_BLACK);
    		dc.clear();
    		dc.setColor(Gfx.COLOR_BLUE,Gfx.COLOR_TRANSPARENT);
    		if(useDelegate) {
    			dc.drawText(width/2,height/2,Gfx.FONT_SMALL,"Hit Menu for Menu\nBack to Exit",Gfx.TEXT_JUSTIFY_CENTER|Gfx.TEXT_JUSTIFY_VCENTER);
    		} else {
    			dc.drawText(width/2,height/2,Gfx.FONT_SMALL,"Hit Back to Exit",Gfx.TEXT_JUSTIFY_CENTER|Gfx.TEXT_JUSTIFY_VCENTER);
    		}
    	}
    }
    
    class M2WDelegate extends WatchUi.BehaviorDelegate {
        function initialize() {
            BehaviorDelegate.initialize();
        }
          
        function onMenu() {
    	   	var myMenu=new WatchUi.Menu2({:title=>"Items"});
    		myMenu.addItem(new WatchUi.MenuItem("item 1","","i1",{}));
    		myMenu.addItem(new WatchUi.MenuItem("item 2","","i2",{}));	 		
    	 	WatchUi.pushView(myMenu, new M2WMenuDelegate(),WatchUi.SLIDE_IMMEDIATE);	    	
        	return true;
        }
    }
    
    class M2WMenuDelegate extends WatchUi.Menu2InputDelegate {
    
        function initialize() {
            Menu2InputDelegate.initialize();
        }
        
      	function onSelect(item) {
      		var id=item.getId();
      		if(id.equals("i1")) {System.println("item 1");}
      		if(id.equals("i2")) {System.println("item 2");}  		 	  	
    	}    
    }	
    

  • If this is your first CIQ widget, another thing to note is in the sim, widgets don't time out, but on watches they do after 30s-2m depending on device.  If you start a widget and don't interact with it, you'll be returned to the watch face after the timeout.

  • i'am doing exactly the same :-) just for IPTV

  • What I do is I have an extra screen at the end telling the user to press back

    Sorry, but it boggles my mind that Garmin thinks this kind of thing is a good UX for the users of widgets.

  • In my case, I had to push a second view (maps), but in most of my widgets, I just use a single view, with a "page number" to display different data.  Single view, no problem.

    At the Oct Conference, it was discussed that widgets are going away on CIQ 4.0 devices, and glances would be added to device apps

    https://forums.garmin.com/developer/garmin-developer-virtual-conference-2020/

    I think it was in the Monkey C presentation in the Connect IQ Track.

    Maybe you should just convert your widget to a device app?

  • At the Oct Conference, it was discussed that widgets are going away on CIQ 4.0 devices, and glances would be added to device apps

    Yeah, I noticed that. That's probably a huge step in the right direction.

    The app in question is a stopwatch, and I have it in both Widget and Device App form. The former for convenience (and usage during an activity), and the latter for usage without timeout and with full features (e.g. activity recording.)

    The problem is I want to use the Back button to take laps and reset the stopwatch, so I need a different way to exit the "full UI view" of my stopwatch while it's running / not reset. In non-glance mode I have a landing page as my initial view which is fine. But in glance mode my glance view is the landing page and I don't want to have a second landing page just because I'm not allowed to programmatically exit a widget.

    Thanks!

  • I have an interesting situation. I'm trying to minimise a repro to make sure it's not something else, but basically I'm also trying to show a menu upon startup using this thread as an example. It works fine in the simulator, but when I try to sideload an app to my fenix 7 and start it, it shows menu loading for less than a second and then my device (not even an app) instantly crashes and reboots.

    It doesn't even produce any of the logs mentioned in the documentation, neither app-specific ones nor device-wide ERR_LOG.txt that is supposed to be there when device itself crashes.

    I tried couple of SDK versions, but behaviour is the same.

    Has anyone seen this before?