SlideShare a Scribd company logo
Creating an Uber Clone - Part XXI
Next we’ll bring these changes into the MapForm class which handles the actual heavy lifting of search…
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
First we need to add a couple of members to the class. Some of these variables already exist In the method body, I just moved them into the class level. I'm skipping that
code since it's pretty trivial.

We use MapContainer to place a pin and position it. We can track map position events using this object
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
We need the lastFocused entry so we can set the text in the field when the user drags the map to point at a location
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
The listener is important for cleanup to prevent multiple listener instances, that way we always have at most one
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
The timer instance allows us to cancel it, we use it to delay WebService requests so we don't send them too frequently
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
The "Where to?" Button. We need to hide it when the search UI is showing and show it again when it’s done…
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
We place a lot of elements in that layer on top of the map, it's pretty useful
private MapContainer mc;
private AutoCompleteAddressInput lastFocused;
private MapListener lastMapListener;
private UITimer lastTimer;
private Button whereTo;
private Container mapLayer;
private boolean inNavigationMode;
MapForm
Indicates whether we are in the navigation mode or in another mode such as map or browse mode. This is important as we can't enter navigation mode twice
void showNavigationToolbar() {
final Container layer = getLayeredPane(MapForm.class, true);
layer.setName("MapFormLayer");
layer.setLayout(new BorderLayout());
final Container pinLayer = getLayeredPane(AutoCompleteAddressInput.class, false);
pinLayer.setName("PinLayer");
pinLayer.setLayout(new BorderLayout(CENTER_BEHAVIOR_CENTER_ABSOLUTE));
Image pin = Resources.getGlobalResources().getImage("Pin.png");
Label pinLabel = new Label(pin);
MapLayout.setHorizontalAlignment(pinLabel, MapLayout.HALIGN.CENTER);
MapLayout.setVerticalAlignment(pinLabel, MapLayout.VALIGN.BOTTOM);
pinLayer.add(CENTER, pinLabel);
Button back = new Button("", "TitleCommand");
FontImage.setMaterialIcon(back, FontImage.MATERIAL_ARROW_BACK);
CompletionContainer cc = new CompletionContainer();
AutoCompleteAddressInput from =
new AutoCompleteAddressInput("Current Location", "From",layer,cc);
AutoCompleteAddressInput to =
new AutoCompleteAddressInput("", "Where To?", layer, cc);
from.setCurrentLocation(LocationService.getCurrentLocation());
Image circle = Image.createImage(square.getWidth(),square.getHeight(),0);
Graphics g = circle.getGraphics();
showNavigationToolbar
Now that we have these variables in place lets look at the code

We created and placed a new layer for the pin image placement. This allows us to drag the CompletionContainer down and see the pin image on the map. That also
means we can remove it easily once we exit the search UI
void showNavigationToolbar() {
final Container layer = getLayeredPane(MapForm.class, true);
layer.setName("MapFormLayer");
layer.setLayout(new BorderLayout());
final Container pinLayer = getLayeredPane(AutoCompleteAddressInput.class, false);
pinLayer.setName("PinLayer");
pinLayer.setLayout(new BorderLayout(CENTER_BEHAVIOR_CENTER_ABSOLUTE));
Image pin = Resources.getGlobalResources().getImage("Pin.png");
Label pinLabel = new Label(pin);
MapLayout.setHorizontalAlignment(pinLabel, MapLayout.HALIGN.CENTER);
MapLayout.setVerticalAlignment(pinLabel, MapLayout.VALIGN.BOTTOM);
pinLayer.add(CENTER, pinLabel);
Button back = new Button("", "TitleCommand");
FontImage.setMaterialIcon(back, FontImage.MATERIAL_ARROW_BACK);
CompletionContainer cc = new CompletionContainer();
AutoCompleteAddressInput from =
new AutoCompleteAddressInput("Current Location", "From",layer,cc);
AutoCompleteAddressInput to =
new AutoCompleteAddressInput("", "Where To?", layer, cc);
from.setCurrentLocation(LocationService.getCurrentLocation());
Image circle = Image.createImage(square.getWidth(),square.getHeight(),0);
Graphics g = circle.getGraphics();
showNavigationToolbar
I refactored the text fields to use this new API and set the location to the current location be default. Normally a user wouldn't enter the origin address only the
destination so using the current location makes sense
from.setCurrentLocation(LocationService.getCurrentLocation());
Image circle = Image.createImage(square.getWidth(),square.getHeight(),0);
Graphics g = circle.getGraphics();
g.setColor(0xa4a4ac);
g.setAntiAliased(true);
g.fillArc(0, 0, circle.getWidth(), circle.getHeight(), 0, 360);
final Label fromSelected = new Label(circle);
final Label toSelected = new Label(square);
SearchService.nameMyCurrentLocation(
LocationService.getCurrentLocation(), name -> from.setTextNoEvent(name));
to.requestFocus();
lastFocused = to;
from.addFocusListener(new FocusListener() {
@Override
public void focusGained(Component cmp) {
fromSelected.setIcon(square);
lastFocused = from;
}
@Override
public void focusLost(Component cmp) {
fromSelected.setIcon(circle);
}
showNavigationToolbar
I'm using the nameMyCurrentLocation method to fetch the name of the location of origin
@Override
public void focusLost(Component cmp) {
toSelected.setIcon(circle);
}
});
addMapListener((source, zoom, center) -> {
if(lastTimer != null) {
lastTimer.cancel();
}
lastTimer = UITimer.timer(500, false, () -> {
lastTimer = null;
SearchService.nameMyCurrentLocation(
new Location(center.getLatitude(), center.getLongitude()),
name -> {
lastFocused.setTextNoEvent(name);
lastFocused.setCurrentLocation(
new Location(center.getLatitude(), center.getLongitude()));
});
});
});
Container navigationToolbar = BoxLayout.encloseY(back,
showNavigationToolbar
The map listener is used for the point location on the map functionality, if I drag the map it will fetch the location from there and set it to the last focused text field.
However, we wait 500ms before doing that so we don't send too many WebService requests. We cancel the timer if there is one that's already in the waiting stage
lastFocused.setCurrentLocation(
new Location(center.getLatitude(), center.getLongitude()));
});
});
});
Container navigationToolbar = BoxLayout.encloseY(back,
BorderLayout.centerCenterEastWest(from, null, fromSelected),
BorderLayout.centerCenterEastWest(to, null, toSelected)
);
navigationToolbar.setUIID("WhereToToolbar");
navigationToolbar.getUnselectedStyle().setBgPainter((g1, rect) -> {
g1.setAlpha(255);
g1.setColor(0xffffff);
if(dropShadow != null) {
if(((BorderLayout)layer.getLayout()).getCenter() != null) {
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
g1.drawImage(dropShadow, rect.getX() - shadowHeight, rect.getY() +
rect.getHeight() - dropShadow.getHeight() / 4 * 3);
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getY() +
rect.getHeight() - shadowHeight);
} else {
showNavigationToolbar
This used to be if(layer.getComponentCount() > 1) but that doesn't make sense anymore as the CompletionContainer is always there only folded or expanded. So I check
if the CompletionContainer is in the CENTER or SOUTH
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getY() +
rect.getHeight() - shadowHeight);
} else {
g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight());
}
g1.setColor(0xa4a4ac);
g1.setAntiAliased(true);
int x = fromSelected.getAbsoluteX() + fromSelected.getWidth() / 2 - 1;
int y = fromSelected.getAbsoluteY() + fromSelected.getHeight() / 2 +
circle.getHeight() / 2;
g1.fillRect(x, y, 2, toSelected.getAbsoluteY() - y +
toSelected.getHeight() / 2 - circle.getHeight() / 2);
});
cc.addCompletionListener(e -> {
if(to.getCurrentLocation() != null) {
SearchService.directions(from.getCurrentLocation(), to.getCurrentLocation(),
(path, duration, distance) -> {
enterNavigationMode(pinLayer, navigationToolbar, layer, path,
from.getText(), to.getText(), duration);
});
}
showNavigationToolbar
When a button is pressed in the search completion we get an event to begin navigation at which point we ask for directions and enter navigation mode. I'll discuss the
whole navigation mode in the route section
SearchService.directions(from.getCurrentLocation(), to.getCurrentLocation(),
(path, duration, distance) -> {
enterNavigationMode(pinLayer, navigationToolbar, layer, path,
from.getText(), to.getText(), duration);
});
}
});
back.addActionListener(e -> {
pinLayer.removeAll();
navigationToolbar.setY(-navigationToolbar.getHeight());
layer.getComponentAt(1).setY(getDisplayHeight());
navigationToolbar.getParent().animateUnlayout(200, 120, () -> {
layer.removeAll();
revalidate();
});
});
layer.add(NORTH, navigationToolbar);
navigationToolbar.setWidth(getDisplayWidth());
navigationToolbar.setHeight(getPreferredH());
navigationToolbar.setY(-navigationToolbar.getHeight());
getAnimationManager().addAnimation(layer.createAnimateLayout(200),
() -> cc.showCompletionBar(layer));
}
showNavigationToolbar
I use the animation completion event to show the completion bar which also has an animation in place
private void addMapListener(MapListener ml) {
if(lastMapListener != null) {
mc.removeMapListener(lastMapListener);
}
lastMapListener = ml;
mc.addMapListener(ml);
}
addMapListener
One thing I neglected to mention is the map listener which we bind using this new method. This prevents duplicate map listeners and allows us to easily clear the
selection.

