Fixes #2843 New main screen UI in v3.0 (#3891)

* Add additional classes from 2019 hackathon implementation

* Make first tab work

* Make explore tab work

* Handle back button for contrib and nearby

* Fix framelayout and nav bar allignment

* Fix nav bar tint

* Fix nearby card layout

* Make contributions number visible

* Change menu icon according to fragment

* Make notification icon work and remove drawer

* Make favourites accessible from nav bar

* Turn bookmark and explore activities into fragments

* Use bottom sheet instead of more fragment

* Add actions

* Remove unused classes

* Fix indentation

* remove more fragment title

* Fix explore fragment indentation

* Make toolbar settings as we wanted

* Set card view styles

* Make colors for explore actiivty

* Remove drawer from achievements activity

* Add back button to achievements activity

* remove drawer from review activity

* Remove drawer from settings activity

* Remove drawer from about activity

* Fix dagger injection of fragment

* Implement skip login version

* Add theme missing colors

* Add style to moresheet

* refactor name

* call login with button

* Remove all old bookmarks activity dependency

* Make explore tab items clickable

* Do nothing if same tab is selected

* Fix notification icon color for dark theme

* Fix wrong drawable colors

* Handle back button after media details is visible from contrib and explore fragments

* make favourites open media details

* Fix profile icon

* Make user name visible instead

* Move user back to contrib fragment

* Remove NavigationBaseAvticity

* Fix typo in bookmark fragment

* Fix menu button colors

* Remove explore activity

* remove drawer and dependencies

* Make bookmark media details visible

* Cleanup code

* Code cleanup

* Remove unused layout

* Make contriblist UI look like in mockups

* Change limited connecton toggle

* Move list menu item to nearby fragment

* Fix search button crash

* Make media detail appear

* Back button added

* Fix back button npe

* Change bookmark list view

* Fix always the firs item displayed issue

* Allign contrib list bottom line to simple drawee bottom

* fix fragment string

* Fix back button for mobile uploads

* Make lists appear

* Make fav item selected

* Make favourites clickable

* Add back button to media details

* Add toolbar of notification activity

* Change contributions icon

* Fix card UI

* Fix back button in explore

* Make card views look similar to mockups

* Solve campaign bug visible issue

* Make borders a little softer
This commit is contained in:
neslihanturan 2020-11-06 19:04:04 +03:00 committed by GitHub
parent 5d82629109
commit 71d200ee41
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
110 changed files with 2225 additions and 1629 deletions

View file

