Skip to content

Commit

Permalink
Merge pull request #159 from scolsen/basemap-selector
Browse files Browse the repository at this point in the history
Offline Imagery: Add basemap selector UI
  • Loading branch information
scolsen committed Aug 15, 2019
2 parents d089fd0 + c255e07 commit 7fad5f5
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 0 deletions.
Expand Up @@ -19,6 +19,8 @@
import androidx.appcompat.app.AppCompatActivity;
import com.google.android.gnd.inject.ActivityScoped;
import com.google.android.gnd.inject.FragmentScoped;
import com.google.android.gnd.ui.basemapselector.BasemapSelectorFragment;
import com.google.android.gnd.ui.basemapselector.BasemapSelectorModule;
import com.google.android.gnd.ui.editrecord.EditRecordFragment;
import com.google.android.gnd.ui.editrecord.EditRecordModule;
import com.google.android.gnd.ui.home.AddFeatureDialogFragment;
Expand Down Expand Up @@ -89,4 +91,8 @@ public abstract class MainActivityModule {
@FragmentScoped
@ContributesAndroidInjector(modules = EditRecordModule.class)
abstract EditRecordFragment editRecordFragmentInjector();

@FragmentScoped
@ContributesAndroidInjector(modules = BasemapSelectorModule.class)
abstract BasemapSelectorFragment basemapSelectorFragmentInjector();
}
@@ -0,0 +1,78 @@
package com.google.android.gnd.ui.basemapselector;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;

import com.google.android.gnd.MainViewModel;
import com.google.android.gnd.R;
import com.google.android.gnd.databinding.BasemapSelectorFragBinding;
import com.google.android.gnd.inject.ActivityScoped;
import com.google.android.gnd.ui.common.AbstractFragment;
import com.google.android.gnd.ui.map.MapProvider;
import com.google.android.gnd.ui.map.MapProvider.MapAdapter;

import javax.inject.Inject;

import io.reactivex.Single;

/**
* Allows the user to select specific areas on a map for offline display. Users can toggle sections of
* the map to add or remove imagery. Upon selection, basemap tiles are queued for download. When
* deselected, they are removed from the device.
*/
@ActivityScoped
public class BasemapSelectorFragment extends AbstractFragment {

private static final String TAG = BasemapSelectorFragment.class.getName();
private static final String MAP_FRAGMENT_KEY = MapProvider.class.getName() + "#fragment";
private BasemapSelectorViewModel viewModel;
private MainViewModel mainViewModel;

@Inject MapProvider mapProvider;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = getViewModel(BasemapSelectorViewModel.class);
mainViewModel = getViewModel(MainViewModel.class);
Single<MapAdapter> mapAdapter = mapProvider.getMapAdapter();
}

@Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
BasemapSelectorFragBinding binding =
BasemapSelectorFragBinding.inflate(inflater, container, false);
binding.setViewModel(viewModel);
return binding.getRoot();
}

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
if (savedInstanceState == null) {
replaceFragment(R.id.map, mapProvider.getFragment());
} else {
mapProvider.restore(restoreChildFragment(savedInstanceState, MAP_FRAGMENT_KEY));
}
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mainViewModel.getWindowInsets().observe(this, this::onApplyWindowInsets);
}

private void onApplyWindowInsets(WindowInsetsCompat windowInsets) {
ViewCompat.onApplyWindowInsets(mapProvider.getFragment().getView(), windowInsets);
// TODO: Once we add control UI elements, translate them based on the inset to avoid collision
// with the android navbar.
}
}
@@ -0,0 +1,16 @@
package com.google.android.gnd.ui.basemapselector;

import androidx.fragment.app.Fragment;

import com.google.android.gnd.inject.FragmentScoped;

import dagger.Binds;
import dagger.Module;

@Module
public abstract class BasemapSelectorModule {

@Binds
@FragmentScoped
abstract Fragment fragment(BasemapSelectorFragment fragment);
}
@@ -0,0 +1,19 @@
package com.google.android.gnd.ui.basemapselector;

import androidx.lifecycle.ViewModel;

import javax.inject.Inject;

/**
* This view model is responsible for managing state for the {@link BasemapSelectorFragment}.
* Together, they constitute a basemap selector that users can interact with to select portions of a
* basemap for offline viewing. Among other things, this view model is responsible for receiving
* requests to download basemap files and for scheduling those requests with an {@link
* com.google.android.gnd.workers.FileDownloadWorker}.
*/
public class BasemapSelectorViewModel extends ViewModel {
@Inject
BasemapSelectorViewModel() {}

// TODO: Implement view model.
}
Expand Up @@ -69,6 +69,14 @@ public void showRecordDetails(String projectId, String featureId, String recordI
navigate(HomeScreenFragmentDirections.showRecordDetails(projectId, featureId, recordId));
}

