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.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import com.google.android.material.textfield.TextInputEditText;
|
||||||
|
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.R;
|
||||||
import app.organicmaps.sdk.editor.data.FeatureCategory;
|
import app.organicmaps.sdk.editor.data.FeatureCategory;
|
||||||
|
import app.organicmaps.sdk.util.StringUtils;
|
||||||
import app.organicmaps.sdk.util.UiUtils;
|
import app.organicmaps.sdk.util.UiUtils;
|
||||||
import com.google.android.material.textview.MaterialTextView;
|
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 FeatureCategoryFragment mFragment;
|
||||||
private final FeatureCategory mSelectedCategory;
|
private final FeatureCategory mSelectedCategory;
|
||||||
|
|
||||||
|
public interface FooterListener
|
||||||
|
{
|
||||||
|
void onNoteTextChanged(String newText);
|
||||||
|
void onSendNoteClicked();
|
||||||
|
}
|
||||||
|
|
||||||
public FeatureCategoryAdapter(@NonNull FeatureCategoryFragment host, @NonNull FeatureCategory[] categories,
|
public FeatureCategoryAdapter(@NonNull FeatureCategoryFragment host, @NonNull FeatureCategory[] categories,
|
||||||
@Nullable FeatureCategory category)
|
@Nullable FeatureCategory category)
|
||||||
{
|
{
|
||||||
@@ -57,7 +67,7 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||||||
case TYPE_FOOTER ->
|
case TYPE_FOOTER ->
|
||||||
{
|
{
|
||||||
return new FooterViewHolder(
|
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");
|
default -> throw new IllegalArgumentException("Unsupported");
|
||||||
}
|
}
|
||||||
@@ -70,6 +80,10 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||||||
{
|
{
|
||||||
((FeatureViewHolder) holder).bind(position);
|
((FeatureViewHolder) holder).bind(position);
|
||||||
}
|
}
|
||||||
|
else if (holder instanceof FooterViewHolder)
|
||||||
|
{
|
||||||
|
((FooterViewHolder) holder).bind(mFragment.getPendingNoteText());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -105,11 +119,36 @@ public class FeatureCategoryAdapter extends RecyclerView.Adapter<RecyclerView.Vi
|
|||||||
|
|
||||||
protected static class FooterViewHolder extends RecyclerView.ViewHolder
|
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);
|
super(itemView);
|
||||||
MaterialTextView categoryUnsuitableText = itemView.findViewById(R.id.editor_category_unsuitable_text);
|
MaterialTextView categoryUnsuitableText = itemView.findViewById(R.id.editor_category_unsuitable_text);
|
||||||
categoryUnsuitableText.setMovementMethod(LinkMovementMethod.getInstance());
|
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;
|
package app.organicmaps.editor;
|
||||||
|
|
||||||
import static app.organicmaps.sdk.util.Utils.getLocalizedFeatureType;
|
import static app.organicmaps.sdk.util.Utils.getLocalizedFeatureType;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -9,21 +8,32 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.CallSuper;
|
import androidx.annotation.CallSuper;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import app.organicmaps.R;
|
import app.organicmaps.MwmApplication;
|
||||||
import app.organicmaps.base.BaseMwmRecyclerFragment;
|
|
||||||
import app.organicmaps.sdk.editor.Editor;
|
import app.organicmaps.sdk.editor.Editor;
|
||||||
import app.organicmaps.sdk.editor.data.FeatureCategory;
|
import app.organicmaps.sdk.editor.data.FeatureCategory;
|
||||||
import app.organicmaps.sdk.util.Language;
|
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.util.Utils;
|
||||||
import app.organicmaps.widget.SearchToolbarController;
|
import app.organicmaps.widget.SearchToolbarController;
|
||||||
import app.organicmaps.widget.ToolbarController;
|
import app.organicmaps.widget.ToolbarController;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
|
||||||
public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCategoryAdapter>
|
public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCategoryAdapter> implements FeatureCategoryAdapter.FooterListener
|
||||||
{
|
{
|
||||||
private FeatureCategory mSelectedCategory;
|
private FeatureCategory mSelectedCategory;
|
||||||
protected ToolbarController mToolbarController;
|
protected ToolbarController mToolbarController;
|
||||||
|
private static final String NOTE_CONFIRMATION_SHOWN = "NoteConfirmationAlertWasShown";
|
||||||
|
private static String mPendingNoteText = "";
|
||||||
|
|
||||||
public interface FeatureCategoryListener
|
public interface FeatureCategoryListener
|
||||||
{
|
{
|
||||||
@@ -48,7 +58,8 @@ public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCate
|
|||||||
mSelectedCategory =
|
mSelectedCategory =
|
||||||
Utils.getParcelable(args, FeatureCategoryActivity.EXTRA_FEATURE_CATEGORY, FeatureCategory.class);
|
Utils.getParcelable(args, FeatureCategoryActivity.EXTRA_FEATURE_CATEGORY, FeatureCategory.class);
|
||||||
}
|
}
|
||||||
mToolbarController = new SearchToolbarController(view, requireActivity()) {
|
mToolbarController = new SearchToolbarController(view, requireActivity())
|
||||||
|
{
|
||||||
@Override
|
@Override
|
||||||
protected void onTextChanged(String query)
|
protected void onTextChanged(String query)
|
||||||
{
|
{
|
||||||
@@ -104,4 +115,62 @@ public class FeatureCategoryFragment extends BaseMwmRecyclerFragment<FeatureCate
|
|||||||
else if (getParentFragment() instanceof FeatureCategoryListener)
|
else if (getParentFragment() instanceof FeatureCategoryListener)
|
||||||
((FeatureCategoryListener) getParentFragment()).onFeatureCategorySelected(category);
|
((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"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_gravity="center"
|
android:layout_gravity="center"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:background="?windowBackgroundForced"
|
android:background="?windowBackgroundForced"
|
||||||
@@ -17,10 +18,40 @@
|
|||||||
android:textStyle="bold" />
|
android:textStyle="bold" />
|
||||||
<com.google.android.material.textview.MaterialTextView
|
<com.google.android.material.textview.MaterialTextView
|
||||||
android:id="@+id/editor_category_unsuitable_text"
|
android:id="@+id/editor_category_unsuitable_text"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="@dimen/margin_half"
|
android:layout_marginTop="@dimen/margin_half"
|
||||||
android:maxWidth="500dp"
|
android:maxWidth="500dp"
|
||||||
android:text="@string/editor_category_unsuitable_text"
|
android:text="@string/editor_category_unsuitable_text"
|
||||||
android:textAppearance="@style/MwmTextAppearance.Body3" />
|
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>
|
</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_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="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_place_button">Add Place to OpenStreetMap</string>
|
||||||
<string name="placepage_add_note">Leave Note to OpenStreetMap</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_hint">Describe the issue, add details, or suggest an improvement.</string>
|
<string name="osm_note_toast">Note will be sent to OpenStreetMap</string>
|
||||||
<string name="error_enter_note">Please enter a note text.</string>
|
|
||||||
<!-- Displayed when saving some edits to the map to warn against publishing personal data -->
|
<!-- 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>
|
<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. -->
|
<!-- 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));
|
g_editableMapObject, osm::Editor::NoteProblemType::General, jni::ToNativeString(env, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL
|
JNIEXPORT void JNICALL Java_app_organicmaps_sdk_editor_Editor_nativeCreateStandaloneNote(JNIEnv * env, jclass clazz,
|
||||||
Java_app_organicmaps_editor_Editor_nativeCreateStandaloneNote(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon,jstring text)
|
jdouble lat, jdouble lon,
|
||||||
|
jstring text)
|
||||||
{
|
{
|
||||||
osm::Editor::Instance().CreateStandaloneNote(ms::LatLon(lat, lon), jni::ToNativeString(env, 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)
|
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");
|
m_notes->CreateNote(latLon, noteText + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user