More Related Content

Similar to Creating an Uber Clone - Part XXI - Transcript.pdf

Developing Applications with Microsoft Virtual Earth
Developing Applications with Microsoft Virtual EarthDeveloping Applications with Microsoft Virtual Earth
Developing Applications with Microsoft Virtual Earth
goodfriday
 
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for XamarinGet the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Xamarin
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
ShaiAlmog1
 
Creating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdfCreating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdf
ShaiAlmog1
 
Mashup caravan android-talks
Mashup caravan android-talksMashup caravan android-talks
Mashup caravan android-talkshonjo2
 
UI Design From Scratch - Part 5 - transcript.pdf
UI Design From Scratch - Part 5 - transcript.pdfUI Design From Scratch - Part 5 - transcript.pdf
UI Design From Scratch - Part 5 - transcript.pdf
ShaiAlmog1
 
Keeping Track of Moving Things: MapKit and CoreLocation in Depth
Keeping Track of Moving Things: MapKit and CoreLocation in DepthKeeping Track of Moving Things: MapKit and CoreLocation in Depth
Keeping Track of Moving Things: MapKit and CoreLocation in Depth
Geoffrey Goetz
 
Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...
Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...
Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...
Chris Adamson
 
Creating an Uber Clone - Part XX - Transcript.pdf
Creating an Uber Clone - Part XX - Transcript.pdfCreating an Uber Clone - Part XX - Transcript.pdf
Creating an Uber Clone - Part XX - Transcript.pdf
ShaiAlmog1
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
Ali Parmaksiz
 
