diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetFragment.java b/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetFragment.java deleted file mode 100644 index 9ea59488ed..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetFragment.java +++ /dev/null @@ -1,238 +0,0 @@ -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 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.CommonsApplication.ActivityLogoutListener; -import fr.free.nrw.commons.R; -import fr.free.nrw.commons.WelcomeActivity; -import fr.free.nrw.commons.actions.PageEditClient; -import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetBinding; -import fr.free.nrw.commons.di.ApplicationlessInjection; -import fr.free.nrw.commons.feedback.FeedbackContentCreator; -import fr.free.nrw.commons.feedback.model.Feedback; -import fr.free.nrw.commons.feedback.FeedbackDialog; -import fr.free.nrw.commons.kvstore.BasicKvStore; -import fr.free.nrw.commons.kvstore.JsonKvStore; -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 io.reactivex.Single; -import io.reactivex.SingleSource; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.schedulers.Schedulers; -import java.util.concurrent.Callable; -import javax.inject.Inject; -import javax.inject.Named; - -public class MoreBottomSheetFragment extends BottomSheetDialogFragment { - - @Inject - CommonsLogSender commonsLogSender; - - private TextView moreProfile; - - @Inject @Named("default_preferences") - JsonKvStore store; - - @Inject - @Named("commons-page-edit") - PageEditClient pageEditClient; - - private static final String GITHUB_ISSUES_URL = "https://github.com/commons-app/apps-android-commons/issues"; - @Nullable - @Override - public View onCreateView(@NonNull final LayoutInflater inflater, - @Nullable final ViewGroup container, @Nullable final Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - final @NonNull FragmentMoreBottomSheetBinding binding = - FragmentMoreBottomSheetBinding.inflate(inflater, container, false); - moreProfile = binding.moreProfile; - - if(store.getBoolean(CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED)){ - binding.morePeerReview.setVisibility(View.GONE); - } - - binding.moreLogout.setOnClickListener(v -> onLogoutClicked()); - binding.moreFeedback.setOnClickListener(v -> onFeedbackClicked()); - binding.moreAbout.setOnClickListener(v -> onAboutClicked()); - binding.moreTutorial.setOnClickListener(v -> onTutorialClicked()); - binding.moreSettings.setOnClickListener(v -> onSettingsClicked()); - binding.moreProfile.setOnClickListener(v -> onProfileClicked()); - binding.morePeerReview.setOnClickListener(v -> onPeerReviewClicked()); - binding.moreFeedbackGithub.setOnClickListener(v -> onFeedbackGithubClicked()); - - setUserName(); - return binding.getRoot(); - } - - private void onFeedbackGithubClicked() { - final Intent intent; - intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(GITHUB_ISSUES_URL)); - startActivity(intent); - } - - @Override - public void onAttach(@NonNull final Context context) { - super.onAttach(context); - ApplicationlessInjection - .getInstance(requireActivity().getApplicationContext()) - .getCommonsApplicationComponent() - .inject(this); - } - - /** - * Set the username and user achievements level (if available) in navigationHeader. - */ - private void setUserName() { - BasicKvStore store = new BasicKvStore(this.getContext(), getUserName()); - String level = store.getString("userAchievementsLevel","0"); - if (level.equals("0")) { - moreProfile.setText(getUserName() + " (" + getString(R.string.see_your_achievements) + ")"); - } - else { - moreProfile.setText(getUserName() + " (" + getString(R.string.level) + " " + level + ")"); - } - } - - private String getUserName(){ - final AccountManager accountManager = AccountManager.get(getActivity()); - final Account[] allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE); - if (allAccounts.length != 0) { - return allAccounts[0].name; - } - return ""; - } - - - protected void onLogoutClicked() { - new AlertDialog.Builder(requireActivity()) - .setMessage(R.string.logout_verification) - .setCancelable(false) - .setPositiveButton(R.string.yes, (dialog, which) -> { - final CommonsApplication app = (CommonsApplication) - requireContext().getApplicationContext(); - app.clearApplicationData(requireContext(), new ActivityLogoutListener(requireActivity(), getContext())); - }) - .setNegativeButton(R.string.no, (dialog, which) -> dialog.cancel()) - .show(); - } - - protected void onFeedbackClicked() { - showFeedbackDialog(); - } - - /** - * Creates and shows a dialog asking feedback from users - */ - private void showFeedbackDialog() { - new FeedbackDialog(getContext(), this::uploadFeedback).show(); - } - - /** - * uploads feedback data on the server - */ - void uploadFeedback(final Feedback feedback) { - final FeedbackContentCreator feedbackContentCreator = new FeedbackContentCreator(getContext(), feedback); - - final Single single = - pageEditClient.createNewSection( - "Commons:Mobile_app/Feedback", - feedbackContentCreator.getSectionTitle(), - feedbackContentCreator.getSectionText(), - "New feedback on version " + feedback.getVersion() + " of the app" - ) - .flatMapSingle(Single::just) - .firstOrError(); - - Single.defer((Callable>) () -> single) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(aBoolean -> { - if (aBoolean) { - Toast.makeText(getContext(), getString(R.string.thanks_feedback), Toast.LENGTH_SHORT) - .show(); - } else { - Toast.makeText(getContext(), getString(R.string.error_feedback), - Toast.LENGTH_SHORT).show(); - } - }); - } - - /** - * This method shows the alert dialog when a user wants to send feedback about the app. - */ - private void showAlertDialog() { - new AlertDialog.Builder(requireActivity()) - .setMessage(R.string.feedback_sharing_data_alert) - .setCancelable(false) - .setPositiveButton(R.string.ok, (dialog, which) -> sendFeedback()) - .show(); - } - - /** - * This method collects the feedback message and starts the activity with implicit intent - * to available email client. - */ - private void sendFeedback() { - 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(); - } - } - - protected void onAboutClicked() { - final Intent intent = new Intent(getActivity(), AboutActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); - requireActivity().startActivity(intent); - } - - protected void onTutorialClicked() { - WelcomeActivity.startYourself(getActivity()); - } - - protected void onSettingsClicked() { - final Intent intent = new Intent(getActivity(), SettingsActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); - requireActivity().startActivity(intent); - } - - protected void onProfileClicked() { - ProfileActivity.startYourself(getActivity(), getUserName(), false); - } - - protected void onPeerReviewClicked() { - ReviewActivity.Companion.startYourself(getActivity(), getString(R.string.title_activity_review)); - } -} - diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetFragment.kt b/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetFragment.kt new file mode 100644 index 0000000000..857e18ec31 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetFragment.kt @@ -0,0 +1,242 @@ +package fr.free.nrw.commons.navtab + +import android.accounts.AccountManager +import android.annotation.SuppressLint +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.appcompat.app.AlertDialog +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.CommonsApplication.ActivityLogoutListener +import fr.free.nrw.commons.R +import fr.free.nrw.commons.WelcomeActivity +import fr.free.nrw.commons.actions.PageEditClient +import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetBinding +import fr.free.nrw.commons.di.ApplicationlessInjection +import fr.free.nrw.commons.feedback.FeedbackContentCreator +import fr.free.nrw.commons.feedback.FeedbackDialog +import fr.free.nrw.commons.feedback.model.Feedback +import fr.free.nrw.commons.kvstore.BasicKvStore +import fr.free.nrw.commons.kvstore.JsonKvStore +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 io.reactivex.Single +import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.schedulers.Schedulers +import javax.inject.Inject +import javax.inject.Named + + +class MoreBottomSheetFragment : BottomSheetDialogFragment() { + + @Inject + lateinit var commonsLogSender: CommonsLogSender + + @Inject + @field: Named("default_preferences") + lateinit var store: JsonKvStore + + @Inject + @field: Named("commons-page-edit") + lateinit var pageEditClient: PageEditClient + + companion object { + private const val GITHUB_ISSUES_URL = + "https://github.com/commons-app/apps-android-commons/issues" + } + + private var binding: FragmentMoreBottomSheetBinding? = null + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentMoreBottomSheetBinding.inflate(inflater, container, false) + + if (store.getBoolean(CommonsApplication.IS_LIMITED_CONNECTION_MODE_ENABLED)) { + binding?.morePeerReview?.visibility = View.GONE + } + + binding?.apply { + moreLogout.setOnClickListener { onLogoutClicked() } + moreFeedback.setOnClickListener { onFeedbackClicked() } + moreAbout.setOnClickListener { onAboutClicked() } + moreTutorial.setOnClickListener { onTutorialClicked() } + moreSettings.setOnClickListener { onSettingsClicked() } + moreProfile.setOnClickListener { onProfileClicked() } + morePeerReview.setOnClickListener { onPeerReviewClicked() } + moreFeedbackGithub.setOnClickListener { onFeedbackGithubClicked() } + } + + setUserName() + return binding?.root + } + + private fun onFeedbackGithubClicked() { + val intent = Intent(Intent.ACTION_VIEW).apply { + data = Uri.parse(GITHUB_ISSUES_URL) + } + startActivity(intent) + } + + override fun onAttach(context: Context) { + super.onAttach(context) + ApplicationlessInjection + .getInstance(requireActivity().applicationContext) + .commonsApplicationComponent + .inject(this) + } + + override fun onDestroyView() { + super.onDestroyView() + binding = null + } + + /** + * Set the username and user achievements level (if available) in navigationHeader. + */ + private fun setUserName() { + val store = BasicKvStore(requireContext(), getUserName()) + val level = store.getString("userAchievementsLevel", "0") + binding?.moreProfile?.text = if (level == "0") { + "${getUserName()} (${getString(R.string.see_your_achievements)})" + } else { + "${getUserName()} (${getString(R.string.level)} $level)" + } + } + + private fun getUserName(): String { + val accountManager = AccountManager.get(requireActivity()) + val allAccounts = accountManager.getAccountsByType(BuildConfig.ACCOUNT_TYPE) + return if (allAccounts.isNotEmpty()) { + allAccounts[0].name + } else { + "" + } + } + + fun onLogoutClicked() { + AlertDialog.Builder(requireActivity()) + .setMessage(R.string.logout_verification) + .setCancelable(false) + .setPositiveButton(R.string.yes) { _, _ -> + val app = requireContext().applicationContext as CommonsApplication + app.clearApplicationData(requireContext(), ActivityLogoutListener(requireActivity(), requireContext())) + } + .setNegativeButton(R.string.no) { dialog, _ -> dialog.cancel() } + .show() + } + + fun onFeedbackClicked() { + showFeedbackDialog() + } + + /** + * Creates and shows a dialog asking feedback from users + */ + private fun showFeedbackDialog() { + FeedbackDialog(requireContext()) { uploadFeedback(it) }.show() + } + + /** + * Uploads feedback data on the server + */ + @SuppressLint("CheckResult") + fun uploadFeedback(feedback: Feedback) { + val feedbackContentCreator = FeedbackContentCreator(requireContext(), feedback) + + val single = pageEditClient.createNewSection( + "Commons:Mobile_app/Feedback", + feedbackContentCreator.sectionTitle, + feedbackContentCreator.sectionText, + "New feedback on version ${feedback.version} of the app" + ) + .flatMapSingle { Single.just(it) } + .firstOrError() + + Single.defer { single } + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe { success -> + val messageResId = if (success) { + R.string.thanks_feedback + } else { + R.string.error_feedback + } + Toast.makeText(requireContext(), getString(messageResId), Toast.LENGTH_SHORT).show() + } + } + + /** + * This method shows the alert dialog when a user wants to send feedback about the app. + */ + private fun showAlertDialog() { + AlertDialog.Builder(requireActivity()) + .setMessage(R.string.feedback_sharing_data_alert) + .setCancelable(false) + .setPositiveButton(R.string.ok) { _, _ -> sendFeedback() } + .show() + } + + /** + * This method collects the feedback message and starts the activity with implicit intent + * to the available email client. + */ + @SuppressLint("IntentReset") + private fun sendFeedback() { + val technicalInfo = commonsLogSender.getExtraInfo() + + val feedbackIntent = Intent(Intent.ACTION_SENDTO).apply { + type = "message/rfc822" + data = Uri.parse("mailto:") + putExtra(Intent.EXTRA_EMAIL, arrayOf(CommonsApplication.FEEDBACK_EMAIL)) + putExtra(Intent.EXTRA_SUBJECT, CommonsApplication.FEEDBACK_EMAIL_SUBJECT) + putExtra(Intent.EXTRA_TEXT, "\n\n${CommonsApplication.FEEDBACK_EMAIL_TEMPLATE_HEADER}\n$technicalInfo") + } + + try { + startActivity(feedbackIntent) + } catch (e: ActivityNotFoundException) { + Toast.makeText(activity, R.string.no_email_client, Toast.LENGTH_SHORT).show() + } + } + + fun onAboutClicked() { + val intent = Intent(activity, AboutActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + requireActivity().startActivity(intent) + } + + fun onTutorialClicked() { + WelcomeActivity.startYourself(requireActivity()) + } + + fun onSettingsClicked() { + val intent = Intent(activity, SettingsActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + requireActivity().startActivity(intent) + } + + fun onProfileClicked() { + ProfileActivity.startYourself(requireActivity(), getUserName(), false) + } + + fun onPeerReviewClicked() { + ReviewActivity.startYourself(requireActivity(), getString(R.string.title_activity_review)) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetLoggedOutFragment.java b/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetLoggedOutFragment.java deleted file mode 100644 index 3537d7f7bb..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetLoggedOutFragment.java +++ /dev/null @@ -1,142 +0,0 @@ -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 androidx.appcompat.app.AlertDialog; -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.auth.LoginActivity; -import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetLoggedOutBinding; -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 { - - private FragmentMoreBottomSheetLoggedOutBinding binding; - @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) { - binding = FragmentMoreBottomSheetLoggedOutBinding.inflate(inflater, container, false); - return binding.getRoot(); - } - - @Override - public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { - binding.moreLogin.setOnClickListener(v -> onLogoutClicked()); - binding.moreFeedback.setOnClickListener(v -> onFeedbackClicked()); - binding.moreAbout.setOnClickListener(v -> onAboutClicked()); - binding.moreSettings.setOnClickListener(v -> onSettingsClicked()); - } - - @Override - public void onDestroyView() { - super.onDestroyView(); - binding = null; - } - - @Override - public void onAttach(@NonNull final Context context) { - super.onAttach(context); - ApplicationlessInjection - .getInstance(requireActivity().getApplicationContext()) - .getCommonsApplicationComponent() - .inject(this); - } - - public void onLogoutClicked() { - applicationKvStore.putBoolean("login_skipped", false); - final Intent intent = new Intent(getContext(), LoginActivity.class); - requireActivity().finish(); //Kill the activity from which you will go to next activity - startActivity(intent); - } - - public void onFeedbackClicked() { - showAlertDialog(); - } - - /** - * This method shows the alert dialog when a user wants to send feedback about the app. - */ - private void showAlertDialog() { - new AlertDialog.Builder(requireActivity()) - .setMessage(R.string.feedback_sharing_data_alert) - .setCancelable(false) - .setPositiveButton(R.string.ok, (dialog, which) -> { - sendFeedback(); - }) - .show(); - } - - /** - * This method collects the feedback message and starts and activity with implicit intent to - * available email client. - */ - private void sendFeedback() { - 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(); - } - } - - public void onAboutClicked() { - final Intent intent = new Intent(getActivity(), AboutActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); - requireActivity().startActivity(intent); - } - - public void onSettingsClicked() { - final Intent intent = new Intent(getActivity(), SettingsActivity.class); - intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); - requireActivity().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); - requireActivity().finish(); - } - } -} - diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetLoggedOutFragment.kt b/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetLoggedOutFragment.kt new file mode 100644 index 0000000000..96baf9e5ea --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/navtab/MoreBottomSheetLoggedOutFragment.kt @@ -0,0 +1,151 @@ +package fr.free.nrw.commons.navtab + +import android.annotation.SuppressLint +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.appcompat.app.AlertDialog +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.auth.LoginActivity +import fr.free.nrw.commons.databinding.FragmentMoreBottomSheetLoggedOutBinding +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 + + +class MoreBottomSheetLoggedOutFragment : BottomSheetDialogFragment() { + + private var binding: FragmentMoreBottomSheetLoggedOutBinding? = null + + @Inject + lateinit var commonsLogSender: CommonsLogSender + + @Inject + @field: Named("default_preferences") + lateinit var applicationKvStore: JsonKvStore + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle? + ): View? { + binding = FragmentMoreBottomSheetLoggedOutBinding.inflate( + inflater, + container, + false + ) + return binding?.root + } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle? + ) { + binding?.apply { + moreLogin.setOnClickListener { onLogoutClicked() } + moreFeedback.setOnClickListener { onFeedbackClicked() } + moreAbout.setOnClickListener { onAboutClicked() } + moreSettings.setOnClickListener { onSettingsClicked() } + } + } + + override fun onDestroyView() { + super.onDestroyView() + binding = null + } + + override fun onAttach(context: Context) { + super.onAttach(context) + ApplicationlessInjection + .getInstance(requireActivity().applicationContext) + .commonsApplicationComponent + .inject(this) + } + + fun onLogoutClicked() { + applicationKvStore.putBoolean("login_skipped", false) + val intent = Intent(context, LoginActivity::class.java) + requireActivity().finish() // Kill the activity from which you will go to next activity + startActivity(intent) + } + + fun onFeedbackClicked() { + showAlertDialog() + } + + /** + * This method shows the alert dialog when a user wants to send feedback about the app. + */ + private fun showAlertDialog() { + AlertDialog.Builder(requireActivity()) + .setMessage(R.string.feedback_sharing_data_alert) + .setCancelable(false) + .setPositiveButton(R.string.ok) { _, _ -> sendFeedback() } + .show() + } + + /** + * This method collects the feedback message and starts an activity with an implicit intent to + * the available email client. + */ + @SuppressLint("IntentReset") + private fun sendFeedback() { + val technicalInfo = commonsLogSender.getExtraInfo() + + val feedbackIntent = Intent(Intent.ACTION_SENDTO).apply { + type = "message/rfc822" + data = Uri.parse("mailto:") + putExtra(Intent.EXTRA_EMAIL, arrayOf(CommonsApplication.FEEDBACK_EMAIL)) + putExtra(Intent.EXTRA_SUBJECT, CommonsApplication.FEEDBACK_EMAIL_SUBJECT) + putExtra( + Intent.EXTRA_TEXT, + "\n\n${CommonsApplication.FEEDBACK_EMAIL_TEMPLATE_HEADER}\n$technicalInfo" + ) + } + + try { + startActivity(feedbackIntent) + } catch (e: ActivityNotFoundException) { + Toast.makeText(activity, R.string.no_email_client, Toast.LENGTH_SHORT).show() + } + } + + fun onAboutClicked() { + val intent = Intent(activity, AboutActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + requireActivity().startActivity(intent) + } + + fun onSettingsClicked() { + val intent = Intent(activity, SettingsActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT or Intent.FLAG_ACTIVITY_SINGLE_TOP) + } + requireActivity().startActivity(intent) + } + + private inner class BaseLogoutListener : CommonsApplication.LogoutListener { + + override fun onLogoutComplete() { + Timber.d("Logout complete callback received.") + val nearbyIntent = Intent(context, LoginActivity::class.java).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK) + } + startActivity(nearbyIntent) + requireActivity().finish() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTab.java b/app/src/main/java/fr/free/nrw/commons/navtab/NavTab.java deleted file mode 100644 index 0a3123c1cd..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/navtab/NavTab.java +++ /dev/null @@ -1,95 +0,0 @@ -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.nearby.fragments.NearbyParentFragment; -import fr.free.nrw.commons.wikidata.model.EnumCode; -import fr.free.nrw.commons.wikidata.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(); - } - }, - BOOKMARKS(R.string.bookmarks, 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 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; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTab.kt b/app/src/main/java/fr/free/nrw/commons/navtab/NavTab.kt new file mode 100644 index 0000000000..4573fccadb --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/navtab/NavTab.kt @@ -0,0 +1,79 @@ +package fr.free.nrw.commons.navtab + +import androidx.annotation.DrawableRes +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.nearby.fragments.NearbyParentFragment +import fr.free.nrw.commons.wikidata.model.EnumCode +import fr.free.nrw.commons.wikidata.model.EnumCodeMap + +import fr.free.nrw.commons.R + + +enum class NavTab( + @StringRes private val text: Int, + @DrawableRes private val icon: Int +) : EnumCode { + + CONTRIBUTIONS(R.string.contributions_fragment, R.drawable.ic_baseline_person_24) { + override fun newInstance(): Fragment { + return ContributionsFragment.newInstance() + } + }, + NEARBY(R.string.nearby_fragment, R.drawable.ic_location_on_black_24dp) { + override fun newInstance(): Fragment { + return NearbyParentFragment.newInstance() + } + }, + EXPLORE(R.string.navigation_item_explore, R.drawable.ic_globe) { + override fun newInstance(): Fragment { + return ExploreFragment.newInstance() + } + }, + BOOKMARKS(R.string.bookmarks, R.drawable.ic_round_star_border_24px) { + override fun newInstance(): Fragment { + return BookmarkFragment.newInstance() + } + }, + MORE(R.string.more, R.drawable.ic_menu_black_24dp) { + override fun newInstance(): Fragment? { + return null + } + }; + + companion object { + private val MAP: EnumCodeMap = EnumCodeMap(NavTab::class.java) + + @JvmStatic + fun of(code: Int): NavTab { + return MAP[code] + } + + @JvmStatic + fun size(): Int { + return MAP.size() + } + } + + @StringRes + fun text(): Int { + return text + } + + @DrawableRes + fun icon(): Int { + return icon + } + + abstract fun newInstance(): Fragment? + + override fun code(): Int { + // This enumeration is not marshalled so tying declaration order to presentation order is + // convenient and consistent. + return ordinal + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabFragmentPagerAdapter.java b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabFragmentPagerAdapter.java deleted file mode 100644 index 5384f2e01c..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabFragmentPagerAdapter.java +++ /dev/null @@ -1,38 +0,0 @@ -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); - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabFragmentPagerAdapter.kt b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabFragmentPagerAdapter.kt new file mode 100644 index 0000000000..369c39ed69 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabFragmentPagerAdapter.kt @@ -0,0 +1,36 @@ +package fr.free.nrw.commons.navtab + +import android.view.ViewGroup + +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.fragment.app.FragmentPagerAdapter + + +class NavTabFragmentPagerAdapter( + mgr: FragmentManager +) : FragmentPagerAdapter(mgr, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) { + + private var currentFragment: Fragment? = null + + fun getCurrentFragment(): Fragment? { + return currentFragment + } + + override fun getItem(pos: Int): Fragment { + return NavTab.of(pos).newInstance()!! + } + + override fun getCount(): Int { + return NavTab.size() + } + + override fun setPrimaryItem( + container: ViewGroup, + position: Int, + `object`: Any + ) { + currentFragment = `object` as Fragment + super.setPrimaryItem(container, position, `object`) + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLayout.java b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLayout.java deleted file mode 100644 index 399cbc7891..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLayout.java +++ /dev/null @@ -1,41 +0,0 @@ -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()); - } - } - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLayout.kt b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLayout.kt new file mode 100644 index 0000000000..8d5298cacd --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLayout.kt @@ -0,0 +1,47 @@ +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 + + +class NavTabLayout : BottomNavigationView { + + constructor(context: Context) : super(context) { + setTabViews() + } + + constructor( + context: Context, + attrs: AttributeSet? + ) : super(context, attrs) { + setTabViews() + } + + constructor( + context: Context, + attrs: AttributeSet?, + defStyleAttr: Int + ) : super(context, attrs, defStyleAttr) { + setTabViews() + } + + private fun setTabViews() { + val isLoginSkipped = (context as MainActivity) + .applicationKvStore.getBoolean("login_skipped") + if (isLoginSkipped) { + for (i in 0 until NavTabLoggedOut.size()) { + val navTab = NavTabLoggedOut.of(i) + menu.add(Menu.NONE, i, i, navTab.text()).setIcon(navTab.icon()) + } + } else { + for (i in 0 until NavTab.size()) { + val navTab = NavTab.of(i) + menu.add(Menu.NONE, i, i, navTab.text()).setIcon(navTab.icon()) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLoggedOut.java b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLoggedOut.java deleted file mode 100644 index dc1c7ce6bd..0000000000 --- a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLoggedOut.java +++ /dev/null @@ -1,79 +0,0 @@ -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.bookmarks.BookmarkFragment; -import fr.free.nrw.commons.explore.ExploreFragment; -import fr.free.nrw.commons.wikidata.model.EnumCode; -import fr.free.nrw.commons.wikidata.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(); - } - }, - BOOKMARKS(R.string.bookmarks, 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 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; - } -} diff --git a/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLoggedOut.kt b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLoggedOut.kt new file mode 100644 index 0000000000..ad73f1bbd9 --- /dev/null +++ b/app/src/main/java/fr/free/nrw/commons/navtab/NavTabLoggedOut.kt @@ -0,0 +1,65 @@ +package fr.free.nrw.commons.navtab + +import androidx.annotation.DrawableRes +import androidx.annotation.StringRes +import androidx.fragment.app.Fragment +import fr.free.nrw.commons.R +import fr.free.nrw.commons.bookmarks.BookmarkFragment +import fr.free.nrw.commons.explore.ExploreFragment +import fr.free.nrw.commons.wikidata.model.EnumCode +import fr.free.nrw.commons.wikidata.model.EnumCodeMap + + +enum class NavTabLoggedOut( + @StringRes private val text: Int, + @DrawableRes private val icon: Int +) : EnumCode { + + EXPLORE(R.string.navigation_item_explore, R.drawable.ic_globe) { + override fun newInstance(): Fragment { + return ExploreFragment.newInstance() + } + }, + BOOKMARKS(R.string.bookmarks, R.drawable.ic_round_star_border_24px) { + override fun newInstance(): Fragment { + return BookmarkFragment.newInstance() + } + }, + MORE(R.string.more, R.drawable.ic_menu_black_24dp) { + override fun newInstance(): Fragment? { + return null + } + }; + + companion object { + private val MAP: EnumCodeMap = EnumCodeMap(NavTabLoggedOut::class.java) + + @JvmStatic + fun of(code: Int): NavTabLoggedOut { + return MAP[code] + } + + @JvmStatic + fun size(): Int { + return MAP.size() + } + } + + @StringRes + fun text(): Int { + return text + } + + @DrawableRes + fun icon(): Int { + return icon + } + + abstract fun newInstance(): Fragment? + + override fun code(): Int { + // This enumeration is not marshalled so tying declaration order to presentation order is + // convenient and consistent. + return ordinal + } +} \ No newline at end of file