This commit is contained in:
Sujal-Gupta-SG 2025-01-28 00:11:31 +05:30
parent 91174778b5
commit 8747226a4d
3 changed files with 85 additions and 124 deletions

View file

@ -1,5 +1,6 @@
package fr.free.nrw.commons.contributions
import android.annotation.SuppressLint
import androidx.paging.PagedList.BoundaryCallback
import fr.free.nrw.commons.auth.SessionManager
import fr.free.nrw.commons.di.CommonsApplicationModule.Companion.IO_THREAD
@ -66,31 +67,34 @@ class ContributionBoundaryCallback
* with either error or success.
*/
private fun fetchContributions(onRefreshFinish: () -> Unit = {}) {
if (sessionManager.userName != null) {
userName
?.let { userName ->
mediaClient
.getMediaListForUser(userName)
.map { mediaList ->
mediaList.map { media ->
Contribution(media = media, state = Contribution.STATE_COMPLETED)
}
}.subscribeOn(ioThreadScheduler)
.subscribe({ list ->
saveContributionsToDB(list, onRefreshFinish)
},{ error ->
onRefreshFinish()
Timber.e(
"Failed to fetch contributions: %s",
error.message,
)
})
}?.let {
compositeDisposable.add(
it,
)
}
sessionManager.userName?.let { userName ->
mediaClient
.getMediaListForUser(userName)
.map { mediaList ->
Timber.d("Mapping media list of size: ${mediaList.size}")
mediaList.map { media ->
Contribution(media = media, state = Contribution.STATE_COMPLETED)
}
}.subscribeOn(ioThreadScheduler)
.subscribe({ list ->
saveContributionsToDB(list, onRefreshFinish)
},{ error ->
Timber.e("Failed to fetch contributions: ${error.message}")
Timber.e(error) // Log full stack trace
onRefreshFinish()
})
}?.let {
compositeDisposable.add(it)
} ?: run {
// Add logging if userName?.let returns null
Timber.d("userName?.let returned null")
}
} else {
Timber.d("SessionManager userName is null, clearing disposable")
compositeDisposable.clear()
}
}

View file

@ -129,11 +129,4 @@ public class ContributionsListPresenter implements UserActionListener {
});
}
/**
* Check for new contributions by comparing the latest contribution identifier.
*/
void fetchContributions() {
contributionBoundaryCallback.refreshList(() -> Unit.INSTANCE);
}
}

View file