Value isnt changing and I cant seem to get the conversion to wor.pdf
Value isnt changing and I cant seem to get the conversion to wor.pdfValue isnt changing and I cant seem to get the conversion to wor.pdf
Value isnt changing and I cant seem to get the conversion to wor.pdf
amirthagiftsmadurai
 
UI Design From Scratch - Part 5.pdf
UI Design From Scratch - Part 5.pdfUI Design From Scratch - Part 5.pdf
UI Design From Scratch - Part 5.pdf
ShaiAlmog1
 
Creating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdfCreating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdf
ShaiAlmog1
 
Google Maps JS API
Google Maps JS APIGoogle Maps JS API
Google Maps JS API
Alberto Simões
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
DroidConTLV
 
Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)
Korhan Bircan
 
Creating an Uber Clone - Part VIII - Transcript.pdf
Creating an Uber Clone - Part VIII - Transcript.pdfCreating an Uber Clone - Part VIII - Transcript.pdf
Creating an Uber Clone - Part VIII - Transcript.pdf
ShaiAlmog1
 
Creating an Uber Clone - Part XVIII - Transcript.pdf
Creating an Uber Clone - Part XVIII - Transcript.pdfCreating an Uber Clone - Part XVIII - Transcript.pdf
Creating an Uber Clone - Part XVIII - Transcript.pdf
ShaiAlmog1
 

Similar to Creating an Uber Clone - Part XXI - Transcript.pdf (20)

Developing Applications with Microsoft Virtual Earth
Developing Applications with Microsoft Virtual EarthDeveloping Applications with Microsoft Virtual Earth
Developing Applications with Microsoft Virtual Earth
 
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for XamarinGet the Most Out of iOS 11 with Visual Studio Tools for Xamarin
Get the Most Out of iOS 11 with Visual Studio Tools for Xamarin
 
