The document discusses changes made to integrate a model with the UI for a restaurant ordering application. Key points:
1) The code was updated to retrieve currency formatting and dish data from the restaurant model instead of hardcoded values, integrating the model with the UI.
2) A listener was added to track changes to the dishes map to automatically recalculate the order total when items are added or removed.
3) Similar code updates were made to the checkout and menu forms to populate them with data from the restaurant model.
4) The contact form retrieves location and phone data from the model instead of hardcoded values. Ordering functionality was also updated to use the model.
5) Top-down development,
Initial UI Mockup - Part 3 - Transcript.pdfShaiAlmog1
The document discusses code for a dish list form and dish edit form. It summarizes:
1) The dish list form contains a grid layout to display dishes. A floating action button allows adding new dishes. Dishes are displayed with images, titles, and descriptions.
2) The dish edit form displays dish details and allows editing name, price, description, and image. It positions title/button components above the image and positions the delete button at the bottom.
3) Complex layouts are used to precisely position components like the floating action button between the title and body sections. Margin adjustments are made to align components like the button with the toolbar height.
The document discusses changes made to integrate a model with the UI for a restaurant ordering application. Key points:
1) The code was updated to retrieve currency formatting and dish data from the restaurant model instead of hardcoded values, integrating the model with the UI.
2) A listener was added to track changes to the dishes map to automatically recalculate the order total when items are added or removed.
3) Similar code updates were made to the checkout and menu forms to populate them with data from the restaurant model.
4) The contact form retrieves location and phone data from the model instead of hardcoded values. Ordering functionality was also updated to use the model.
5) Top-down development,
Initial UI Mockup - Part 3 - Transcript.pdfShaiAlmog1
The document discusses code for a dish list form and dish edit form. It summarizes:
1) The dish list form contains a grid layout to display dishes. A floating action button allows adding new dishes. Dishes are displayed with images, titles, and descriptions.
2) The dish edit form displays dish details and allows editing name, price, description, and image. It positions title/button components above the image and positions the delete button at the bottom.
3) Complex layouts are used to precisely position components like the floating action button between the title and body sections. Margin adjustments are made to align components like the button with the toolbar height.
The document discusses integrating persistence with SQLite and ORM binding in three main ways:
1. It loads dish objects from app storage if the dishes list is empty.
2. It uses a delete listener to refresh the UI after a deletion by removing any component representing a deleted dish.
3. It binds dish properties to the UI so that if properties change when data is persisted, those changes are reflected in the main dish list.
AngularJS training provides an overview of key AngularJS concepts and best practices for building Angular applications. The document introduces the trainer, Lauri Svan, and discusses AngularJS fundamentals like two-way data binding, dependency injection, templates, controllers and directives. It also outlines the typical structure of an Angular app, including modules, services and routing. Form validation, custom directives and asynchronous validation with ngModelOptions are also covered to demonstrate common Angular patterns and techniques.
Using the SharePoint Framework as a surface to express yourself through client side solutions is great but at some point in time, you will require that this beauty you built interacts with APIs holding data that lives within the Office 365 environment. In this session, you will learn how to utilize and optimize your calls to SharePoint via its REST APIs, to the Microsoft Graph and to external services that you might find useful to deliver a rich experience in your solution. You will also learn about how to simplify those calls using the Community-Driven library PnP JS Core that aims to save your time (and sanity) by simplifying the access to the SharePoint REST APIs and to the Microsoft Graph. Goodbye URLs, hello intellisense!
This summarizes an Android developer toolbox document. The document provides recommendations for 5 categories of Android libraries: 1) Libraries, 2) Networking, 3) Databases, 4) Images, and 5) Utilities. Key libraries recommended include Retrofit, Glide, Realm, Dagger 2, and EventBus. The document provides brief descriptions and links for each library.
This document discusses using CouchDB on Android applications. It provides instructions on adding CouchDB functionality to an Android project using Couchbase Mobile for Android. It also describes how to access a CouchDB instance from an Android device using Futon and the Couchbase Service. The document contains code examples for creating, reading, updating and deleting CouchDB documents from an Android app.
This document provides instructions for creating a basic ToDo list Android application from scratch. It describes creating an Android project called ToDoList, modifying the main layout file to include an EditText, Button, and ListView within a LinearLayout, and giving each widget an ID. It then explains getting references to these widgets in the main activity class, creating an ArrayList to store todo items and an ArrayAdapter to bind the list to the ListView. Finally, it details adding an onClickListener to the button to add new items to the ArrayList and notify the adapter of changes. Running the application should display an editable todo list.
React table tutorial project setup, use table, and usefilterKaty Slemon
Learn about React Table v7 and its new features in this React Table tutorial. Moreover, explore how can you implement useTable and useFilter hooks in your app.
Firebase and ng2
This document discusses Firebase and AngularFire/AngularFire2. It summarizes that Firebase is a backend as a service that provides realtime database functionality. AngularFire/AngularFire2 are wrappers that make the Firebase API accessible to Angular applications. Key features covered include authentication, authorization, data validation, and working with data through observable references and promises. Best practices like shallow data structures and avoiding deep nesting are also highlighted.
Content providers in Android provide access to data that is shared between different apps.
1. First App: The producer application is designed to construct the SQLite database and the data entry screen.
2. Second App: The consumer application is designed to view the data stored by the first app (as list) the data can be edited also.
Hooray, open source Swift finally arrived on Linux in December. Let’s see how easy it is to use Swift for your backend and why Swift is a good choice for safe and fast development.
Adding a modern twist to legacy web applicationsJeff Durta
Avoid misery of working with legacy code
We will see how you can add independent and isolated components to existing pages; pages that may be difficult to change
React and Flux allow you to make self-contained additions that handle their own data access/persistence
Day 8: Dealing with Lists and ListViewsAhsanul Karim
The document discusses ListViews and ListActivities in Android. It covers:
1) Using the ListView and ListActivity classes to display scrollable lists of data from an Adapter.
2) Developing custom Adapters by extending the BaseAdapter class to provide data and convert it to list item views.
3) Techniques like view recycling and ViewHolders to improve ListView performance with large datasets.
4) Examples of creating ListActivities with ArrayAdapters, custom row layouts, and handling click/long click events.
This document discusses building REST APIs with Laravel 5. It covers topics like using REST instead of SOAP, authentication with basic authentication and middleware, response formats, controller hierarchy, repositories, data transformers, error handling, and an internal dispatcher for making internal API requests. The goal is to provide best practices and patterns for building robust and well-structured REST APIs with Laravel.
The document provides instructions for creating a basic ToDo list Android application. It describes creating an Android project called ToDoList, modifying the main layout to include a list view, edit text, and button within a linear layout. It also covers getting references to these elements, creating an array list to store todo items and array adapter to populate the list view. Finally, it discusses adding an on click listener to the add button to add new items from the edit text to the array list and refresh the list view.
How to Use ReorderableListView Widget in Flutter App Development.pptxFlutter Agency
In todays article we will discuss how developers can use ReorderableListView widget while developing any application in Flutter. Learn more about ReorderableListView widget & its use case in this article.
This document provides an overview of best practices for Android development. It discusses topics such as UI design, including layouts and styles; using the action bar for search and progress indicators; accessibility; network connections; asynchronous tasks and services; fragments and navigation patterns; geolocation and performance; dependency injection; and recommended tools and libraries. The document provides code snippets and links to the Android developer documentation for further information on these topics.
The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
The document outlines an agenda for a workshop on debugging techniques. The workshop covers installing tools, flow and breakpoints debugging, watching variables, Kubernetes debugging, and developer observability. Key techniques discussed include tracepoints, memory debugging, exception breakpoints, object marking, and logs, snapshots, and metrics for observability. The goal is to teach practical debugging skills that can be applied at scale in production environments like Kubernetes.
The document discusses integrating persistence with SQLite and ORM binding in three main ways:
1. It loads dish objects from app storage if the dishes list is empty.
2. It uses a delete listener to refresh the UI after a deletion by removing any component representing a deleted dish.
3. It binds dish properties to the UI so that if properties change when data is persisted, those changes are reflected in the main dish list.
AngularJS training provides an overview of key AngularJS concepts and best practices for building Angular applications. The document introduces the trainer, Lauri Svan, and discusses AngularJS fundamentals like two-way data binding, dependency injection, templates, controllers and directives. It also outlines the typical structure of an Angular app, including modules, services and routing. Form validation, custom directives and asynchronous validation with ngModelOptions are also covered to demonstrate common Angular patterns and techniques.
Using the SharePoint Framework as a surface to express yourself through client side solutions is great but at some point in time, you will require that this beauty you built interacts with APIs holding data that lives within the Office 365 environment. In this session, you will learn how to utilize and optimize your calls to SharePoint via its REST APIs, to the Microsoft Graph and to external services that you might find useful to deliver a rich experience in your solution. You will also learn about how to simplify those calls using the Community-Driven library PnP JS Core that aims to save your time (and sanity) by simplifying the access to the SharePoint REST APIs and to the Microsoft Graph. Goodbye URLs, hello intellisense!
This summarizes an Android developer toolbox document. The document provides recommendations for 5 categories of Android libraries: 1) Libraries, 2) Networking, 3) Databases, 4) Images, and 5) Utilities. Key libraries recommended include Retrofit, Glide, Realm, Dagger 2, and EventBus. The document provides brief descriptions and links for each library.
This document discusses using CouchDB on Android applications. It provides instructions on adding CouchDB functionality to an Android project using Couchbase Mobile for Android. It also describes how to access a CouchDB instance from an Android device using Futon and the Couchbase Service. The document contains code examples for creating, reading, updating and deleting CouchDB documents from an Android app.
This document provides instructions for creating a basic ToDo list Android application from scratch. It describes creating an Android project called ToDoList, modifying the main layout file to include an EditText, Button, and ListView within a LinearLayout, and giving each widget an ID. It then explains getting references to these widgets in the main activity class, creating an ArrayList to store todo items and an ArrayAdapter to bind the list to the ListView. Finally, it details adding an onClickListener to the button to add new items to the ArrayList and notify the adapter of changes. Running the application should display an editable todo list.
React table tutorial project setup, use table, and usefilterKaty Slemon
Learn about React Table v7 and its new features in this React Table tutorial. Moreover, explore how can you implement useTable and useFilter hooks in your app.
Firebase and ng2
This document discusses Firebase and AngularFire/AngularFire2. It summarizes that Firebase is a backend as a service that provides realtime database functionality. AngularFire/AngularFire2 are wrappers that make the Firebase API accessible to Angular applications. Key features covered include authentication, authorization, data validation, and working with data through observable references and promises. Best practices like shallow data structures and avoiding deep nesting are also highlighted.
Content providers in Android provide access to data that is shared between different apps.
1. First App: The producer application is designed to construct the SQLite database and the data entry screen.
2. Second App: The consumer application is designed to view the data stored by the first app (as list) the data can be edited also.
Hooray, open source Swift finally arrived on Linux in December. Let’s see how easy it is to use Swift for your backend and why Swift is a good choice for safe and fast development.
Adding a modern twist to legacy web applicationsJeff Durta
Avoid misery of working with legacy code
We will see how you can add independent and isolated components to existing pages; pages that may be difficult to change
React and Flux allow you to make self-contained additions that handle their own data access/persistence
Day 8: Dealing with Lists and ListViewsAhsanul Karim
The document discusses ListViews and ListActivities in Android. It covers:
1) Using the ListView and ListActivity classes to display scrollable lists of data from an Adapter.
2) Developing custom Adapters by extending the BaseAdapter class to provide data and convert it to list item views.
3) Techniques like view recycling and ViewHolders to improve ListView performance with large datasets.
4) Examples of creating ListActivities with ArrayAdapters, custom row layouts, and handling click/long click events.
This document discusses building REST APIs with Laravel 5. It covers topics like using REST instead of SOAP, authentication with basic authentication and middleware, response formats, controller hierarchy, repositories, data transformers, error handling, and an internal dispatcher for making internal API requests. The goal is to provide best practices and patterns for building robust and well-structured REST APIs with Laravel.
The document provides instructions for creating a basic ToDo list Android application. It describes creating an Android project called ToDoList, modifying the main layout to include a list view, edit text, and button within a linear layout. It also covers getting references to these elements, creating an array list to store todo items and array adapter to populate the list view. Finally, it discusses adding an on click listener to the add button to add new items from the edit text to the array list and refresh the list view.
How to Use ReorderableListView Widget in Flutter App Development.pptxFlutter Agency
In todays article we will discuss how developers can use ReorderableListView widget while developing any application in Flutter. Learn more about ReorderableListView widget & its use case in this article.
This document provides an overview of best practices for Android development. It discusses topics such as UI design, including layouts and styles; using the action bar for search and progress indicators; accessibility; network connections; asynchronous tasks and services; fragments and navigation patterns; geolocation and performance; dependency injection; and recommended tools and libraries. The document provides code snippets and links to the Android developer documentation for further information on these topics.
Similar to Finishing the App - Part 1 - Transcript.pdf (20)
The Duck Teaches Learn to debug from the masters. Local to production- kill ...ShaiAlmog1
The document outlines an agenda for a workshop on debugging techniques. The workshop covers installing tools, flow and breakpoints debugging, watching variables, Kubernetes debugging, and developer observability. Key techniques discussed include tracepoints, memory debugging, exception breakpoints, object marking, and logs, snapshots, and metrics for observability. The goal is to teach practical debugging skills that can be applied at scale in production environments like Kubernetes.
The document describes code for implementing the server-side functionality of a WhatsApp clone. It includes classes for representing users, messages, and server connections. The Server class initializes user and message data from files, handles login/signup, and establishes a websocket connection for real-time messaging. It can send and receive messages when connected, or queue messages when offline.
GraphSummit Singapore | The Future of Agility: Supercharging Digital Transfor...Neo4j
Leonard Jayamohan, Partner & Generative AI Lead, Deloitte
This keynote will reveal how Deloitte leverages Neo4j’s graph power for groundbreaking digital twin solutions, achieving a staggering 100x performance boost. Discover the essential role knowledge graphs play in successful generative AI implementations. Plus, get an exclusive look at an innovative Neo4j + Generative AI solution Deloitte is developing in-house.
Why You Should Replace Windows 11 with Nitrux Linux 3.5.0 for enhanced perfor...SOFTTECHHUB
The choice of an operating system plays a pivotal role in shaping our computing experience. For decades, Microsoft's Windows has dominated the market, offering a familiar and widely adopted platform for personal and professional use. However, as technological advancements continue to push the boundaries of innovation, alternative operating systems have emerged, challenging the status quo and offering users a fresh perspective on computing.
One such alternative that has garnered significant attention and acclaim is Nitrux Linux 3.5.0, a sleek, powerful, and user-friendly Linux distribution that promises to redefine the way we interact with our devices. With its focus on performance, security, and customization, Nitrux Linux presents a compelling case for those seeking to break free from the constraints of proprietary software and embrace the freedom and flexibility of open-source computing.
Sudheer Mechineni, Head of Application Frameworks, Standard Chartered Bank
Discover how Standard Chartered Bank harnessed the power of Neo4j to transform complex data access challenges into a dynamic, scalable graph database solution. This keynote will cover their journey from initial adoption to deploying a fully automated, enterprise-grade causal cluster, highlighting key strategies for modelling organisational changes and ensuring robust disaster recovery. Learn how these innovations have not only enhanced Standard Chartered Bank’s data infrastructure but also positioned them as pioneers in the banking sector’s adoption of graph technology.
Essentials of Automations: The Art of Triggers and Actions in FMESafe Software
In this second installment of our Essentials of Automations webinar series, we’ll explore the landscape of triggers and actions, guiding you through the nuances of authoring and adapting workspaces for seamless automations. Gain an understanding of the full spectrum of triggers and actions available in FME, empowering you to enhance your workspaces for efficient automation.
We’ll kick things off by showcasing the most commonly used event-based triggers, introducing you to various automation workflows like manual triggers, schedules, directory watchers, and more. Plus, see how these elements play out in real scenarios.
Whether you’re tweaking your current setup or building from the ground up, this session will arm you with the tools and insights needed to transform your FME usage into a powerhouse of productivity. Join us to discover effective strategies that simplify complex processes, enhancing your productivity and transforming your data management practices with FME. Let’s turn complexity into clarity and make your workspaces work wonders!
Pushing the limits of ePRTC: 100ns holdover for 100 daysAdtran
At WSTS 2024, Alon Stern explored the topic of parametric holdover and explained how recent research findings can be implemented in real-world PNT networks to achieve 100 nanoseconds of accuracy for up to 100 days.
Programming Foundation Models with DSPy - Meetup SlidesZilliz
Prompting language models is hard, while programming language models is easy. In this talk, I will discuss the state-of-the-art framework DSPy for programming foundation models with its powerful optimizers and runtime constraint system.
AI 101: An Introduction to the Basics and Impact of Artificial IntelligenceIndexBug
Imagine a world where machines not only perform tasks but also learn, adapt, and make decisions. This is the promise of Artificial Intelligence (AI), a technology that's not just enhancing our lives but revolutionizing entire industries.
HCL Notes and Domino License Cost Reduction in the World of DLAUpanagenda
Webinar Recording: https://www.panagenda.com/webinars/hcl-notes-and-domino-license-cost-reduction-in-the-world-of-dlau/
The introduction of DLAU and the CCB & CCX licensing model caused quite a stir in the HCL community. As a Notes and Domino customer, you may have faced challenges with unexpected user counts and license costs. You probably have questions on how this new licensing approach works and how to benefit from it. Most importantly, you likely have budget constraints and want to save money where possible. Don’t worry, we can help with all of this!
We’ll show you how to fix common misconfigurations that cause higher-than-expected user counts, and how to identify accounts which you can deactivate to save money. There are also frequent patterns that can cause unnecessary cost, like using a person document instead of a mail-in for shared mailboxes. We’ll provide examples and solutions for those as well. And naturally we’ll explain the new licensing model.
Join HCL Ambassador Marc Thomas in this webinar with a special guest appearance from Franz Walder. It will give you the tools and know-how to stay on top of what is going on with Domino licensing. You will be able lower your cost through an optimized configuration and keep it low going forward.
These topics will be covered
- Reducing license cost by finding and fixing misconfigurations and superfluous accounts
- How do CCB and CCX licenses really work?
- Understanding the DLAU tool and how to best utilize it
- Tips for common problem areas, like team mailboxes, functional/test users, etc
- Practical examples and best practices to implement right away
Driving Business Innovation: Latest Generative AI Advancements & Success StorySafe Software
Are you ready to revolutionize how you handle data? Join us for a webinar where we’ll bring you up to speed with the latest advancements in Generative AI technology and discover how leveraging FME with tools from giants like Google Gemini, Amazon, and Microsoft OpenAI can supercharge your workflow efficiency.
During the hour, we’ll take you through:
Guest Speaker Segment with Hannah Barrington: Dive into the world of dynamic real estate marketing with Hannah, the Marketing Manager at Workspace Group. Hear firsthand how their team generates engaging descriptions for thousands of office units by integrating diverse data sources—from PDF floorplans to web pages—using FME transformers, like OpenAIVisionConnector and AnthropicVisionConnector. This use case will show you how GenAI can streamline content creation for marketing across the board.
Ollama Use Case: Learn how Scenario Specialist Dmitri Bagh has utilized Ollama within FME to input data, create custom models, and enhance security protocols. This segment will include demos to illustrate the full capabilities of FME in AI-driven processes.
Custom AI Models: Discover how to leverage FME to build personalized AI models using your data. Whether it’s populating a model with local data for added security or integrating public AI tools, find out how FME facilitates a versatile and secure approach to AI.
We’ll wrap up with a live Q&A session where you can engage with our experts on your specific use cases, and learn more about optimizing your data workflows with AI.
This webinar is ideal for professionals seeking to harness the power of AI within their data management systems while ensuring high levels of customization and security. Whether you're a novice or an expert, gain actionable insights and strategies to elevate your data processes. Join us to see how FME and AI can revolutionize how you work with data!
In his public lecture, Christian Timmerer provides insights into the fascinating history of video streaming, starting from its humble beginnings before YouTube to the groundbreaking technologies that now dominate platforms like Netflix and ORF ON. Timmerer also presents provocative contributions of his own that have significantly influenced the industry. He concludes by looking at future challenges and invites the audience to join in a discussion.
Infrastructure Challenges in Scaling RAG with Custom AI modelsZilliz
Building Retrieval-Augmented Generation (RAG) systems with open-source and custom AI models is a complex task. This talk explores the challenges in productionizing RAG systems, including retrieval performance, response synthesis, and evaluation. We’ll discuss how to leverage open-source models like text embeddings, language models, and custom fine-tuned models to enhance RAG performance. Additionally, we’ll cover how BentoML can help orchestrate and scale these AI components efficiently, ensuring seamless deployment and management of RAG systems in the cloud.
Threats to mobile devices are more prevalent and increasing in scope and complexity. Users of mobile devices desire to take full advantage of the features
available on those devices, but many of the features provide convenience and capability but sacrifice security. This best practices guide outlines steps the users can take to better protect personal devices and information.
For the full video of this presentation, please visit: https://www.edge-ai-vision.com/2024/06/building-and-scaling-ai-applications-with-the-nx-ai-manager-a-presentation-from-network-optix/
Robin van Emden, Senior Director of Data Science at Network Optix, presents the “Building and Scaling AI Applications with the Nx AI Manager,” tutorial at the May 2024 Embedded Vision Summit.
In this presentation, van Emden covers the basics of scaling edge AI solutions using the Nx tool kit. He emphasizes the process of developing AI models and deploying them globally. He also showcases the conversion of AI models and the creation of effective edge AI pipelines, with a focus on pre-processing, model conversion, selecting the appropriate inference engine for the target hardware and post-processing.
van Emden shows how Nx can simplify the developer’s life and facilitate a rapid transition from concept to production-ready applications.He provides valuable insights into developing scalable and efficient edge AI solutions, with a strong focus on practical implementation.
Goodbye Windows 11: Make Way for Nitrux Linux 3.5.0!SOFTTECHHUB
As the digital landscape continually evolves, operating systems play a critical role in shaping user experiences and productivity. The launch of Nitrux Linux 3.5.0 marks a significant milestone, offering a robust alternative to traditional systems such as Windows 11. This article delves into the essence of Nitrux Linux 3.5.0, exploring its unique features, advantages, and how it stands as a compelling choice for both casual users and tech enthusiasts.
UiPath Test Automation using UiPath Test Suite series, part 5DianaGray10
Welcome to UiPath Test Automation using UiPath Test Suite series part 5. In this session, we will cover CI/CD with devops.
Topics covered:
CI/CD with in UiPath
End-to-end overview of CI/CD pipeline with Azure devops
Speaker:
Lyndsey Byblow, Test Suite Sales Engineer @ UiPath, Inc.
5. public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
Lets get started with the first item on the agenda the network layer and I’ll do this by creating an abstraction of the server communication. Despite skipping the server
code most of this code should be pretty clear as we go over it.
6. public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
The dish service implements caching for the dish list we fetch from the server to make sure the app loads instantly. If we fetch new data we will show it later as it’s more
important that the app loads quickly. Here we check whether cache even exists, this is important for first time activation.
7. public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
Assuming cache exists we can just load the data from the cache into the global restaurant object. The cache has the JSON as it was returned from the server so we can
parse it using the standard parsing code.
This is convenient for debugging as we can inspect the json file in the filesystem for the simulator and see what’s saved locally
8. public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
The JSON file contains a map object which contains two arrays dishes and categories. The dishes array contains all the information in a dish and every entry within this
map has the same key value pairs as the Dish object properties. One of the features of property objects is the ability to populate a property from a Map object or from
JSON directly and this is exactly the case for which this is useful
9. public class DishService {
public static boolean hasCachedDishList() {
return Storage.getInstance().exists("DishListCache");
}
public static void loadDishesFromCache() {
JSONParser p = new JSONParser();
try {
Map<String, Object> m = p.parseJSON(new InputStreamReader(
Storage.getInstance().createInputStream("DishListCache"), "UTF-8"));
List<Object> l = (List<Object>)m.get("dishes");
Restaurant.getInstance().menu.get().dishes.clear();
for(Object o : l) {
Dish d = new Dish();
d.getPropertyIndex().populateFromMap((Map)o);
Restaurant.getInstance().menu.get().dishes.add(d);
}
List<String> cats = (List<String>)m.get("categories");
Restaurant.getInstance().menu.get().categories.clear();
for(String str : cats) {
Restaurant.getInstance().menu.get().categories.add(str);
}
if(!Restaurant.getInstance().menu.get().dishDownloadFinished.get()) {
Restaurant.getInstance().menu.get().dishDownloadFinished.set(Boolean.TRUE);
}
} catch(IOException err) {
Log.e(err);
ToastBar.showErrorMessage("Error loading list of dishes: " + err);
Log.sendLog();
DishService (Client)
The categories are just string names of all the available categories. We could probably just go over the dishes and extract the categories from there though.
Once we add the categories we set the boolean flag indicating the download was finished, this is important as external code might have a listener bound to the property
so it can refresh the UI once the data finished loading.
10. public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
Moving on we have two separate methods to update the dishes. They are both identical and just use the addToQueueAndWait or addToQueue.
The reason we need both is simple, we use addToQueue when the app launches as we want to launch right away and don’t want to wait for the data. However, pull to
refresh needs to block until the data is here and in that case we need to use addToQueueAndWait.
11. public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
The aptly named update dishes from server is the common code for both update methods, it creates a connection request to the dish URL that performs a GET HTTP
method on the server.
12. public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
The response is parsed mostly so we can check the time stamp and update the local time stamp. The time stamp trick allows us to send a request with the last received
time stamp and initially we just send 0. This means the server is responsible for updating that value and if no change was made since the last time the server changed
that value we don’t need to receive new data.
13. public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
You will notice that if the data is changed we save it to cache then load it from cache later. This is pretty important, we call the loading code from the post response call
which runs on the event dispatch thread. The other callbacks in the connection request occur on a network thread but the post response call is on the event dispatch
thread and thus it can change the UI or UI related elements.
14. public static void updateDishesFromServerSync() {
NetworkManager.getInstance().addToQueueAndWait(updateDishesFromServer());
}
public static void updateDishesFromServerAsync() {
NetworkManager.getInstance().addToQueue(updateDishesFromServer());
}
private static ConnectionRequest updateDishesFromServer() {
ConnectionRequest cr = new ConnectionRequest(MyRestaurant.SERVER_URL + "dish", false) {
private boolean autoLoad;
protected void readResponse(InputStream input) throws IOException {
JSONParser p = new JSONParser();
Map<String, Object> m = p.parseJSON(new InputStreamReader(input, "UTF-8"));
String stamp = (String)m.get("stamp");
if(stamp != null) {
Preferences.set("lastTimeStamp", stamp);
OutputStream o = Storage.getInstance().createOutputStream("DishListCache");
o.write(Result.fromContent(m).toString().getBytes());
o.close();
autoLoad = true;
}
}
protected void postResponse() {
if(autoLoad) {
loadDishesFromCache();
}
}
};
cr.addArgument("stamp", Preferences.get("lastTimeStamp", "0"));
cr.addArgument("appId", MyRestaurant.APP_AUTH);
return cr;
DishService (Client)
As I mentioned before we send the time stamp and also an authorization key to the server. The latter is hardcoded forthe app but the former gets updated by the server
every time the data changes.
15. @Override
protected Container createContent() {
Container c = new Container(BoxLayout.y());
final Menu m = Restaurant.getInstance().menu.get();
if(m.dishes.size() == 0) {
if(DishService.hasCachedDishList()) {
DishService.loadDishesFromCache();
}
}
if(m.dishes.size() > 0) {
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.addPullToRefresh(() -> {
DishService.updateDishesFromServerSync();
c.removeAll();
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.revalidate();
});
} else {
MainMenuForm
Let’s move on to the main menu form where we now fetch the dishes from cache if they aren’t loaded yet.
16. @Override
protected Container createContent() {
Container c = new Container(BoxLayout.y());
final Menu m = Restaurant.getInstance().menu.get();
if(m.dishes.size() == 0) {
if(DishService.hasCachedDishList()) {
DishService.loadDishesFromCache();
}
}
if(m.dishes.size() > 0) {
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.addPullToRefresh(() -> {
DishService.updateDishesFromServerSync();
c.removeAll();
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
c.revalidate();
});
} else {
MainMenuForm
You will also notice that the pull to refresh call makes use of the update sync method to fetch the updated dishes synchronously.
17. } else {
final Container infi = FlowLayout.encloseCenter(new InfiniteProgress());
c.add(infi);
m.dishDownloadFinished.addChangeListener(p -> {
c.removeAll();
for(Dish currentDish : m.dishes) {
c.add(createDishContainer(currentDish));
}
categoryModel.removeAll();
for(String s : m.categories) {
categoryModel.addItem(s);
}
c.revalidate();
});
}
c.setScrollableY(true);
c.setScrollVisible(false);
dishesContainer = c;
return c;
}
MainMenuForm
This block represents a very special case of the first invocation when we have no dishes available and are still waiting. In this case we place an infinite progress in place
and bind a listener to the finished download so we can replace the progress. Notice we aren’t concerned about dishes suddenly appearing in a background thread
because everything is modified via the event dispatch thread so we can rely on this being in sync.