@ -1,13 +1,12 @@
package fr.free.nrw.commons.contributions;
import static android.mediautil.MediaUtil.getContext;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@ -23,6 +22,7 @@ import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentManager.OnBackStackChangedListener;
import androidx.work.ExistingWorkPolicy;
import com.google.android.material.bottomnavigation.BottomNavigationView.OnNavigationItemSelectedListener;
import fr.free.nrw.commons.databinding.FragmentContributionsListBinding;
import fr.free.nrw.commons.databinding.MainBinding;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.WelcomeActivity;
@ -42,8 +42,8 @@ import fr.free.nrw.commons.nearby.Place;
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment;
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment.NearbyParentFragmentInstanceReadyCallback;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.notification.NotificationActivity.Companion;
import fr.free.nrw.commons.notification.NotificationController;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.quiz.QuizChecker;
import fr.free.nrw.commons.settings.SettingsFragment;
import fr.free.nrw.commons.theme.BaseActivity;
@ -59,9 +59,11 @@ import io.reactivex.schedulers.Schedulers;
import java.util.Calendar;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import javax.inject.Inject;
import javax.inject.Named;
import kotlin.Unit;
import org.apache.commons.lang3.StringUtils;
import timber.log.Timber;
public class MainActivity extends BaseActivity
@ -95,8 +97,7 @@ public class MainActivity extends BaseActivity
QuizChecker quizChecker;
@Inject
@Named("default_preferences")
public
JsonKvStore applicationKvStore;
public JsonKvStore applicationKvStore;
@Inject
ViewUtilWrapper viewUtilWrapper;
@ -106,6 +107,9 @@ public class MainActivity extends BaseActivity
NavTabLayout tabLayout;
private FragmentContributionsListBinding refresh;
private String userName;
/**
* Consumers should be simply using this method to use this activity.
@ -143,15 +147,7 @@ public class MainActivity extends BaseActivity
binding.toolbarBinding.toolbar.setNavigationOnClickListener(view -> {
onSupportNavigateUp();
});
/*
"first_edit_depict" is a key for getting information about opening the depiction editor
screen for the first time after opening the app.
Getting true by the key means the depiction editor screen is opened for the first time
after opening the app.
Getting false by the key means the depiction editor screen is not opened for the first time
after opening the app.
*/
applicationKvStore.putBoolean("first_edit_depict", true);
if (applicationKvStore.getBoolean("login_skipped") == true) {
setTitle(getString(R.string.navigation_item_explore));
@ -162,8 +158,6 @@ public class MainActivity extends BaseActivity
applicationKvStore.putBoolean("hasAlreadyLaunchedCategoriesDialog", false);
}
if (savedInstanceState == null) {
//starting a fresh fragment.
// Open Last opened screen if it is Contributions or Nearby, otherwise Contributions
if (applicationKvStore.getBoolean("last_opened_nearby")) {
setTitle(getString(R.string.nearby_fragment));
showNearby();
@ -173,22 +167,15 @@ public class MainActivity extends BaseActivity
loadFragment(ContributionsFragment.newInstance(), false);
}
}
refresh = FragmentContributionsListBinding.inflate(getLayoutInflater());
if (getIntent().getExtras() != null) {
userName = getIntent().getExtras().getString(ProfileActivity.KEY_USERNAME);
}
if (StringUtils.isEmpty(userName)) {
userName = sessionManager.getUserName();
}
setUpPager();
/**
* Ask the user for media location access just after login
* so that location in the EXIF metadata of the images shared by the user
* is retained on devices running Android 10 or above
*/
// if (VERSION.SDK_INT >= VERSION_CODES.Q) {
// ActivityCompat.requestPermissions(this,
// new String[]{Manifest.permission.ACCESS_MEDIA_LOCATION}, 0);
// PermissionUtils.checkPermissionsAndPerformAction(
// this,
// () -> {},
// R.string.media_location_permission_denied,
// R.string.add_location_manually,
// permission.ACCESS_MEDIA_LOCATION);
// }
checkAndResumeStuckUploads();
}
}
@ -201,10 +188,8 @@ public class MainActivity extends BaseActivity
binding.fragmentMainNavTabLayout.setOnNavigationItemSelectedListener(
navListener = (item) -> {
if (!item.getTitle().equals(getString(R.string.more))) {
// do not change title for more fragment
setTitle(item.getTitle());
}
// set last_opened_nearby true if item is nearby screen else set false
applicationKvStore.putBoolean("last_opened_nearby",
item.getTitle().equals(getString(R.string.nearby_fragment)));
final Fragment fragment = NavTab.of(item.getOrder()).newInstance();
@ -216,7 +201,6 @@ public class MainActivity extends BaseActivity
loadFragment(ExploreFragment.newInstance(), false);
binding.fragmentMainNavTabLayout.setOnNavigationItemSelectedListener(item -> {
if (!item.getTitle().equals(getString(R.string.more))) {
// do not change title for more fragment
setTitle(item.getTitle());
}
Fragment fragment = NavTabLoggedOut.of(item.getOrder()).newInstance();
@ -225,44 +209,38 @@ public class MainActivity extends BaseActivity
}
private boolean loadFragment(Fragment fragment, boolean showBottom) {
//showBottom so that we do not show the bottom tray again when constructing
//from the saved instance state.
if (fragment instanceof ContributionsFragment) {
if (activeFragment == ActiveFragment.CONTRIBUTIONS) {
// scroll to top if already on the Contributions tab
contributionsFragment.scrollToTop();
return true;
}
contributionsFragment = (ContributionsFragment) fragment;
activeFragment = ActiveFragment.CONTRIBUTIONS;
} else if (fragment instanceof NearbyParentFragment) {
if (activeFragment == ActiveFragment.NEARBY) { // Do nothing if same tab
if (activeFragment == ActiveFragment.NEARBY) {
return true;
}
nearbyParentFragment = (NearbyParentFragment) fragment;
activeFragment = ActiveFragment.NEARBY;
} else if (fragment instanceof ExploreFragment) {
if (activeFragment == ActiveFragment.EXPLORE) { // Do nothing if same tab
if (activeFragment == ActiveFragment.EXPLORE) {
return true;
}
exploreFragment = (ExploreFragment) fragment;
activeFragment = ActiveFragment.EXPLORE;
} else if (fragment instanceof BookmarkFragment) {
if (activeFragment == ActiveFragment.BOOKMARK) { // Do nothing if same tab
if (activeFragment == ActiveFragment.BOOKMARK) {
return true;
}
bookmarkFragment = (BookmarkFragment) fragment;
activeFragment = ActiveFragment.BOOKMARK;
} else if (fragment == null && showBottom) {
if (applicationKvStore.getBoolean("login_skipped")
== true) { // If logged out, more sheet is different
if (applicationKvStore.getBoolean("login_skipped") == true) {
MoreBottomSheetLoggedOutFragment bottomSheet = new MoreBottomSheetLoggedOutFragment();
bottomSheet.show(getSupportFragmentManager(),
"MoreBottomSheetLoggedOut");
bottomSheet.show(getSupportFragmentManager(), "MoreBottomSheetLoggedOut");
} else {
MoreBottomSheetFragment bottomSheet = new MoreBottomSheetFragment();
bottomSheet.show(getSupportFragmentManager(),
"MoreBottomSheet");
bottomSheet.show(getSupportFragmentManager(), "MoreBottomSheet");
}
}
@ -284,12 +262,6 @@ public class MainActivity extends BaseActivity
binding.fragmentMainNavTabLayout.setVisibility(View.VISIBLE);
}
/**
* Adds number of uploads next to tab text "Contributions" then it will look like "Contributions
* (NUMBER)"
*
* @param uploadCount
*/
public void setNumOfUploads(int uploadCount) {
if (activeFragment == ActiveFragment.CONTRIBUTIONS) {
setTitle(getResources().getString(R.string.contributions_fragment) + " " + (
@ -301,15 +273,6 @@ public class MainActivity extends BaseActivity
}
}
/**
* Resume the uploads that got stuck because of the app being killed or the device being
* rebooted.
* <p>
* When the app is terminated or the device is restarted, contributions remain in the
* 'STATE_IN_PROGRESS' state. This status persists and doesn't change during these events. So,
* retrieving contributions labeled as 'STATE_IN_PROGRESS' from the database will provide the
* list of uploads that appear as stuck on opening the app again
*/
@SuppressLint("CheckResult")
private void checkAndResumeStuckUploads() {
List<Contribution> stuckUploads = contributionDao.getContribution(
@ -333,7 +296,6 @@ public class MainActivity extends BaseActivity
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//quizChecker.initQuizCheck(this);
}
@Override
@ -371,22 +333,16 @@ public class MainActivity extends BaseActivity
@Override
public void onBackPressed() {
if (contributionsFragment != null && activeFragment == ActiveFragment.CONTRIBUTIONS) {
// Means that contribution fragment is visible
if (!contributionsFragment.backButtonClicked()) {//If this one does not wan't to handle
// the back press, let the activity do so
if (!contributionsFragment.backButtonClicked()) {
super.onBackPressed();
}
} else if (nearbyParentFragment != null && activeFragment == ActiveFragment.NEARBY) {
// Means that nearby fragment is visible
/* If function nearbyParentFragment.backButtonClick() returns false, it means that the bottomsheet is
not expanded. So if the back button is pressed, then go back to the Contributions tab */
if (!nearbyParentFragment.backButtonClicked()) {
getSupportFragmentManager().beginTransaction().remove(nearbyParentFragment)
.commit();
setSelectedItemId(NavTab.CONTRIBUTIONS.code());
}
} else if (exploreFragment != null && activeFragment == ActiveFragment.EXPLORE) {
// Means that explore fragment is visible
if (!exploreFragment.onBackPressed()) {
if (applicationKvStore.getBoolean("login_skipped")) {
super.onBackPressed();
@ -395,7 +351,6 @@ public class MainActivity extends BaseActivity
}
}
} else if (bookmarkFragment != null && activeFragment == ActiveFragment.BOOKMARK) {
// Means that bookmark fragment is visible
bookmarkFragment.onBackPressed();
} else {
super.onBackPressed();
@ -404,12 +359,8 @@ public class MainActivity extends BaseActivity
@Override
public void onBackStackChanged() {
//initBackButton();
}
/**
* Retry all failed uploads as soon as the user returns to the app
*/
@SuppressLint("CheckResult")
private void retryAllFailedUploads() {
contributionDao.
@ -422,10 +373,6 @@ public class MainActivity extends BaseActivity
});
}
/**
* Handles item selection in the options menu. This method is called when a user interacts with
* the options menu in the Top Bar.
*/
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
@ -436,21 +383,17 @@ public class MainActivity extends BaseActivity
NotificationActivity.Companion.startYourself(this, "unread");
return true;
case R.id.menu_refresh:
// Refresh button handled in onCreateOptionsMenu through action layout
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
menu.clear(); // Clear the old menu to prevent duplication
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.contribution_activity_notification_menu, menu);
// Handle refresh button click
MenuItem refreshItem = menu.findItem(R.id.menu_refresh);
if (refreshItem != null) {
View actionView = refreshItem.getActionView();
@ -462,8 +405,22 @@ public class MainActivity extends BaseActivity
Animation rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.rotate);
v.startAnimation(rotateAnimation);
// Trigger refresh logic
contributionsListPresenter.fetchContributions();
// Initialize userName if it's null
if (userName == null) {
userName = sessionManager.getUserName();
}
if (Objects.equals(sessionManager.getUserName(), userName)) {
if (refresh != null && refresh.swipeRefreshLayout != null) {
refresh.swipeRefreshLayout.setRefreshing(true);
refresh.swipeRefreshLayout.setEnabled(true);
contributionsListPresenter.refreshList(refresh.swipeRefreshLayout);
}
} else {
if (refresh != null && refresh.swipeRefreshLayout != null) {
refresh.swipeRefreshLayout.setEnabled(false);
}
}
});
}
}
@ -486,7 +443,6 @@ public class MainActivity extends BaseActivity
@Override
protected void onResume() {
super.onResume();
// Check if it's the first run and the user hasn't skipped login
if (applicationKvStore.getBoolean("firstrun", true) &&
!applicationKvStore.getBoolean("login_skipped")) {
defaultKvStore.putBoolean("inAppCameraFirstRun", true);
@ -494,22 +450,33 @@ public class MainActivity extends BaseActivity
}
retryAllFailedUploads();
// Background check for new contributions
contributionsListPresenter.fetchContributions();
//check for new contributions
// Initialize userName if it's null
if (userName == null) {
userName = sessionManager.getUserName();
}
if (Objects.equals(sessionManager.getUserName(), userName)) {
if (refresh != null && refresh.swipeRefreshLayout != null) {
refresh.swipeRefreshLayout.setRefreshing(true);
refresh.swipeRefreshLayout.setEnabled(true);
contributionsListPresenter.refreshList(refresh.swipeRefreshLayout);
}
} else {
if (refresh != null && refresh.swipeRefreshLayout != null) {
refresh.swipeRefreshLayout.setEnabled(false);
}
}
}
@Override
protected void onDestroy() {
quizChecker.cleanup();
locationManager.unregisterLocationManager();
// Remove ourself from hashmap to prevent memory leaks
locationManager = null;
super.onDestroy();
}
/**
* Public method to show nearby from the reference of this.
*/
public void showNearby() {
binding.fragmentMainNavTabLayout.setSelectedItemId(NavTab.NEARBY.code());
}
@ -522,9 +489,6 @@ public class MainActivity extends BaseActivity
MORE
}
/**
* Load default language in onCreate from SharedPreferences
*/
private void loadLocale() {
final SharedPreferences preferences = getSharedPreferences("Settings",
Activity.MODE_PRIVATE);
@ -536,4 +500,4 @@ public class MainActivity extends BaseActivity
public OnNavigationItemSelectedListener getNavListener() {
return navListener;
}
}
}