Creating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdfCreating a Whatsapp Clone - Part V - Transcript.pdf
Creating a Whatsapp Clone - Part V - Transcript.pdf
 
Map kit light
Map kit lightMap kit light
Map kit light
 
Creating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdfCreating an Uber Clone - Part IX.pdf
Creating an Uber Clone - Part IX.pdf
 
Mashup caravan android-talks
Mashup caravan android-talksMashup caravan android-talks
Mashup caravan android-talks
 
UI Design From Scratch - Part 5 - transcript.pdf
UI Design From Scratch - Part 5 - transcript.pdfUI Design From Scratch - Part 5 - transcript.pdf
UI Design From Scratch - Part 5 - transcript.pdf
 
Keeping Track of Moving Things: MapKit and CoreLocation in Depth
Keeping Track of Moving Things: MapKit and CoreLocation in DepthKeeping Track of Moving Things: MapKit and CoreLocation in Depth
Keeping Track of Moving Things: MapKit and CoreLocation in Depth
 
Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...
Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...
Core Location and Map Kit: Bringing Your Own Maps [Voices That Matter: iPhone...
 
Creating an Uber Clone - Part XX - Transcript.pdf
Creating an Uber Clone - Part XX - Transcript.pdfCreating an Uber Clone - Part XX - Transcript.pdf
Creating an Uber Clone - Part XX - Transcript.pdf
 
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo A GWT Application with MVP Pattern Deploying to CloudFoundry using  Spring Roo
A GWT Application with MVP Pattern Deploying to CloudFoundry using Spring Roo
 
Value isnt changing and I cant seem to get the conversion to wor.pdf
Value isnt changing and I cant seem to get the conversion to wor.pdfValue isnt changing and I cant seem to get the conversion to wor.pdf
Value isnt changing and I cant seem to get the conversion to wor.pdf
 
UI Design From Scratch - Part 5.pdf
UI Design From Scratch - Part 5.pdfUI Design From Scratch - Part 5.pdf
UI Design From Scratch - Part 5.pdf
 
Creating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdfCreating an Uber Clone - Part VII - Transcript.pdf
Creating an Uber Clone - Part VII - Transcript.pdf
 
Applications
ApplicationsApplications
Applications
 
Google Maps JS API
Google Maps JS APIGoogle Maps JS API
Google Maps JS API
 
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
Tricks to Making a Realtime SurfaceView Actually Perform in Realtime - Maarte...
 
Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)Useful Tools for Making Video Games - XNA (2008)
Useful Tools for Making Video Games - XNA (2008)
 
Creating an Uber Clone - Part VIII - Transcript.pdf
Creating an Uber Clone - Part VIII - Transcript.pdfCreating an Uber Clone - Part VIII - Transcript.pdf
Creating an Uber Clone - Part VIII - Transcript.pdf
 
Creating an Uber Clone - Part XVIII - Transcript.pdf
Creating an Uber Clone - Part XVIII - Transcript.pdfCreating an Uber Clone - Part XVIII - Transcript.pdf
Creating an Uber Clone - Part XVIII - Transcript.pdf
 

More from ShaiAlmog1

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
ShaiAlmog1
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
ShaiAlmog1
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
ShaiAlmog1
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
ShaiAlmog1
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
ShaiAlmog1
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
ShaiAlmog1
 
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfCreating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdf
ShaiAlmog1
 

More from ShaiAlmog1 (20)

The Duck Teaches Learn to debug from the masters. Local to production- kill ...
The Duck Teaches  Learn to debug from the masters. Local to production- kill ...The Duck Teaches  Learn to debug from the masters. Local to production- kill ...
The Duck Teaches Learn to debug from the masters. Local to production- kill ...
 
create-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdfcreate-netflix-clone-06-client-ui.pdf
create-netflix-clone-06-client-ui.pdf
 
create-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdfcreate-netflix-clone-01-introduction_transcript.pdf
create-netflix-clone-01-introduction_transcript.pdf
 
create-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdfcreate-netflix-clone-02-server_transcript.pdf
create-netflix-clone-02-server_transcript.pdf
 
create-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdfcreate-netflix-clone-04-server-continued_transcript.pdf
create-netflix-clone-04-server-continued_transcript.pdf
 
create-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdfcreate-netflix-clone-01-introduction.pdf
create-netflix-clone-01-introduction.pdf
 
