Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion app/res/layout/nav_drawer_sublist_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,21 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingStart="48dp"
android:paddingStart="24dp"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:gravity="center_vertical"
android:background="@color/cc_brand_color">

<ImageView
android:id="@+id/sublist_highlight_icon"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="12dp"
android:src="@drawable/icon_chevron_right_white"
android:contentDescription="@null"
android:visibility="gone"/>

<ImageView
android:layout_width="24dp"
android:layout_height="24dp"
Expand Down
2 changes: 0 additions & 2 deletions app/src/org/commcare/activities/CommCareActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@
import org.commcare.google.services.analytics.FirebaseAnalyticsUtil;
import org.commcare.interfaces.WithUIController;
import org.commcare.logic.DetailCalloutListenerDefaultImpl;
import org.commcare.navdrawer.BaseDrawerController;
import org.commcare.navdrawer.DrawerViewRefs;
import org.commcare.preferences.LocalePreferences;
import org.commcare.services.DataSyncCompleteBroadcastReceiver;
import org.commcare.services.FCMMessageData;
Expand Down
1 change: 0 additions & 1 deletion app/src/org/commcare/activities/CommCareSetupActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import org.commcare.logging.DataChangeLog;
import org.commcare.logging.DataChangeLogger;
import org.commcare.navdrawer.BaseDrawerActivity;
import org.commcare.navdrawer.BaseDrawerController;
import org.commcare.preferences.GlobalPrivilegesManager;
import org.commcare.resources.ResourceManager;
import org.commcare.resources.model.InvalidResourceException;
Expand Down
23 changes: 16 additions & 7 deletions app/src/org/commcare/activities/DispatchActivity.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.commcare.activities;

import static org.commcare.activities.LoginActivity.EXTRA_APP_ID;
import static org.commcare.commcaresupportlibrary.CommCareLauncher.SESSION_ENDPOINT_APP_ID;
import static org.commcare.connect.ConnectAppUtils.IS_LAUNCH_FROM_CONNECT;
import static org.commcare.connect.ConnectConstants.CONNECT_MANAGED_LOGIN;
import static org.commcare.connect.ConnectConstants.PERSONALID_MANAGED_LOGIN;

