Merge branch 'master' into 354-password-protection

This commit is contained in:
Christoph Loy 2020-03-08 12:45:14 +01:00
commit 5782a49e66
No known key found for this signature in database
GPG key ID: 9179970615A6E7C9
31 changed files with 130 additions and 147 deletions

View file

@ -30,10 +30,7 @@ public class AlwaysAutoCompleteTextView extends AppCompatAutoCompleteTextView {
@Override @Override
public void setThreshold(int threshold) { public void setThreshold(int threshold) {
if (threshold < 0) { myThreshold = Math.max(threshold, 0);
threshold = 0;
}
myThreshold = threshold;
} }
@Override @Override

View file

@ -71,7 +71,7 @@ public class MultiSelectedActionModeCallback implements Callback {
@Override @Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.menu_delete: { case R.id.menu_delete:
try { try {
SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context); SingleSignOnAccount ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(context);
List<DBNote> deletedNotes = new ArrayList<>(); List<DBNote> deletedNotes = new ArrayList<>();
@ -106,14 +106,13 @@ public class MultiSelectedActionModeCallback implements Callback {
e.printStackTrace(); e.printStackTrace();
} }
return true; return true;
} case R.id.menu_move:
case R.id.menu_move: {
AccountChooserDialogFragment.newInstance().show(fragmentManager, NotesListViewActivity.class.getCanonicalName()); AccountChooserDialogFragment.newInstance().show(fragmentManager, NotesListViewActivity.class.getCanonicalName());
return true; return true;
} default:
}
return false; return false;
} }
}
@Override @Override
public void onDestroyActionMode(ActionMode mode) { public void onDestroyActionMode(ActionMode mode) {

View file

@ -60,7 +60,7 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
@Override @Override
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) { public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
switch (direction) { switch (direction) {
case ItemTouchHelper.LEFT: { case ItemTouchHelper.LEFT:
final DBNote dbNoteWithoutContent = (DBNote) adapter.getItem(viewHolder.getAdapterPosition()); final DBNote dbNoteWithoutContent = (DBNote) adapter.getItem(viewHolder.getAdapterPosition());
final DBNote dbNote = db.getNote(dbNoteWithoutContent.getAccountId(), dbNoteWithoutContent.getId()); final DBNote dbNote = db.getNote(dbNoteWithoutContent.getAccountId(), dbNoteWithoutContent.getId());
db.deleteNoteAndSync(ssoAccount, dbNote.getId()); db.deleteNoteAndSync(ssoAccount, dbNote.getId());
@ -77,13 +77,13 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
}) })
.show(); .show();
break; break;
} case ItemTouchHelper.RIGHT:
case ItemTouchHelper.RIGHT: { final DBNote adapterNote = (DBNote) adapter.getItem(viewHolder.getAdapterPosition());
final DBNote dbNote = (DBNote) adapter.getItem(viewHolder.getAdapterPosition()); db.toggleFavorite(ssoAccount, adapterNote, syncCallBack);
db.toggleFavorite(ssoAccount, dbNote, syncCallBack);
refreshLists.run(); refreshLists.run();
break; break;
} default:
//NoOp
} }
} }

View file

@ -157,7 +157,7 @@ public class EditNoteActivity extends LockedActivity implements BaseNoteFragment
String category = null; String category = null;
boolean favorite = false; boolean favorite = false;
if (intent.hasExtra(PARAM_CATEGORY)) { if (intent.hasExtra(PARAM_CATEGORY)) {
Category categoryPreselection = (Category) intent.getSerializableExtra(PARAM_CATEGORY); Category categoryPreselection = (Category) Objects.requireNonNull(intent.getSerializableExtra(PARAM_CATEGORY));
category = categoryPreselection.category; category = categoryPreselection.category;
favorite = categoryPreselection.favorite != null ? categoryPreselection.favorite : false; favorite = categoryPreselection.favorite != null ? categoryPreselection.favorite : false;
} }

View file