/**
* Navigates from a {@link com.google.android.gnd.ui.home.HomeScreenFragment} to a {@link
* com.google.android.gnd.ui.basemapselector.BasemapSelectorFragment}.
*/
public void showBasemapSelector() {
navigate(HomeScreenFragmentDirections.showBasemapSelector());
}

/**
* Navigates from the {@link com.google.android.gnd.ui.home.HomeScreenFragment} to a {@link
* com.google.android.gnd.ui.editrecord.EditRecordFragment} initialized with a new empty record
Expand Down
Expand Up @@ -19,6 +19,7 @@
import androidx.lifecycle.ViewModel;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.gnd.MainViewModel;
import com.google.android.gnd.ui.basemapselector.BasemapSelectorViewModel;
import com.google.android.gnd.ui.editrecord.EditRecordViewModel;
import com.google.android.gnd.ui.home.HomeScreenViewModel;
import com.google.android.gnd.ui.home.featuresheet.FeatureSheetViewModel;
Expand All @@ -38,6 +39,11 @@ public abstract class ViewModelModule {
@ViewModelKey(MapContainerViewModel.class)
abstract ViewModel bindMapContainerViewModel(MapContainerViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(BasemapSelectorViewModel.class)
abstract ViewModel bindBasemapSelectorViewModel(BasemapSelectorViewModel viewModel);

@Binds
@IntoMap
@ViewModelKey(MainViewModel.class)
Expand Down
Expand Up @@ -224,6 +224,10 @@ private void showProjectSelector() {
ProjectSelectorDialogFragment.show(getFragmentManager());
}

private void showBasemapSelector() {
viewModel.showBasemapSelector();
}

private void onApplyWindowInsets(WindowInsetsCompat insets) {
statusBarScrim.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0);
toolbarWrapper.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0);
Expand Down Expand Up @@ -335,6 +339,10 @@ public boolean onNavigationItemSelected(@NonNull MenuItem item) {
showProjectSelector();
closeDrawer();
break;
case R.id.nav_offline_maps:
showBasemapSelector();
closeDrawer();
break;
case R.id.nav_sign_out:
authenticationManager.signOut();
break;
Expand Down
Expand Up @@ -146,6 +146,10 @@ public void addRecord() {
navigator.addRecord(feature.getProject().getId(), feature.getId(), selectedForm.getId());
}

public void showBasemapSelector() {
navigator.showBasemapSelector();
}

/**
* Reactivates the last active project, emitting true once loaded, or false if no project was
* previously activated.
Expand Down
30 changes: 30 additions & 0 deletions gnd/src/main/res/layout/basemap_selector_frag.xml
@@ -0,0 +1,30 @@
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<data>
<variable
name="viewModel"
type="com.google.android.gnd.ui.basemapselector.BasemapSelectorViewModel" />
</data>

<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">

<RelativeLayout
android:id="@+id/map_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top"
android:gravity="center"
app:layout_behavior="com.google.android.gnd.ui.home.mapcontainer.MapLayoutBehavior">

<FrameLayout
android:id="@+id/map"
android:layout_width="match_parent"
android:layout_height="match_parent" />

<!--TODO: Add controls for returning Home and downloading selected tiles.-->
</RelativeLayout>
</FrameLayout>
</layout>
4 changes: 4 additions & 0 deletions gnd/src/main/res/menu/nav_drawer_menu.xml
Expand Up @@ -21,6 +21,10 @@
android:id="@+id/nav_join_project"
android:icon="@drawable/ic_menu_project"
android:title="@string/select_project_menu_item"/>
<item
android:id="@+id/nav_offline_maps"
android:icon="@drawable/ic_arrow_drop_down"
android:title="@string/offline_maps"/>
<item
android:id="@+id/nav_sign_out"
android:icon="@drawable/ic_sign_out"
Expand Down
14 changes: 14 additions & 0 deletions gnd/src/main/res/navigation/nav_graph.xml
Expand Up @@ -67,8 +67,22 @@
android:defaultValue="NEW_RECORD"
android:name="recordId"/>
</action>
<action
android:id="@+id/showBasemapSelector"
app:destination="@id/basemap_selector_fragment"
/>
</fragment>

<fragment
android:id="@+id/basemap_selector_fragment"
android:label="@string/offline_maps"
android:name="com.google.android.gnd.ui.basemapselector.BasemapSelectorFragment"
tools:layout="@layout/basemap_selector_frag">
<action
android:id="@+id/backToHomeScreen"
app:destination="@id/home_screen_fragment"
/></fragment>

<fragment
android:id="@+id/record_details_fragment"
android:label="@string/view_record_details"
Expand Down
1 change: 1 addition & 0 deletions gnd/src/main/res/values/strings.xml
Expand Up @@ -139,5 +139,6 @@
<string name="google_api_install_failed">Google Play Services installation failed</string>
<string name="sign_in_unsuccessful">Sign in unsuccessful</string>
<string name="sign_out">Sign out</string>
<string name="offline_maps">Offline maps</string>

</resources>

0 comments on commit 7fad5f5

Please sign in to comment.