import android.content.Intent;
import android.os.Bundle;
Expand Down Expand Up @@ -68,7 +71,7 @@ public class DispatchActivity extends AppCompatActivity {
private boolean startFromLogin;
private LoginMode lastLoginMode;
private boolean userManuallyEnteredPasswordMode;
private boolean connectIdManagedLogin;
private boolean personalIdManagedLogin;
private boolean connectManagedLogin;
private boolean shouldFinish;
private boolean userTriggeredLogout;
Expand All @@ -85,6 +88,7 @@ public class DispatchActivity extends AppCompatActivity {
static final String REBUILD_SESSION = "rebuild_session";
private boolean redirectToConnectHome = false;
private boolean redirectToConnectOpportunityInfo = false;
private String redirectToLoginAppId = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
Expand Down Expand Up @@ -296,9 +300,13 @@ private void launchLoginScreen() {
i.putExtra(LoginActivity.USER_TRIGGERED_LOGOUT, userTriggeredLogout);
i.putExtra(IS_LAUNCH_FROM_CONNECT, getLaunchedFromConnect());

String sesssionEndpointAppID = getSessionEndpointAppId();
if (sesssionEndpointAppID != null) {
i.putExtra(LoginActivity.EXTRA_APP_ID, sesssionEndpointAppID);
String sessionEndpointAppID = getSessionEndpointAppId();
if(sessionEndpointAppID == null && redirectToLoginAppId != null) {
sessionEndpointAppID = redirectToLoginAppId;
redirectToLoginAppId = null;
}
if (sessionEndpointAppID != null) {
i.putExtra(EXTRA_APP_ID, sessionEndpointAppID);
}

startActivityForResult(i, LOGIN_USER);
Expand Down Expand Up @@ -335,7 +343,7 @@ private void launchHomeScreen() {
i.putExtra(START_FROM_LOGIN, startFromLogin);
i.putExtra(LoginActivity.LOGIN_MODE, lastLoginMode);
i.putExtra(LoginActivity.MANUAL_SWITCH_TO_PW_MODE, userManuallyEnteredPasswordMode);
i.putExtra(LoginActivity.PERSONALID_MANAGED_LOGIN, connectIdManagedLogin);
i.putExtra(PERSONALID_MANAGED_LOGIN, personalIdManagedLogin);
startFromLogin = false;
clearSessionEndpointAppId();
startActivityForResult(i, HOME_SCREEN);
Expand Down Expand Up @@ -456,6 +464,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
if (intent != null) {
needToExecuteRecoveryMeasures = intent.getBooleanExtra(EXECUTE_RECOVERY_MEASURES, false);
redirectToConnectOpportunityInfo = intent.getBooleanExtra(REDIRECT_TO_CONNECT_OPPORTUNITY_INFO, false);
redirectToLoginAppId = intent.getStringExtra(EXTRA_APP_ID);
}

// if handling new return code (want to return to home screen) but a return at the end of your statement
Expand Down Expand Up @@ -483,8 +492,8 @@ protected void onActivityResult(int requestCode, int resultCode, Intent intent)
lastLoginMode = (LoginMode)intent.getSerializableExtra(LoginActivity.LOGIN_MODE);
userManuallyEnteredPasswordMode =
intent.getBooleanExtra(LoginActivity.MANUAL_SWITCH_TO_PW_MODE, false);
connectIdManagedLogin = intent.getBooleanExtra(LoginActivity.PERSONALID_MANAGED_LOGIN, false);
connectManagedLogin = intent.getBooleanExtra(LoginActivity.CONNECT_MANAGED_LOGIN, false);
personalIdManagedLogin = intent.getBooleanExtra(PERSONALID_MANAGED_LOGIN, false);
connectManagedLogin = intent.getBooleanExtra(CONNECT_MANAGED_LOGIN, false);
startFromLogin = true;
}
return;
Expand Down
12 changes: 9 additions & 3 deletions app/src/org/commcare/activities/LoginActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import static org.commcare.activities.DispatchActivity.REDIRECT_TO_CONNECT_OPPORTUNITY_INFO;
import static org.commcare.connect.ConnectAppUtils.IS_LAUNCH_FROM_CONNECT;
import static org.commcare.connect.ConnectConstants.CONNECT_MANAGED_LOGIN;
import static org.commcare.connect.ConnectConstants.PERSONALID_MANAGED_LOGIN;
import static org.commcare.connect.PersonalIdManager.ConnectAppMangement.Connect;
import static org.commcare.connect.PersonalIdManager.ConnectAppMangement.PersonalId;
import static org.commcare.connect.PersonalIdManager.ConnectAppMangement.Unmanaged;
Expand Down Expand Up @@ -56,7 +58,6 @@
import org.commcare.models.database.user.DemoUserBuilder;
import org.commcare.navdrawer.BaseDrawerActivity;
import org.commcare.navdrawer.BaseDrawerController;
import org.commcare.navdrawer.DrawerViewRefs;
import org.commcare.preferences.DevSessionRestorer;
import org.commcare.preferences.HiddenPreferences;
import org.commcare.recovery.measures.RecoveryMeasuresHelper;
Expand Down Expand Up @@ -127,8 +128,6 @@ public class LoginActivity extends BaseDrawerActivity<LoginActivity>
private int selectedAppIndex = -1;
private boolean appLaunchedFromConnect = false;
private String presetAppId;
public static final String PERSONALID_MANAGED_LOGIN = "personalid-managed-login";
public static final String CONNECT_MANAGED_LOGIN = "connect-managed-login";
private PersonalIdManager personalIdManager;
private PersonalIdManager.ConnectAppMangement connectAppState = Unmanaged;
private boolean connectLaunchPerformed;
Expand Down Expand Up @@ -1013,17 +1012,24 @@ protected boolean shouldShowDrawer() {
return personalIdManager.isloggedIn();
}

@Override
protected boolean shouldHighlightSeatedApp() {
return true;
}

protected PersonalIdManager.ConnectAppMangement getConnectAppState() {
return connectAppState;
}

@Override
protected void handleDrawerItemClick(@NonNull BaseDrawerController.NavItemType itemType, String recordId) {
if (itemType == BaseDrawerController.NavItemType.COMMCARE_APPS) {
if (recordId != null) {
if (!appIdDropdownList.isEmpty()) {
selectedAppIndex = appIdDropdownList.indexOf(recordId);
}
seatAppIfNeeded(recordId);
closeDrawer();
}
} else {
super.handleDrawerItemClick(itemType, recordId);
Expand Down
56 changes: 49 additions & 7 deletions app/src/org/commcare/activities/StandardHomeActivity.java
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
package org.commcare.activities;

import static org.commcare.activities.LoginActivity.EXTRA_APP_ID;
import static org.commcare.connect.ConnectConstants.PERSONALID_MANAGED_LOGIN;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

import androidx.annotation.NonNull;

import org.commcare.CommCareApplication;
import org.commcare.CommCareNoficationManager;
import org.commcare.connect.ConnectJobHelper;
import org.commcare.android.database.connect.models.ConnectJobRecord;
import org.commcare.connect.PersonalIdManager;
import org.commcare.connect.database.ConnectJobUtils;
import org.commcare.connect.ConnectNavHelper;
import org.commcare.dalvik.R;
import org.commcare.google.services.analytics.AnalyticsParamValue;
import org.commcare.google.services.analytics.FirebaseAnalyticsUtil;
import org.commcare.interfaces.CommCareActivityUIController;
import org.commcare.interfaces.WithUIController;
import org.commcare.navdrawer.BaseDrawerController;
import org.commcare.navdrawer.DrawerViewRefs;
import org.commcare.preferences.DeveloperPreferences;
import org.commcare.tasks.DataPullTask;
import org.commcare.tasks.ResultAndError;
Expand All @@ -32,9 +34,6 @@
import java.util.HashMap;
import java.util.Map;

import kotlin.Unit;
import kotlin.jvm.functions.Function2;

/**
* Normal CommCare home screen
*/
Expand All @@ -48,12 +47,15 @@ public class StandardHomeActivity

private StandardHomeActivityUIController uiController;
private Map<Integer, String> menuIdToAnalyticsParam;
private boolean personalIdManagedLogin = false;


@Override
public void onCreateSessionSafe(Bundle savedInstanceState) {
super.onCreateSessionSafe(savedInstanceState);
uiController.setupUI();
personalIdManagedLogin = getIntent()
.getBooleanExtra(PERSONALID_MANAGED_LOGIN, false);
}

@Override
Expand Down Expand Up @@ -238,6 +240,41 @@ private static Map<Integer, String> createMenuItemToAnalyticsParamMapping() {
return menuIdToAnalyticsEvent;
}

@Override
protected void handleDrawerItemClick(@NonNull BaseDrawerController.NavItemType itemType, String recordId) {
switch (itemType) {
case COMMCARE_APPS -> {
if(recordId != null) {
String currentSeatedId = CommCareApplication.instance().getCurrentApp().getUniqueId();
if(!recordId.equals(currentSeatedId)) {
//Navigate to LoginActivity for selected app
CommCareApplication.instance().closeUserSession();
Intent i = new Intent();
i.putExtra(EXTRA_APP_ID, recordId);
setResult(RESULT_OK, i);
finish();
}
}
}
case OPPORTUNITIES -> {
if(personalIdManagedLogin) {
ConnectNavHelper.INSTANCE.goToConnectJobsList(this);
closeDrawer();
} else {
navigateToConnectMenu();
}
}
case MESSAGING -> {
if(personalIdManagedLogin) {
ConnectNavHelper.INSTANCE.goToMessaging(this);
closeDrawer();
} else {
navigateToMessaging();
}
}
}
}

@Override
public void initUIController() {
uiController = new StandardHomeActivityUIController(this);
Expand Down Expand Up @@ -272,6 +309,11 @@ protected boolean shouldShowDrawer() {
return true;
}

@Override
protected boolean shouldHighlightSeatedApp() {
return true;
}

@Override
public void refreshUI() {
uiController.refreshView();
Expand Down
2 changes: 2 additions & 0 deletions app/src/org/commcare/connect/ConnectConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ public class ConnectConstants {
public static final int COMMCARE_SETUP_CONNECT_LAUNCH_REQUEST_CODE = 1051;
public static final int CONFIGURE_BIOMETRIC_REQUEST_CODE = 1053;
public static final int NETWORK_ACTIVITY_ID = 7000;
public static final String PERSONALID_MANAGED_LOGIN = "personalid-managed-login";
public static final String CONNECT_MANAGED_LOGIN = "connect-managed-login";

public static final String PIN = "PIN";
public static final String CONNECT_KEY_TOKEN = "access_token";
Expand Down
13 changes: 9 additions & 4 deletions app/src/org/commcare/navdrawer/BaseDrawerActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,17 @@ abstract class BaseDrawerActivity<T> : CommCareActivity<T>() {
return false
}

protected open fun shouldHighlightSeatedApp(): Boolean {
return false
}

private fun setupDrawerController() {
val rootView = findViewById<View>(android.R.id.content)
val drawerRefs = DrawerViewRefs(rootView)
drawerController = BaseDrawerController(
this,
drawerRefs
drawerRefs,
shouldHighlightSeatedApp()
) { navItemType: NavItemType, recordId: String? ->
handleDrawerItemClick(navItemType, recordId)
}
Expand All @@ -53,7 +58,7 @@ abstract class BaseDrawerActivity<T> : CommCareActivity<T>() {
}
}

private fun navigateToConnectMenu() {
protected fun navigateToConnectMenu() {
unlockAndGoToConnectJobsList(this, object : ConnectActivityCompleteListener {
override fun connectActivityComplete(success: Boolean) {
if (success) {
Expand All @@ -63,7 +68,7 @@ abstract class BaseDrawerActivity<T> : CommCareActivity<T>() {
})
}

private fun navigateToMessaging() {
protected fun navigateToMessaging() {
unlockAndGoToMessaging(this, object : ConnectActivityCompleteListener {
override fun connectActivityComplete(success: Boolean) {
if (success) {
Expand All @@ -73,7 +78,7 @@ abstract class BaseDrawerActivity<T> : CommCareActivity<T>() {
})
}

private fun closeDrawer() {
protected fun closeDrawer() {
drawerController?.closeDrawer()
}
}
Expand Down
10 changes: 7 additions & 3 deletions app/src/org/commcare/navdrawer/BaseDrawerController.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.commcare.navdrawer
import android.text.SpannableString
import android.text.style.UnderlineSpan
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import androidx.appcompat.app.ActionBarDrawerToggle
Expand All @@ -10,8 +9,8 @@ import androidx.core.view.GravityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import org.commcare.CommCareApplication
import org.commcare.activities.CommCareActivity
import org.commcare.activities.LoginActivity
import org.commcare.connect.ConnectConstants
import org.commcare.connect.PersonalIdManager
import org.commcare.connect.database.ConnectMessagingDatabaseHelper
Expand All @@ -26,6 +25,7 @@ import org.commcare.views.dialogs.DialogCreationHelpers
class BaseDrawerController(
private val activity: CommCareActivity<*>,
private val binding: DrawerViewRefs,
private val highlightSeatedApp: Boolean,
private val onItemClicked: (NavItemType, String?) -> Unit
) {
private lateinit var drawerToggle: ActionBarDrawerToggle
Expand Down Expand Up @@ -129,8 +129,12 @@ class BaseDrawerController(
.error(R.drawable.nav_drawer_person_avatar)
).into(binding.imageUserProfile)

val seatedApp = if(highlightSeatedApp)
CommCareApplication.instance().currentApp.uniqueId else null

val commcareApps = MultipleAppsUtil.getUsableAppRecords().map {
NavDrawerItem.ChildItem(it.displayName, it.uniqueId, NavItemType.COMMCARE_APPS)
NavDrawerItem.ChildItem(it.displayName, it.uniqueId, NavItemType.COMMCARE_APPS,
it.uniqueId == seatedApp)
}
Comment on lines +132 to 138
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Possible NPE when resolving current app; make lookup null-safe

CommCareApplication.instance().currentApp can be null in edge cases (e.g., before an app is seated). Use a null-safe access to avoid crashes and keep highlighting off when no app is seated.

Apply:

-            val seatedApp = if(highlightSeatedApp)
-                CommCareApplication.instance().currentApp.uniqueId else null
+            val seatedApp = if (highlightSeatedApp) {
+                CommCareApplication.instance().currentApp?.uniqueId
+            } else {
+                null
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val seatedApp = if(highlightSeatedApp)
CommCareApplication.instance().currentApp.uniqueId else null
val commcareApps = MultipleAppsUtil.getUsableAppRecords().map {
NavDrawerItem.ChildItem(it.displayName, it.uniqueId, NavItemType.COMMCARE_APPS)
NavDrawerItem.ChildItem(it.displayName, it.uniqueId, NavItemType.COMMCARE_APPS,
it.uniqueId == seatedApp)
}
val seatedApp = if (highlightSeatedApp) {
CommCareApplication.instance().currentApp?.uniqueId
} else {
null
}
val commcareApps = MultipleAppsUtil.getUsableAppRecords().map {
NavDrawerItem.ChildItem(it.displayName, it.uniqueId, NavItemType.COMMCARE_APPS,
it.uniqueId == seatedApp)
}
🤖 Prompt for AI Agents
In app/src/org/commcare/navdrawer/BaseDrawerController.kt around lines 132 to
138, computing seatedApp uses CommCareApplication.instance().currentApp which
can be null; change the lookup to a null-safe access (e.g.,
CommCareApplication.instance().currentApp?.uniqueId) so seatedApp becomes null
when no app is seated, and ensure the highlight condition uses that nullable
value (keep highlighting off when seatedApp is null) to avoid an NPE.


val channels = ConnectMessagingDatabaseHelper.getMessagingChannels(activity)
Expand Down
2 changes: 2 additions & 0 deletions app/src/org/commcare/navdrawer/NavDrawerAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,14 @@ class NavDrawerAdapter(
*/
inner class ChildViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val childText = itemView.findViewById<TextView>(R.id.sublist_title)
private val highlight = itemView.findViewById<ImageView>(R.id.sublist_highlight_icon)

/**
* Binds a child item and sets up click listener.
*/
fun bind(item: NavDrawerItem.ChildItem) {
childText.text = item.childTitle
highlight.visibility = if (item.isHighlighted) View.VISIBLE else View.INVISIBLE
itemView.setOnClickListener { onChildClick(item.parentType, item) }
}
}
Expand Down
3 changes: 2 additions & 1 deletion app/src/org/commcare/navdrawer/NavDrawerParentItem.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ sealed class NavDrawerItem {
data class ChildItem(
val childTitle: String,
val recordId: String,
val parentType: BaseDrawerController.NavItemType
val parentType: BaseDrawerController.NavItemType,
val isHighlighted: Boolean = false
) : NavDrawerItem()
}