mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-11-19 00:19:25 +01:00
Use modern navigation component
This commit is contained in:
parent
a550aca626
commit
70a8b80af0
@ -228,6 +228,8 @@ dependencies {
|
||||
implementation "androidx.palette:palette:1.0.0"
|
||||
implementation "androidx.activity:activity:1.7.2"
|
||||
implementation "androidx.fragment:fragment:1.6.2"
|
||||
implementation "androidx.navigation:navigation-fragment:2.6.0"
|
||||
implementation "androidx.navigation:navigation-ui:2.6.0"
|
||||
|
||||
implementation "com.google.android.material:material:1.9.0"
|
||||
implementation 'com.google.android.flexbox:flexbox:3.0.0'
|
||||
|
@ -19,10 +19,10 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
@ -31,15 +31,18 @@ import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.floatingactionbutton.FloatingActionButton;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
@ -50,8 +53,9 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DailyTotals;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class ControlCenterv2 extends Fragment {
|
||||
@ -63,6 +67,33 @@ public class ControlCenterv2 extends Fragment {
|
||||
List<GBDevice> deviceList;
|
||||
private HashMap<String,long[]> deviceActivityHashMap = new HashMap();
|
||||
|
||||
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
switch (Objects.requireNonNull(action)) {
|
||||
case DeviceManager.ACTION_DEVICES_CHANGED:
|
||||
case GBApplication.ACTION_NEW_DATA:
|
||||
createRefreshTask("get activity data", requireContext()).execute();
|
||||
mGBDeviceAdapter.rebuildFolders();
|
||||
refreshPairedDevices();
|
||||
break;
|
||||
case DeviceService.ACTION_REALTIME_SAMPLES:
|
||||
handleRealtimeSample(intent.getSerializableExtra(DeviceService.EXTRA_REALTIME_SAMPLE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void handleRealtimeSample(Serializable extra) {
|
||||
if (extra instanceof ActivitySample) {
|
||||
ActivitySample sample = (ActivitySample) extra;
|
||||
if (HeartRateUtils.getInstance().isValidHeartRateValue(sample.getHeartRate())) {
|
||||
refreshPairedDevices();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
|
||||
View currentView = inflater.inflate(R.layout.activity_controlcenterv2_content_main, container, false);
|
||||
@ -130,6 +161,12 @@ public class ControlCenterv2 extends Fragment {
|
||||
|
||||
registerForContextMenu(deviceListView);
|
||||
|
||||
IntentFilter filterLocal = new IntentFilter();
|
||||
filterLocal.addAction(GBApplication.ACTION_NEW_DATA);
|
||||
filterLocal.addAction(DeviceManager.ACTION_DEVICES_CHANGED);
|
||||
filterLocal.addAction(DeviceService.ACTION_REALTIME_SAMPLES);
|
||||
LocalBroadcastManager.getInstance(requireContext()).registerReceiver(mReceiver, filterLocal);
|
||||
|
||||
refreshPairedDevices();
|
||||
|
||||
if (GB.isBluetoothEnabled() && deviceList.isEmpty() && Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
@ -160,6 +197,7 @@ public class ControlCenterv2 extends Fragment {
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
unregisterForContextMenu(deviceListView);
|
||||
LocalBroadcastManager.getInstance(requireContext()).unregisterReceiver(mReceiver);
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@ -181,17 +219,6 @@ public class ControlCenterv2 extends Fragment {
|
||||
return new RefreshTask(task, context);
|
||||
}
|
||||
|
||||
private void handleShortcut(Intent intent) {
|
||||
if(ACTION_CONNECT.equals(intent.getAction())) {
|
||||
String btDeviceAddress = intent.getStringExtra("device");
|
||||
if(btDeviceAddress!=null){
|
||||
GBDevice candidate = DeviceHelper.getInstance().findAvailableDevice(btDeviceAddress, getActivity());
|
||||
if (candidate != null && !candidate.isConnected()) {
|
||||
GBApplication.deviceService(candidate).connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public class RefreshTask extends DBAccess {
|
||||
public RefreshTask(String task, Context context) {
|
||||
super(task, context);
|
||||
|
@ -51,8 +51,8 @@ import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardGoalsW
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardSleepWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardStepsWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardTodayWidget;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DashboardUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
public class DashboardFragment extends Fragment {
|
||||
@ -103,11 +103,21 @@ public class DashboardFragment extends Fragment {
|
||||
distanceWidget = null;
|
||||
activeTimeWidget = null;
|
||||
sleepWidget = null;
|
||||
refresh();
|
||||
|
||||
// Only load widgets here if the Dashboard is the initial view.
|
||||
// This prevents a hard crash when replacing the fragment in createWidget() via a FragmentManager.
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
if (prefs.getBoolean("dashboard_as_default_view", true)) refresh();
|
||||
|
||||
return dashboardView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
|
||||
super.onCreateOptionsMenu(menu, inflater);
|
||||
@ -222,7 +232,7 @@ public class DashboardFragment extends Fragment {
|
||||
FragmentContainerView fragment = new FragmentContainerView(requireActivity());
|
||||
int fragmentId = View.generateViewId();
|
||||
fragment.setId(fragmentId);
|
||||
getChildFragmentManager()
|
||||
getParentFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(fragmentId, widgetObj)
|
||||
.commit();
|
||||
|
@ -17,6 +17,8 @@
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities;
|
||||
|
||||
import static nodomain.freeyourgadget.gadgetbridge.model.DeviceService.ACTION_CONNECT;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Dialog;
|
||||
@ -33,12 +35,10 @@ import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.PhoneStateListener;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
@ -46,6 +46,10 @@ import androidx.core.app.NotificationManagerCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.NavGraph;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
@ -64,15 +68,16 @@ import java.util.Set;
|
||||
import nodomain.freeyourgadget.gadgetbridge.BuildConfig;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceManager;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DeviceService;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.AndroidUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GBChangeLog;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
public class MainActivity extends AbstractGBActivity implements BottomNavigationView.OnNavigationItemSelectedListener, GBActivity {
|
||||
public class MainActivity extends AbstractGBActivity implements GBActivity {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(MainActivity.class);
|
||||
public static final String ACTION_REQUEST_PERMISSIONS
|
||||
= "nodomain.freeyourgadget.gadgetbridge.activities.controlcenter.requestpermissions";
|
||||
@ -82,12 +87,6 @@ public class MainActivity extends AbstractGBActivity implements BottomNavigation
|
||||
private boolean isThemeInvalid = false;
|
||||
private static PhoneStateListener fakeStateListener;
|
||||
|
||||
private BottomNavigationView bottomNavigationView;
|
||||
private int activeFragment;
|
||||
private DashboardFragment dashboardFragment = new DashboardFragment();
|
||||
private ControlCenterv2 devicesFragment = new ControlCenterv2();
|
||||
private MainMenuFragment mainMenuFragment = new MainMenuFragment();
|
||||
|
||||
//needed for KK compatibility
|
||||
static {
|
||||
AppCompatDelegate.setCompatVectorFromResourcesEnabled(true);
|
||||
@ -107,25 +106,20 @@ public class MainActivity extends AbstractGBActivity implements BottomNavigation
|
||||
case GBApplication.ACTION_QUIT:
|
||||
finish();
|
||||
break;
|
||||
case DeviceManager.ACTION_DEVICES_CHANGED:
|
||||
case GBApplication.ACTION_NEW_DATA:
|
||||
devicesFragment.createRefreshTask("get activity data", getApplication()).execute();
|
||||
// mGBDeviceAdapter.rebuildFolders();
|
||||
devicesFragment.refreshPairedDevices();
|
||||
break;
|
||||
case DeviceService.ACTION_REALTIME_SAMPLES:
|
||||
handleRealtimeSample(intent.getSerializableExtra(DeviceService.EXTRA_REALTIME_SAMPLE));
|
||||
break;
|
||||
case ACTION_REQUEST_PERMISSIONS:
|
||||
checkAndRequestPermissions();
|
||||
break;
|
||||
case ACTION_REQUEST_LOCATION_PERMISSIONS:
|
||||
checkAndRequestLocationPermissions();
|
||||
break;
|
||||
case DeviceService.ACTION_REALTIME_SAMPLES:
|
||||
handleRealtimeSample(intent.getSerializableExtra(DeviceService.EXTRA_REALTIME_SAMPLE));
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
private boolean pesterWithPermissions = true;
|
||||
|
||||
private ActivitySample currentHRSample;
|
||||
|
||||
public ActivitySample getCurrentHRSample() {
|
||||
@ -135,9 +129,6 @@ public class MainActivity extends AbstractGBActivity implements BottomNavigation
|
||||
private void setCurrentHRSample(ActivitySample sample) {
|
||||
if (HeartRateUtils.getInstance().isValidHeartRateValue(sample.getHeartRate())) {
|
||||
currentHRSample = sample;
|
||||
if (devicesFragment.isResumed()) {
|
||||
devicesFragment.refreshPairedDevices();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -156,25 +147,24 @@ public class MainActivity extends AbstractGBActivity implements BottomNavigation
|
||||
|
||||
Prefs prefs = GBApplication.getPrefs();
|
||||
|
||||
bottomNavigationView = findViewById(R.id.bottom_nav_bar);
|
||||
bottomNavigationView.setOnNavigationItemSelectedListener(this);
|
||||
if (prefs.getBoolean("dashboard_as_default_view", true)) {
|
||||
bottomNavigationView.setSelectedItemId(R.id.bottom_nav_dashboard);
|
||||
activeFragment = R.id.bottom_nav_dashboard;
|
||||
} else {
|
||||
bottomNavigationView.setSelectedItemId(R.id.bottom_nav_devices);
|
||||
activeFragment = R.id.bottom_nav_devices;
|
||||
NavHostFragment navHostFragment = (NavHostFragment)
|
||||
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
|
||||
NavController navController = navHostFragment.getNavController();
|
||||
if (!prefs.getBoolean("dashboard_as_default_view", true)) {
|
||||
NavGraph navGraph = navController.getNavInflater().inflate(R.navigation.main);
|
||||
navGraph.setStartDestination(R.id.bottom_nav_devices);
|
||||
navController.setGraph(navGraph);
|
||||
}
|
||||
BottomNavigationView navigationView = findViewById(R.id.bottom_nav_bar);
|
||||
NavigationUI.setupWithNavController(navigationView, navController);
|
||||
|
||||
IntentFilter filterLocal = new IntentFilter();
|
||||
filterLocal.addAction(GBApplication.ACTION_LANGUAGE_CHANGE);
|
||||
filterLocal.addAction(GBApplication.ACTION_THEME_CHANGE);
|
||||
filterLocal.addAction(GBApplication.ACTION_QUIT);
|
||||
filterLocal.addAction(GBApplication.ACTION_NEW_DATA);
|
||||
filterLocal.addAction(DeviceManager.ACTION_DEVICES_CHANGED);
|
||||
filterLocal.addAction(DeviceService.ACTION_REALTIME_SAMPLES);
|
||||
filterLocal.addAction(ACTION_REQUEST_PERMISSIONS);
|
||||
filterLocal.addAction(ACTION_REQUEST_LOCATION_PERMISSIONS);
|
||||
filterLocal.addAction(DeviceService.ACTION_REALTIME_SAMPLES);
|
||||
LocalBroadcastManager.getInstance(this).registerReceiver(mReceiver, filterLocal);
|
||||
|
||||
/*
|
||||
@ -256,27 +246,15 @@ public class MainActivity extends AbstractGBActivity implements BottomNavigation
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
outState.putInt("activeFragment", activeFragment); // Save variables into the Bundle
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
activeFragment = savedInstanceState.getInt("activeFragment"); // Retrieve variables from the Bundle
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
handleShortcut(getIntent());
|
||||
if (isLanguageInvalid || isThemeInvalid) {
|
||||
isLanguageInvalid = false;
|
||||
isThemeInvalid = false;
|
||||
recreate();
|
||||
}
|
||||
updateFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -285,34 +263,15 @@ public class MainActivity extends AbstractGBActivity implements BottomNavigation
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean
|
||||
onNavigationItemSelected(@NonNull MenuItem item) {
|
||||
activeFragment = item.getItemId();
|
||||
updateFragment();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void updateFragment() {
|
||||
switch (activeFragment) {
|
||||
case R.id.bottom_nav_dashboard:
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragment_container, dashboardFragment)
|
||||
.commit();
|
||||
break;
|
||||
case R.id.bottom_nav_devices:
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragment_container, devicesFragment)
|
||||
.commit();
|
||||
break;
|
||||
case R.id.bottom_nav_menu:
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.fragment_container, mainMenuFragment)
|
||||
.commit();
|
||||
break;
|
||||
private void handleShortcut(Intent intent) {
|
||||
if(ACTION_CONNECT.equals(intent.getAction())) {
|
||||
String btDeviceAddress = intent.getStringExtra("device");
|
||||
if(btDeviceAddress!=null){
|
||||
GBDevice candidate = DeviceHelper.getInstance().findAvailableDevice(btDeviceAddress, this);
|
||||
if (candidate != null && !candidate.isConnected()) {
|
||||
GBApplication.deviceService(candidate).connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -213,7 +213,6 @@ public class DashboardTodayWidget extends AbstractDashboardWidget {
|
||||
private final List<GeneralizedActivity> generalizedActivities = new ArrayList<>();
|
||||
|
||||
private void addActivity(long timeFrom, long timeTo, int activityKind) {
|
||||
LOG.info("Adding activity: timeFrom=" + timeFrom + ", timeTo=" + timeTo + ", activityKind=" + activityKind);
|
||||
for (long i = timeFrom; i<=timeTo; i++) {
|
||||
// If the current timestamp isn't saved yet, do so immediately
|
||||
if (activityTimestamps.get(i) == null) {
|
||||
|
@ -9,6 +9,9 @@
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_container"
|
||||
android:name="androidx.navigation.fragment.NavHostFragment"
|
||||
app:navGraph="@navigation/main"
|
||||
app:defaultNavHost="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
app:layout_constraintBottom_toTopOf="@id/bottom_nav_bar"
|
||||
@ -22,7 +25,6 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:background="?android:attr/windowBackground"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
|
44
app/src/main/res/navigation/main.xml
Normal file
44
app/src/main/res/navigation/main.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/main"
|
||||
app:startDestination="@id/bottom_nav_dashboard">
|
||||
|
||||
<fragment
|
||||
android:id="@+id/bottom_nav_dashboard"
|
||||
android:name="nodomain.freeyourgadget.gadgetbridge.activities.DashboardFragment"
|
||||
android:label="fragment_dashboard"
|
||||
tools:layout="@layout/fragment_dashboard" >
|
||||
<action
|
||||
android:id="@+id/dashboard_to_devices"
|
||||
app:destination="@id/bottom_nav_devices" />
|
||||
<action
|
||||
android:id="@+id/dashboard_to_menu"
|
||||
app:destination="@id/bottom_nav_menu" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/bottom_nav_devices"
|
||||
android:name="nodomain.freeyourgadget.gadgetbridge.activities.ControlCenterv2"
|
||||
android:label="activity_controlcenterv2_content_main"
|
||||
tools:layout="@layout/activity_controlcenterv2_content_main" >
|
||||
<action
|
||||
android:id="@+id/devices_to_menu"
|
||||
app:destination="@id/bottom_nav_menu" />
|
||||
<action
|
||||
android:id="@+id/devices_to_dashboard"
|
||||
app:destination="@id/bottom_nav_dashboard" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/bottom_nav_menu"
|
||||
android:name="nodomain.freeyourgadget.gadgetbridge.activities.MainMenuFragment"
|
||||
android:label="fragment_main_menu"
|
||||
tools:layout="@layout/fragment_main_menu" >
|
||||
<action
|
||||
android:id="@+id/menu_to_dashboard"
|
||||
app:destination="@id/bottom_nav_dashboard" />
|
||||
<action
|
||||
android:id="@+id/menu_to_devices"
|
||||
app:destination="@id/bottom_nav_devices" />
|
||||
</fragment>
|
||||
</navigation>
|
Loading…
Reference in New Issue
Block a user