mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-21 13:53:37 +00:00
[Android] Standalone Note UI in Category select screen
Signed-off-by: hemanggs <hemangmanhas@gmail.com>
This commit is contained in:
committed by
Konstantin Pastbin
parent
9e494ed8a5
commit
2492e8bda4
@@ -7,8 +7,12 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.textfield.TextInputEditText;
|
||||
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.sdk.editor.data.FeatureCategory;
|
||||
import app.organicmaps.sdk.util.StringUtils;
|
||||
import app.organicmaps.sdk.util.UiUtils;
|
||||
import com.google.android.material.textview.MaterialTextView;
|
||||
|
||||
@@ -21,6 +25,12 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
||||
private final FeatureCategoryFragment mFragment;
|
||||
private final FeatureCategory mSelectedCategory;
|
||||
|
||||
public interface FooterListener
|
||||
{
|
||||
void onNoteTextChanged(String newText);
|
||||
void onSendNoteClicked();
|
||||
}
|
||||
|
||||
public FeatureCategoryAdapter(@NonNull FeatureCategoryFragment host, @NonNull FeatureCategory[] categories,
|
||||
@Nullable FeatureCategory category)
|
||||
{
|
||||
@@ -57,7 +67,7 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
||||
case TYPE_FOOTER ->
|
||||
{
|
||||
return new FooterViewHolder(
|
||||
LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feature_category_footer, parent, false));
|
||||
LayoutInflater.from(parent.getContext()).inflate(R.layout.item_feature_category_footer, parent, false), (FooterListener) mFragment);
|
||||
}
|
||||
default -> throw new IllegalArgumentException("Unsupported");
|
||||
}
|
||||
@@ -70,6 +80,10 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
||||
{
|
||||
((FeatureViewHolder) holder).bind(position);
|
||||
}
|
||||
else if (holder instanceof FooterViewHolder)
|
||||
{
|
||||
((FooterViewHolder) holder).bind(mFragment.getPendingNoteText());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,11 +119,36 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
||||
|
||||
protected static class FooterViewHolder extends RecyclerView.ViewHolder
|
||||
{
|
||||
FooterViewHolder(@NonNull View itemView)
|
||||
private final TextInputEditText mNoteEditText;
|
||||
private final View mSendNoteButton;
|
||||
|
||||
FooterViewHolder(@NonNull View itemView, @NonNull FooterListener listener)
|
||||
{
|
||||
super(itemView);
|
||||
MaterialTextView categoryUnsuitableText = itemView.findViewById(R.id.editor_category_unsuitable_text);
|
||||
categoryUnsuitableText.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
mNoteEditText = itemView.findViewById(R.id.note_edit_text);
|
||||
mSendNoteButton = itemView.findViewById(R.id.send_note_button);
|
||||
mSendNoteButton.setOnClickListener(v -> listener.onSendNoteClicked());
|
||||
mNoteEditText.addTextChangedListener(new StringUtils.SimpleTextWatcher() {
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count)
|
||||
{
|
||||
final String str = s.toString();
|
||||
listener.onNoteTextChanged(str);
|
||||
mSendNoteButton.setEnabled(!str.trim().isEmpty());
|
||||
}
|
||||
});
|
||||
}
|
||||
public void bind(String pendingNoteText)
|
||||
{
|
||||
if (!mNoteEditText.getText().toString().equals(pendingNoteText))
|
||||
{
|
||||
mNoteEditText.setText(pendingNoteText);
|
||||
if (pendingNoteText != null)
|
||||
mNoteEditText.setSelection(pendingNoteText.length());
|
||||
}
|
||||
mSendNoteButton.setEnabled(pendingNoteText != null && !pendingNoteText.trim().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package app.organicmaps.editor;
|
||||
|
||||
import static app.organicmaps.sdk.util.Utils.getLocalizedFeatureType;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -9,21 +8,32 @@ import android.view.ViewGroup;
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.base.BaseMwmRecyclerFragment;
|
||||
import app.organicmaps.MwmApplication;
|
||||
import app.organicmaps.sdk.editor.Editor;
|
||||
import app.organicmaps.sdk.editor.data.FeatureCategory;
|
||||
import app.organicmaps.sdk.util.Language;
|
||||
import app.organicmaps.sdk.editor.OsmOAuth;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import android.text.TextUtils;
|
||||
import android.content.Intent;
|
||||
import android.widget.Toast;
|
||||
|
||||
import app.organicmaps.sdk.Framework;
|
||||
import app.organicmaps.R;
|
||||
import app.organicmaps.base.BaseMwmRecyclerFragment;
|
||||
import app.organicmaps.dialog.EditTextDialogFragment;
|
||||
import app.organicmaps.util.Utils;
|
||||
import app.organicmaps.widget.SearchToolbarController;
|
||||
import app.organicmaps.widget.ToolbarController;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
|
||||
public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCategoryAdapter>
|
||||
public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCategoryAdapter> implements FeatureCategoryAdapter.FooterListener
|
||||
{
|
||||
private FeatureCategory mSelectedCategory;
|
||||
protected ToolbarController mToolbarController;
|
||||
private static final String NOTE_CONFIRMATION_SHOWN = "NoteConfirmationAlertWasShown";
|
||||
private static String mPendingNoteText = "";
|
||||
|
||||
public interface FeatureCategoryListener
|
||||
{
|
||||
@@ -48,7 +58,8 @@ public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCate
|
||||
mSelectedCategory =
|
||||
Utils.getParcelable(args, FeatureCategoryActivity.EXTRA_FEATURE_CATEGORY, FeatureCategory.class);
|
||||
}
|
||||
mToolbarController = new SearchToolbarController(view, requireActivity()) {
|
||||
mToolbarController = new SearchToolbarController(view, requireActivity())
|
||||
{
|
||||
@Override
|
||||
protected void onTextChanged(String query)
|
||||
{
|
||||
@@ -104,4 +115,62 @@ public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCate
|
||||
else if (getParentFragment() instanceof FeatureCategoryListener)
|
||||
((FeatureCategoryListener) getParentFragment()).onFeatureCategorySelected(category);
|
||||
}
|
||||
|
||||
public String getPendingNoteText()
|
||||
{
|
||||
return mPendingNoteText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNoteTextChanged(String newText)
|
||||
{
|
||||
mPendingNoteText = newText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendNoteClicked()
|
||||
{
|
||||
if (!OsmOAuth.isAuthorized())
|
||||
{
|
||||
final Intent intent = new Intent(requireActivity(), OsmLoginActivity.class);
|
||||
startActivity(intent);
|
||||
return;
|
||||
}
|
||||
|
||||
final double[] center = Framework.nativeGetScreenRectCenter();
|
||||
final double lat = center[0];
|
||||
final double lon = center[1];
|
||||
|
||||
if (!MwmApplication.prefs(requireContext().getApplicationContext()).contains(NOTE_CONFIRMATION_SHOWN))
|
||||
{
|
||||
showNoteConfirmationDialog(lat, lon, mPendingNoteText);
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.nativeCreateStandaloneNote(lat, lon, mPendingNoteText);
|
||||
mPendingNoteText = "";
|
||||
Toast.makeText(requireContext(), R.string.osm_note_toast, Toast.LENGTH_SHORT).show();
|
||||
requireActivity().finish();
|
||||
}
|
||||
}
|
||||
|
||||
// Duplicate of showNoobDialog()
|
||||
private void showNoteConfirmationDialog(double lat, double lon, String noteText)
|
||||
{
|
||||
new MaterialAlertDialogBuilder(requireActivity(), R.style.MwmTheme_AlertDialog)
|
||||
.setTitle(R.string.editor_share_to_all_dialog_title)
|
||||
.setMessage(getString(R.string.editor_share_to_all_dialog_message_1)
|
||||
+ " " + getString(R.string.editor_share_to_all_dialog_message_2))
|
||||
.setPositiveButton(android.R.string.ok, (dlg, which) -> {
|
||||
MwmApplication.prefs(requireContext().getApplicationContext()).edit()
|
||||
.putBoolean(NOTE_CONFIRMATION_SHOWN, true)
|
||||
.apply();
|
||||
Editor.nativeCreateStandaloneNote(lat, lon, noteText);
|
||||
mPendingNoteText = "";
|
||||
Toast.makeText(requireContext(), R.string.osm_note_toast, Toast.LENGTH_SHORT).show();
|
||||
requireActivity().finish();
|
||||
})
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:background="?windowBackgroundForced"
|
||||
@@ -17,10 +18,40 @@
|
||||
android:textStyle="bold" />
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/editor_category_unsuitable_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/margin_half"
|
||||
android:maxWidth="500dp"
|
||||
android:text="@string/editor_category_unsuitable_text"
|
||||
android:textAppearance="@style/MwmTextAppearance.Body3" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/note_input_layout"
|
||||
style="@style/MwmWidget.Editor.CustomTextInput"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColorHint="?android:textColorSecondary"
|
||||
android:layout_marginTop="@dimen/margin_base_plus"
|
||||
app:hintEnabled="false">
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/note_edit_text"
|
||||
style="@style/MwmWidget.Editor.FieldLayout.EditText"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/osm_note_hint"
|
||||
android:inputType="textMultiLine"
|
||||
android:gravity="top"
|
||||
android:minLines="3"
|
||||
android:maxLines="6" />
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/send_note_button"
|
||||
style="@style/MwmWidget.Button.Accent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="@dimen/margin_base"
|
||||
android:enabled="false"
|
||||
android:text="@string/editor_report_problem_send_button" />
|
||||
</LinearLayout>
|
||||
@@ -610,9 +610,8 @@
|
||||
<string name="error_enter_correct_fediverse_page">Enter a valid Mastodon username or web address</string>
|
||||
<string name="error_enter_correct_bluesky_page">Enter a valid Bluesky username or web address</string>
|
||||
<string name="placepage_add_place_button">Add Place to OpenStreetMap</string>
|
||||
<string name="placepage_add_note">Leave Note to OpenStreetMap</string>
|
||||
<string name="osm_note_hint">Describe the issue, add details, or suggest an improvement.</string>
|
||||
<string name="error_enter_note">Please enter a note text.</string>
|
||||
<string name="osm_note_hint">Or, alternatively, leave a note to OpenStreetMap community so that someone else can add or fix a place here.</string>
|
||||
<string name="osm_note_toast">Note will be sent to OpenStreetMap</string>
|
||||
<!-- Displayed when saving some edits to the map to warn against publishing personal data -->
|
||||
<string name="editor_share_to_all_dialog_title">Do you want to send it to all users?</string>
|
||||
<!-- Dialog before publishing the modifications to the public map. -->
|
||||
|
||||
@@ -391,8 +391,9 @@ Java_app_organicmaps_sdk_editor_Editor_nativeCreateNote(JNIEnv * env, jclass cla
|
||||
g_editableMapObject, osm::Editor::NoteProblemType::General, jni::ToNativeString(env, text));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_app_organicmaps_editor_Editor_nativeCreateStandaloneNote(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon,jstring text)
|
||||
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeCreateStandaloneNote(JNIEnv * env, jclass clazz,
|
||||
jdouble lat, jdouble lon,
|
||||
jstring text)
|
||||
{
|
||||
osm::Editor::Instance().CreateStandaloneNote(ms::LatLon(lat, lon), jni::ToNativeString(env, text));
|
||||
}
|
||||
|
||||
@@ -1186,7 +1186,7 @@ void Editor::CreateNote(ms::LatLon const & latLon, FeatureID const & fid,
|
||||
|
||||
void Editor::CreateStandaloneNote(ms::LatLon const & latLon, std::string const & noteText)
|
||||
{
|
||||
CHECK_THREAD_CHECKER(MainThreadChecker,(""));
|
||||
CHECK_THREAD_CHECKER(MainThreadChecker, (""));
|
||||
m_notes->CreateNote(latLon, noteText + "\n");
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user