Step #8: Offering the Download Option

At this point, ToDoRepository knows how to import JSON-encoded to-do items retrieved from a URL, and PrefsRepository knows how to give us that URL. Now, we need to add a way for the user to trigger this work — in our case, we will put an option in RosterListFragment for that.

So, let’s update RosterMotor to be able to import our to-do items. First, update the RosterMotor constructor to take a PrefsRepository along with all of its other parameters:

class RosterMotor(
  private val repo: ToDoRepository,
  private val report: RosterReport,
  private val context: Application,
  private val appScope: CoroutineScope,
  private val prefs: PrefsRepository
) : ViewModel() {

That will also require us to add another get() to the line in ToDoApp where we are creating our RosterMotor instances:

    viewModel {
      RosterMotor(
        get(),
        get(),
        androidApplication(),
        get(named("appScope")),
        get()
      )
    }

Then, add this function to RosterMotor:

  fun importItems() {
    viewModelScope.launch {
      repo.importItems(prefs.loadWebServiceUrl())
    }
  }

This just calls loadWebServiceUrl() on our PrefsRepository and passes the result to importItems() on the ToDoRepository. Since both of those are suspend functions, that code is wrapped in a viewModelScope coroutine. We do not need to do anything here to update our viewstate, though — Room will deliver fresh results to us after the import, the same way it does after EditFragment modifies our data.

Now, we need to arrange to call that importItems() function… triggered by yet another app bar item.

Right-click over res/drawable/ in the project tree and choose “New” > “Vector Asset” from the context menu. This brings up the Vector Asset Wizard. There, click the “Icon” button and search for download. Choose the “cloud download” icon and click “OK” to close up the icon selector. Change the icon’s name to ic_download. Then, click “Next” and “Finish” to close up the wizard and set up our icon.

If the icon selector did not open, that may be due to this Arctic Fox bug. Instead, just close up the Vector Asset wizard, and download this file into res/drawable instead. That is the desired icon, already set up for you.

Open up the res/menu/actions_roster.xml resource file, and switch to the graphical designer. Drag an “Item” from the “Palette” view into the Component Tree, slotting it after the other items.

In the Attributes view for this new item, assign it an ID of “importItems”. Then, choose “never” for the “showAsAction” option. Next, click on the “O” button next to the “icon” field. This will bring up an drawable resource selector. Click on ic_download in the list of drawables, then click OK to accept that choice of icon.

Then, click the “O” button next to the “title” field. As before, this brings up a string resource selector. Click on “Add new resource” > “New string Value” in the drop-down towards the top. In the dialog, fill in menu_import as the resource name and “Import” as the resource value.

Finally, in RosterListFragment, add another branch to the when in onOptionsItemSelected() to handle our importItems case:

      R.id.importItems -> {
        motor.importItems()
        return true
      }

Now, if you run the app, you should see the new “Import” app bar item in the overflow. If you click it, you will get a couple of new entries in your list of to-do items, reflecting the JSON shown earlier in this chapter. And, if you choose “Import” again… nothing will happen, as those items already exist in the local database, so they are ignored on a subsequent import. This assumes that your device has Internet access and the author of the book has not accidentally deleted the “Web service” that we are trying to access.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.