@ -0,0 +1,153 @@
package fr.free.nrw.commons.navtab;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
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.auth.LoginActivity;
import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.logging.CommonsLogSender;
import fr.free.nrw.commons.profile.ProfileActivity;
import fr.free.nrw.commons.review.ReviewActivity;
import fr.free.nrw.commons.settings.SettingsActivity;
import javax.inject.Inject;
import timber.log.Timber;
public class MoreBottomSheetFragment extends BottomSheetDialogFragment {
@Inject
CommonsLogSender commonsLogSender;
@BindView(R.id.more_profile)
TextView moreProfile;
@Nullable
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
final View view = inflater.inflate(R.layout.fragment_more_bottom_sheet, container, false);
ButterKnife.bind(this, view);
setUserName();
return view;
}
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
ApplicationlessInjection
.getInstance(getActivity().getApplicationContext())
.getCommonsApplicationComponent()
.inject(this);
}
/**
* Set the username in navigationHeader.
*/
private void setUserName() {
AccountManager accountManager = AccountManager.get(getActivity());
Account[] allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE);
if (allAccounts.length != 0) {
moreProfile.setText(allAccounts[0].name);
}
}
@OnClick(R.id.more_logout)
public void onLogoutClicked() {
new AlertDialog.Builder(getActivity())
.setMessage(R.string.logout_verification)
.setCancelable(false)
.setPositiveButton(R.string.yes, (dialog, which) -> {
BaseLogoutListener logoutListener = new BaseLogoutListener();
CommonsApplication app = (CommonsApplication) getContext().getApplicationContext();
app.clearApplicationData(getContext(), logoutListener);
})
.setNegativeButton(R.string.no, (dialog, which) -> dialog.cancel())
.show();
}
@OnClick(R.id.more_feedback)
public void onFeedbackClicked() {
final String technicalInfo = commonsLogSender.getExtraInfo();
final Intent feedbackIntent = new Intent(Intent.ACTION_SENDTO);
feedbackIntent.setType("message/rfc822");
feedbackIntent.setData(Uri.parse("mailto:"));
feedbackIntent.putExtra(Intent.EXTRA_EMAIL,
new String[]{CommonsApplication.FEEDBACK_EMAIL});
feedbackIntent.putExtra(Intent.EXTRA_SUBJECT,
CommonsApplication.FEEDBACK_EMAIL_SUBJECT);
feedbackIntent.putExtra(Intent.EXTRA_TEXT, String.format(
"\n\n%s\n%s", CommonsApplication.FEEDBACK_EMAIL_TEMPLATE_HEADER, technicalInfo));
try {
startActivity(feedbackIntent);
} catch (final ActivityNotFoundException e) {
Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show();
}
}
@OnClick(R.id.more_about)
public void onAboutClicked() {
final Intent intent = new Intent(getActivity(), AboutActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getActivity().startActivity(intent);
}
@OnClick(R.id.more_tutorial)
public void onTutorialClicked() {
WelcomeActivity.startYourself(getActivity());
}
@OnClick(R.id.more_settings)
public void onSettingsClicked() {
final Intent intent = new Intent(getActivity(), SettingsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getActivity().startActivity(intent);
}
@OnClick(R.id.more_profile)
public void onProfileClicked() {
final Intent intent = new Intent(getActivity(), ProfileActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getActivity().startActivity(intent);
}
@OnClick(R.id.more_peer_review)
public void onPeerReviewClicked() {
ReviewActivity.startYourself(getActivity(), getString(R.string.title_activity_review));
}
private class BaseLogoutListener implements CommonsApplication.LogoutListener {
@Override
public void onLogoutComplete() {
Timber.d("Logout complete callback received.");
final Intent nearbyIntent = new Intent(
getContext(), LoginActivity.class);
nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(nearbyIntent);
getActivity().finish();
}
}
}

View file

@ -0,0 +1,118 @@
package fr.free.nrw.commons.navtab;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import butterknife.ButterKnife;
import butterknife.OnClick;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import fr.free.nrw.commons.AboutActivity;
import fr.free.nrw.commons.CommonsApplication;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.WelcomeActivity;
import fr.free.nrw.commons.auth.LoginActivity;
import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.kvstore.JsonKvStore;
import fr.free.nrw.commons.logging.CommonsLogSender;
import fr.free.nrw.commons.settings.SettingsActivity;
import javax.inject.Inject;
import javax.inject.Named;
import timber.log.Timber;
public class MoreBottomSheetLoggedOutFragment extends BottomSheetDialogFragment {
@Inject
CommonsLogSender commonsLogSender;
@Inject
@Named("default_preferences")
JsonKvStore applicationKvStore;
@Nullable
@Override
public View onCreateView(@NonNull final LayoutInflater inflater,
@Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
final View view = inflater.inflate(R.layout.fragment_more_bottom_sheet_logged_out, container, false);
ButterKnife.bind(this, view);
return view;
}
@Override
public void onAttach(@NonNull final Context context) {
super.onAttach(context);
ApplicationlessInjection
.getInstance(getActivity().getApplicationContext())
.getCommonsApplicationComponent()
.inject(this);
}
@OnClick(R.id.more_login)
public void onLogoutClicked() {
applicationKvStore.putBoolean("login_skipped", false);
Intent intent = new Intent(getContext(), LoginActivity.class);
getActivity().finish(); //Kill the activity from which you will go to next activity
startActivity(intent);
}
@OnClick(R.id.more_feedback)
public void onFeedbackClicked() {
final String technicalInfo = commonsLogSender.getExtraInfo();
final Intent feedbackIntent = new Intent(Intent.ACTION_SENDTO);
feedbackIntent.setType("message/rfc822");
feedbackIntent.setData(Uri.parse("mailto:"));
feedbackIntent.putExtra(Intent.EXTRA_EMAIL,
new String[]{CommonsApplication.FEEDBACK_EMAIL});
feedbackIntent.putExtra(Intent.EXTRA_SUBJECT,
CommonsApplication.FEEDBACK_EMAIL_SUBJECT);
feedbackIntent.putExtra(Intent.EXTRA_TEXT, String.format(
"\n\n%s\n%s", CommonsApplication.FEEDBACK_EMAIL_TEMPLATE_HEADER, technicalInfo));
try {
startActivity(feedbackIntent);
} catch (final ActivityNotFoundException e) {
Toast.makeText(getActivity(), R.string.no_email_client, Toast.LENGTH_SHORT).show();
}
}
@OnClick(R.id.more_about)
public void onAboutClicked() {
final Intent intent = new Intent(getActivity(), AboutActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getActivity().startActivity(intent);
}
@OnClick(R.id.more_tutorial)
public void onTutorialClicked() {
WelcomeActivity.startYourself(getActivity());
}
@OnClick(R.id.more_settings)
public void onSettingsClicked() {
final Intent intent = new Intent(getActivity(), SettingsActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
getActivity().startActivity(intent);
}
private class BaseLogoutListener implements CommonsApplication.LogoutListener {
@Override
public void onLogoutComplete() {
Timber.d("Logout complete callback received.");
final Intent nearbyIntent = new Intent(
getContext(), LoginActivity.class);
nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(nearbyIntent);
getActivity().finish();
}
}
}

View file

@ -0,0 +1,97 @@
package fr.free.nrw.commons.navtab;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import fr.free.nrw.commons.bookmarks.BookmarkFragment;
import fr.free.nrw.commons.contributions.ContributionsFragment;
import fr.free.nrw.commons.explore.ExploreFragment;
import fr.free.nrw.commons.explore.categories.search.SearchCategoryFragment;
import fr.free.nrw.commons.nearby.fragments.NearbyParentFragment;
import org.wikipedia.model.EnumCode;
import org.wikipedia.model.EnumCodeMap;
import fr.free.nrw.commons.R;
public enum NavTab implements EnumCode {
CONTRIBUTIONS(R.string.contributions_fragment, R.drawable.ic_baseline_person_24) {
@NonNull
@Override
public Fragment newInstance() {
return ContributionsFragment.newInstance();
}
},
NEARBY(R.string.nearby_fragment, R.drawable.ic_location_on_black_24dp){
@NonNull
@Override
public Fragment newInstance() {
return NearbyParentFragment.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 BookmarkFragment.newInstance();
}
},
MORE(R.string.more, R.drawable.ic_menu_black_24dp) {
@NonNull
@Override
public Fragment newInstance() {
return null;
}
};
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,41 @@
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;
import fr.free.nrw.commons.contributions.MainActivity;
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() {
if (((MainActivity)getContext()).applicationKvStore.getBoolean("login_skipped") == true) {
for (int i = 0; i < NavTabLoggedOut.size(); i++) {
NavTabLoggedOut navTab = NavTabLoggedOut.of(i);
getMenu().add(Menu.NONE, i, i, navTab.text()).setIcon(navTab.icon());
}
} else {
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

@ -0,0 +1,70 @@
package fr.free.nrw.commons.navtab;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.StringRes;
import androidx.fragment.app.Fragment;
import fr.free.nrw.commons.R;
import fr.free.nrw.commons.explore.ExploreFragment;
import org.wikipedia.model.EnumCode;
import org.wikipedia.model.EnumCodeMap;
public enum NavTabLoggedOut implements EnumCode {
EXPLORE(R.string.navigation_item_explore, R.drawable.ic_globe) {
@NonNull
@Override
public Fragment newInstance() {
return ExploreFragment.newInstance();
}
},
MORE(R.string.more, R.drawable.ic_menu_black_24dp) {
@NonNull
@Override
public Fragment newInstance() {
return null;
}
};
private static final EnumCodeMap<NavTabLoggedOut> MAP = new EnumCodeMap<>(NavTabLoggedOut.class);
@StringRes
private final int text;
@DrawableRes
private final int icon;
@NonNull
public static NavTabLoggedOut 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();
}
NavTabLoggedOut(@StringRes int text, @DrawableRes int icon) {
this.text = text;
this.icon = icon;
}
}