@ -11,6 +11,8 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import java.util.Objects;
import it.niedermann.nextcloud.exception.ExceptionUtil; import it.niedermann.nextcloud.exception.ExceptionUtil;
import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.R;
@ -18,8 +20,6 @@ import static it.niedermann.nextcloud.exception.ExceptionHandler.KEY_THROWABLE;
public class ExceptionActivity extends AppCompatActivity { public class ExceptionActivity extends AppCompatActivity {
Throwable throwable;
private TextView stacktrace; private TextView stacktrace;
@SuppressLint("SetTextI18n") // only used for logging @SuppressLint("SetTextI18n") // only used for logging
@ -38,7 +38,7 @@ public class ExceptionActivity extends AppCompatActivity {
findViewById(R.id.close).setOnClickListener((v) -> close()); findViewById(R.id.close).setOnClickListener((v) -> close());
setSupportActionBar(toolbar); setSupportActionBar(toolbar);
throwable = ((Throwable) getIntent().getSerializableExtra(KEY_THROWABLE)); Throwable throwable = (Throwable) Objects.requireNonNull(getIntent().getSerializableExtra(KEY_THROWABLE));
throwable.printStackTrace(); throwable.printStackTrace();
toolbar.setTitle(getString(R.string.simple_error)); toolbar.setTitle(getString(R.string.simple_error));
message.setText(throwable.getMessage()); message.setText(throwable.getMessage());
@ -46,14 +46,14 @@ public class ExceptionActivity extends AppCompatActivity {
} }
void copyStacktraceToClipboard() { private void copyStacktraceToClipboard() {
final ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); final ClipboardManager clipboardManager = (ClipboardManager) Objects.requireNonNull(getSystemService(CLIPBOARD_SERVICE));
ClipData clipData = ClipData.newPlainText(getString(R.string.simple_exception), "```\n" + this.stacktrace.getText() + "\n```"); ClipData clipData = ClipData.newPlainText(getString(R.string.simple_exception), "```\n" + this.stacktrace.getText() + "\n```");
clipboardManager.setPrimaryClip(clipData); clipboardManager.setPrimaryClip(clipData);
Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show(); Toast.makeText(this, R.string.copied_to_clipboard, Toast.LENGTH_SHORT).show();
} }
void close() { private void close() {
finish(); finish();
} }
} }

View file

@ -35,10 +35,11 @@ public class NoteListWidgetConfigurationActivity extends LockedActivity {
private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID; private int appWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
LocalAccount localAccount = null; private LocalAccount localAccount = null;
private NavigationAdapter adapterCategories; private NavigationAdapter adapterCategories;
private NavigationAdapter.NavigationItem itemRecent, itemFavorites; private NavigationAdapter.NavigationItem itemRecent;
private NavigationAdapter.NavigationItem itemFavorites;
private NotesDatabase db = null; private NotesDatabase db = null;
@Override @Override
@ -144,7 +145,9 @@ public class NoteListWidgetConfigurationActivity extends LockedActivity {
} }
Map<String, Integer> favorites = db.getFavoritesCount(localAccount.getId()); Map<String, Integer> favorites = db.getFavoritesCount(localAccount.getId());
//noinspection ConstantConditions
int numFavorites = favorites.containsKey("1") ? favorites.get("1") : 0; int numFavorites = favorites.containsKey("1") ? favorites.get("1") : 0;
//noinspection ConstantConditions
int numNonFavorites = favorites.containsKey("0") ? favorites.get("0") : 0; int numNonFavorites = favorites.containsKey("0") ? favorites.get("0") : 0;
itemFavorites.count = numFavorites; itemFavorites.count = numFavorites;
itemRecent.count = numFavorites + numNonFavorites; itemRecent.count = numFavorites + numNonFavorites;

View file

@ -106,7 +106,9 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
private ActionBarDrawerToggle drawerToggle; private ActionBarDrawerToggle drawerToggle;
private NavigationAdapter adapterCategories; private NavigationAdapter adapterCategories;
private NavigationItem itemRecent, itemFavorites, itemUncategorized; private NavigationItem itemRecent;
private NavigationItem itemFavorites;
private NavigationItem itemUncategorized;
private Category navigationSelection = new Category(null, null); private Category navigationSelection = new Category(null, null);
private String navigationOpen = ""; private String navigationOpen = "";
private ActionMode mActionMode; private ActionMode mActionMode;
@ -412,7 +414,9 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
} }
Map<String, Integer> favorites = db.getFavoritesCount(localAccount.getId()); Map<String, Integer> favorites = db.getFavoritesCount(localAccount.getId());
//noinspection ConstantConditions
int numFavorites = favorites.containsKey("1") ? favorites.get("1") : 0; int numFavorites = favorites.containsKey("1") ? favorites.get("1") : 0;
//noinspection ConstantConditions
int numNonFavorites = favorites.containsKey("0") ? favorites.get("0") : 0; int numNonFavorites = favorites.containsKey("0") ? favorites.get("0") : 0;
itemFavorites.count = numFavorites; itemFavorites.count = numFavorites;
itemRecent.count = numFavorites + numNonFavorites; itemRecent.count = numFavorites + numNonFavorites;
@ -420,7 +424,8 @@ public class NotesListViewActivity extends LockedActivity implements ItemAdapter
ArrayList<NavigationItem> items = new ArrayList<>(); ArrayList<NavigationItem> items = new ArrayList<>();
items.add(itemRecent); items.add(itemRecent);
items.add(itemFavorites); items.add(itemFavorites);
NavigationItem lastPrimaryCategory = null, lastSecondaryCategory = null; NavigationItem lastPrimaryCategory = null;
NavigationItem lastSecondaryCategory = null;
for (NavigationItem item : categories) { for (NavigationItem item : categories) {
int slashIndex = item.label.indexOf('/'); int slashIndex = item.label.indexOf('/');
String currentPrimaryCategory = slashIndex < 0 ? item.label : item.label.substring(0, slashIndex); String currentPrimaryCategory = slashIndex < 0 ? item.label : item.label.substring(0, slashIndex);

View file

@ -154,8 +154,8 @@ public class NoteListWidget extends AppWidgetProvider {
} else { } else {
return category; return category;
} }
} default:
return null; return null;
} }
}
} }

