Initial commit (#2956)

* Initial commit

* System Backpress activated

* Removed nav drawer

* Explore feed ui update

* Explore list image ui update

* GridView image list ui update
This commit is contained in:
Sharvani Haran 2019-05-19 09:13:30 +02:00 committed by Vivek Maskara
parent 47047e423d
commit 9dd369e8ce
32 changed files with 1361 additions and 450 deletions

View file

@ -7,7 +7,7 @@ apply from: 'quality.gradle'
def isRunningOnTravisAndIsNotPRBuild = System.getenv("CI") == "true" && file('../play.p12').exists()
if(isRunningOnTravisAndIsNotPRBuild) {
if (isRunningOnTravisAndIsNotPRBuild) {
apply plugin: 'com.github.triplet.play'
}
@ -139,7 +139,7 @@ android {
test.resources.srcDirs += 'src/main/resoures'
}
signingConfigs {
signingConfigs {
release
}
@ -148,7 +148,7 @@ android {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
testProguardFile 'test-proguard-rules.txt'
if(isRunningOnTravisAndIsNotPRBuild) {
if (isRunningOnTravisAndIsNotPRBuild) {
signingConfig signingConfigs.release
}
}
@ -160,7 +160,7 @@ android {
versionNameSuffix "-debug-" + getBranchName()
}
}
if (isRunningOnTravisAndIsNotPRBuild) {
// configure keystore based on env vars in Travis for automated alpha builds
signingConfigs.release.storeFile = file("../nr-commons.keystore")
@ -177,7 +177,7 @@ android {
productFlavors {
prod {
applicationId 'fr.free.nrw.commons'
applicationId 'fr.free.nrw.commons'
buildConfigField "String", "WIKIMEDIA_API_POTD", "\"https://commons.wikimedia.org/w/api.php?action=featuredfeed&feed=potd&feedformat=rss&language=en\""
buildConfigField "String", "WIKIMEDIA_API_HOST", "\"https://commons.wikimedia.org/w/api.php\""
@ -252,7 +252,7 @@ android {
buildToolsVersion buildToolsVersion
}
if(isRunningOnTravisAndIsNotPRBuild) {
if (isRunningOnTravisAndIsNotPRBuild) {
play {
track = "alpha"
userFraction = 1

View file

@ -209,7 +209,8 @@ public class BookmarkPicturesFragment extends DaggerFragment {
gridAdapter = new GridViewAdapter(
this.getContext(),
R.layout.layout_category_images,
mediaList
mediaList,
false
);
gridView.setAdapter(gridAdapter);
}

View file

@ -13,13 +13,14 @@ import android.widget.ProgressBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import javax.inject.Named;
import androidx.annotation.Nullable;
import butterknife.BindView;
import butterknife.ButterKnife;
import dagger.android.support.DaggerFragment;
@ -55,12 +56,20 @@ public class CategoryImagesListFragment extends DaggerFragment {
private boolean hasMoreImages = true;
private boolean isLoading = true;
private String categoryName = null;
private AdapterView.OnItemClickListener listener;
@Inject CategoryImageController controller;
@Inject
@Named("default_preferences")
JsonKvStore categoryKvStore;
public CategoryImagesListFragment(){
}
public CategoryImagesListFragment(AdapterView.OnItemClickListener listener){
this.listener = listener;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_category_images, container, false);
@ -71,7 +80,7 @@ public class CategoryImagesListFragment extends DaggerFragment {
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
gridView.setOnItemClickListener((AdapterView.OnItemClickListener) getActivity());
gridView.setOnItemClickListener(listener==null?((AdapterView.OnItemClickListener) getActivity()):listener);
initViews();
}
@ -169,7 +178,7 @@ public class CategoryImagesListFragment extends DaggerFragment {
* @param mediaList List of new Media to be displayed
*/
private void setAdapter(List<Media> mediaList) {
gridAdapter = new GridViewAdapter(this.getContext(), R.layout.layout_category_images, mediaList);
gridAdapter = new GridViewAdapter(this.getContext(), R.layout.layout_category_images, mediaList, true);
gridView.setAdapter(gridAdapter);
}

View file

@ -6,6 +6,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.facebook.drawee.view.SimpleDraweeView;
@ -23,15 +24,18 @@ import fr.free.nrw.commons.R;
public class GridViewAdapter extends ArrayAdapter {
private List<Media> data;
private boolean showSecondaryViews;
public GridViewAdapter(Context context, int layoutResourceId, List<Media> data) {
public GridViewAdapter(Context context, int layoutResourceId, List<Media> data, boolean showSecondaryViews) {
super(context, layoutResourceId, data);
this.data = data;
this.showSecondaryViews = showSecondaryViews;
}
/**
* Adds more item to the list
* Its triggered on scrolling down in the list
*
* @param images
*/
public void addItems(List<Media> images) {
@ -45,9 +49,10 @@ public class GridViewAdapter extends ArrayAdapter {
/**
* Check the first item in the new list with old list and returns true if they are same
* Its triggered on successful response of the fetch images API.
*
* @param images
*/
public boolean containsAll(List<Media> images){
public boolean containsAll(List<Media> images) {
if (images == null || images.isEmpty()) {
return false;
}
@ -70,6 +75,7 @@ public class GridViewAdapter extends ArrayAdapter {
/**
* Sets up the UI for the category image item
*
* @param position
* @param convertView
* @param parent
@ -86,14 +92,20 @@ public class GridViewAdapter extends ArrayAdapter {
SimpleDraweeView imageView = convertView.findViewById(R.id.categoryImageView);
TextView fileName = convertView.findViewById(R.id.categoryImageTitle);
TextView author = convertView.findViewById(R.id.categoryImageAuthor);
ImageView favoriteImage = convertView.findViewById(R.id.favorite);
ImageView downloadImage = convertView.findViewById(R.id.download);
favoriteImage.setVisibility(showSecondaryViews ? View.VISIBLE : View.GONE);
downloadImage.setVisibility(showSecondaryViews ? View.VISIBLE : View.GONE);
fileName.setText(item.getDisplayTitle());
setAuthorView(item, author);
imageView.setImageURI(item.getThumbUrl());
return convertView;
}
/**
* Shows author information if its present
*
* @param item
* @param author
*/

View file

@ -459,7 +459,7 @@ public class ContributionsFragment
return;
}
((MainActivity)getActivity()).setNumOfUploads(uploadCount);
// ((MainActivity)getActivity()).setNumOfUploads(uploadCount);
}

View file

@ -0,0 +1,572 @@
package fr.free.nrw.commons.contributions;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import java.util.List;
import javax.inject.Inject;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.nearby.NearbyFragment;
import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.notification.NotificationController;
import fr.free.nrw.commons.quiz.QuizChecker;
import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import timber.log.Timber;
import static fr.free.nrw.commons.location.LocationServiceManager.LOCATION_REQUEST;
/**
* A simple {@link Fragment} subclass.
* Activities that contain this fragment must implement the
* to handle interaction events.
*/
public class ContributionsMainFragment extends CommonsDaggerSupportFragment implements FragmentManager.OnBackStackChangedListener {
@Inject
SessionManager sessionManager;
@Inject
ContributionController controller;
@BindView(R.id.tab_layout)
TabLayout tabLayout;
@BindView(R.id.ContPager)
public UnswipableViewPager viewPager;
@Inject
public LocationServiceManager locationManager;
@Inject
NotificationController notificationController;
@Inject
QuizChecker quizChecker;
public Intent uploadServiceIntent;
public boolean isAuthCookieAcquired = false;
public ContributionsActivityPagerAdapter contributionsActivityPagerAdapter;
public final int CONTRIBUTIONS_TAB_POSITION = 0;
public final int NEARBY_TAB_POSITION = 1;
public boolean isContributionsFragmentVisible = true; // False means nearby fragment is visible
private Menu menu;
private boolean onOrientationChanged = false;
private MenuItem notificationsMenuItem;
private TextView notificationCount;
public ContributionsMainFragment() {
// Required empty public constructor
}
@NonNull
public static ContributionsMainFragment newInstance() {
ContributionsMainFragment fragment = new ContributionsMainFragment();
fragment.setRetainInstance(true);
return fragment;
}
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/*Todo: after
requestAuthToken();
initDrawer();
setTitle(getString(R.string.navigation_item_home)); // Should I create a new string variable with another name instead?
if (savedInstanceState != null) {
onOrientationChanged = true; // Will be used in nearby fragment to determine significant update of map
//If nearby map was visible, call on Tab Selected to call all nearby operations
*//*if (savedInstanceState.getInt("viewPagerCurrentItem") == 1) {
((NearbyFragment)contributionsActivityPagerAdapter.getItem(1)).onTabSelected(onOrientationChanged);
}*//*
}
*/
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_contributions, container, false);
ButterKnife.bind(this, view);
addTabsAndFragments();
return view;
}
/*//Todo: after might need to go to activity
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt("viewPagerCurrentItem", viewPager.getCurrentItem());
}
@Override
protected void onAuthCookieAcquired(String authCookie) {
// Do a sync everytime we get here!
requestSync(sessionManager.getCurrentAccount(), BuildConfig.CONTRIBUTION_AUTHORITY, new Bundle());
uploadServiceIntent = new Intent(requireActivity(), UploadService.class);
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
requireActivity().startService(uploadServiceIntent);
addTabsAndFragments();
isAuthCookieAcquired = true;
if (contributionsActivityPagerAdapter.getItem(0) != null) {
((ContributionsFragment) contributionsActivityPagerAdapter.getItem(0)).onAuthCookieAcquired(uploadServiceIntent);
}
}*/
private void addTabsAndFragments() {
contributionsActivityPagerAdapter = new ContributionsActivityPagerAdapter(requireActivity().getSupportFragmentManager());
viewPager.setAdapter(contributionsActivityPagerAdapter);
tabLayout.addTab(tabLayout.newTab().setText(getResources().getString(R.string.contributions_fragment)));
tabLayout.addTab(tabLayout.newTab().setText(getResources().getString(R.string.nearby_fragment)));
// Set custom view to add nearby info icon next to text
View nearbyTabLinearLayout = LayoutInflater.from(requireActivity()).inflate(R.layout.custom_nearby_tab_layout, null);
ImageView nearbyInfo = nearbyTabLinearLayout.findViewById(R.id.nearby_info_image);
tabLayout.getTabAt(1).setCustomView(nearbyTabLinearLayout);
nearbyInfo.setOnClickListener(view ->
new AlertDialog.Builder(requireActivity()).setTitle(R.string.title_activity_nearby).setMessage(R.string.showcase_view_whole_nearby_activity)
.setCancelable(true)
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
.create()
.show()
);
if (uploadServiceIntent != null) {
// If auth cookie already acquired notify contrib fragment so that it san operate auth required actions
((ContributionsFragment) contributionsActivityPagerAdapter.getItem(CONTRIBUTIONS_TAB_POSITION)).onAuthCookieAcquired(uploadServiceIntent);
}
setTabAndViewPagerSynchronisation();
}
/**
* Adds number of uploads next to tab text "Contributions" then it will look like
* "Contributions (NUMBER)"
*
* @param uploadCount
*/
public void setNumOfUploads(int uploadCount) {
tabLayout.getTabAt(0).setText(getResources().getString(R.string.contributions_fragment) + " " + getResources()
.getQuantityString(R.plurals.contributions_subtitle,
uploadCount, uploadCount));
}
/**
* Normally tab layout and view pager has no relation, which means when you swipe view pager
* tab won't change and vice versa. So we have to notify each of them.
*/
private void setTabAndViewPagerSynchronisation() {
//viewPager.canScrollHorizontally(false);
viewPager.setFocusableInTouchMode(true);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position) {
case CONTRIBUTIONS_TAB_POSITION:
Timber.d("Contributions tab selected");
tabLayout.getTabAt(CONTRIBUTIONS_TAB_POSITION).select();
isContributionsFragmentVisible = true;
updateMenuItem();
break;
case NEARBY_TAB_POSITION:
Timber.d("Nearby tab selected");
tabLayout.getTabAt(NEARBY_TAB_POSITION).select();
isContributionsFragmentVisible = false;
updateMenuItem();
// Do all permission and GPS related tasks on tab selected, not on create
((NearbyFragment) contributionsActivityPagerAdapter.getItem(1)).onTabSelected(onOrientationChanged);
break;
default:
tabLayout.getTabAt(CONTRIBUTIONS_TAB_POSITION).select();
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
public void hideTabs() {
//Todo: after changeDrawerIconToBackButton();
if (tabLayout != null) {
tabLayout.setVisibility(View.GONE);
}
}
public void showTabs() {
// Todo: afterchangeDrawerIconToDefault();
if (tabLayout != null) {
tabLayout.setVisibility(View.VISIBLE);
}
}
/* //Todo: after
@Override
protected void onAuthFailure() {
}*/
/* //Todo: after
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
String contributionsFragmentTag = ((MainActivity.ContributionsActivityPagerAdapter) viewPager.getAdapter()).makeFragmentName(R.id.pager, 0);
String nearbyFragmentTag = ((MainActivity.ContributionsActivityPagerAdapter) viewPager.getAdapter()).makeFragmentName(R.id.pager, 1);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (getSupportFragmentManager().findFragmentByTag(contributionsFragmentTag) != null && isContributionsFragmentVisible) {
// Meas that contribution fragment is visible (not nearby fragment)
ContributionsFragment contributionsFragment = (ContributionsFragment) getSupportFragmentManager().findFragmentByTag(contributionsFragmentTag);
if (contributionsFragment.getChildFragmentManager().findFragmentByTag(ContributionsFragment.MEDIA_DETAIL_PAGER_FRAGMENT_TAG) != null) {
// Means that media details fragment is visible to uer instead of contributions list fragment (As chils fragment)
// Then we want to go back to contributions list fragment on backbutton pressed from media detail fragment
contributionsFragment.getChildFragmentManager().popBackStack();
// Tabs were invisible when Media Details Fragment is active, make them visible again on Contrib List Fragment active
showTabs();
// Nearby Notification Card View was invisible when Media Details Fragment is active, make it visible again on Contrib List Fragment active, according to preferences
if (defaultKvStore.getBoolean("displayNearbyCardView", true)) {
if (contributionsFragment.nearbyNotificationCardView.cardViewVisibilityState == NearbyNotificationCardView.CardViewVisibilityState.READY) {
contributionsFragment.nearbyNotificationCardView.setVisibility(View.VISIBLE);
}
} else {
contributionsFragment.nearbyNotificationCardView.setVisibility(View.GONE);
}
} else {
finish();
}
} else if (getSupportFragmentManager().findFragmentByTag(nearbyFragmentTag) != null && !isContributionsFragmentVisible) {
// Means that nearby fragment is visible (not contributions fragment)
NearbyFragment nearbyFragment = (NearbyFragment) contributionsActivityPagerAdapter.getItem(1);
if (nearbyFragment.isBottomSheetExpanded()) {
// Back should first hide the bottom sheet if it is expanded
nearbyFragment.listOptionMenuItemClicked();
} else {
// Otherwise go back to contributions fragment
viewPager.setCurrentItem(0);
}
} else {
super.onBackPressed();
}
}*/
@Override
public void onBackStackChanged() {
//Todo: after requireActivity().initBackButton();
}
/* //Todo: afetr activity needs to do it
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.contribution_activity_notification_menu, menu);
notificationsMenuItem = menu.findItem(R.id.notifications);
final View notification = notificationsMenuItem.getActionView();
notificationCount = notification.findViewById(R.id.notification_count_badge);
notification.setOnClickListener(view -> {
NotificationActivity.startYourself(MainActivity.this, "unread");
});
this.menu = menu;
updateMenuItem();
setNotificationCount();
return true;
}*/
@SuppressLint("CheckResult")
private void setNotificationCount() {
//Todo: afetr check the compositeDisposable instantiation
((MainActivity) requireActivity()).compositeDisposable.add(Observable.fromCallable(() -> notificationController.getNotifications(false))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::initNotificationViews,
throwable -> Timber.e(throwable, "Error occurred while loading notifications")));
}
private void initNotificationViews(List<Notification> notificationList) {
Timber.d("Number of notifications is %d", notificationList.size());
if (notificationList.isEmpty()) {
notificationCount.setVisibility(View.GONE);
} else {
notificationCount.setVisibility(View.VISIBLE);
notificationCount.setText(String.valueOf(notificationList.size()));
}
}
/**
* Responsible with displaying required menu items according to displayed fragment.
* Notifications icon when contributions list is visible, list sheet icon when nearby is visible
*/
private void updateMenuItem() {
if (menu != null) {
if (isContributionsFragmentVisible) {
// Display notifications menu item
menu.findItem(R.id.notifications).setVisible(true);
menu.findItem(R.id.list_sheet).setVisible(false);
Timber.d("Contributions activity notifications menu item is visible");
} else {
// Display bottom list menu item
menu.findItem(R.id.notifications).setVisible(false);
menu.findItem(R.id.list_sheet).setVisible(true);
Timber.d("Contributions activity list sheet menu item is visible");
}
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.notifications:
// Starts notification activity on click to notification icon
NotificationActivity.startYourself(requireActivity(), "unread");
return true;
case R.id.list_sheet:
if (contributionsActivityPagerAdapter.getItem(1) != null) {
((NearbyFragment) contributionsActivityPagerAdapter.getItem(1)).listOptionMenuItemClicked();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private boolean deviceHasCamera() {
PackageManager pm = requireActivity().getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA) ||
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
}
public class ContributionsActivityPagerAdapter extends FragmentPagerAdapter {
FragmentManager fragmentManager;
private boolean isContributionsListFragment = true; // to know what to put in first tab, Contributions of Media Details
public ContributionsActivityPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
this.fragmentManager = fragmentManager;
}
@Override
public int getCount() {
return 2;
}
/*
* Do not use getItem method to access fragments on pager adapter. User reference variables
* instead.
* */
@Override
public Fragment getItem(int position) {
switch (position) {
case 0:
ContributionsFragment retainedContributionsFragment = getContributionsFragment(0);
if (retainedContributionsFragment != null) {
// ContributionsFragment is parent of ContributionsListFragment and
// MediaDetailsFragment. If below decides which child will be visible.
if (isContributionsListFragment) {
retainedContributionsFragment.setContributionsListFragment();
} else {
retainedContributionsFragment.setMediaDetailPagerFragment();
}
return retainedContributionsFragment;
} else {
// If we reach here, retainedContributionsFragment is null
return new ContributionsFragment();
}
case 1:
NearbyFragment retainedNearbyFragment = getNearbyFragment(1);
if (retainedNearbyFragment != null) {
return retainedNearbyFragment;
} else {
// If we reach here, retainedNearbyFragment is null
return new NearbyFragment();
}
default:
return null;
}
}
/**
* Generates fragment tag with makeFragmentName method to get retained contributions fragment
*
* @param position index of tabs, in our case 0 or 1
* @return
*/
private ContributionsFragment getContributionsFragment(int position) {
String tag = makeFragmentName(R.id.ContPager, position);
return (ContributionsFragment) fragmentManager.findFragmentByTag(tag);
}
/**
* Generates fragment tag with makeFragmentName method to get retained nearby fragment
*
* @param position index of tabs, in our case 0 or 1
* @return
*/
private NearbyFragment getNearbyFragment(int position) {
String tag = makeFragmentName(R.id.ContPager, position);
return (NearbyFragment) fragmentManager.findFragmentByTag(tag);
}
/**
* A simple hack to use retained fragment when getID is called explicitly, if we don't use
* this method, a new fragment will be initialized on each explicit calls of getID
*
* @param viewId id of view pager
* @param index index of tabs, in our case 0 or 1
* @return
*/
public String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
/**
* In first tab we can have ContributionsFragment or Media details fragment. This method
* is responsible to update related boolean
*
* @param isContributionsListFragment true when contribution fragment should be visible, false
* means user clicked to MediaDetails
*/
private void updateContributionFragmentTabContent(boolean isContributionsListFragment) {
this.isContributionsListFragment = isContributionsListFragment;
}
}
/* Todo: after Activity might need to handle this
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Timber.d(data != null ? data.toString() : "onActivityResult data is null");
super.onActivityResult(requestCode, resultCode, data);
controller.handleActivityResult(this, requestCode, resultCode, data);
}*/
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case LOCATION_REQUEST: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Location permission given");
((ContributionsFragment) contributionsActivityPagerAdapter
.getItem(0)).locationManager.registerLocationManager();
} else {
// If nearby fragment is visible and location permission is not given, send user back to contrib fragment
if (!isContributionsFragmentVisible) {
viewPager.setCurrentItem(CONTRIBUTIONS_TAB_POSITION);
// TODO: If contrib fragment is visible and location permission is not given, display permission request button
} else {
}
}
return;
}
default:
return;
}
}
/* Todo: after might need to go into attach and detach
@Override
protected void onResume() {
super.onResume();
setNotificationCount();
quizChecker.initQuizCheck(this);
}
@Override
protected void onDestroy() {
quizChecker.cleanup();
locationManager.unregisterLocationManager();
// Remove ourself from hashmap to prevent memory leaks
locationManager = null;
super.onDestroy();
}*/
@Override
public void onAttach(Context context) {
super.onAttach(context);
}
@Override
public void onDetach() {
super.onDetach();
}
}

View file

@ -1,30 +1,19 @@
package fr.free.nrw.commons.contributions;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.widget.ImageView;
import android.widget.AdapterView;
import android.widget.TextView;
import com.google.android.material.tabs.TabLayout;
import androidx.fragment.app.FragmentManager;
import java.util.List;
import javax.inject.Inject;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.BuildConfig;
@ -32,10 +21,10 @@ import fr.free.nrw.commons.R;
import fr.free.nrw.commons.auth.AuthenticatedActivity;
import fr.free.nrw.commons.auth.SessionManager;
import fr.free.nrw.commons.location.LocationServiceManager;
import fr.free.nrw.commons.nearby.NearbyFragment;
import fr.free.nrw.commons.nearby.NearbyNotificationCardView;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
import fr.free.nrw.commons.navtab.NavTabFragmentPagerAdapter;
import fr.free.nrw.commons.navtab.NavTabLayout;
import fr.free.nrw.commons.notification.Notification;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.notification.NotificationController;
import fr.free.nrw.commons.quiz.QuizChecker;
import fr.free.nrw.commons.upload.UploadService;
@ -47,15 +36,20 @@ import timber.log.Timber;
import static android.content.ContentResolver.requestSync;
import static fr.free.nrw.commons.location.LocationServiceManager.LOCATION_REQUEST;
public class MainActivity extends AuthenticatedActivity implements FragmentManager.OnBackStackChangedListener {
public class MainActivity extends AuthenticatedActivity implements FragmentManager.OnBackStackChangedListener , AdapterView.OnItemClickListener{
@Inject
SessionManager sessionManager;
@Inject ContributionController controller;
@BindView(R.id.tab_layout)
TabLayout tabLayout;
@Inject
ContributionController controller;
@BindView(R.id.pager)
public UnswipableViewPager viewPager;
@BindView(R.id.fragment_main_nav_tab_layout)
NavTabLayout tabLayout;
private MediaDetailPagerFragment mediaDetails;
@Inject
public LocationServiceManager locationManager;
@Inject
@ -67,12 +61,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
public Intent uploadServiceIntent;
public boolean isAuthCookieAcquired = false;
public ContributionsActivityPagerAdapter contributionsActivityPagerAdapter;
public final int CONTRIBUTIONS_TAB_POSITION = 0;
public final int NEARBY_TAB_POSITION = 1;
public boolean isContributionsFragmentVisible = true; // False means nearby fragment is visible
private Menu menu;
private boolean onOrientationChanged = false;
@ -81,15 +71,15 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_contributions);
setContentView(R.layout.main);
ButterKnife.bind(this);
requestAuthToken();
initDrawer();
setTitle(getString(R.string.navigation_item_home)); // Should I create a new string variable with another name instead?
setUpPager();
if (savedInstanceState != null ) {
if (savedInstanceState != null) {
onOrientationChanged = true; // Will be used in nearby fragment to determine significant update of map
//If nearby map was visible, call on Tab Selected to call all nearby operations
@ -99,6 +89,17 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
}
}
private void setUpPager() {
viewPager.setAdapter(new NavTabFragmentPagerAdapter(getSupportFragmentManager()));
viewPager.setOffscreenPageLimit(2);
tabLayout.setOnNavigationItemSelectedListener(item -> {
viewPager.setCurrentItem(item.getOrder());
return true;
});
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
@ -113,126 +114,13 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
uploadServiceIntent.setAction(UploadService.ACTION_START_SERVICE);
startService(uploadServiceIntent);
addTabsAndFragments();
//Todo: after needs to happen at addTabsAndFragments();
isAuthCookieAcquired = true;
if (contributionsActivityPagerAdapter.getItem(0) != null) {
/*if (contributionsActivityPagerAdapter.getItem(0) != null) {
((ContributionsFragment)contributionsActivityPagerAdapter.getItem(0)).onAuthCookieAcquired(uploadServiceIntent);
}
}*/
}
private void addTabsAndFragments() {
contributionsActivityPagerAdapter = new ContributionsActivityPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(contributionsActivityPagerAdapter);
tabLayout.addTab(tabLayout.newTab().setText(getResources().getString(R.string.contributions_fragment)));
tabLayout.addTab(tabLayout.newTab().setText(getResources().getString(R.string.nearby_fragment)));
// Set custom view to add nearby info icon next to text
View nearbyTabLinearLayout = LayoutInflater.from(this).inflate(R.layout.custom_nearby_tab_layout, null);
ImageView nearbyInfo = nearbyTabLinearLayout.findViewById(R.id.nearby_info_image);
tabLayout.getTabAt(1).setCustomView(nearbyTabLinearLayout);
nearbyInfo.setOnClickListener(view ->
new AlertDialog.Builder(MainActivity.this).setTitle(R.string.title_activity_nearby).setMessage(R.string.showcase_view_whole_nearby_activity)
.setCancelable(true)
.setPositiveButton(android.R.string.ok, (dialog, id) -> dialog.cancel())
.create()
.show()
);
if (uploadServiceIntent != null) {
// If auth cookie already acquired notify contrib fragment so that it san operate auth required actions
((ContributionsFragment)contributionsActivityPagerAdapter.getItem(CONTRIBUTIONS_TAB_POSITION)).onAuthCookieAcquired(uploadServiceIntent);
}
setTabAndViewPagerSynchronisation();
}
/**
* Adds number of uploads next to tab text "Contributions" then it will look like
* "Contributions (NUMBER)"
* @param uploadCount
*/
public void setNumOfUploads(int uploadCount) {
tabLayout.getTabAt(0).setText(getResources().getString(R.string.contributions_fragment) +" "+ getResources()
.getQuantityString(R.plurals.contributions_subtitle,
uploadCount, uploadCount));
}
/**
* Normally tab layout and view pager has no relation, which means when you swipe view pager
* tab won't change and vice versa. So we have to notify each of them.
*/
private void setTabAndViewPagerSynchronisation() {
//viewPager.canScrollHorizontally(false);
viewPager.setFocusableInTouchMode(true);
viewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
switch (position) {
case CONTRIBUTIONS_TAB_POSITION:
Timber.d("Contributions tab selected");
tabLayout.getTabAt(CONTRIBUTIONS_TAB_POSITION).select();
isContributionsFragmentVisible = true;
updateMenuItem();
break;
case NEARBY_TAB_POSITION:
Timber.d("Nearby tab selected");
tabLayout.getTabAt(NEARBY_TAB_POSITION).select();
isContributionsFragmentVisible = false;
updateMenuItem();
// Do all permission and GPS related tasks on tab selected, not on create
((NearbyFragment)contributionsActivityPagerAdapter.getItem(1)).onTabSelected(onOrientationChanged);
break;
default:
tabLayout.getTabAt(CONTRIBUTIONS_TAB_POSITION).select();
break;
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager.setCurrentItem(tab.getPosition());
}
@Override
public void onTabUnselected(TabLayout.Tab tab) {
}
@Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
}
public void hideTabs() {
changeDrawerIconToBackButton();
if (tabLayout != null) {
tabLayout.setVisibility(View.GONE);
}
}
public void showTabs() {
changeDrawerIconToDefault();
if (tabLayout != null) {
tabLayout.setVisibility(View.VISIBLE);
}
}
@Override
protected void onAuthFailure() {
@ -241,7 +129,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
/* Todo: after stability
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
String contributionsFragmentTag = ((ContributionsActivityPagerAdapter) viewPager.getAdapter()).makeFragmentName(R.id.pager, 0);
String nearbyFragmentTag = ((ContributionsActivityPagerAdapter) viewPager.getAdapter()).makeFragmentName(R.id.pager, 1);
if (drawer.isDrawerOpen(GravityCompat.START)) {
@ -278,9 +167,9 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
// Otherwise go back to contributions fragment
viewPager.setCurrentItem(0);
}
} else {
} else {*/
super.onBackPressed();
}
}
@Override
@ -288,7 +177,8 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
initBackButton();
}
@Override
/* Todo: after set up menu
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.contribution_activity_notification_menu, menu);
@ -300,10 +190,10 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
NotificationActivity.startYourself(MainActivity.this, "unread");
});
this.menu = menu;
updateMenuItem();
//updateMenuItem();
setNotificationCount();
return true;
}
}*/
@SuppressLint("CheckResult")
private void setNotificationCount() {
@ -315,19 +205,23 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
}
private void initNotificationViews(List<Notification> notificationList) {
Timber.d("Number of notifications is %d", notificationList.size());
/* Timber.d("Number of notifications is %d", notificationList.size());
if (notificationList.isEmpty()) {
notificationCount.setVisibility(View.GONE);
} else {
notificationCount.setVisibility(View.VISIBLE);
//notificationCount.setVisibility(View.VISIBLE);
notificationCount.setText(String.valueOf(notificationList.size()));
}
}*/
}
/*Todo: after set up menu
*/
/**
* Responsible with displaying required menu items according to displayed fragment.
* Notifications icon when contributions list is visible, list sheet icon when nearby is visible
*/
*//*
private void updateMenuItem() {
if (menu != null) {
if (isContributionsFragmentVisible) {
@ -360,110 +254,10 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
return super.onOptionsItemSelected(item);
}
}
private boolean deviceHasCamera() {
PackageManager pm = getPackageManager();
return pm.hasSystemFeature(PackageManager.FEATURE_CAMERA) ||
pm.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
}
public class ContributionsActivityPagerAdapter extends FragmentPagerAdapter {
FragmentManager fragmentManager;
private boolean isContributionsListFragment = true; // to know what to put in first tab, Contributions of Media Details
public ContributionsActivityPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
this.fragmentManager = fragmentManager;
}
@Override
public int getCount() {
return 2;
}
/*
* Do not use getItem method to access fragments on pager adapter. User reference variables
* instead.
* */
@Override
public Fragment getItem(int position) {
switch (position){
case 0:
ContributionsFragment retainedContributionsFragment = getContributionsFragment(0);
if (retainedContributionsFragment != null) {
// ContributionsFragment is parent of ContributionsListFragment and
// MediaDetailsFragment. If below decides which child will be visible.
if (isContributionsListFragment) {
retainedContributionsFragment.setContributionsListFragment();
} else {
retainedContributionsFragment.setMediaDetailPagerFragment();
}
return retainedContributionsFragment;
} else {
// If we reach here, retainedContributionsFragment is null
return new ContributionsFragment();
}
case 1:
NearbyFragment retainedNearbyFragment = getNearbyFragment(1);
if (retainedNearbyFragment != null) {
return retainedNearbyFragment;
} else {
// If we reach here, retainedNearbyFragment is null
return new NearbyFragment();
}
default:
return null;
}
}
/**
* Generates fragment tag with makeFragmentName method to get retained contributions fragment
* @param position index of tabs, in our case 0 or 1
* @return
*/
private ContributionsFragment getContributionsFragment(int position) {
String tag = makeFragmentName(R.id.pager, position);
return (ContributionsFragment)fragmentManager.findFragmentByTag(tag);
}
/**
* Generates fragment tag with makeFragmentName method to get retained nearby fragment
* @param position index of tabs, in our case 0 or 1
* @return
*/
private NearbyFragment getNearbyFragment(int position) {
String tag = makeFragmentName(R.id.pager, position);
return (NearbyFragment)fragmentManager.findFragmentByTag(tag);
}
/**
* A simple hack to use retained fragment when getID is called explicitly, if we don't use
* this method, a new fragment will be initialized on each explicit calls of getID
* @param viewId id of view pager
* @param index index of tabs, in our case 0 or 1
* @return
*/
public String makeFragmentName(int viewId, int index) {
return "android:switcher:" + viewId + ":" + index;
}
/**
* In first tab we can have ContributionsFragment or Media details fragment. This method
* is responsible to update related boolean
* @param isContributionsListFragment true when contribution fragment should be visible, false
* means user clicked to MediaDetails
*/
private void updateContributionFragmentTabContent(boolean isContributionsListFragment) {
this.isContributionsListFragment = isContributionsListFragment;
}
}
*/
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Timber.d(data!=null?data.toString():"onActivityResult data is null");
Timber.d(data != null ? data.toString() : "onActivityResult data is null");
super.onActivityResult(requestCode, resultCode, data);
controller.handleActivityResult(this, requestCode, resultCode, data);
}
@ -473,8 +267,9 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
String permissions[], int[] grantResults) {
switch (requestCode) {
case LOCATION_REQUEST: {
//Todo after set this right
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0
/* if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Timber.d("Location permission given");
((ContributionsFragment)contributionsActivityPagerAdapter
@ -486,7 +281,7 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
// TODO: If contrib fragment is visible and location permission is not given, display permission request button
}
}
}*/
return;
}
@ -495,6 +290,21 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
}
}
public void hideTabs() {
changeDrawerIconToBackButton();
if (tabLayout != null) {
tabLayout.setVisibility(View.GONE);
}
}
public void showTabs() {
changeDrawerIconToDefault();
if (tabLayout != null) {
tabLayout.setVisibility(View.VISIBLE);
}
}
@Override
protected void onResume() {
super.onResume();
@ -510,4 +320,29 @@ public class MainActivity extends AuthenticatedActivity implements FragmentManag
locationManager = null;
super.onDestroy();
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int i, long id) {
if (mediaDetails == null || !mediaDetails.isVisible()) {
// set isFeaturedImage true for featured images, to include author field on media detail
mediaDetails = new MediaDetailPagerFragment(false, true);
FragmentManager supportFragmentManager = getSupportFragmentManager();
supportFragmentManager
.beginTransaction()
.hide(supportFragmentManager.getFragments().get(supportFragmentManager.getBackStackEntryCount()))
.add(R.id.fragmentContainer, mediaDetails)
.addToBackStack(null)
.commit();
// Reason for using hide, add instead of replace is to maintain scroll position after
// coming back to the search activity. See https://github.com/commons-app/apps-android-commons/issues/1631
// https://stackoverflow.com/questions/11353075/how-can-i-maintain-fragment-state-when-added-to-the-back-stack/19022550#19022550 supportFragmentManager.executePendingTransactions();
}
mediaDetails.showImage(i);
forceInitBackButton();
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
}

View file

@ -9,6 +9,8 @@ import fr.free.nrw.commons.category.CategoryImagesListFragment;
import fr.free.nrw.commons.category.SubCategoryListFragment;
import fr.free.nrw.commons.contributions.ContributionsFragment;
import fr.free.nrw.commons.contributions.ContributionsListFragment;
import fr.free.nrw.commons.contributions.ContributionsMainFragment;
import fr.free.nrw.commons.explore.ExploreFragment;
import fr.free.nrw.commons.explore.categories.SearchCategoryFragment;
import fr.free.nrw.commons.explore.images.SearchImageFragment;
import fr.free.nrw.commons.explore.recentsearches.RecentSearchesFragment;
@ -27,6 +29,13 @@ public abstract class FragmentBuilderModule {
@ContributesAndroidInjector
abstract ContributionsListFragment bindContributionsListFragment();
@ContributesAndroidInjector
abstract ExploreFragment bindExploreFragment();
@ContributesAndroidInjector
abstract ContributionsMainFragment bindContributionsMainFragment();
@ContributesAndroidInjector
abstract MediaDetailFragment bindMediaDetailFragment();

View file

@ -0,0 +1,265 @@
package fr.free.nrw.commons.explore;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import dagger.Provides;
import fr.free.nrw.commons.Media;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.category.CategoryImagesListFragment;
import fr.free.nrw.commons.di.CommonsDaggerSupportFragment;
import fr.free.nrw.commons.media.MediaDetailPagerFragment;
/**
* A simple {@link Fragment} subclass.
*/
public class ExploreFragment
extends CommonsDaggerSupportFragment
implements MediaDetailPagerFragment.MediaDetailProvider,
AdapterView.OnItemClickListener {
private static final String FEATURED_IMAGES_CATEGORY = "Category:Featured_pictures_on_Wikimedia_Commons";
private static final String MOBILE_UPLOADS_CATEGORY = "Category:Uploaded_with_Mobile/Android";
@BindView(R.id.mediaContainer)
FrameLayout mediaContainer;
@BindView(R.id.tab_layout)
TabLayout tabLayout;
@BindView(R.id.viewPager)
ViewPager viewPager;
ViewPagerAdapter viewPagerAdapter;
private FragmentManager supportFragmentManager;
private MediaDetailPagerFragment mediaDetails;
private CategoryImagesListFragment mobileImagesListFragment;
private CategoryImagesListFragment featuredImagesListFragment;
public static ExploreFragment newInstance() {
ExploreFragment fragment = new ExploreFragment();
fragment.setRetainInstance(true);
return fragment;
}
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState
) {
View v = inflater.inflate(R.layout.activity_explore, container, false);
ButterKnife.bind(this, v);
viewPagerAdapter = new ViewPagerAdapter(requireActivity().getSupportFragmentManager());
viewPager.setAdapter(viewPagerAdapter);
tabLayout.setupWithViewPager(viewPager);
setTabs();
return v;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Todo: after setContentView(R.layout.activity_explore);
ButterKnife.bind(requireActivity());
//Todo:after setTitle(getString(R.string.title_activity_explore));
supportFragmentManager = requireActivity().getSupportFragmentManager();
}
/**
* Sets the titles in the tabLayout and fragments in the viewPager
*/
public void setTabs() {
List<Fragment> fragmentList = new ArrayList<>();
List<String> titleList = new ArrayList<>();
featuredImagesListFragment = new CategoryImagesListFragment(this);
Bundle featuredArguments = new Bundle();
featuredArguments.putString("categoryName", FEATURED_IMAGES_CATEGORY);
featuredImagesListFragment.setArguments(featuredArguments);
fragmentList.add(featuredImagesListFragment);
titleList.add(getString(R.string.explore_tab_title_featured));
mobileImagesListFragment = new CategoryImagesListFragment();
Bundle mobileArguments = new Bundle();
mobileArguments.putString("categoryName", MOBILE_UPLOADS_CATEGORY);
mobileImagesListFragment.setArguments(mobileArguments);
fragmentList.add(mobileImagesListFragment);
titleList.add(getString(R.string.explore_tab_title_mobile));
viewPagerAdapter.setTabData(fragmentList, titleList);
viewPagerAdapter.notifyDataSetChanged();
}
/**
* This method is called mediaDetailPagerFragment. It returns the Media Object at that Index
*
* @param i It is the index of which media object is to be returned which is same as
* current index of viewPager.
* @return Media Object
*/
@Override
public Media getMediaAtPosition(int i) {
if (mobileImagesListFragment.getAdapter() != null && tabLayout.getSelectedTabPosition() == 1) {
return (Media) mobileImagesListFragment.getAdapter().getItem(i);
} else if (featuredImagesListFragment.getAdapter() != null && tabLayout.getSelectedTabPosition() == 0) {
return (Media) featuredImagesListFragment.getAdapter().getItem(i);
} else {
return null;
}
}
/**
* This method is called on from getCount of MediaDetailPagerFragment
* The viewpager will contain same number of media items as that of media elements in adapter.
*
* @return Total Media count in the adapter
*/
@Override
public int getTotalMediaCount() {
if (mobileImagesListFragment.getAdapter() != null && tabLayout.getSelectedTabPosition() == 1) {
return mobileImagesListFragment.getAdapter().getCount();
} else if (featuredImagesListFragment.getAdapter() != null && tabLayout.getSelectedTabPosition() == 0) {
return featuredImagesListFragment.getAdapter().getCount();
} else {
return 0;
}
}
/**
* This method is never called but it was in MediaDetailProvider Interface
* so it needs to be overrided.
*/
@Override
public void notifyDatasetChanged() {
}
/**
* This method is called on success of API call for featured images or mobile uploads.
* The viewpager will notified that number of items have changed.
*/
public void viewPagerNotifyDataSetChanged() {
if (mediaDetails != null) {
mediaDetails.notifyDataSetChanged();
}
}
/**
* This method is never called but it was in MediaDetailProvider Interface
* so it needs to be overrided.
*/
@Override
public void registerDataSetObserver(DataSetObserver observer) {
}
/**
* This method is never called but it was in MediaDetailProvider Interface
* so it needs to be overrided.
*/
@Override
public void unregisterDataSetObserver(DataSetObserver observer) {
}
/** Todo: after
* This method is called on backPressed of anyFragment in the activity.
* If condition is called when mediaDetailFragment is opened.
*//*
@Override
public void onBackPressed() {
if (supportFragmentManager.getBackStackEntryCount() == 1) {
tabLayout.setVisibility(View.VISIBLE);
viewPager.setVisibility(View.VISIBLE);
mediaContainer.setVisibility(View.GONE);
}
super.onBackPressed();
}*/
/**
* This method is called when viewPager has reached its end.
* Fetches more images and adds them to the recycler view and viewpager adapter
*/
public void requestMoreImages() {
if (mobileImagesListFragment != null && tabLayout.getSelectedTabPosition() == 1) {
mobileImagesListFragment.fetchMoreImagesViewPager();
} else if (featuredImagesListFragment != null && tabLayout.getSelectedTabPosition() == 0) {
featuredImagesListFragment.fetchMoreImagesViewPager();
}
}
/**
* This method is called onClick of media inside category featured images or mobile uploads.
*/
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
tabLayout.setVisibility(View.GONE);
viewPager.setVisibility(View.GONE);
mediaContainer.setVisibility(View.VISIBLE);
if (mediaDetails == null || !mediaDetails.isVisible()) {
// set isFeaturedImage true for featured images, to include author field on media detail
mediaDetails = new MediaDetailPagerFragment(false, true, this);
FragmentManager supportFragmentManager = requireActivity().getSupportFragmentManager();
supportFragmentManager
.beginTransaction()
.hide(supportFragmentManager.getFragments().get(supportFragmentManager.getBackStackEntryCount()))
.add(R.id.mediaContainer, mediaDetails)
.addToBackStack(null)
.commit();
// Reason for using hide, add instead of replace is to maintain scroll position after
// coming back to the explore activity. See https://github.com/commons-app/apps-android-commons/issues/1631
// https://stackoverflow.com/questions/11353075/how-can-i-maintain-fragment-state-when-added-to-the-back-stack/19022550#19022550 supportFragmentManager.executePendingTransactions();
}
mediaDetails.showImage(i);
//Todo: after forceInitBackButton();
}
/*Todo: after
*//**
* This method inflates the menu in the toolbar
*//*
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = requireActivity().getMenuInflater();
inflater.inflate(R.menu.menu_search, menu);
return super.onCreateOptionsMenu(menu);
}
*//**
* This method handles the logic on ItemSelect in toolbar menu
* Currently only 1 choice is available to open search page of the app
*//*
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_search:
NavigationBaseActivity.startActivityWithFlags(this, SearchActivity.class);
return true;
default:
return super.onOptionsItemSelected(item);
}
}*/
}

View file

@ -16,14 +16,14 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import javax.inject.Inject;
import javax.inject.Named;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.viewpager.widget.ViewPager;
import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView;
import butterknife.ButterKnife;
import fr.free.nrw.commons.Media;
@ -74,6 +74,11 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
this.isFeaturedImage = isFeaturedImage;
}
public MediaDetailPagerFragment(Boolean editable, boolean isFeaturedImage, MediaDetailProvider provider) {
this(editable, isFeaturedImage);
this.provider = provider;
}
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
@ -130,10 +135,12 @@ public class MediaDetailPagerFragment extends CommonsDaggerSupportFragment imple
* or a fragment
*/
private void initProvider() {
if (getParentFragment() != null) {
provider = (MediaDetailProvider) getParentFragment();
} else {
provider = (MediaDetailProvider) getActivity();
if (provider == null) {
if (getParentFragment() != null) {
provider = (MediaDetailProvider) getParentFragment();
} else {
provider = (MediaDetailProvider) getActivity();
}
}
}

View file

@ -0,0 +1,86 @@
package fr.free.nrw.commons.navtab;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import org.wikipedia.model.EnumCode;
import org.wikipedia.model.EnumCodeMap;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.bookmarks.BookmarksFragment;
import fr.free.nrw.commons.contributions.ContributionsMainFragment;
import fr.free.nrw.commons.explore.ExploreFragment;
public enum NavTab implements EnumCode {
CONTRIBUTIONS(R.string.contributions_fragment, R.drawable.ic_person_black_24dp) {
@NonNull
@Override
public Fragment newInstance() {
return ContributionsMainFragment.newInstance();
}
}, EXPLORE(R.string.navigation_item_explore, R.drawable.ic_globe) {
@NonNull
@Override
public Fragment newInstance() {
return ExploreFragment.newInstance();
}
},
FAVORITES(R.string.favorites, R.drawable.ic_round_star_border_24px) {
@NonNull
@Override
public Fragment newInstance() {
return new BookmarksFragment();
}
},
MORE(R.string.more, R.drawable.ic_menu_black_24dp) {
@NonNull
@Override
public Fragment newInstance() {
return ContributionsMainFragment.newInstance();
}
};
private static final EnumCodeMap<NavTab> MAP = new EnumCodeMap<>(NavTab.class);
@StringRes
private final int text;
@DrawableRes
private final int icon;
@NonNull
public static NavTab of(int code) {
return MAP.get(code);
}
public static int size() {
return MAP.size();
}
@StringRes
public int text() {
return text;
}
@DrawableRes
public int icon() {
return icon;
}
@NonNull
public abstract Fragment newInstance();
@Override
public int code() {
// This enumeration is not marshalled so tying declaration order to presentation order is
// convenient and consistent.
return ordinal();
}
NavTab(@StringRes int text, @DrawableRes int icon) {
this.text = text;
this.icon = icon;
}
}

View file

@ -0,0 +1,35 @@
package fr.free.nrw.commons.navtab;
import android.view.ViewGroup;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
public class NavTabFragmentPagerAdapter extends FragmentPagerAdapter {
private Fragment currentFragment;
public NavTabFragmentPagerAdapter(FragmentManager mgr) {
super(mgr);
}
@Nullable
public Fragment getCurrentFragment() {
return currentFragment;
}
@Override public Fragment getItem(int pos) {
return NavTab.of(pos).newInstance();
}
@Override public int getCount() {
return NavTab.size();
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
currentFragment = ((Fragment) object);
super.setPrimaryItem(container, position, object);
}
}

View file

@ -0,0 +1,32 @@
package fr.free.nrw.commons.navtab;
import android.content.Context;
import android.util.AttributeSet;
import android.view.Menu;
import com.google.android.material.bottomnavigation.BottomNavigationView;
public class NavTabLayout extends BottomNavigationView {
public NavTabLayout(Context context) {
super(context);
setTabViews();
}
public NavTabLayout(Context context, AttributeSet attrs) {
super(context, attrs);
setTabViews();
}
public NavTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setTabViews();
}
private void setTabViews() {
for (int i = 0; i < NavTab.size(); i++) {
NavTab navTab = NavTab.of(i);
getMenu().add(Menu.NONE, i, i, navTab.text()).setIcon(navTab.icon());
}
}
}

View file

@ -15,7 +15,7 @@ public abstract class BaseActivity extends CommonsDaggerAppCompatActivity {
@Named("default_preferences")
public JsonKvStore defaultKvStore;
protected CompositeDisposable compositeDisposable = new CompositeDisposable();
public CompositeDisposable compositeDisposable = new CompositeDisposable();
protected boolean wasPreviouslyDarkTheme;
@Override

View file

@ -1,45 +1,36 @@
package fr.free.nrw.commons.theme;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.app.ActivityManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import com.google.android.material.navigation.NavigationView;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.material.navigation.NavigationView;
import javax.inject.Inject;
import javax.inject.Named;
import butterknife.BindView;
import fr.free.nrw.commons.AboutActivity;
import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.WelcomeActivity;
import fr.free.nrw.commons.achievements.AchievementsActivity;
import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.bookmarks.BookmarksActivity;
import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.explore.categories.ExploreActivity;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.logging.CommonsLogSender;
import fr.free.nrw.commons.notification.NotificationActivity;
import fr.free.nrw.commons.review.ReviewActivity;
import fr.free.nrw.commons.settings.SettingsActivity;
import timber.log.Timber;
@ -51,47 +42,17 @@ public abstract class NavigationBaseActivity extends BaseActivity
@BindView(R.id.toolbar)
Toolbar toolbar;
@BindView(R.id.navigation_view)
NavigationView navigationView;
@BindView(R.id.drawer_layout)
DrawerLayout drawerLayout;
@Inject
@Named("default_preferences")
JsonKvStore applicationKvStore;
@Inject CommonsLogSender commonsLogSender;
@Inject
CommonsLogSender commonsLogSender;
private ActionBarDrawerToggle toggle;
public void initDrawer() {
navigationView.setNavigationItemSelectedListener(this);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawerLayout.addDrawerListener(toggle);
toggle.setDrawerIndicatorEnabled(true);
toggle.syncState();
setUserName();
Menu nav_Menu = navigationView.getMenu();
View headerLayout = navigationView.getHeaderView(0);
ImageView userIcon = headerLayout.findViewById(R.id.user_icon);
if (applicationKvStore.getBoolean("login_skipped", false)) {
userIcon.setVisibility(View.GONE);
nav_Menu.findItem(R.id.action_login).setVisible(true);
nav_Menu.findItem(R.id.action_home).setVisible(false);
nav_Menu.findItem(R.id.action_settings).setVisible(true);
nav_Menu.findItem(R.id.action_logout).setVisible(false);
nav_Menu.findItem(R.id.action_bookmarks).setVisible(true);
}else {
userIcon.setVisibility(View.VISIBLE);
nav_Menu.findItem(R.id.action_login).setVisible(false);
nav_Menu.findItem(R.id.action_home).setVisible(true);
nav_Menu.findItem(R.id.action_settings).setVisible(true);
nav_Menu.findItem(R.id.action_logout).setVisible(true);
nav_Menu.findItem(R.id.action_bookmarks).setVisible(true);
}
}
public void changeDrawerIconToBackButton() {
@ -110,19 +71,6 @@ public abstract class NavigationBaseActivity extends BaseActivity
* Set the username in navigationHeader.
*/
private void setUserName() {
View navHeaderView = navigationView.getHeaderView(0);
TextView username = navHeaderView.findViewById(R.id.username);
AccountManager accountManager = AccountManager.get(this);
Account[] allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE);
if (allAccounts.length != 0) {
username.setText(allAccounts[0].name);
}
ImageView userIcon = navHeaderView.findViewById(R.id.user_icon);
userIcon.setOnClickListener(v -> {
drawerLayout.closeDrawer(navigationView);
AchievementsActivity.startYourself(NavigationBaseActivity.this);
});
}
public void initBackButton() {
@ -151,7 +99,6 @@ public abstract class NavigationBaseActivity extends BaseActivity
final int itemId = item.getItemId();
switch (itemId) {
case R.id.action_login:
drawerLayout.closeDrawer(navigationView);
startActivityWithFlags(
this, LoginActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP,
Intent.FLAG_ACTIVITY_SINGLE_TOP);
@ -159,27 +106,22 @@ public abstract class NavigationBaseActivity extends BaseActivity
finish();
return true;
case R.id.action_home:
drawerLayout.closeDrawer(navigationView);
startActivityWithFlags(
this, MainActivity.class, Intent.FLAG_ACTIVITY_CLEAR_TOP,
Intent.FLAG_ACTIVITY_SINGLE_TOP);
return true;
case R.id.action_about:
drawerLayout.closeDrawer(navigationView);
startActivityWithFlags(this, AboutActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,
Intent.FLAG_ACTIVITY_SINGLE_TOP);
return true;
case R.id.action_settings:
drawerLayout.closeDrawer(navigationView);
startActivityWithFlags(this, SettingsActivity.class, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT,
Intent.FLAG_ACTIVITY_SINGLE_TOP);
return true;
case R.id.action_introduction:
drawerLayout.closeDrawer(navigationView);
WelcomeActivity.startYourself(this);
return true;
case R.id.action_feedback:
drawerLayout.closeDrawer(navigationView);
String technicalInfo = commonsLogSender.getExtraInfo();
@ -211,16 +153,13 @@ public abstract class NavigationBaseActivity extends BaseActivity
.show();
return true;
case R.id.action_explore:
drawerLayout.closeDrawer(navigationView);
ExploreActivity.startYourself(this);
return true;
case R.id.action_bookmarks:
drawerLayout.closeDrawer(navigationView);
BookmarksActivity.startYourself(this);
return true;
case R.id.action_review:
drawerLayout.closeDrawer(navigationView);
ReviewActivity.startYourself(this, getString(R.string.title_activity_review));
return true;
default:
@ -244,7 +183,7 @@ public abstract class NavigationBaseActivity extends BaseActivity
public static <T> void startActivityWithFlags(Context context, Class<T> cls, int... flags) {
Intent intent = new Intent(context, cls);
for (int flag: flags) {
for (int flag : flags) {
intent.addFlags(flag);
}
context.startActivity(intent);
@ -257,7 +196,7 @@ public abstract class NavigationBaseActivity extends BaseActivity
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
if ((intent.getFlags() | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) > 0) {
isRestoredToTop = true;
isRestoredToTop = true;
}
}
@ -277,23 +216,19 @@ public abstract class NavigationBaseActivity extends BaseActivity
/**
* Handles visibility of navigation base toolbar
*
* @param show : Used to handle visibility of toolbar
*/
public void setNavigationBaseToolbarVisibility(boolean show){
if (show){
public void setNavigationBaseToolbarVisibility(boolean show) {
if (show) {
toolbar.setVisibility(View.VISIBLE);
}else {
} else {
toolbar.setVisibility(View.GONE);
}
}
@Override
public void onBackPressed() {
DrawerLayout drawer = findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
super.onBackPressed();
}
}

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/primaryDarkColor" />
<item android:color="@color/nav_tab_icon_unselected_color" />
</selector>

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_checked="true" android:color="@color/primaryDarkColor" />
<item android:color="@color/nav_tab_icon_unselected_color" />
</selector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M17,3H7c-1.1,0 -1.99,0.9 -1.99,2L5,21l7,-3 7,3V5c0,-1.1 -0.9,-2 -2,-2z"/>
</vector>

View file

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,10.9c-0.61,0 -1.1,0.49 -1.1,1.1s0.49,1.1 1.1,1.1c0.61,0 1.1,-0.49 1.1,-1.1s-0.49,-1.1 -1.1,-1.1zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM14.19,14.19L6,18l3.81,-8.19L18,6l-3.81,8.19z"/>
</vector>

View file

@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:pathData="M8.91,2.49a10,10 0,1 0,12.6 6.42A10,10 0,0 0,8.91 2.49ZM14.47,19.61A8,8 0,1 1,19.61 9.53,8 8,0 0,1 14.47,19.61Z"
android:fillColor="#000000"/>
<path
android:pathData="M3.35,7.45s2.5,1.82 7.26,0.27 5.71,-4.49 5.71,-4.49l1.11,1.22s-1.61,3.15 -6.36,4.7 -7.91,-0.06 -7.91,-0.06Z"
android:fillColor="#000000"/>
<path
android:pathData="M7.52,20.29s1,-2.94 5.71,-4.49 7.26,0.27 7.26,0.27l0.18,-1.64s-3.15,-1.61 -7.91,-0.06 -6.36,4.7 -6.36,4.7Z"
android:fillColor="#000000"/>
<path
android:pathData="M3.97,13.82l15.6,-5.07l0.46,1.43l-6.81,2.21l-8.79,2.86l-0.46,-1.43z"
android:fillColor="#000000"/>
<path
android:pathData="M15.8,10.76A9.77,9.77 0,0 0,9.48 4.26l1.25,-1a11.16,11.16 0,0 1,6.49 7,11.16 11.16,0 0,1 -1.12,9.51l-1.6,-0.07A9.77,9.77 0,0 0,15.8 10.76Z"
android:fillColor="#000000"/>
<path
android:pathData="M8.2,13.24a9.77,9.77 0,0 1,1.29 -9l-1.6,-0.07A11.16,11.16 0,0 0,6.77 13.7a11.16,11.16 0,0 0,6.49 7l1.25,-1A9.77,9.77 0,0 1,8.2 13.24Z"
android:fillColor="#000000"/>
<path
android:pathData="M8.754,4.438l1.427,-0.464l5.068,15.597l-1.427,0.464z"
android:fillColor="#000000"/>
</vector>

View file

@ -1,5 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
<path android:fillColor="@color/white" android:pathData="M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z"/>
</vector>

View file

@ -0,0 +1,5 @@
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
</vector>

View file

@ -1,9 +1,5 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:viewportWidth="30.928"
android:viewportHeight="30.928"
android:width="30.928dp"
android:height="30.928dp">
<path
android:pathData="M24.791 4.451C24.811 3.503 24.775 2.904 24.775 2.904l-9.264 -0.007 0 0 -0.047 0 -0.047 0 0 0 -9.265 0.007c0 0 -0.035 0.599 -0.015 1.547L0 4.451 0 5.463c0 0.231 0.039 5.68 3.402 8.665 1.403 1.245 3.153 1.871 5.216 1.872 0.312 0 0.633 -0.021 0.958 -0.049 1.172 1.605 2.526 2.729 4.049 3.289l0 4.445 -4.471 0 0 2.784 -1.477 0 0 1.561 7.74 0 0.094 0 7.74 0 0 -1.56 -1.478 0 0 -2.784 -4.471 0 0 -4.445c1.522 -0.56 2.877 -1.684 4.049 -3.289 0.327 0.028 0.648 0.048 0.96 0.048 2.062 -0.002 3.812 -0.627 5.215 -1.873 3.363 -2.985 3.402 -8.434 3.402 -8.665l0 -1.011 -6.137 0zM4.752 12.619C2.831 10.919 2.263 8.009 2.095 6.475l4.158 0c0.176 1.911 0.59 4.292 1.545 6.385 0.175 0.384 0.359 0.748 0.547 1.104C6.912 13.909 5.706 13.462 4.752 12.619Zm21.424 0c-0.953 0.844 -2.16 1.29 -3.592 1.345 0.188 -0.355 0.372 -0.72 0.547 -1.104 0.955 -2.093 1.369 -4.474 1.544 -6.385l4.158 0c-0.168 1.533 -0.735 4.443 -2.657 6.144z"
android:fillColor="#fff" />
</vector>
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View file

@ -1,46 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/contributionsListBackground"
>
android:paddingBottom="?attr/actionBarSize"
android:gravity="center_horizontal">
<RelativeLayout
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/tabBackground"
app:tabIndicatorColor="?attr/tabIndicatorColor"
app:tabMode="fixed"
app:tabSelectedTextColor="?attr/tabSelectedTextColor"
app:tabTextColor="?attr/tabTextColor" />
<FrameLayout
android:id="@+id/contributionsFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal"
>
<include layout="@layout/toolbar"/>
android:layout_below="@id/tab_layout"
android:orientation="horizontal">
<com.google.android.material.tabs.TabLayout
android:id="@+id/tab_layout"
<fr.free.nrw.commons.contributions.UnswipableViewPager
android:id="@+id/ContPager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/tabBackground"
app:tabIndicatorColor="?attr/tabIndicatorColor"
app:tabSelectedTextColor="?attr/tabSelectedTextColor"
app:tabTextColor="?attr/tabTextColor"
android:layout_below="@id/toolbar"
app:tabMode="fixed" />
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/contributionsFragmentContainer"
android:orientation="horizontal"
android:layout_below="@id/tab_layout">
<fr.free.nrw.commons.contributions.UnswipableViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</RelativeLayout>
<include layout="@layout/drawer_view" />
</androidx.drawerlayout.widget.DrawerLayout>
</RelativeLayout>

View file

@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="?attr/actionBarSize"
android:orientation="vertical">
<com.google.android.material.tabs.TabLayout

View file

@ -1,15 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
android:orientation="vertical">
<androidx.viewpager.widget.ViewPager
android:id="@+id/mediaDetailsPager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
/>
android:fadingEdge="none" />
</LinearLayout>

View file

@ -1,67 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:paddingBottom="0dp"
>
android:orientation="vertical"
android:padding="2dp">
<TextView
android:id="@+id/categoryImagesSequenceNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="98sp"
android:textColor="#33FFFFFF"
android:typeface="serif"
android:layout_gravity="end|bottom"
/>
android:textColor="#33FFFFFF"
android:textSize="98sp"
android:typeface="serif"
android:visibility="gone" />
<com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/categoryImageView"
android:layout_width="match_parent"
android:layout_height="240dp"
app:actualImageScaleType="centerCrop"
/>
app:actualImageScaleType="centerCrop" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center|bottom"
android:background="#AA000000"
android:orientation="vertical"
android:padding="@dimen/small_gap"
>
<ProgressBar
android:id="@+id/categoryProgress"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/ProgressBar"
android:indeterminateOnly="false"
android:max="100"
android:visibility="gone"
/>
android:orientation="horizontal">
<TextView
android:id="@+id/categoryImageTitle"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="32dp">
<ProgressBar
android:id="@+id/categoryProgress"
style="@style/ProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminateOnly="false"
android:max="100"
android:visibility="gone" />
<TextView
android:id="@+id/categoryImageTitle"
style="?android:textAppearanceMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textColor="@color/black" />
<TextView
android:id="@+id/categoryImageAuthor"
style="?android:textAppearanceSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="1"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textColor="@color/nav_tab_icon_unselected_color" />
</LinearLayout>
<ImageView
android:id="@+id/favorite"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFFFF"
style="?android:textAppearanceLarge"
android:maxLines="1"
android:ellipsize="end"
/>
android:layout_gravity="center_vertical"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:tint="@color/nav_tab_icon_unselected_color"
app:srcCompat="@drawable/ic_round_star_filled_24px" />
<TextView
android:id="@+id/categoryImageAuthor"
<ImageView
android:id="@+id/download"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFFFFFFF"
style="?android:textAppearanceMedium"
android:maxLines="1"
android:ellipsize="end"
/>
android:layout_gravity="center_vertical"
android:layout_marginEnd="16dp"
android:contentDescription="@null"
android:tint="@color/nav_tab_icon_unselected_color"
app:srcCompat="@drawable/ic_download_white_24dp" />
</LinearLayout>
</FrameLayout>
</LinearLayout>

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center_horizontal">
<include layout="@layout/toolbar" />
<FrameLayout
android:id="@+id/contributionsFragmentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/tab_layout"
android:orientation="horizontal">
<fr.free.nrw.commons.contributions.UnswipableViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<fr.free.nrw.commons.navtab.NavTabLayout
android:id="@+id/fragment_main_nav_tab_layout"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:background="@android:color/white"
android:elevation="6dp"
app:itemIconTint="?attr/nav_tab_item_color_state"
app:itemTextColor="?attr/colorPrimaryDark"
app:tabGravity="fill"
app:tabIndicatorColor="@android:color/transparent" />
</RelativeLayout>

View file

@ -27,6 +27,7 @@
<attr name="mainCardBackground" format="reference"/>
<attr name="mainScreenNearbyPermissionbutton" format="reference"/>
<attr name="icon" format="reference"/>
<attr name="nav_tab_item_color_state" format="reference" />
<declare-styleable name="CompatTextView">

View file

@ -69,4 +69,5 @@
<color name="swipe_red" tools:ignore="MissingDefaultResource">#FF0000</color>
<color name="yes_button_color">#B22222</color>
<color name="no_button_color">#006400</color>
<color name="nav_tab_icon_unselected_color">#61000000</color>
</resources>

View file

@ -540,4 +540,10 @@ Upload your first media by tapping on the add button.</string>
<string name="share_text">Upload photos to Wikimedia Commons on your phone Download the Commons app: %1$s</string>
<string name="share_via">Share app via...</string>
<string name="image_info">Image Info</string>
<!-- Hackathon-->
<string name="favorites">Favorites</string>
<string name="more">More</string>
</resources>

View file

@ -33,6 +33,7 @@
<item name="textEnabled">@color/enabled_button_text_color_dark</item>
<item name="mainCardBackground">@color/main_background_dark</item>
<item name="mainScreenNearbyPermissionbutton">@style/DarkFlatNearbyPermissionButton</item>
<item name="nav_tab_item_color_state">@color/color_state_nav_tab_dark</item>
</style>
<style name="LightAppTheme" parent="Theme.AppCompat.Light.NoActionBar">
@ -67,6 +68,7 @@
<item name="textEnabled">@color/enabled_button_text_color_light</item>
<item name="mainCardBackground">@color/primaryDarkColor</item>
<item name="mainScreenNearbyPermissionbutton">@style/LightFlatNearbyPermissionButton</item>
<item name="nav_tab_item_color_state">@color/color_state_nav_tab_light</item>
</style>
<style name="WhiteSearchBarTheme" parent="DarkAppTheme">