Code News

Adding Physics-Based Animations to Android Apps

  • Animations that feel fluid and realistic tend to make user interfaces more attractive. No wonder Material Design places so much emphasis on them! 

    If you've ever tried creating such animations, however, you know that the simple animators and interpolators offered by the Android SDK are often not good enough. That's why recent revisions of the Android Support Library come with a physics module called Dynamic Animation.

    With Dynamic Animation, you can create physics-based animations that closely resemble the movements of objects in the real world. You can also make them respond to user actions in real time. In this tutorial, I'll show you how to create a few such animations.

    Prerequisites

    To follow along, make sure you have the following:

    1. Adding Dependencies

    To be able to use Dynamic Animation in your project, you must add it as an implementation dependency in your app module's build.gradle file:

    implementation 'com.android.support:support-dynamic-animation:26.0.0-beta2'

    In this tutorial, we're going to be animating an ImageView widget. It will, of course, have to display some images, so open the Vector Assets Studio and add the following Material icons to your project:

    • sentiment neutral
    • sentiment very satisfied

    Here's what they look like:

    For best results, I suggest you set the size of the icons to 56 x 56 dp.

    2. Creating a Fling Animation

    When you fling an object in the real world, you give it a large momentum. Because momentum is nothing but the product of mass and velocity, the object will initially have a high velocity. Gradually, however, thanks to friction, it slows down until it stops moving completely. Using Dynamic Animation's FlingAnimation class, you can simulate this behavior inside your app.

    For the sake of demonstration, let us now create a layout containing a flingable ImageView widget, displaying the ic_sentiment_neutral_black_56dp icon, and a Button widget users can press to trigger the fling animation. If you place them both inside a RelativeLayout widget, your layout XML file will look like this:

    <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="16dp"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_sentiment_neutral_black_56dp" android:id="@+id/emoji" android:layout_centerInParent="true" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Fling" android:id="@+id/flinger" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:onClick="flingIt" /> </RelativeLayout>

    In the above code, you can see that the Button widget has an onClick attribute. By clicking on the red light-bulb icon Android Studio shows beside it, you can generate an associated on-click event handler inside your Activity class:

    public void flingIt(View view) { // more code here }

    You can now create a new instance of the FlingAnimation class using its constructor, which expects a View object and the name of an animatable property. Dynamic Animation supports several animatable properties, such as scale, translation, rotation, and alpha.

    The following code shows you how to create a FlingAnimation instance that can animate the X-coordinate of our layout's ImageView:

    // Get a reference to the view ImageView emoji = (ImageView)findViewById(R.id.emoji); // Pass it to the constructor FlingAnimation flingAnimation = new FlingAnimation(emoji, DynamicAnimation.X);

    By default, a FlingAnimation instance is configured to use 0 pixels/second as its initial velocity. That means the animation would stop as soon as it's started. To simulate a realistic fling, you must always remember to call the setStartVelocity() method and pass a large value to it.

    Additionally, you must understand that without friction, the animation will not stop. Therefore, you must also call the setFriction() method and pass a small number to it.

    The following code configures the FlingAnimation instance such that the ImageView is not flung out of the bounds of the user's screen:

    flingAnimation.setStartVelocity(500f); flingAnimation.setFriction(0.5f);

    At this point, you can simply call the start() method to start the animation.

    flingAnimation.start();

    If you run the app now and press the button, you should be able to see the fling animation.

     

    It is worth noting that you don't specify a duration or an end value when creating a physics-based animation—the animation stops automatically when it realizes that its target object is not showing any visible movement on the user's screen.

    3. Simulating Springs

    Dynamic Animation allows you to easily add spring dynamics to your animations. In other words, it can help you create animations that make your widgets bounce, stretch, and squash in ways that feel natural.

    To keep things simple, let's now reuse our layout's ImageView and apply a spring-based animation to it. To allow the user to initiate the animation, however, you'll need to add another Button widget to the layout.

    <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Bounce" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:onClick="bounce" />

    To create a spring-based animation, you must use the SpringAnimation class. Its constructor too expects a View object and an animatable property. The following code creates a SpringAnimation instance configured to animate the x-coordinate of the ImageView:

    // Get a reference to the view final ImageView emoji = (ImageView)findViewById(R.id.emoji); // Pass it to the constructor SpringAnimation springAnimation = new SpringAnimation(emoji, DynamicAnimation.X);

    To control the behavior of a spring-based animation, you'll need a spring. You can create one using the SpringForce class, which allows you to specify the resting position of the spring, its damping ratio, and its stiffness. You can think of the damping ratio as a constant that, like friction, is responsible for slowing the animation down until it stops. The stiffness, on the other hand, specifies how much force is required to stretch the spring.

    If all that sounds a bit too complicated, the good news is that the SpringForce class offers several intuitively named constants you can use to quickly configure your spring. For instance, the following code creates a spring that is both very bouncy and very flexible:

    SpringForce springForce = new SpringForce(); springForce.setFinalPosition(emoji.getX()); springForce.setDampingRatio(SpringForce.DAMPING_RATIO_HIGH_BOUNCY); springForce.setStiffness(SpringForce.STIFFNESS_LOW);

    In the above code, you can see that we've set the value of the final resting position of the spring to the initial X-coordinate of the ImageView. With this configuration, you can imagine that the ImageView is attached to a tight, invisible rubber band, which quickly pulls the ImageView back to its original position every time it is moved.

    You can now associate the spring with the SpringAnimation instance using the setSpring() method.

    springAnimation.setSpring(springForce);

    Lastly, before starting the animation, you must make sure you give it a large initial velocity using the setStartVelocity() method.

    springAnimation.setStartVelocity(2000f); springAnimation.start();

    If you run the app now, you should see something like this:

      4. Listening to Animation Events

    An animation that's created using the Dynamic Animation library must always be started from the UI thread. You can also be sure that it will start as soon as you call the start() method. However, it runs asynchronously. Therefore, if you want to be notified when it ends, you must attach an OnAnimationEndListener object to it using the addEndListener() method.

    To see the listener in action, let's change the Material icon the ImageView displays every time the spring-based animation, which we created in the previous step, starts and ends. I suggest you use the ic_sentiment_very_satisfied_black_56dp icon when the animation starts, and the ic_sentiment_neutral_black_56dp icon when it ends. The following code shows you how:

    // Change icon before animation starts emoji.setImageResource( R.drawable.ic_sentiment_very_satisfied_black_56dp); // Start animation springAnimation.start(); springAnimation.addEndListener( new DynamicAnimation.OnAnimationEndListener() { @Override public void onAnimationEnd(DynamicAnimation animation, boolean canceled, float value, float velocity) { // Change icon after animation ends emoji.setImageResource( R.drawable.ic_sentiment_neutral_black_56dp); } });

    With the above code, the animation will look like this:

      5. Animating Multiple Properties

    The constructors of both the FlingAnimation and the SpringAnimation classes can only accept one animatable property. If you want to animate multiple properties at the same time, you can either create multiple instances of the classes, which can get cumbersome, or create a new custom property that encapsulates all your desired properties.

    To create a custom animatable property, you must create a subclass of the FloatPropertyCompat class, which has two abstract methods: setValue() and getValue(). As you might have guessed, you can update the values of all your desired animatable properties inside the setValue() method. Inside the getValue() method, however, you must return the current value of any one property only. Because of this limitation, you'll usually have to make sure that the values of the encapsulated properties are not completely independent of each other.

    For example, the following code shows you how to create a custom property called scale, which can uniformly animate both the SCALE_X and SCALE_Y properties of a widget:

    FloatPropertyCompat<View> scale = new FloatPropertyCompat<View>("scale") { @Override public float getValue(View view) { // return the value of any one property return view.getScaleX(); } @Override public void setValue(View view, float value) { // Apply the same value to two properties view.setScaleX(value); view.setScaleY(value); } };

    Now that the custom property is ready, you can use it like any other animatable property. The following code shows you how to create a SpringAnimation object with it:

    SpringAnimation stretchAnimation = new SpringAnimation(emoji, scale);

    While creating an animation that uses a custom property, it is a good idea to also call the setMinimumVisibleChange() method and pass a meaningful value to it in order to make sure that the animation doesn't consume too many CPU cycles. For our animation, which scales a widget, you can use the following code:

    stretchAnimation.setMinimumVisibleChange( DynamicAnimation.MIN_VISIBLE_CHANGE_SCALE);

    Here's what the custom property animation looks like:

     Conclusion

    You now know the basics of working with Dynamic Animation. With the techniques you learned in this tutorial, you can create convincing physics-based animations in a matter of minutes, even if you have very little knowledge of Newtonian physics.

    To learn more about Dynamic Animation, refer to the official documentation. In the meantime, check out some of our other recent posts on Android app development!

    20 hours 12 min ago

7 Best Weather WordPress Widgets & Plugins

  • There are many instances when providing current temperatures and weather forecasts on a website can be useful. Restaurants, retreat centers, country clubs, and many other businesses and organizations can benefit from this kind of feature.

    There are a few things you'll want to consider:

    • How does the widget design fit within the current website theme?

    Many of the following weather WordPress widgets and plugins have design options built in or can be easily modified to fit your website's design.

    • Does the weather WordPress plugin being considered require another service?

    Some weather plugins require the World Weather Online API. Before April 2017, they provided free registered API keys. Now they require a premium subscription.

    • Where will the weather be displayed?

    There are a variety of options and features which weather widgets offer. There are some that can only be placed in a widget area, whereas some provide a shortcode option, allowing you to place the weather widget on any page.

    Every website has its own unique needs, so you may need to consider additional things as well. Take a look at these 7 best weather WordPress widgets and plugins, and I'm sure you'll find something that will meet your need.

    1. Astero WordPress Weather Plugin

    The Astero WordPress Weather Plugin includes much of what you'll ever want in a weather WordPress plugin. With its clean lines, multiple sizes and styles, and solid feature set, your weather widget will be looking good, even if the weather isn't.

    Some of the technical features include:

    • HTML5 geolocation with IP fallback
    • supports 600+ Google Fonts
    • fully responsive layout
    • local cache
    • and more

    And the design features include:

    • use HTML5 video or YouTube for your background
    • or use a static image or flat background
    • simple or full-screen modes
    • unlimited colors
    • and more

    As for your weather sources, you can switch between Forecast.io and Openweathermap.org, and users can also leverage the built-in city or zip code search function.

    The Astero WordPress Weather Plugin includes excellent features and throws in some impressive design choices, making it a top choice for weather WordPress widgets and plugins.

    2. City Weather for WordPress

    If you're looking for a nicely designed weather widget that displays the weather for only a predefined location, you might want to give City Weather for WordPress a try. It includes a few basic options and can easily be configured to match just about any design.

    Features included:

    • select a custom background color or use an image
    • supports Fahrenheit and Celsius units
    • select wide or tall widget size
    • fully responsive
    • and more

    City Weather for WordPress doesn't include many options, but it's designed well, and it would be perfect for restaurants, country clubs, and other local websites that benefit from users knowing the weather.

    3. WeatherSlider Premium WordPress Weather Widget

    If you need the weather a little more front and center, then something like the WeatherSlider Premium WordPress Weather Widget is what you want. This weather WordPress widget doesn't just display the current temperature, it's a full-featured weather slider.

    The design features include:

    • CSS3 animations with jQuery fallback
    • auto-slideshow and auto-refresh option
    • fully responsive from 240x200 to 1300x600
    • touch control, keyboard navigation, and supported on all major browsers
    • and more

    Weather features include:

    • 12 or 24 hour time formats and localization ready
    • display current weather or three-day forecast
    • custom location search bar
    • 48 different weather types
    • and more

    You'll also find the detailed documentation and layered graphic elements PSD file very helpful.

    Display the weather in style with the WeatherSlider Premium WordPress Weather Widget.

    4. aWeather Forecast

    The aWeather Forecast weather WordPress plugin displays weather conditions like no other. With its cast of animated icons, animated headers, and full color customization, this is easily one of the most charming weather widgets you'll find.

    This widget can display:

    • current weather icon and temperature
    • current weather conditions
    • wind speed and direction
    • pressure, humidity, and more

    Some features include, but not limited to:

    • Fahrenheit, Celsius, and Kelvin unit formats
    • 18 animated icons and 4 animated headers
    • select from over 700 Google Fonts
    • and more

    The aWeather Forecast plugin is one of the most uniquely designed weather WordPress widgets.

    5. Weather WordPress Shortcode & Widget - Simple Weather Plugin

    This weather widget can be placed in both widget spaces and via shortcode. Combining this feature with the Weather WordPress Shortcode & Widget - Simple Weather Plugin's sleek design makes it one of the more versatile weather WordPress plugins.

    Some of the great features you'll find include:

    • unlimited color selection and custom date format
    • supports both Fahrenheit and Celsius
    • customize weather update intervals
    • display day and night temperatures
    • location and GPS coordinates
    • seven-day forecast option
    • and more

    It's easy to see why the Weather WordPress Shortcode & Widget - Simple Weather Plugin is a favorite among weather WordPress plugins.

    6. Weather Widget One

    The Weather Widget One weather WordPress plugin is so pretty. Its simple design is a joy to view, and its clever UI makes it very useable. This is clearly one of the best weather WordPress plugins available.

    Features include, but certainly not limited to:

    • displays temp, wind, humidity, and chance of precipitation
    • auto detect user location via HTML5 Geolocation
    • five-day forecast with 24-hour daily forecast
    • multiple location search options
    • supports multiple units
    • shortcode support
    • and more

    With its minimal design and full set of features, the Weather Widget One is an easy favorite among weather WordPress widgets.

    7. Bonobo - Weather Widget

    This weather WordPress widget is super simple and easy to use. The Bonobo - Weather Widget also boasts a sleek metro style that's minimal and sleek.

    Features include:

    • supports both Fahrenheit and Celsius
    • OpenWeatherMap API
    • multi-language
    • and more 

    The included eight color schemes and metro design makes it easy to adapt to your current—or future—WordPress theme.

    For a simple, no nonsense weather widget, check out Bonobo - Weather Widget.

    BONUS! Weather on Google Maps for WordPress

    The Weather on Google Maps for WordPress is not your typical weather WordPress widget, so I consider this to be more of a bonus entry among the other plugins.

    Like a TV weather screen, transform Google Maps to an interactive weather map—on your own website.

    “Weather on Google Maps is a WordPress plugin, which allows you to easily embed any number of Google Maps with live weather information for any number of cities using simple HTML snippets. You can customize the look and feel of the weather information box via CSS and even choose what data to display.”

    Some of the features you'll find here:

    • auto-center of Google Map based cities
    • works with Google Maps API v3
    • weather forecast for four days
    • included weather icons
    • and more

    Weather on Google Maps for WordPress is a unique and powerful plugin, combining the power of Google Maps with Yahoo Weather.

    Conclusion

    Providing weather information for an organization's website can be a super useful feature. It's easy to overlook, but when someone is looking up more information or getting ready to make a booking online, being able to check the forecast can be very helpful.

    If you don't see exactly what you're looking for, make sure to check out Envato Tuts+. They have excellent WordPress tutorials, eBooks, and courses. Try WordPress Plugin Development Essentials or maybe the WordPress Hacker's Guide to the Galaxy. Some other helpful eBooks also include Useful Tricks and Techniques for WordPress and Mastering WordPress.

    What kind of website will you be using a weather WordPress widget for?

    1 day 22 min ago

Take Our New Course: Get Started With Elixir

  • What You'll Be Creating

    Do you want to learn the Elixir language? If so, our new course, Get Started With Elixir, is ideal for you.

    In this course, experienced instructor Markus Mühlberger will help you learn the Elixir language, starting with Elixir's Ruby-inspired syntax, and moving on to learn how to code distributed and highly concurrent services in the Elixir language.

    You can take our new course straight away with a free 10-day trial of our monthly subscription. If you decide to continue, it costs just $15 a month, and you’ll get access to hundreds of courses, with new ones added every week.

     

    You can also discover thousands of time-saving code scripts and plugins over on Envato Market, so head over there to see what you can find.

    1 day 17 hours ago

Code a Real-Time NativeScript App: Geolocation and Google Maps

  • NativeScript is a framework for building cross-platform native mobile apps using XML, CSS, and JavaScript. In this series, we'll try out some of the cool things you can do with a NativeScript app: geolocation and Google Maps integration, SQLite database, Firebase integration, and push notifications. Along the way, we'll build a fitness app with real-time capabilities that will use each of these features.

    In this tutorial, you'll learn how to work with geolocation and Google Maps in NativeScript apps. 

    I'm assuming that you already know how to create apps in NativeScript. If you're new to NativeScript, I recommend that you first check out one of the earlier tutorials in NativeScript before trying to follow this tutorial.

    What You'll Be Creating

    You'll be creating a walking tracker using geolocation and Google Maps. It will show the user how much distance they've covered and the number of steps they've taken to cover that distance. There will also be a map that will show the user's current location.

    To give you an idea, here's what the final output will look like:

    Setting Up the Project

    Start by creating a new NativeScript app:

    tns create fitApp --appid "com.yourname.fitApp"

    To make it easier to set up the UI of the app, I've created a GitHub repo which includes both the starter and final version of the project. You can go ahead and copy the contents of the app folder to your project's app folder. We will only be working with two files: main-page.xml and main-page.js file. The rest is just boilerplate from the NativeScript demo project. 

    Running the App

    We will be using the Android emulator provided by Android Studio to test the app. This will allow us to use the Android GPS Emulator to simulate the changing of locations from the comfort of our own homes. I don't really like aimlessly walking around outside to test geolocation either! But if that's your thing then I won't stop you.

    If you execute tns run android, it will automatically call the Android emulator if it's already installed. If it's not yet installed, you can install it by launching Android Studio, clicking configure, and selecting SDK Manager. This will open the SDK Platforms by default. Click on the SDK Tools tab and make sure to select Android Emulator, and click on Apply to install it.

    To use the GPS emulator, download it from GitHub and run the executable war file:

    java -jar android-gps-emulator-0.2.war

    Once that's done, you should be able to access http://localhost:8080/gpsemulator/ from your browser and connect to localhost. Make sure that the Android emulator is already running when you do this. Once you're connected, simply zoom in the map and click on any place you want to use as the location. The app will detect this and use it as its current location.

    Working With Geolocation

    Geolocation in NativeScript is similar to the Geolocation API in JavaScript. The only difference in functionality is the addition of a distance() function which is used for calculating the distance between two locations.

    Installing the Geolocation Plugin

    In order to work with geolocation, you first need to install the geolocation plugin:

    tns plugin add nativescript-geolocation

    Once that's done, you can now include it from your script files:

    var geolocation = require("nativescript-geolocation");Getting the User's Current Location

    The NativeScript geolocation plugin includes three functions which you can use for working with the user's current location. We will be using each of these in this app:

    • getCurrentLocation
    • watchLocation
    • distance

    Open the main-view-model.js file and add the following code inside the createViewModel() function. Here we're initializing the variables that we will be using later on for storing the different values that are needed for keeping track of the user's location. 

    I've added some comments in the code so you know what's going on. There are also some lines of code that are commented out; these are for the Google Maps integration. I've commented them out for now to keep things simple. Once we get to the Google Maps integration, you'll need to remove those comments.

    function createViewModel() { var viewModel = new Observable(); var watchId; // stores the ID of the location watcher so we can stop it later var start_location; // stores the location of the user when they first started tracking var current_location; // stores the current location of the user viewModel.is_tracking = false; // whether the user's location is currently being tracked or not //viewModel.latitude = 15.447819409392789; //viewModel.longitude = 120.93888133764267; //viewModel.zoom = 20; var total_distance = 0; var total_steps = 0; var locations = []; // array which will store the locations //var mapView; //var marker = new mapsModule.Marker(); if (!geolocation.isEnabled()) { // check if geolocation is not enabled geolocation.enableLocationRequest(); // request for the user to enable it } // next: add code for getting the user's current location }

    Next, add the code for getting the user's current location. This code is executed when the user taps on the button for starting and stopping the location tracking. The geolocation.getCurrentLocation() method is used to get the current location. 

    Here we've specified three options: desiredAccuracy, updateDistance, and timeout. desiredAccuracy allows you to specify the accuracy in meters. It has two possible values: Accuracy.high, which is about 3 meters, and Accuracy.any, which is about 300 meters. updateDistance specifies how much difference (in meters) there must be between the previous location and the current location before it will update. Lastly, timeout specifies how many milliseconds to wait for a location. 

    Once a location is received, we set it as the start_location and push it on the locations array. Later on, this location will be used along with the first location that will be fetched from watching the user's current location to determine the distance traveled.

    viewModel.toggleTracking = function() { if (geolocation.isEnabled()) { this.set('is_tracking', !viewModel.is_tracking); // flip the toggle for tracking if (viewModel.is_tracking) { geolocation.getCurrentLocation( { desiredAccuracy: Accuracy.high, // 3 meter accuracy updateDistance: 5, // 5 meters timeout: 2000 // 2 seconds } ). then(function(loc) { if (loc) { start_location = loc; locations.push(start_location); //viewModel.set('latitude', loc.latitude); //viewModel.set('longitude', loc.longitude); } }, function(e){ dialogs.alert(e.message); }); // next: add code for watching user's current location } else { // next: add code to stop watching the user's current location } } else { dialogs.alert("Please enable Geolocation"); } }Watching for the User's Current Location

    To get the current location, we use the geolocation.watchLocation() function. This function is similar to the setInterval() function in JavaScript, because it also executes the callback function repeatedly until you stop it with the geolocation.clearWatch() function. The callback function is automatically called based on the updateDistance and minimumUpdateTime. 

    In the code below, the location will be updated if it is at least 5 meters different from the previous location that was fetched. But this update will only happen every 5 seconds. This means that if the user hasn't walked 5 meters or more within 5 seconds, the location won't update. 

    watchId = geolocation.watchLocation( function (loc) { if (loc) { current_location = loc; // next: add code for getting the distance between two locations } }, function(e){ dialogs.alert(e.message); }, { desiredAccuracy: Accuracy.high, updateDistance: 5, // 5 meters minimumUpdateTime : 5000 // update every 5 seconds } );

    Once the user indicates that they want to stop tracking, you need to call the geolocation.clearWatch() function. You also need to reset the rest of the values that are being updated every time the location is changed. 

    geolocation.clearWatch(watchId); // stop watching the user's location total_distance = 0; total_steps = 0; locations = []; viewModel.set('distance', "distance travelled: " + total_distance + " meters"); viewModel.set('steps', "steps: " + total_steps);Getting the Distance Between Two Locations

    Now we're ready to get the distance. This can be done by calling the geolocation.distance() function. This function accepts two location objects as its arguments, so we'll use the last two locations that were pushed to the locations array to determine the distance (in meters) traveled by the user from a previously recorded location to the current one. From there, we can use an approximate conversion from meters to the number of steps—I say approximate because not all people will travel the same distance in a single step. 

    After that, we can just add the resulting distance and steps to the total_distance and total_steps so we can keep track of the total distance and steps they have taken since they started tracking their location.

    locations.push(loc); //viewModel.set('latitude', loc.latitude); //viewModel.set('longitude', loc.longitude); //marker.position = mapsModule.Position.positionFromLatLng(viewModel.latitude, viewModel.longitude); location_count = locations.length; if (location_count >= 2) { var distance = Math.round(geolocation.distance(locations[location_count - 2], locations[location_count - 1])); // get the distance between the last two locations var steps = Math.round(distance * 1.3123); // determine the approximate number of steps // add the current distance to the overall distance travelled total_distance = total_distance + distance; total_steps = total_steps + steps; // update the UI viewModel.set('distance', "distance travelled: " + total_distance + " meters"); viewModel.set('steps', "steps: " + total_steps); }

    At this point, you can now start testing the app using the GPS emulator that I mentioned earlier. Do note that you need to hit save on the main-view-model.js file to trigger an app reload. 

    Then pick a location in the GPS emulator so that a fresh location will be fetched by the app once it loads. If you don't do this, it will default to the Googleplex location in Mountain View, California. This means that the next time you pick a location on the emulator, it will jump from this location to the location that you picked. If it's far away then you'll get a really large number for the distance and steps. 

    Alternately, you could test on a real device with internet and GPS enabled. Only GPS is required at this point, but once we add Google Maps, the app will need an internet connection.

    Working With Google Maps

    We will now use Google Maps to add a map that shows the user's current location.

    Installing the Google Maps Plugintns plugin add nativescript-google-maps-sdk

    Once installed, you need to copy the template string resource files for Android:

    cp -r node_modules/nativescript-google-maps-sdk/platforms/android/res/values app/App_Resources/Android/

    Next, open the app/App_Resources/Android/values/nativescript_google_maps_api.xml file and add your own Google Maps API key (server key):

    <?xml version="1.0" encoding="utf-8"?> <resources> <string name="nativescript_google_maps_api_key">YOUR GOOGLE MAPS API KEY HERE</string> </resources>

    Make sure that you have enabled the Google Maps Android API from the Google Console before you try to use it.

    Adding the Map

    For the map, open the main-page.xml file and you should see the following:

    <maps:mapView latitude="{{ latitude }}" longitude="{{ longitude }}" zoom="{{ zoom }}" mapReady="{{ onMapReady }}" />

    Here we've specified three options (longitude, latitude, and zoom) and a function to execute once the map is ready. longitude and latitude specify the location you want to render in the map. The zoom specifies the zoom level of the map. mapReady is where we specify the function for adding the marker on the map. This marker represents the user's current location, so it will be rendered at the center of the map.

    By default, this won't work as you haven't added the schema definition for the maps yet. So in your Page element, add the definition for the maps element:

    <Page xmlns="http://schemas.nativescript.org/tns.xsd" xmlns:maps="nativescript-google-maps-sdk" > </Page>

    Once that's done, a Google map instance should be rendered right below the button for tracking location. It won't have any maps yet since the latitude and longitude haven't been specified yet. To do that, go back to the main-view-model.js file and remove the comments for the lines of code for working with Google Maps:

    // default coordinates viewModel.latitude = 15.447819409392789; viewModel.longitude = 120.93888133764267; viewModel.zoom = 20; // default map zoom level var mapView; // variable for storing the current map instance var marker = new mapsModule.Marker(); // variable for storing the marker instanceAdding the Marker

    Since we've already declared default coordinates for the marker, we can actually plot a marker once the map is ready:

    viewModel.onMapReady = function(args) { mapView = args.object; // get the map view marker.position = mapsModule.Position.positionFromLatLng(viewModel.latitude, viewModel.longitude); // set the marker's position on the map mapView.addMarker(marker); // add the marker to the map }

    Next, we need to update the marker position once the user starts tracking their location. You can do that inside the success callback function for the getCurrentLocation() function:

    locations.push(start_location); // remove the comments for these: //viewModel.set('latitude', loc.latitude); //viewModel.set('longitude', loc.longitude); //marker.position = mapsModule.Position.positionFromLatLng(viewModel.latitude, viewModel.longitude);

    We also need update it when the user's location is updated (inside the success callback function for watchLocation):

    current_location = loc; locations.push(loc); // remove the comments for these: //viewModel.set('latitude', loc.latitude); //viewModel.set('longitude', loc.longitude); //marker.position = mapsModule.Position.positionFromLatLng(viewModel.latitude, viewModel.longitude);

    Once that's done, a map which renders the default location should show in the app.

    Conclusion

    In this tutorial, you've created a NativeScript app that allows the user to track how much distance they have covered and the approximate number of steps they've taken to cover that distance. You've also used Google Maps to let the user view their current location. By doing so, you've learned how to use the geolocation and Google Maps plugins for NativeScript.

    This is just the start! In the next posts of this series, we'll add a local database, push notifications and other cool features to our app.

    In the meantime, check out some of our other posts on NativeScript and cross-platform mobile coding.

    For a comprehensive introduction to NativeScript, try our video course Code a Mobile App With NativeScript. In this course, Keyvan Kasaei will show you step by step how to build a simple application. Along the way, you'll learn how to implement a simple app workflow with network requests, an MVVM architecture, and some of the most important NativeScript UI components. By the end, you'll understand why you should consider NativeScript for your next mobile app project.

     

    1 day 20 hours ago

Team Conflict: Four Ways to Deflate the Discord that&#8217;s Killing Your Team

  • It was supposed to be a simple web project. Our client needed a site that would allow users to create, deploy and review survey results. Aside from some APIs that weren’t done, I wasn’t very worried about the project. I was surprised that my product manager was spending so much time at the client’s office.

    Then, she explained the problem. It seemed that the leaders of product, UX and engineering didn’t speak to each other and, as a result, she had to walk from office to office getting information and decisions.

    When two people have a bad interaction, they can work it out or let the conflict grow, spreading it to other team members and their leaders.

    The conflicts probably started small. One bad interaction, then another, then people don’t like each other, then teams don’t work together well. The small scrape becomes a festering wound that slows things down, limits creativity and lowers morale.

    Somehow as a kid working my way through school I discovered I had a knack for getting around individuals or groups that were fighting with each other. I simply figured out who I needed to help me accomplish a task, and I learned how to convince, cajole or charm them into doing it. I went on to teach these skills to my teams.

    That sufficed for a while. But as I became a department head and an adviser to my clients, I realized it’s not enough to make it work. I needed to learn how to make it better. I needed to find a way to stop the infighting I’ve seen plague organizations my entire career. I needed to put aside my tendency to make the quick fix and have hard conversations.

    It’s messy, awkward and hard for team leaders to resolve conflict but the results are absolutely worth it. You don’t need a big training program, a touchy-feely retreat or an expensive consultant. Team members or team leads don’t have to like each other. What they have to do is find common ground, a measure of respect for one another, and a willingness to work together to benefit the project.

    Here are four ways to approach the problem.

    Start talking

    No matter how it looks at first, it’s always a people problem. Gerald M. Weinberg, The Secrets of Consulting: A Guide to Giving and Getting Advice Successfully

    Resist the urge to wait for the perfect time to address team conflict. There’s no such thing. There will always be another deadline, another rollout, another challenge to be met.

    In our office, a UX designer and product manager were having trouble getting along. Rather than take responsibility, they each blamed our “process” and said we needed to clarify roles and procedures. In other words, they each wanted to be deemed “in charge” of the project. Certainly I could have taken that bullet and begun a full-on assessment of our processes and structure. By taking the blame for a bad company framework, I could have dodged some difficult conversations.  But I knew our process wasn’t the problem.

    First, I coached the product manager to be vulnerable, not an easy thing for him to do. I asked him to share his concerns and his desire to have a more productive relationship with the UX designer. The PM’s willingness to be uncomfortable and open about his concerns lifted the tension. Once he acknowledged the elephant in the room—namely that the UX designer was not happy working with him—the designer became more willing to risk being honest. Eventually, they were able to find a solution to their disagreements on the project, largely because they were willing to give each other a measure of respect.

    The worst thing I’ve seen is when leaders move people from team to team hoping that they will magically find a group of people that work well together, and work well with them. Sometimes the relocated team members have no idea that their behavior or performance isn’t acceptable. Instead of solving the problem, this just spreads the dissatisfaction.

    Instead, be clear right from the beginning that you want teams that will be open about challenges, feel safe discussing conflicts, and be accountable for solving them.

    Have a clear purpose

    Although many aspects of our collective endeavor are open for discussion, choice of mountain is not among them. J. Richard Hackman, Leading Teams: Setting the Stage for Great Performances

    I was working on an enterprise CMS re-design and re-platform. Our weekly review and estimation sessions were some of the most painful meetings of my career. There was no trust or shared purpose—even estimating a simple task was a big fight.

    When purpose and priorities are murky you are likely to find conflict. When the team doesn’t know what mountain they are trying to climb, they tend to focus on the parts of the project that are most relevant to them. With each team member jealously guarding his or her little ledge, it’s almost impossible to have cooperation.

    This assault on productivity is likely because the project objective is non-existent, or muddled nonsense, or so broad the team doesn’t see how it can have an impact. Or, maybe the objective is a moving target, constantly shifting.

    Size can be a factor.  I’ve seen enterprise teams with clear missions and startups with such world-changing objectives they can’t figure out how to ship something that costs less than a million dollars.

    When I’m meeting with prospects or new clients I look at three areas to see if they are having this problem:

    • What language do they use to describe each other? Disconnected teams say “UX thinks,” “The dev team” or “product wants.” Unified teams say “we.”
    • How easy or hard is task estimation? Disconnected teams fight about the level of difficulty. United teams talk about tradeoffs and argue about what’s best for the product or customers.
    • Can they easily and consistently describe their purpose? Disconnected teams don’t have a crisp and consistent answer. Unified teams nod their heads when one of their members shares a concise answer.

    If a team is disconnected, it’s likely because you haven’t given them a common goal. A single email or a fancy deck isn’t enough. Make your objectives simple and repeat them so much that the team groans every time you start.

    Plan conversations

    Words do not sit in our brains in isolation. Each word is surrounded by its own connotations, memories and associations Simon Lancaster, Winning Minds: Secrets From the Language of Leadership

    Years ago I was frustrated to tears by a manager who, I felt, took from me the product I spent two years building. I knew I needed to talk with him but I struggled to find a productive way to tell him why I was upset.  (Telling someone he is being a jackass is not productive.)

    A good friend in HR helped me script the conversation. It had three parts:

    • I really work well when…
    • This situation is bothering me because…
    • What I’d like to see happen is…

    Leaders have an important role to play in resolving issues. When a leader decides that their person is right and another person is wrong it turns a team problem into an organization problem. Instead we should should provide perspective, context and show how actions could be misunderstood.

    Leaders also need to quickly, clearly and strongly call about bad behavior. When I found out one of my people raised their voice at a colleague, I made it clear that wasn’t acceptable and shouldn’t happen again. He admitted that he lost his cool, apologized and then we started working on the resolving the situation.

    Require accountability Being responsible sometimes means pissing people off. General Colin Powell,former U.S. Secretary of State

    If you have a problem and you go to Holly Paul, an inspiring HR leader, you can expect that she will listen. You can also expect that she’ll work with you on a plan to resolve it. Most importantly you can expect she will make sure you are doing what you said you’d do when you said you would do it.

    Before I met Holly I would listen to problems then try to go solve them. Now I work with the person and tell them that I will be checking back with them, often putting the reminder in my calendar during the conversation so I don’t forget.

    Since I started focusing on fixing conflict, I’ve seen great changes on my team. Many of them have started for the first time dealing with the people, fixing their issues and forging much stronger relationships. Our team is stronger and having a greater influence on the organization.

    It’s messy, awkward and hard. I’ve been working on this for a long time and I still make mistakes. I still don’t always want to push when I meet resistance. This will never be easy, but it will be worth it and it’s your responsibility as a leader. For however long these people are with you, you need to make them better as individuals and a unit.

    You don’t need a big training, a touchy-feely retreat or an expensive consultant. You just need to start doing the work every day. The rest will come.

    1 day 22 hours ago

Create a Mobile Application for Displaying Your Website RSS Content With Ionic

  • What You'll Be Creating

    In this tutorial we will take a look at creating a mobile application which displays the RSS content of a website. We will configure the RSS URL and the application will download it, parse it and display the posts from the RSS. 

    To create the mobile application, we will use the Ionic Framework v1 together with AngularJS. To complete this tutorial, you need to have some experience with JavaScript and HTML. Also, it helps if you've worked with AngularJS before. 

    If you have never worked with Ionic Framework before, I recommend at least taking a look at the Getting Started guide as it gives you a quick insight into how things work.

    Let's begin!

    Setting Up the Ionic Project

    I will assume that you have installed Node on your system and you also have the npm (the Node package manager). Installing the Ionic framework is as easy as running the following:

    npm install -g cordova ionic

    This will install both Cordova and Ionic on your computer. 

    Cordova is the core technology for Ionic, and basically it allows us to have an embedded browser in our mobile application. In that browser we will be able to run all our HTML and JavaScript code. This is called a hybrid mobile application, as the application does not run native code, but runs inside the browser. 

    Next to Cordova, Ionic adds to that the possibility of using AngularJS for writing our code, and it also adds a very neat UI framework.

    With Ionic in place, we can create our project using the Ionic CLI, a very useful command-line tool. Ionic provides three default project templates which can be used as a starting point:

    • blank: as the name says, it's an empty project with only the minimal necessary components in place.
    • tabs: an application using tabs for navigating through its screens.
    • sidemenu: an application using a standard mobile side menu for navigation.

    For this tutorial, we will be using the tabs application template. To start our project, let's run:

    ionic start myWebsiteOnMobile tabs

    Ionic will download and install all components needed, and it will create the project folder named myWebsiteOnMobile. Go into the project directory by running:

    cd myWebsiteOnMobile

    Because our application is a hybrid mobile application, we have the advantage of being able to run the application inside a browser. To do this, Ionic provides a neat built-in web server which runs our application like this:

    ionic serve

    This will open a browser with our application loaded, and it will look like this:

    To stop the server, use Control-C on your command-line screen. To get a better idea of how the application looks on a mobile, you can use:

    ionic serve --lab

    This will open the application in the browser, showing an iOS and an Android preview of the app side by side.

    The tabs Ionic application template has three tabs: Status, Chats, and Account. In the next steps we will adjust the application to fit our needs.

    How to Adjust the Default Ionic Tabs Template Application

    For our application we will have two tabs:

    • Latest posts: showing a list of latest posts retrieved from the RSS feed.
    • Settings: where the user will be able to configure several aspects of the application.

    From the Latest posts tab, the user will be able to click on any of the latest posts and see more information about the post, with the possibility of opening up the post in an external browser.

    Since our Latest posts tab is similar to the Chats tab provided by the template, we will reuse that together with the Account tab, which will become our Settings tab. We can do all modifications with the Ionic webserver running, and Ionic will reload the app for us. This is a very neat feature which will speed up development.

    As mentioned before, Ionic uses AngularJS, and the whole application is actually an AngularJS module. The module is defined in www/js/app.js, and here is also where the paths or routes of the application are defined. Each screen of the application has a corresponding route.

    Let's remove the Status tab since we will not need it. To do this, we first need to change the default screen (or route) of our application to point to the Chats screen, which will become our main screen. The default screen is configured via $urlRouterProvider.otherwise(), so let's change that to:

    $urlRouterProvider.otherwise('/tab/chats');

    If we now reload http://localhost:8100 in our browser, we will see that the Chats tab will be loaded by default.

    To remove the Status tab, we need to edit the www/templates/tabs.html file that holds the template for the tab component. We will remove the element:

    <!-- Dashboard Tab --> <ion-tab title="Status" icon-off="ion-ios-pulse" icon-on="ion-ios-pulse-strong" href="#/tab/dash"> <ion-nav-view name="tab-dash"></ion-nav-view> </ion-tab>

    When saving, we will see that the application now has only two tabs: Chats and Account.

    While in the www/templates/tabs.html file we notice that there are some HTML tags that are not standard HTML, like ion-tabs, ion-tab, and ion-nav-view. These are actually AngularJS directives defined by the Ionic Framework. The directives are tags that pack functionality behind them, and they are very convenient ways to write more structured and more concise code.

    In our case, the ion-tabs directive is the tabs component, which for each tab requires an ion-tab directive.

    Let's change our tabs from Chat and Account to our required names Latest posts and Settings. To do this, we will modify several things in the www/templates/tabs.html file:

    • title attribute of the ion-tab elements which determines the text on the tab button. We will change that to Latest posts and Settings respectively.
    • href attribute of the ion-tab elements which points to the route or screen URL. We will change those to #/tab/latest-posts and #/tab/settings.
    • name attribute of the ion-nav-view elements to tab-latest-posts and tab-settings. These are the identifiers for the view templates used for the Latest posts and Settings screens.

    As a result, www/templates/tabs.html should look like this:

    <ion-tabs class="tabs-icon-top tabs-color-active-positive"> <!-- Latest posts Tab --> <ion-tab title="Latest posts" icon-off="ion-ios-chatboxes-outline" icon-on="ion-ios-chatboxes" href="#/tab/latest-posts"> <ion-nav-view name="tab-latest-posts"></ion-nav-view> </ion-tab> <!-- Settings Tab --> <ion-tab title="Settings" icon-off="ion-ios-gear-outline" icon-on="ion-ios-gear" href="#/tab/settings"> <ion-nav-view name="tab-settings"></ion-nav-view> </ion-tab> </ion-tabs>

    After making these changes, we will get some errors. This is because we also have to adjust our routes to use the new identifiers we have used. In www/js/app.js, we need to change the state identifiers, the view identifiers and the url for each route according to what we have set above.

    For each route (or screen), there is a controller defined. This is a basic MVC (Model-View-Controller) design pattern. Controllers are defined within the file www/js/controllers.js. For consistency purposes, we will change the names of the controllers in both www/js/app.js and www/js/controller.js:

    • ChatsCtrl becomes LatestPostsCtrl.
    • ChatDetailCtrl becomes PostDetailCtrl.
    • AccountCtrl becomes SettingsCtrl.

    Also, for each route we have a view template defined, so let's change them too. Edit www/js/app.js and modify templateUrl like this:

    • Change tab-chats.html to tab-latest-posts.html. Also rename the file www/templates/tab-chats.html to www/templates/tab-latest-posts.html.
    • Change chat-detail.html to post-detail.html. Also rename the file www/templates/chat-detail.html to www/templates/post-detail.html.
    • Change tab-account.html to tab-settings.html. Also rename the file www/templates/tab-account.html to www/templates/tab-settings.html.
    • Finally, change the view that gets loaded by default to latest-posts by using $urlRouterProvider.otherwise('/tab/latest-posts').

    If all went well then you should end up with the www/js/app.js file looking like this:

    ... // Each tab has its own nav history stack: .state('tab.latest-posts', { url: '/latest-posts', views: { 'tab-latest-posts': { templateUrl: 'templates/tab-latest-posts.html', controller: 'LatestPostsCtrl' } } }) .state('tab.post-detail', { url: '/latest-posts/:postId', views: { 'tab-latest-posts': { templateUrl: 'templates/post-detail.html', controller: 'PostDetailCtrl' } } }) .state('tab.settings', { url: '/settings', views: { 'tab-settings': { templateUrl: 'templates/tab-settings.html', controller: 'SettingsCtrl' } } }); // if none of the above states are matched, use this as the fallback $urlRouterProvider.otherwise('/tab/latest-posts'); ...

    And our cleaned up www/js/controllers.js file looks like this:

    angular.module('starter.controllers', []) .controller('LatestPostsCtrl', function($scope) {}) .controller('PostDetailCtrl', function($scope, $stateParams) {}) .controller('SettingsCtrl', function($scope) {});

    Now that we have restructured the app to fit our needs, let's move on to the next part and add some functionality.

    How to Retrieve an RSS Feed With Ionic

    In order to display the list of latest posts, our application will need to retrieve the RSS feed from a URL. As a best practice, it is advisable that this kind of functionality reside in the service layer of the application. In this way we can use it more easily in our controller and then present it to the user by using a view.

    The RSS service will make use of Yahoo's YQL REST API to retrieve the RSS of our website. To call on the REST API, we will use the $http provider offered by AngularJS.

    Ionic services are usually defined in the www/js/services.js file, so that's where we will put ours too. The code will look like this:

    angular.module('starter.services', []) .service('RSS',function($http){ var self = this; this.download = function(next){ var feedUrl = "https://tutorials.tutsplus.com/posts.atom"; var yql_query = "select * from xml where url = '"+feedUrl+"'"; var url = 'https://query.yahooapis.com/v1/public/yql?q='+encodeURIComponent(yql_query)+'&format=json&callback=JSON_CALLBACK'; $http .jsonp(url) .success(function(response){ if (response.query.results["feed"]){ next(self.parseAtom(response.query.results)); } else if (response.query.results["rss"]){ next(self.parseRSS(response.query.results)); } else { throw "Unknown RSS format"; } }) .error(function(data, status){ }); } this.parseAtom = function(atomFeed){ var posts = []; angular.forEach(atomFeed.feed.entry,function(item,idx){ var post = { id:idx, title:item.title, description:item.content.content, link:item.link.href } posts.push(post); }) return posts; } this.parseRSS = function(rssFeed){ var posts = []; angular.forEach(rssFeed.rss.channel.item,function(item,idx){ var post = { id:idx, title:item.title, description:item.description, link:item.link } posts.push(post); }) return posts; } })

    We declare the service using the service() method provided by AngularJS. We then inject Angular's $http module so we can call it in our service.

    The self variable is a reference to the RSS service so that we can call it from within the service's methods. The main method of the service is the download() method, which downloads the feed information and processes it. There are two main formats used for website feeds: RSS and ATOM. For our application, we have used the feed of tutorials from Tuts+ https://tutorials.tutsplus.com/posts.atom which is in ATOM format, but for completeness we have taken into account the RSS format too.

    The download() method calls on the YQL API and parses the results using the parseAtom() or the parseRSS() methods depending on the type of feed. The idea here is to have the same output format which will be passed further via the callback next(). With the RSS service in place, we can move on to the controller.

    Hooking the RSS Service to the Latest Posts Controller

    In our www/js/controllers.js file, we need to load the RSS data and pass it to our view. To do that, we only need to modify our LatestPostsCtrl controller like this:

    .controller('LatestPostsCtrl', function($scope, RSS) { RSS.download(function(posts){ $scope.posts = posts; }); })

    Using Angular's dependency injection mechanism, we only need to specify the $scope and RSS variables as method parameters, and it will know how to load those modules. The $scope module allows us to set variables on the model bound to the view. Any values set in the scope can be then retrieved and displayed inside the view associated with the controller.

    When the view for latest posts is loaded, it will call on the LatestPostsCtrl controller, and this in turn will use the RSS service to download the feed information. The results are parsed and passed back as an array using the posts variable, which we store in the current scope.

    With all that out of the way, we can now move on to the view part, displaying the list of posts retrieved from the feed.

    Hooking the Latest Posts View to the Feed Data

    We now need to modify our view for the latest posts. If you remember, this is configured in the www/js/app.js file via the templateUrl attribute, and it points to the www/templates/tab-latest-posts.html file.

    What we will want to do is display the list of feeds. Since the feed information may contain HTML, and this will only clutter the list of latest posts, we need something to extract the text without the HTML tags from a post's content. The easiest way to do that is by defining an AngularJS filter that strips the HTML tags from text. Let's do that in www/js/services.js by adding:

    .filter('htmlToPlaintext', function() { return function(text) { return text ? String(text).replace(/<[^>]+>/gm, '') : ''; }; } )

    No back to our view inside the www/templates/tab-latest-posts.html file, let's modify it to look like this:

    <ion-view view-title="Latest posts"> <ion-content> <ion-list> <ion-item class="item-icon-left item-icon-right" ng-repeat="post in posts" type="item-text-wrap" href="#/tab/latest-posts/{{post.id}}"> <span class="icon ion-social-rss-outline"></span> <h2>{{post.title}}</h2> <p>{{post.description | htmlToPlaintext}}</p> <i class="icon ion-chevron-right icon-accessory"></i> </ion-item> </ion-list> </ion-content> </ion-view>

    We are using the Ionic list UI component together with Angular's ng-repeat directive, which will iterate through the posts set on the scope of our controller. For each post entry, we will have a list item with its title and with the description stripped of HTML tags by the use of the htmlToPlaintext filter. Also note that clicking a post should take us to the detail of the post because of the href attribute set to #/tab/latest-posts/{{post.id}}. That does not work yet, but we will take care of that in the next section.

    If we now run the application using ionic serve --lab, we should get something like this:

    Showing the Details of a Post

    When clicking on a post in the list, we go to the post details screen of the application. Because each screen of the application has its own controller and therefore its own scope, we can't access the list of posts to display a specific post. We can call the RSS service again, but that would be inefficient.

    To solve this problem, we can make use of the $rootScope directive offered by Angular. This references a scope that overarches all controllers in the application. Let's modify our LatestPostCtrl to set the posts in the $rootScope and then search for the specific post that the user clicked in the PostDetailCtrl. The resulting code in www/js/controllers.js will look like this:

    .controller('LatestPostsCtrl', function($scope, $rootScope, RSS) { RSS.download(function(posts){ $rootScope.posts = posts; }); }) .controller('PostDetailCtrl', function($scope,$rootScope, $stateParams) { angular.forEach($rootScope.posts,function(post){ if (post.id == $stateParams.postId){ $scope.post = post; } }) })

    We simply injected $rootScope in both controllers and used it for passing posts between the two controllers. Please note that we don't need to make any changes in our latest posts view as $rootScope and $scope are both accessible in the same way from the view.

    Inside the PostDetailCtrl controller, we simply search for the post with the id passed in the link clicked by the user. We do that by comparing each post ID with the value in the URL passed via the $stateParams.postId variable. If we find a match then we set the post on the scope so we can use it in our view.

    Let's now adjust our post detail view www/templates/post-detail.html like this:

    <ion-view view-title="{{post.title}}"> <ion-nav-buttons side="right"> <a ng-href="{{post.link}}" class="button" target="_system"> Open </a> </ion-nav-buttons> <ion-content class="padding"> <h1>{{post.title}}</h1> <span ng-bind-html="post.description"></span> </ion-content> </ion-view>

    This is what we have done in the view:

    • We have placed the title of the post in the header of the screen.
    • We have placed an "Open" button in the header on the right. This button will open the post link in an external browser because of the attribute target="_system". We have to do this because the application is already running in a browser due to Cordova. If we didn't set that attribute, the post would have opened in the same browser as the application, and then we would not have a way to return to the application.
    • We display the description of the post as HTML by using Angular's ng-bind-html directive.

    While running the application, I noticed that if the post description contains images, some of them fall off the screen. This might be the case with other HTML elements like videos. We can easily fix this by adding the following CSS rule in www/css/style.css.

    ion-content *{ max-width: 100%; }

    If we now take a look at the application and click on one of the posts, we should see something like this:

    And our application is almost complete. In the next section, we will take a look at implementing the settings screen.

    Adding Settings for Our Ionic Application

    For our settings screen, we will implement a way to indicate how many posts to display on the main screen of the application. We will store this setting in the localStorage memory, which is not erased when the application is closed. Let's edit the controllers file www/js/controllers.js and change the SettingsCtrl controller like this:

    .controller('SettingsCtrl', function($scope,$rootScope) { $scope.settings = { maxPosts: window.localStorage.getItem("myWebsiteOnMobile.maxPosts") }; $scope.$watch('settings.maxPosts',function(){ window.localStorage.setItem("myWebsiteOnMobile.maxPosts",$scope.settings.maxPosts); $rootScope.maxPosts = window.localStorage.getItem("myWebsiteOnMobile.maxPosts"); }); });

    Also, we need to modify the settings screen in www/templates/tab-settings.html like this:

    <ion-view view-title="Settings"> <ion-content> <div class="item item-divider item-balanced">Maximum posts</div> <ion-radio ng-model="settings.maxPosts" ng-value="null">Unlimited</ion-radio> <ion-radio ng-model="settings.maxPosts" ng-value="5">5</ion-radio> <ion-radio ng-model="settings.maxPosts" ng-value="10">10</ion-radio> </ion-content> </ion-view>

    The controller retrieves the setting myWebsiteOnMobile.maxPosts from the localStorage. If it does not exist, it will be null, and we will consider that there is no limit for the maximum number of posts.

    We call the $scope.$watch() method to monitor changes of the settings.maxPosts variable, which is bound to the radio control in the settings screen.

    With all this in place, every time we change the maximum number of posts on the settings screen, the setting will be stored in the localStorage, and it will be retrieved from there when the application restarts.

    Now let's make use of this setting. This is as simple as adding this in the LatestPostsCtrl from www/js/controllers.js:

    $rootScope.maxPosts = window.localStorage.getItem("myWebsiteOnMobile.maxPosts");

    And adding a directive in the latest posts screen www/templates/tab-latest-posts.html:

    <ion-item class="item-icon-left item-icon-right" ng-repeat="post in posts|limitTo:maxPosts" type="item-text-wrap" href="#/tab/latest-posts/{{post.id}}">

    Notice the limitTo:maxPosts Angular filter. This will limit the number of posts displayed to the number taken from the localStorage. By default, this will be null, which will display all the feeds retrieved by the RSS service.

    Congratulations! We now have a fully working application displaying an RSS feed.

    Conclusion

    In this tutorial, we have seen how to create a hybrid mobile application using the Ionic Framework and AngularJS. There is only one more thing to do: run the application on a mobile device or mobile emulator. This is very simple with Ionic. To run the application on an Android emulator, just run:

    ionic platform add android ionic run

    If you want to download a premade Ionic application template for transforming any website to a mobile application, try the Website to Mobile Ionic Application Template from CodeCanyon.

    2 days 22 min ago

What Are Dictionary Comprehensions in Python?

  •  

    Recently, we looked at list comprehensions in Python. Similar to its sibling the list comprehension, a dictionary comprehension is nothing more than a shorthand way of creating a new dictionary collection. While it may seem a little more complicated than the list version, it is actually quite simple to understand. 

    In this video tutorial from my course on Data Handling With Python, I'll show you exactly what dictionary comprehensions are and how you can use them.

    Watch the Full Course

    Do you want to learn Python in depth? If so, the full course, Data Handling With Python, is for you. It goes beyond the basics and takes you through Python data management in detail. Beyond comprehensions, we'll also look at map, filter, lambdas, and generators, as well as reading and writing to files and complex objects. 

    And if you want something even more comprehensive, try my seven-hour course Learn to Code With Python, which includes the lessons on data management but also covers a whole lot more aspects of the Python language.

    2 days 18 hours ago

How to Deploy a WordPress Plugin From TravisCI to WordPress.org

  • Not everyone likes subversion. If you use Git to manage WordPress plugin development, keeping your Git repo and the WordPress.org SVN repo in sync is tedious. Luckily, we can use TravisCI deployment provider to automate SVN deployment after tests.

    Prerequisites

    You need these before moving on:

    1. GitHub account
    2. TravisCI account
    3. Plugin source code
    4. WordPress.org plugin SVN repo (You get this after plugin review approval.)
    First Push to GitHub

    In order to use TravisCI, we have to host the plugin repository on GitHub.

    First, create a new repository on GitHub by going to this page and filling in the repository name.

    Then, we are going to commit all plugin files into Git and push it to this GitHub repository. Remember to replace the remote URL with yours.

    $ cd /path/to/plugin/directory $ git init $ git add -A $ git commit -m "first commit" $ git remote add origin https://github.com/TangRufus/tutsplus-dpl-demo.git $ git push -u origin masterConnecting TravisCI

    Connect your GitHub repository with TravisCI by going to your TravisCI account page and switching on your repository. Click Sync account in the upper right corner if your newly created repository doesn't show up in the list.

    You're all set. Every time you push new commits or someone makes pull requests to GitHub, it will trigger a build on TravisCI.

    First Build on TravisCI

    TravisCI uses a YAML file named .travis.yml in the root of your repository to customize the builds. Learn more from the build customizing document to see how you can control the build lifecycle.

    This is a basic configuration file that instructs TravisCI to run builds on PHP 7.0 and 7.1. Since testing is out of the scope of this tutorial, I replaced the actual test commands with echo 'Tested'. 

    # .travis.yml language: php sudo: false php: - 7.0 - 7.1 script: # Run your tests here. - echo 'Tested'

    Commit this file and push it to GitHub. TravisCI builds will be triggered automatically.

    $ git add .travis.yml $ git ci -am "Add .travis.yml" $ git push origin masterAdding Deployment Provider Configuration

    Deployment providers run if the tests passed and pre-defined conditionals (the on section) are met. TravisCI provides nearly 40 official deployment providers. Sadly, none of them support WordPress.org subversion repositories. Thus, I made my own custom provider. You can find it on GitHub and its pull request.

    To use it, add these lines to the end of .travis.yml.

    before_deploy: - mkdir build - cp LICENSE build - cp README.txt build - cp remove-medium-cross-links.php build deploy: - provider: wordpress-plugin edge: source: TypistTech/dpl branch: add-wordpress-plugin-deployment on: php: 7.1 tags: true repo: TangRufus/tutsplus-dpl-demo slug: remove-medium-cross-links username: tangrufus password: $WORDPRESS_ORG_PASSWORD build_dir: build Configuration Explanationbefore_deploy

    The before_deploy section copies three files into the build directory which is to be checked into the WordPress.org subversion repository. In the real world, this is where you want to run gulp or grunt tasks to prepare the production-ready plugin. 

    Don't copy test files or any unnecessary files into build as the whole build directory is released to users, and users don't need your test files.

    provider and edge

    We tell TravisCI to install my provider from the add-wordpress-plugin-deployment branch https://github.com/TypistTech/dpl. Once the pull request has been merged, the edge part is unnecessary.

    on

    The on section controls whether a deployment should be performed. Deployment is triggered only when all requirements are met.

    In the above example, we deploy to WordPress.org only when:

    1. it's a PHP 7.1 build
    2. it's a tagged commit
    3. it's triggered by the TangRufus/tutsplus-dpl-demo repo (forks and pull requests would not trigger deployment)
    slug

    The plugin's slug. 

    If your plugin's URL is https://wordpress.org/plugins/my-awesome-plugin/, then my-awesome-plugin is the plugin's slug. 

    username

    Your WordPress.org account username with which you submitted the plugin for review approval.

    password

    The password of the WordPress.org account. Never save this password in the .travis.yml in plain text!

    In the above example, we use the $WORDPRESS_ORG_PASSWORD environment variable, which can be set on the TravisCI web dashboard. Choose Settings from the cog menu, and click on Add in the Environment Variables section. Never enable the "Display value in build log" option!

    build_dir

    Everything in this directory will be committed to the WordPress.org subversion repository, i.e. will be included in the downloadable zip file. 

    We set this to build because we have copied plugin files into build during before_deploy.

    Tagging

    Assume that we have fixed some bugs and are ready to publish a new version to WordPress.org.

    These commands commit the changes to the master branch but do not trigger a deployment:

    $ git add -A $ git commit -am "Bug fix" $ git push origin master

    Only tagged commits trigger deployment:

    $ git tag -a 1.0.17 -m "Version bump 1.0.17" $ git push origin master --tagsResults

    Head back to TravisCI and open the PHP 7.1 build log. You should see a deployment is logged.

    Building dpl gem locally with source TypistTech/dpl and branch add-wordpress-plugin-deployment Installing deploy dependencies !!! WordPress Plugin support is experimental !!! Preparing deploy Finding configuration for WordPress plugin deployment... Slug: remove-medium-cross-links Username: tangrufus Password found Build Directory: build Assets Directory: not found Validating configuration for WordPress plugin deployment... Configuration looks good Going to deloy tag: 1.0.17 Cleaning up git repository with `git stash --all`. If you need build artifacts for deployment, set `deploy.skip_cleanup: true`. See https://docs.travis-ci.com/user/deployment/#Uploading-Files. /usr/lib/git-core/git-stash: 186: /usr/lib/git-core/git-stash: cannot create /home/travis/build/TangRufus/tutsplus-dpl-demo/.git/logs/refs/stash: Directory nonexistent Deploying application Checking out https://plugins.svn.wordpress.org/remove-medium-cross-links Clearing /tmp/d20170513-3291-1yh7vqo/trunk... Removing deleted files from subversion... D /tmp/d20170513-3291-1yh7vqo/trunk Temporary removing trunk and assets(if assets_dir is set) Deleting tmp/d20170513-3291-1yh7vqo/trunk Committed revision 1656616. Copying build to /tmp/d20170513-3291-1yh7vqo/trunk... Copying /tmp/d20170513-3291-1yh7vqo/trunk to /tmp/d20170513-3291-1yh7vqo/tags/1.0.17... Adding new files to subversion... A /tmp/d20170513-3291-1yh7vqo/trunk A /tmp/d20170513-3291-1yh7vqo/trunk/LICENSE A /tmp/d20170513-3291-1yh7vqo/trunk/README.txt A /tmp/d20170513-3291-1yh7vqo/trunk/remove-medium-cross-links.php A /tmp/d20170513-3291-1yh7vqo/tags/1.0.17 A /tmp/d20170513-3291-1yh7vqo/tags/1.0.17/LICENSE A /tmp/d20170513-3291-1yh7vqo/tags/1.0.17/README.txt A /tmp/d20170513-3291-1yh7vqo/tags/1.0.17/remove-medium-cross-links.php Committing 1.0.17 Adding tmp/d20170513-3291-1yh7vqo/tags/1.0.17 Adding tmp/d20170513-3291-1yh7vqo/tags/1.0.17/LICENSE Adding tmp/d20170513-3291-1yh7vqo/tags/1.0.17/README.txt Adding tmp/d20170513-3291-1yh7vqo/tags/1.0.17/remove-medium-cross-links.php Adding tmp/d20170513-3291-1yh7vqo/trunk Adding tmp/d20170513-3291-1yh7vqo/trunk/LICENSE Adding tmp/d20170513-3291-1yh7vqo/trunk/README.txt Adding tmp/d20170513-3291-1yh7vqo/trunk/remove-medium-cross-links.php Transmitting file data ...... Committed revision 1656617.

    And on the WordPress.org trac (https://plugins.trac.wordpress.org/browser/<your-plugin-slug>):

    Caveats svn commit Twice

    Since TravisCI ships with an old version of subversion which doesn't play well with subdirectories, I do svn commit twice.

    The first svn commit removes everything inside trunk. The second svn commit copies everything from build_dir to trunk.

    Experimental

    This provider is still experimental and is not merged to TravisCI's official repo yet. You can keep track of TravisCI's feedback on its pull request.

    Using edge doesn't merge my branch into the upstream master. There is a chance that my branch is behind the official repo. When it happens, you can fork my branch and rebase it, and then change source in .travis.yml to your GitHub repository.

    Wrapping Up

    To use this deployment provider:

    1. Host the plugin repository on GitHub.
    2. Connect GitHub and TravisCI.
    3. Add the configuration to .travis.yml.
    4. Push a tag.

    I hope all the above helps you deploy plugins to WordPress.org faster. 

    WordPress has an incredibly active economy. There are themes, plugins, libraries, and many other products that help you build out your site and project. The open-source nature of the platform also makes it a great option for you to improve your programming skills. Whatever the case, you can see everything we have available in the Envato Marketplace.

    Thanks for reading!

    3 days 22 min ago

Now Available on Envato Elements: Unlimited Stock Photos

  • Welcome to unlimited stock photos on Envato Elements!

    If you're already an Elements subscriber, you'll now see that, along with all the graphics, fonts, web templates, 3D models and everything else you've been used to downloading, you have unlimited access to over 240,000 high-quality stock images. Enjoy!

    If you're not an Elements subscriber, here's how it works. For a single monthly subscription of US$29, you get unlimited downloads from a broad and highly curated selection of:

    • graphics (vectors, icons, patterns, textures, illustrations and more)
    • add-ons (think Photoshop and Illustrator actions, Lightroom presets, etc.)
    • fonts
    • graphic templates (logos, infographics, product mockups, etc.)
    • presentation templates (Keynote and PowerPoint)
    • web templates (landing pages, full websites, email newsletters, etc.)
    • CMS templates (Shopify, Magento, OpenCart, and a lot more)
    • 3D models

    Oh, and you also get free access to over 1,000 courses and 170 eBooks here on Envato Tuts+, as well as free AND CO membership to help you with invoicing and contracts. 

    And because all of that just wasn't enough, now you get almost a quarter of a million stock photos too.

    Workplace image from Envato ElementsWhy Envato Elements?

    Of course, there are loads of stock photo sites out there already, both free and paid. So why should you bother with Envato Elements? Here are a few reasons:

    1. Get Premium Quality

    On some other stock photo sites, the emphasis is on quantity: thousands of people uploading millions of images, with little quality control. On Envato Elements, the collection is carefully curated to make sure you have access to the very best images, without having to wade through tons of mediocre ones.

    Photography image on Envato Elements2. Get Broad Commercial Rights

    No matter whether you're using photos for a website, an artwork, a client project or a professional document, you need to know that you have the right to use those images and won't get sued for copyright infringement. All the items on Envato Elements come with a simple, easy-to-understand commercial license, so that you can use them in your projects with confidence—and without having to squint at a mass of small print.

    Happy couple image on Envato Elements3. Find Exactly What You Need

    Elements offers some useful filters to help you find what you need quickly and effectively. You can search by subject, of course, but you can also filter for image orientation (landscape, portrait, or square) and for the predominant colours in the image. So you can find images that not only convey the right message, but also fit seamlessly with your overall design.

    Image of Tuscany from Envato Elements4. Get a Lot of Other Stuff Too

    As I mentioned above, you get a ton of other useful things bundled with an Elements subscription. There are no usage limits, no credits to keep track of. You just use as many photos, templates, fonts and graphics as you need for the projects you're working on. So whether you're a web designer, a developer, an artist a businessperson or a freelancer in a number of creative fields, you'll be able to get good value out of an Elements subscription.

    Food image on Envato ElementsWhat to Do Next

    To learn more about the new selection of photos, head over to Envato Elements. You can browse the full selection of items even if you don't have an account, so take a look around to get an idea of what's on offer and decide whether it would be useful for you.

    Keep in mind that Envato Elements is expanding all the time, both in terms of the number of categories being offered and the number of items in each category. So this is a subscription that's only going to get more valuable over time.

    3 days 5 hours ago

'Prisoners of Gravity': Hey, TV Sci-Fi Can Have Ideas After All

Pages