create-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdfcreate-netflix-clone-06-client-ui_transcript.pdf
create-netflix-clone-06-client-ui_transcript.pdf
 
create-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdfcreate-netflix-clone-03-server.pdf
create-netflix-clone-03-server.pdf
 
create-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdfcreate-netflix-clone-04-server-continued.pdf
create-netflix-clone-04-server-continued.pdf
 
create-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdfcreate-netflix-clone-05-client-model_transcript.pdf
create-netflix-clone-05-client-model_transcript.pdf
 
create-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdfcreate-netflix-clone-03-server_transcript.pdf
create-netflix-clone-03-server_transcript.pdf
 
create-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdfcreate-netflix-clone-02-server.pdf
create-netflix-clone-02-server.pdf
 
create-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdfcreate-netflix-clone-05-client-model.pdf
create-netflix-clone-05-client-model.pdf
 
Creating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdfCreating a Whatsapp Clone - Part II.pdf
Creating a Whatsapp Clone - Part II.pdf
 
Creating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdfCreating a Whatsapp Clone - Part IX - Transcript.pdf
Creating a Whatsapp Clone - Part IX - Transcript.pdf
 
Creating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdfCreating a Whatsapp Clone - Part II - Transcript.pdf
Creating a Whatsapp Clone - Part II - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdfCreating a Whatsapp Clone - Part IV - Transcript.pdf
Creating a Whatsapp Clone - Part IV - Transcript.pdf
 
Creating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdfCreating a Whatsapp Clone - Part IV.pdf
Creating a Whatsapp Clone - Part IV.pdf
 
Creating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdfCreating a Whatsapp Clone - Part I - Transcript.pdf
Creating a Whatsapp Clone - Part I - Transcript.pdf
 
Creating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdfCreating a Whatsapp Clone - Part IX.pdf
Creating a Whatsapp Clone - Part IX.pdf
 

Recently uploaded

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
Guy Korland
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
Alison B. Lowndes
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
DianaGray10
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
Safe Software
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
Product School
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
Product School
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
91mobiles
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
Product School
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Tobias Schneck
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
UiPathCommunity
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
Elena Simperl
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Jeffrey Haguewood
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 

Recently uploaded (20)

How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
GraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge GraphGraphRAG is All You need? LLM & Knowledge Graph
GraphRAG is All You need? LLM & Knowledge Graph
 
Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........Bits & Pixels using AI for Good.........
Bits & Pixels using AI for Good.........
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
Connector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a buttonConnector Corner: Automate dynamic content and events by pushing a button
Connector Corner: Automate dynamic content and events by pushing a button
 
Essentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with ParametersEssentials of Automations: Optimizing FME Workflows with Parameters
Essentials of Automations: Optimizing FME Workflows with Parameters
 
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
From Siloed Products to Connected Ecosystem: Building a Sustainable and Scala...
 
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
From Daily Decisions to Bottom Line: Connecting Product Work to Revenue by VP...
 
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdfSmart TV Buyer Insights Survey 2024 by 91mobiles.pdf
Smart TV Buyer Insights Survey 2024 by 91mobiles.pdf
 
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
De-mystifying Zero to One: Design Informed Techniques for Greenfield Innovati...
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
Kubernetes & AI - Beauty and the Beast !?! @KCD Istanbul 2024
 
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
Dev Dives: Train smarter, not harder – active learning and UiPath LLMs for do...
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
Knowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and backKnowledge engineering: from people to machines and back
Knowledge engineering: from people to machines and back
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 