View file

@ -64,7 +64,7 @@ public class NoteListWidgetFactory implements RemoteViewsService.RemoteViewsFact
@Override @Override
public void onDestroy() { public void onDestroy() {
//NoOp
} }
/** /**

View file

@ -70,7 +70,7 @@ public class SingleNoteWidgetFactory implements RemoteViewsService.RemoteViewsFa
@Override @Override
public void onDestroy() { public void onDestroy() {
//NoOp
} }
/** /**

View file

@ -61,7 +61,7 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
protected NotesDatabase db; protected NotesDatabase db;
private NoteFragmentListener listener; private NoteFragmentListener listener;
boolean isNew = true; protected boolean isNew = true;
@Override @Override
public void onCreate(@Nullable Bundle savedInstanceState) { public void onCreate(@Nullable Bundle savedInstanceState) {
@ -146,7 +146,7 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) { public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_note_fragment, menu); inflater.inflate(R.menu.menu_note_fragment, menu);
if (isRequestPinShortcutSupported(requireActivity()) && android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (isRequestPinShortcutSupported(requireActivity()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
menu.add(Menu.NONE, MENU_ID_PIN, 110, R.string.pin_to_homescreen); menu.add(Menu.NONE, MENU_ID_PIN, 110, R.string.pin_to_homescreen);
} }
} }
@ -198,8 +198,8 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
Intent shareIntent = new Intent(); Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND); shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.setType("text/plain"); shareIntent.setType("text/plain");
shareIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, note.getTitle()); shareIntent.putExtra(Intent.EXTRA_SUBJECT, note.getTitle());
shareIntent.putExtra(android.content.Intent.EXTRA_TEXT, note.getContent()); shareIntent.putExtra(Intent.EXTRA_TEXT, note.getContent());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
@ -211,7 +211,7 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
return false; return false;
case MENU_ID_PIN: case MENU_ID_PIN:
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
ShortcutManager shortcutManager = requireActivity().getSystemService(ShortcutManager.class); ShortcutManager shortcutManager = requireActivity().getSystemService(ShortcutManager.class);
if (shortcutManager != null) { if (shortcutManager != null) {
@ -274,7 +274,8 @@ public abstract class BaseNoteFragment extends Fragment implements CategoryDialo
} }
} }
float getFontSizeFromPreferences(SharedPreferences sp) { @SuppressWarnings("WeakerAccess") //PMD...
protected float getFontSizeFromPreferences(SharedPreferences sp) {
final String prefValueSmall = getString(R.string.pref_value_font_size_small); final String prefValueSmall = getString(R.string.pref_value_font_size_small);
final String prefValueMedium = getString(R.string.pref_value_font_size_medium); final String prefValueMedium = getString(R.string.pref_value_font_size_medium);
// final String prefValueLarge = getString(R.string.pref_value_font_size_large); // final String prefValueLarge = getString(R.string.pref_value_font_size_large);

View file

@ -48,25 +48,23 @@ public class CategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
CategoryViewHolder categoryViewHolder = (CategoryViewHolder) holder; CategoryViewHolder categoryViewHolder = (CategoryViewHolder) holder;
switch (category.id) { switch (category.id) {
case addItemId: { case addItemId:
Drawable wrapDrawable = DrawableCompat.wrap(context.getResources().getDrawable(category.icon)); Drawable wrapDrawable = DrawableCompat.wrap(context.getResources().getDrawable(category.icon));
DrawableCompat.setTint(wrapDrawable, context.getResources().getColor(R.color.icon_color_default)); DrawableCompat.setTint(wrapDrawable, context.getResources().getColor(R.color.icon_color_default));
categoryViewHolder.getIcon().setImageDrawable(wrapDrawable); categoryViewHolder.getIcon().setImageDrawable(wrapDrawable);
categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryAdded()); categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryAdded());
break; break;
} case clearItemId:
case clearItemId: {
categoryViewHolder.getIcon().setImageDrawable(context.getResources().getDrawable(category.icon)); categoryViewHolder.getIcon().setImageDrawable(context.getResources().getDrawable(category.icon));
categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryCleared()); categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryCleared());
break; break;
} default:
default: {
categoryViewHolder.getIcon().setImageDrawable(context.getResources().getDrawable(category.icon)); categoryViewHolder.getIcon().setImageDrawable(context.getResources().getDrawable(category.icon));
categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryChosen(category.label)); categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryChosen(category.label));
} break;
} }
categoryViewHolder.getCategory().setText(NoteUtil.extendCategory(category.label)); categoryViewHolder.getCategory().setText(NoteUtil.extendCategory(category.label));
if (category.count > 0) { if (category.count != null && category.count > 0) {
categoryViewHolder.getCount().setText(String.valueOf(category.count)); categoryViewHolder.getCount().setText(String.valueOf(category.count));
} else { } else {
categoryViewHolder.getCount().setVisibility(View.GONE); categoryViewHolder.getCount().setVisibility(View.GONE);

View file

@ -61,7 +61,7 @@ public class CategoryDialogFragment extends AppCompatDialogFragment {
@Override @Override
public void onAttach(@NonNull Context context) { public void onAttach(@NonNull Context context) {
super.onAttach(context); super.onAttach(context);
if (requireArguments() != null && requireArguments().containsKey(PARAM_ACCOUNT_ID)) { if (getArguments() != null && requireArguments().containsKey(PARAM_ACCOUNT_ID)) {
accountId = requireArguments().getLong(PARAM_ACCOUNT_ID); accountId = requireArguments().getLong(PARAM_ACCOUNT_ID);
} else { } else {
throw new IllegalArgumentException("Provide at least \"" + PARAM_ACCOUNT_ID + "\""); throw new IllegalArgumentException("Provide at least \"" + PARAM_ACCOUNT_ID + "\"");
@ -151,7 +151,7 @@ public class CategoryDialogFragment extends AppCompatDialogFragment {
super.onActivityCreated(savedInstanceState); super.onActivityCreated(savedInstanceState);
if (editCategory.getText() == null || editCategory.getText().length() == 0) { if (editCategory.getText() == null || editCategory.getText().length() == 0) {
editCategory.requestFocus(); editCategory.requestFocus();
if (getDialog().getWindow() != null) { if (getDialog() != null && getDialog().getWindow() != null) {
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
} else { } else {
Log.w(TAG, "can not set SOFT_INPUT_STATE_ALWAYAS_VISIBLE because getWindow() == null"); Log.w(TAG, "can not set SOFT_INPUT_STATE_ALWAYAS_VISIBLE because getWindow() == null");

View file

@ -51,7 +51,8 @@ public class NoteEditFragment extends SearchableBaseNoteFragment {
private FragmentNoteEditBinding binding; private FragmentNoteEditBinding binding;
private Handler handler; private Handler handler;
private boolean saveActive, unsavedEdit; private boolean saveActive;
private boolean unsavedEdit;
private final Runnable runAutoSave = new Runnable() { private final Runnable runAutoSave = new Runnable() {
@Override @Override
public void run() { public void run() {

View file

@ -94,7 +94,7 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup
container, @Nullable Bundle savedInstanceState) { container, @Nullable Bundle savedInstanceState) {
binding = FragmentNotePreviewBinding.inflate(inflater, container, false); binding = FragmentNotePreviewBinding.inflate(inflater, container, false);
return binding.getRoot(); return binding.getRoot();

View file

@ -87,7 +87,7 @@ public class NoteReadonlyFragment extends SearchableBaseNoteFragment {
@Nullable @Nullable
@Override @Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup
container, @Nullable Bundle savedInstanceState) { container, @Nullable Bundle savedInstanceState) {
binding = FragmentNotePreviewBinding.inflate(inflater, container, false); binding = FragmentNotePreviewBinding.inflate(inflater, container, false);
return binding.getRoot(); return binding.getRoot();

View file

@ -42,8 +42,8 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
assert themePref != null; assert themePref != null;
themePref.setOnPreferenceChangeListener((preference, newValue) -> { themePref.setOnPreferenceChangeListener((preference, newValue) -> {
Notes.setAppTheme(DarkModeSetting.valueOf((String) newValue)); Notes.setAppTheme(DarkModeSetting.valueOf((String) newValue));
getActivity().setResult(Activity.RESULT_OK); requireActivity().setResult(Activity.RESULT_OK);
getActivity().recreate(); requireActivity().recreate();
return true; return true;
}); });
@ -58,7 +58,7 @@ public class PreferencesFragment extends PreferenceFragmentCompat {
assert syncPref != null; assert syncPref != null;
syncPref.setOnPreferenceChangeListener((preference, newValue) -> { syncPref.setOnPreferenceChangeListener((preference, newValue) -> {
Log.v(TAG, "syncPref: " + preference + " - newValue: " + newValue); Log.v(TAG, "syncPref: " + preference + " - newValue: " + newValue);
SyncWorker.update(getContext(), newValue.toString()); SyncWorker.update(requireContext(), newValue.toString());
return true; return true;
}); });
} }

View file

@ -172,22 +172,13 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
Layout layout = getLayout(); Layout layout = getLayout();
if (layout == null) { if (layout == null) {
Log.w(TAG, "getLayout() is null"); Log.w(TAG, "getLayout() is null");
return; } else if (getContent() == null || getContent().isEmpty()) {
} Log.w(TAG, "getContent is null or empty");
if (getContent() == null || getContent().isEmpty()) { } else if (currentOccurrence < 1) {
Log.w(TAG, "getContent() returned " + getContent());
return;
}
if (searchQuery == null || searchQuery.isEmpty()) {
// No search term
return;
}
if (currentOccurrence < 1) {
// if currentOccurrence is lower than 1, jump to last occurrence // if currentOccurrence is lower than 1, jump to last occurrence
currentOccurrence = occurrenceCount; currentOccurrence = occurrenceCount;
jumpToOccurrence(); jumpToOccurrence();
return; } else if (searchQuery != null && !searchQuery.isEmpty()) {
}
String currentContent = getContent().toLowerCase(); String currentContent = getContent().toLowerCase();
int indexOfNewText = indexOfNth(currentContent, searchQuery.toLowerCase(), 0, currentOccurrence); int indexOfNewText = indexOfNth(currentContent, searchQuery.toLowerCase(), 0, currentOccurrence);
if (indexOfNewText <= 0) { if (indexOfNewText <= 0) {
@ -206,6 +197,7 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
getScrollView().smoothScrollTo(0, layout.getLineTop(numberLine)); getScrollView().smoothScrollTo(0, layout.getLineTop(numberLine));
} }
} }
}
private static int indexOfNth(String input, String value, int startIndex, int nth) { private static int indexOfNth(String input, String value, int startIndex, int nth) {
if (nth < 1) if (nth < 1)
@ -215,20 +207,18 @@ public abstract class SearchableBaseNoteFragment extends BaseNoteFragment {
int idx = input.indexOf(value, startIndex); int idx = input.indexOf(value, startIndex);
if (idx == -1) if (idx == -1)
return -1; return -1;
return indexOfNth(input, value, idx + 1, --nth); return indexOfNth(input, value, idx + 1, nth - 1);
} }
private static int countOccurrences(String haystack, String needle) { private static int countOccurrences(String haystack, String needle) {
if (haystack == null || haystack.isEmpty() || needle == null || needle.isEmpty()) { if (haystack == null || haystack.isEmpty() || needle == null || needle.isEmpty()) {
return 0; return 0;
} }
haystack = haystack.toLowerCase();
needle = needle.toLowerCase();
int lastIndex = 0; int lastIndex = 0;
int count = 0; int count = 0;
while (lastIndex != -1) { while (lastIndex != -1) {
lastIndex = haystack.indexOf(needle, lastIndex); lastIndex = haystack.toLowerCase().indexOf(needle.toLowerCase(), lastIndex);
if (lastIndex != -1) { if (lastIndex != -1) {
count++; count++;
lastIndex += needle.length(); lastIndex += needle.length();

View file

@ -16,7 +16,7 @@ import it.niedermann.owncloud.notes.util.SupportUtil;
public class AboutFragmentLicenseTab extends Fragment { public class AboutFragmentLicenseTab extends Fragment {
void openLicense() { private void openLicense() {
startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_license)))); startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.url_license))));
} }

View file

@ -14,9 +14,9 @@ import it.niedermann.owncloud.notes.util.NoteUtil;
* It can be directly generated from the JSON answer from the server. * It can be directly generated from the JSON answer from the server.
*/ */
public class CloudNote implements Serializable { public class CloudNote implements Serializable {
private long remoteId = 0; private long remoteId;
private String title = ""; private String title = "";
private Calendar modified = null; private Calendar modified;
private String content = ""; private String content = "";
private boolean favorite = false; private boolean favorite = false;
private String category = ""; private String category = "";
@ -51,7 +51,6 @@ public class CloudNote implements Serializable {
this.title = NoteUtil.removeMarkDown(title); this.title = NoteUtil.removeMarkDown(title);
} }
@SuppressWarnings("WeakerAccess")
public Calendar getModified() { public Calendar getModified() {
return modified; return modified;
} }

View file

@ -57,9 +57,6 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
@NonNull @NonNull
private final View view; private final View view;
@NonNull
private final ItemNavigationBinding binding;
@NonNull @NonNull
private final TextView name; private final TextView name;
@NonNull @NonNull
@ -72,7 +69,7 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
ViewHolder(@NonNull View itemView, @NonNull final ClickListener clickListener) { ViewHolder(@NonNull View itemView, @NonNull final ClickListener clickListener) {
super(itemView); super(itemView);
view = itemView; view = itemView;
binding = ItemNavigationBinding.bind(view); ItemNavigationBinding binding = ItemNavigationBinding.bind(view);
this.name = binding.navigationItemLabel; this.name = binding.navigationItemLabel;
this.count = binding.navigationItemCount; this.count = binding.navigationItemCount;
this.icon = binding.navigationItemIcon; this.icon = binding.navigationItemIcon;
@ -80,7 +77,7 @@ public class NavigationAdapter extends RecyclerView.Adapter<NavigationAdapter.Vi
itemView.setOnClickListener(view -> clickListener.onItemClick(currentItem)); itemView.setOnClickListener(view -> clickListener.onItemClick(currentItem));
} }
void assignItem(@NonNull NavigationItem item) { private void assignItem(@NonNull NavigationItem item) {
currentItem = item; currentItem = item;
boolean isSelected = item.id.equals(selectedItem); boolean isSelected = item.id.equals(selectedItem);
name.setText(NoteUtil.extendCategory(item.label)); name.setText(NoteUtil.extendCategory(item.label));

View file

@ -32,6 +32,7 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
private static final String TAG = AbstractNotesDatabase.class.getSimpleName(); private static final String TAG = AbstractNotesDatabase.class.getSimpleName();
private static final int database_version = 11; private static final int database_version = 11;
@NonNull
private final Context context; private final Context context;
protected static final String database_name = "OWNCLOUD_NOTES"; protected static final String database_name = "OWNCLOUD_NOTES";
@ -55,12 +56,13 @@ abstract class AbstractNotesDatabase extends SQLiteOpenHelper {
protected static final String key_category = "CATEGORY"; protected static final String key_category = "CATEGORY";
protected static final String key_etag = "ETAG"; protected static final String key_etag = "ETAG";
protected AbstractNotesDatabase(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory) { protected AbstractNotesDatabase(@NonNull Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory) {
super(context, name, factory, database_version); super(context, name, factory, database_version);
this.context = context; this.context = context;
} }
@NonNull
public Context getContext() { public Context getContext() {
return context; return context;
} }

View file

@ -103,7 +103,7 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
for (int i = 0; i < noteList.size(); i++) { for (int i = 0; i < noteList.size(); i++) {
DBNote currentNote = noteList.get(i); DBNote currentNote = noteList.get(i);
String timeslot = timeslotter.getTimeslot(currentNote); String timeslot = timeslotter.getTimeslot(currentNote);
if(i > 0 && !timeslot.equals(lastTimeslot)) { if (i > 0 && !timeslot.equals(lastTimeslot)) {
itemList.add(new SectionItem(timeslot)); itemList.add(new SectionItem(timeslot));
} }
itemList.add(colorTheNote(currentNote)); itemList.add(colorTheNote(currentNote));
@ -132,16 +132,16 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
int day = now.get(Calendar.DAY_OF_MONTH); int day = now.get(Calendar.DAY_OF_MONTH);
int offsetWeekStart = (now.get(Calendar.DAY_OF_WEEK) - now.getFirstDayOfWeek() + 7) % 7; int offsetWeekStart = (now.get(Calendar.DAY_OF_WEEK) - now.getFirstDayOfWeek() + 7) % 7;
timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_today), month, day)); timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_today), month, day));
timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_yesterday), month,day - 1)); timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_yesterday), month, day - 1));
timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_this_week), month,day - offsetWeekStart)); timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_this_week), month, day - offsetWeekStart));
timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_last_week), month,day - offsetWeekStart - 7)); timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_last_week), month, day - offsetWeekStart - 7));
timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_this_month), month,1)); timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_this_month), month, 1));
timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_last_month), month - 1, 1)); timeslots.add(new Timeslot(context.getResources().getString(R.string.listview_updated_last_month), month - 1, 1));
lastYear = Calendar.getInstance(); lastYear = Calendar.getInstance();
lastYear.set(now.get(Calendar.YEAR) - 1, 0, 1, 0, 0, 0); lastYear.set(now.get(Calendar.YEAR) - 1, 0, 1, 0, 0, 0);
} }
String getTimeslot(DBNote note) { private String getTimeslot(DBNote note) {
if (note.isFavorite()) { if (note.isFavorite()) {
return ""; return "";
} }
@ -160,8 +160,8 @@ public class LoadNotesListTask extends AsyncTask<Void, Void, List<Item>> {
} }
private class Timeslot { private class Timeslot {
final String label; private final String label;
final Calendar time; private final Calendar time;
Timeslot(String label, int month, int day) { Timeslot(String label, int month, int day) {
this.label = label; this.label = label;

View file

@ -295,7 +295,7 @@ public class NoteServerSyncHelper {
this.onlyLocalChanges = onlyLocalChanges; this.onlyLocalChanges = onlyLocalChanges;
} }
void addCallbacks(SingleSignOnAccount ssoAccount, List<ISyncCallback> callbacks) { private void addCallbacks(SingleSignOnAccount ssoAccount, List<ISyncCallback> callbacks) {
this.callbacks.put(ssoAccount.name, callbacks); this.callbacks.put(ssoAccount.name, callbacks);
} }

View file

@ -59,7 +59,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
private final NoteServerSyncHelper serverSyncHelper; private final NoteServerSyncHelper serverSyncHelper;
private NotesDatabase(Context context) { private NotesDatabase(@NonNull Context context) {
super(context, database_name, null); super(context, database_name, null);
serverSyncHelper = NoteServerSyncHelper.getInstance(this); serverSyncHelper = NoteServerSyncHelper.getInstance(this);
} }
@ -128,7 +128,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
deleteNoteAndSync(ssoAccount, note.getId()); deleteNoteAndSync(ssoAccount, note.getId());
notifyNotesChanged(); notifyNotesChanged();
getNoteServerSyncHelper().scheduleSync(ssoAccount,true); getNoteServerSyncHelper().scheduleSync(ssoAccount, true);
} }
/** /**
@ -389,7 +389,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
table_notes, table_notes,
new String[]{key_category, "COUNT(*)"}, new String[]{key_category, "COUNT(*)"},
key_status + " != ? AND " + key_account_id + " = ? AND " + key_category + " LIKE ? AND " + key_category + " != \"\"", key_status + " != ? AND " + key_account_id + " = ? AND " + key_category + " LIKE ? AND " + key_category + " != \"\"",
new String[]{DBStatus.LOCAL_DELETED.getTitle(), String.valueOf(accountId), "%" + (search == null ? search : search.trim()) + "%"}, new String[]{DBStatus.LOCAL_DELETED.getTitle(), String.valueOf(accountId), "%" + (search == null ? null : search.trim()) + "%"},
key_category, key_category,
null, null,
key_category); key_category);
@ -436,7 +436,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
if (callback != null) { if (callback != null) {
serverSyncHelper.addCallbackPush(ssoAccount, callback); serverSyncHelper.addCallbackPush(ssoAccount, callback);
} }
serverSyncHelper.scheduleSync(ssoAccount,true); serverSyncHelper.scheduleSync(ssoAccount, true);
} }
/** /**
@ -538,7 +538,7 @@ public class NotesDatabase extends AbstractNotesDatabase {
SQLiteDatabase db = this.getWritableDatabase(); SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(key_status, DBStatus.LOCAL_DELETED.getTitle()); values.put(key_status, DBStatus.LOCAL_DELETED.getTitle());
int i = db.update(table_notes, db.update(table_notes,
values, values,
key_id + " = ?", key_id + " = ?",
new String[]{String.valueOf(id)}); new String[]{String.valueOf(id)});

View file

@ -16,6 +16,7 @@ import com.nextcloud.android.sso.AccountImporter;
import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException; import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException;
import com.nextcloud.android.sso.model.SingleSignOnAccount; import com.nextcloud.android.sso.model.SingleSignOnAccount;
import java.util.Objects;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import it.niedermann.owncloud.notes.R; import it.niedermann.owncloud.notes.R;
@ -23,7 +24,7 @@ import it.niedermann.owncloud.notes.model.LocalAccount;
public class SyncWorker extends Worker { public class SyncWorker extends Worker {
private static final String TAG = SyncWorker.class.getCanonicalName(); private static final String TAG = Objects.requireNonNull(SyncWorker.class.getCanonicalName());
private static final String WORKER_TAG = "background_synchronization"; private static final String WORKER_TAG = "background_synchronization";
private static final Constraints constraints = new Constraints.Builder() private static final Constraints constraints = new Constraints.Builder()

View file

@ -26,7 +26,7 @@ public class ClipboardUtil {
try { try {
clipboardURL = new URL(clipboardData.getItemAt(0).getText().toString()).toString(); clipboardURL = new URL(clipboardData.getItemAt(0).getText().toString()).toString();
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
Log.d(TAG, "Clipboard does not contain a valid URL: " + clipboardURL); Log.d(TAG, "Clipboard does not contain a valid URL: " + clipboardData.getItemAt(0).getText().toString());
} }
} }
return clipboardURL; return clipboardURL;

View file

@ -37,13 +37,14 @@ public class NoteUtil {
public static String removeMarkDown(@Nullable String s) { public static String removeMarkDown(@Nullable String s) {
if (s == null) if (s == null)
return ""; return "";
s = pLists.matcher(s).replaceAll(""); String result = s;
s = pHeadings.matcher(s).replaceAll("$1"); result = pLists.matcher(result).replaceAll("");
s = pHeadingLine.matcher(s).replaceAll(""); result = pHeadings.matcher(result).replaceAll("$1");
s = pEmphasis.matcher(s).replaceAll("$2"); result = pHeadingLine.matcher(result).replaceAll("");
s = pSpace1.matcher(s).replaceAll(""); result = pEmphasis.matcher(result).replaceAll("$2");
s = pSpace2.matcher(s).replaceAll(""); result = pSpace1.matcher(result).replaceAll("");
return s; result = pSpace2.matcher(result).replaceAll("");
return result;
} }
/** /**

View file

@ -79,23 +79,17 @@ public abstract class NotesTextWatcher implements TextWatcher {
// Find start of line // Find start of line
int startOfLine = MarkDownUtil.getStartOfLine(s, start); int startOfLine = MarkDownUtil.getStartOfLine(s, start);
String line = s.subSequence(startOfLine, start).toString(); String line = s.subSequence(startOfLine, start).toString();
if (line.startsWith(codeBlock)) {
// "start" is the direct sibling of the codeBlock // "start" is the direct sibling of the codeBlock
if (start - startOfLine == codeBlock.length()) { if (line.startsWith(codeBlock) && start - startOfLine == codeBlock.length() && !resetSelection) {
if (!resetSelection) {
resetSelectionTo = editText.getSelectionEnd(); resetSelectionTo = editText.getSelectionEnd();
resetSelection = true; resetSelection = true;
Log.v(TAG, "Entered a character directly behind a codeBlock - prepare selection reset to " + resetSelectionTo); Log.v(TAG, "Entered a character directly behind a codeBlock - prepare selection reset to " + resetSelectionTo);
} } else if (s.subSequence(startOfLine, start + count).toString().startsWith(codeBlock) && !resetSelection) {
}
} else if (s.subSequence(startOfLine, start + count).toString().startsWith(codeBlock)) {
if (!resetSelection) {
resetSelectionTo = editText.getSelectionEnd(); resetSelectionTo = editText.getSelectionEnd();
resetSelection = true; resetSelection = true;
Log.v(TAG, "One completed a ``-codeBlock with the third `-character - prepare selection reset to " + resetSelectionTo); Log.v(TAG, "One completed a ``-codeBlock with the third `-character - prepare selection reset to " + resetSelectionTo);
} }
} }
}
private void setNewText(@NonNull StringBuilder newText, int selection) { private void setNewText(@NonNull StringBuilder newText, int selection) {
editText.setText(newText); editText.setText(newText);

View file

@ -59,17 +59,16 @@ public class ContextBasedFormattingCallback implements ActionMode.Callback {
@Override @Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.checkbox: { case R.id.checkbox:
insertCheckbox(); insertCheckbox();
return true; return true;
} case R.id.link:
case R.id.link: {
insertLink(); insertLink();
return true; return true;
} default:
}
return false; return false;
} }
}
private void insertCheckbox() { private void insertCheckbox() {
CharSequence text = editText.getText(); CharSequence text = editText.getText();

View file

@ -62,7 +62,7 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback
switch (item.getItemId()) { switch (item.getItemId()) {
case R.id.bold: { case R.id.bold:
markdown = "**"; markdown = "**";
if (hasAlreadyMarkdown(start, end, markdown)) { if (hasAlreadyMarkdown(start, end, markdown)) {
this.removeMarkdown(ssb, start, end, markdown); this.removeMarkdown(ssb, start, end, markdown);
@ -72,8 +72,7 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback
editText.setText(ssb); editText.setText(ssb);
editText.setSelection(end + markdown.length() * 2); editText.setSelection(end + markdown.length() * 2);
return true; return true;
} case R.id.italic:
case R.id.italic: {
markdown = "*"; markdown = "*";
if (hasAlreadyMarkdown(start, end, markdown)) { if (hasAlreadyMarkdown(start, end, markdown)) {
this.removeMarkdown(ssb, start, end, markdown); this.removeMarkdown(ssb, start, end, markdown);
@ -83,8 +82,7 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback
editText.setText(ssb); editText.setText(ssb);
editText.setSelection(end + markdown.length() * 2); editText.setSelection(end + markdown.length() * 2);
return true; return true;
} case R.id.link:
case R.id.link: {
boolean textToFormatIsLink = TextUtils.indexOf(editText.getText().subSequence(start, end), "http") == 0; boolean textToFormatIsLink = TextUtils.indexOf(editText.getText().subSequence(start, end), "http") == 0;
if (textToFormatIsLink) { if (textToFormatIsLink) {
ssb.insert(end, ")"); ssb.insert(end, ")");
@ -108,8 +106,7 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback
editText.setSelection(end + 2); // after <end>]( editText.setSelection(end + 2); // after <end>](
} }
return true; return true;
} case android.R.id.cut:
case android.R.id.cut: {
// https://github.com/stefan-niedermann/nextcloud-notes/issues/604 // https://github.com/stefan-niedermann/nextcloud-notes/issues/604
// https://github.com/stefan-niedermann/nextcloud-notes/issues/477 // https://github.com/stefan-niedermann/nextcloud-notes/issues/477
try { try {
@ -121,10 +118,10 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback
editText.clearFocus(); editText.clearFocus();
return true; return true;
} }
} default:
}
return false; return false;
} }
}
@Override @Override
public void onDestroyActionMode(ActionMode mode) { public void onDestroyActionMode(ActionMode mode) {
@ -148,7 +145,6 @@ public class ContextBasedRangeFormattingCallback implements ActionMode.Callback
ssb.insert(start, markdown); ssb.insert(start, markdown);
editText.getText().charAt(start); editText.getText().charAt(start);
editText.getText().charAt(start + 1); editText.getText().charAt(start + 1);
end += markdown.length() * 2; ssb.setSpan(new StyleSpan(typeface), start, end + markdown.length() * 2, 1);
ssb.setSpan(new StyleSpan(typeface), start, end, 1);
} }
} }