Creating an Uber Clone - Part XXI - Transcript.pdf

  • 1. Creating an Uber Clone - Part XXI Next we’ll bring these changes into the MapForm class which handles the actual heavy lifting of search…
  • 2. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm First we need to add a couple of members to the class. Some of these variables already exist In the method body, I just moved them into the class level. I'm skipping that code since it's pretty trivial. We use MapContainer to place a pin and position it. We can track map position events using this object
  • 3. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm We need the lastFocused entry so we can set the text in the field when the user drags the map to point at a location
  • 4. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm The listener is important for cleanup to prevent multiple listener instances, that way we always have at most one
  • 5. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm The timer instance allows us to cancel it, we use it to delay WebService requests so we don't send them too frequently
  • 6. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm The "Where to?" Button. We need to hide it when the search UI is showing and show it again when it’s done…
  • 7. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm We place a lot of elements in that layer on top of the map, it's pretty useful
  • 8. private MapContainer mc; private AutoCompleteAddressInput lastFocused; private MapListener lastMapListener; private UITimer lastTimer; private Button whereTo; private Container mapLayer; private boolean inNavigationMode; MapForm Indicates whether we are in the navigation mode or in another mode such as map or browse mode. This is important as we can't enter navigation mode twice
  • 9. void showNavigationToolbar() { final Container layer = getLayeredPane(MapForm.class, true); layer.setName("MapFormLayer"); layer.setLayout(new BorderLayout()); final Container pinLayer = getLayeredPane(AutoCompleteAddressInput.class, false); pinLayer.setName("PinLayer"); pinLayer.setLayout(new BorderLayout(CENTER_BEHAVIOR_CENTER_ABSOLUTE)); Image pin = Resources.getGlobalResources().getImage("Pin.png"); Label pinLabel = new Label(pin); MapLayout.setHorizontalAlignment(pinLabel, MapLayout.HALIGN.CENTER); MapLayout.setVerticalAlignment(pinLabel, MapLayout.VALIGN.BOTTOM); pinLayer.add(CENTER, pinLabel); Button back = new Button("", "TitleCommand"); FontImage.setMaterialIcon(back, FontImage.MATERIAL_ARROW_BACK); CompletionContainer cc = new CompletionContainer(); AutoCompleteAddressInput from = new AutoCompleteAddressInput("Current Location", "From",layer,cc); AutoCompleteAddressInput to = new AutoCompleteAddressInput("", "Where To?", layer, cc); from.setCurrentLocation(LocationService.getCurrentLocation()); Image circle = Image.createImage(square.getWidth(),square.getHeight(),0); Graphics g = circle.getGraphics(); showNavigationToolbar Now that we have these variables in place lets look at the code We created and placed a new layer for the pin image placement. This allows us to drag the CompletionContainer down and see the pin image on the map. That also means we can remove it easily once we exit the search UI
  • 10. void showNavigationToolbar() { final Container layer = getLayeredPane(MapForm.class, true); layer.setName("MapFormLayer"); layer.setLayout(new BorderLayout()); final Container pinLayer = getLayeredPane(AutoCompleteAddressInput.class, false); pinLayer.setName("PinLayer"); pinLayer.setLayout(new BorderLayout(CENTER_BEHAVIOR_CENTER_ABSOLUTE)); Image pin = Resources.getGlobalResources().getImage("Pin.png"); Label pinLabel = new Label(pin); MapLayout.setHorizontalAlignment(pinLabel, MapLayout.HALIGN.CENTER); MapLayout.setVerticalAlignment(pinLabel, MapLayout.VALIGN.BOTTOM); pinLayer.add(CENTER, pinLabel); Button back = new Button("", "TitleCommand"); FontImage.setMaterialIcon(back, FontImage.MATERIAL_ARROW_BACK); CompletionContainer cc = new CompletionContainer(); AutoCompleteAddressInput from = new AutoCompleteAddressInput("Current Location", "From",layer,cc); AutoCompleteAddressInput to = new AutoCompleteAddressInput("", "Where To?", layer, cc); from.setCurrentLocation(LocationService.getCurrentLocation()); Image circle = Image.createImage(square.getWidth(),square.getHeight(),0); Graphics g = circle.getGraphics(); showNavigationToolbar I refactored the text fields to use this new API and set the location to the current location be default. Normally a user wouldn't enter the origin address only the destination so using the current location makes sense
  • 11. from.setCurrentLocation(LocationService.getCurrentLocation()); Image circle = Image.createImage(square.getWidth(),square.getHeight(),0); Graphics g = circle.getGraphics(); g.setColor(0xa4a4ac); g.setAntiAliased(true); g.fillArc(0, 0, circle.getWidth(), circle.getHeight(), 0, 360); final Label fromSelected = new Label(circle); final Label toSelected = new Label(square); SearchService.nameMyCurrentLocation( LocationService.getCurrentLocation(), name -> from.setTextNoEvent(name)); to.requestFocus(); lastFocused = to; from.addFocusListener(new FocusListener() { @Override public void focusGained(Component cmp) { fromSelected.setIcon(square); lastFocused = from; } @Override public void focusLost(Component cmp) { fromSelected.setIcon(circle); } showNavigationToolbar I'm using the nameMyCurrentLocation method to fetch the name of the location of origin
  • 12. @Override public void focusLost(Component cmp) { toSelected.setIcon(circle); } }); addMapListener((source, zoom, center) -> { if(lastTimer != null) { lastTimer.cancel(); } lastTimer = UITimer.timer(500, false, () -> { lastTimer = null; SearchService.nameMyCurrentLocation( new Location(center.getLatitude(), center.getLongitude()), name -> { lastFocused.setTextNoEvent(name); lastFocused.setCurrentLocation( new Location(center.getLatitude(), center.getLongitude())); }); }); }); Container navigationToolbar = BoxLayout.encloseY(back, showNavigationToolbar The map listener is used for the point location on the map functionality, if I drag the map it will fetch the location from there and set it to the last focused text field. However, we wait 500ms before doing that so we don't send too many WebService requests. We cancel the timer if there is one that's already in the waiting stage
  • 13. lastFocused.setCurrentLocation( new Location(center.getLatitude(), center.getLongitude())); }); }); }); Container navigationToolbar = BoxLayout.encloseY(back, BorderLayout.centerCenterEastWest(from, null, fromSelected), BorderLayout.centerCenterEastWest(to, null, toSelected) ); navigationToolbar.setUIID("WhereToToolbar"); navigationToolbar.getUnselectedStyle().setBgPainter((g1, rect) -> { g1.setAlpha(255); g1.setColor(0xffffff); if(dropShadow != null) { if(((BorderLayout)layer.getLayout()).getCenter() != null) { g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); } g1.drawImage(dropShadow, rect.getX() - shadowHeight, rect.getY() + rect.getHeight() - dropShadow.getHeight() / 4 * 3); g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getY() + rect.getHeight() - shadowHeight); } else { showNavigationToolbar This used to be if(layer.getComponentCount() > 1) but that doesn't make sense anymore as the CompletionContainer is always there only folded or expanded. So I check if the CompletionContainer is in the CENTER or SOUTH
  • 14. g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getY() + rect.getHeight() - shadowHeight); } else { g1.fillRect(rect.getX(), rect.getY(), rect.getWidth(), rect.getHeight()); } g1.setColor(0xa4a4ac); g1.setAntiAliased(true); int x = fromSelected.getAbsoluteX() + fromSelected.getWidth() / 2 - 1; int y = fromSelected.getAbsoluteY() + fromSelected.getHeight() / 2 + circle.getHeight() / 2; g1.fillRect(x, y, 2, toSelected.getAbsoluteY() - y + toSelected.getHeight() / 2 - circle.getHeight() / 2); }); cc.addCompletionListener(e -> { if(to.getCurrentLocation() != null) { SearchService.directions(from.getCurrentLocation(), to.getCurrentLocation(), (path, duration, distance) -> { enterNavigationMode(pinLayer, navigationToolbar, layer, path, from.getText(), to.getText(), duration); }); } showNavigationToolbar When a button is pressed in the search completion we get an event to begin navigation at which point we ask for directions and enter navigation mode. I'll discuss the whole navigation mode in the route section
  • 15. SearchService.directions(from.getCurrentLocation(), to.getCurrentLocation(), (path, duration, distance) -> { enterNavigationMode(pinLayer, navigationToolbar, layer, path, from.getText(), to.getText(), duration); }); } }); back.addActionListener(e -> { pinLayer.removeAll(); navigationToolbar.setY(-navigationToolbar.getHeight()); layer.getComponentAt(1).setY(getDisplayHeight()); navigationToolbar.getParent().animateUnlayout(200, 120, () -> { layer.removeAll(); revalidate(); }); }); layer.add(NORTH, navigationToolbar); navigationToolbar.setWidth(getDisplayWidth()); navigationToolbar.setHeight(getPreferredH()); navigationToolbar.setY(-navigationToolbar.getHeight()); getAnimationManager().addAnimation(layer.createAnimateLayout(200), () -> cc.showCompletionBar(layer)); } showNavigationToolbar I use the animation completion event to show the completion bar which also has an animation in place
  • 16. private void addMapListener(MapListener ml) { if(lastMapListener != null) { mc.removeMapListener(lastMapListener); } lastMapListener = ml; mc.addMapListener(ml); } addMapListener One thing I neglected to mention is the map listener which we bind using this new method. This prevents duplicate map listeners and allows us to easily clear the selection.