Skip to content

Commit fc8baca

Browse files
#1277 Redesign note details
Signed-off-by: Stefan Niedermann <info@niedermann.it>
1 parent eae7000 commit fc8baca

File tree

10 files changed

+311
-135
lines changed

10 files changed

+311
-135
lines changed

app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java

Lines changed: 21 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
package it.niedermann.owncloud.notes.edit;
22

3-
import android.app.PendingIntent;
43
import android.content.Context;
5-
import android.content.Intent;
6-
import android.content.pm.ShortcutInfo;
7-
import android.content.pm.ShortcutManager;
84
import android.graphics.Color;
9-
import android.graphics.drawable.Icon;
105
import android.os.Build;
116
import android.os.Bundle;
127
import android.util.Log;
@@ -42,31 +37,25 @@
4237
import it.niedermann.owncloud.notes.branding.BrandedFragment;
4338
import it.niedermann.owncloud.notes.edit.category.CategoryDialogFragment;
4439
import it.niedermann.owncloud.notes.edit.category.CategoryDialogFragment.CategoryDialogListener;
40+
import it.niedermann.owncloud.notes.edit.details.NoteDetailsDialogFragment;
4541
import it.niedermann.owncloud.notes.edit.title.EditTitleDialogFragment;
4642
import it.niedermann.owncloud.notes.edit.title.EditTitleDialogFragment.EditTitleListener;
4743
import it.niedermann.owncloud.notes.persistence.NotesRepository;
4844
import it.niedermann.owncloud.notes.persistence.entity.Account;
4945
import it.niedermann.owncloud.notes.persistence.entity.Note;
50-
import it.niedermann.owncloud.notes.shared.model.ApiVersion;
5146
import it.niedermann.owncloud.notes.shared.model.DBStatus;
5247
import it.niedermann.owncloud.notes.shared.model.ISyncCallback;
53-
import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil;
5448
import it.niedermann.owncloud.notes.shared.util.NoteUtil;
5549
import it.niedermann.owncloud.notes.shared.util.NotesColorUtil;
5650
import it.niedermann.owncloud.notes.shared.util.ShareUtil;
5751

58-
import static androidx.core.content.pm.ShortcutManagerCompat.isRequestPinShortcutSupported;
5952
import static it.niedermann.owncloud.notes.NotesApplication.isDarkThemeActive;
60-
import static it.niedermann.owncloud.notes.branding.BrandingUtil.tintMenuIcon;
61-
import static it.niedermann.owncloud.notes.edit.EditNoteActivity.ACTION_SHORTCUT;
62-
import static java.lang.Boolean.TRUE;
6353

6454
public abstract class BaseNoteFragment extends BrandedFragment implements CategoryDialogListener, EditTitleListener {
6555

6656
private static final String TAG = BaseNoteFragment.class.getSimpleName();
6757
protected final ExecutorService executor = Executors.newCachedThreadPool();
6858

69-
protected static final int MENU_ID_PIN = -1;
7059
public static final String PARAM_NOTE_ID = "noteId";
7160
public static final String PARAM_ACCOUNT_ID = "accountId";
7261
public static final String PARAM_CONTENT = "content";
@@ -185,31 +174,9 @@ public void onSaveInstanceState(@NonNull Bundle outState) {
185174
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
186175
inflater.inflate(R.menu.menu_note_fragment, menu);
187176

188-
if (isRequestPinShortcutSupported(requireActivity()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
189-
menu.add(Menu.NONE, MENU_ID_PIN, 110, R.string.pin_to_homescreen);
190-
}
191-
192177
super.onCreateOptionsMenu(menu, inflater);
193178
}
194179

195-
@Override
196-
public void onPrepareOptionsMenu(@NonNull Menu menu) {
197-
super.onPrepareOptionsMenu(menu);
198-
if (note != null) {
199-
prepareFavoriteOption(menu.findItem(R.id.menu_favorite));
200-
201-
final ApiVersion preferredApiVersion = ApiVersionUtil.getPreferredApiVersion(localAccount.getApiVersion());
202-
menu.findItem(R.id.menu_title).setVisible(preferredApiVersion != null && preferredApiVersion.compareTo(ApiVersion.API_VERSION_1_0) >= 0);
203-
menu.findItem(R.id.menu_delete).setVisible(!isNew);
204-
}
205-
}
206-
207-
private void prepareFavoriteOption(MenuItem item) {
208-
item.setIcon(TRUE.equals(note.getFavorite()) ? R.drawable.ic_star_white_24dp : R.drawable.ic_star_border_white_24dp);
209-
item.setChecked(note.getFavorite());
210-
tintMenuIcon(item, colorAccent);
211-
}
212-
213180
/**
214181
* Main-Menu-Handler
215182
*/
@@ -230,46 +197,11 @@ public boolean onOptionsItemSelected(MenuItem item) {
230197
repo.deleteNoteAndSync(localAccount, note.getId());
231198
listener.close();
232199
return true;
233-
} else if (itemId == R.id.menu_favorite) {
234-
repo.toggleFavoriteAndSync(localAccount, note.getId());
235-
listener.onNoteUpdated(note);
236-
prepareFavoriteOption(item);
237-
return true;
238-
} else if (itemId == R.id.menu_category) {
239-
showCategorySelector();
240-
return true;
241-
} else if (itemId == R.id.menu_title) {
242-
showEditTitleDialog();
243-
return true;
244200
} else if (itemId == R.id.menu_move) {
245201
executor.submit(() -> AccountPickerDialogFragment
246202
.newInstance(new ArrayList<>(repo.getAccounts()), note.getAccountId())
247203
.show(requireActivity().getSupportFragmentManager(), BaseNoteFragment.class.getSimpleName()));
248204
return true;
249-
} else if (itemId == R.id.menu_share) {
250-
ShareUtil.openShareDialog(requireContext(), note.getTitle(), note.getContent());
251-
return false;
252-
} else if (itemId == MENU_ID_PIN) {
253-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
254-
final ShortcutManager shortcutManager = requireActivity().getSystemService(ShortcutManager.class);
255-
if (shortcutManager != null) {
256-
if (shortcutManager.isRequestPinShortcutSupported()) {
257-
final ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(getActivity(), note.getId() + "")
258-
.setShortLabel(note.getTitle())
259-
.setIcon(Icon.createWithResource(requireActivity().getApplicationContext(), TRUE.equals(note.getFavorite()) ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp))
260-
.setIntent(new Intent(getActivity(), EditNoteActivity.class).putExtra(EditNoteActivity.PARAM_NOTE_ID, note.getId()).setAction(ACTION_SHORTCUT))
261-
.build();
262-
263-
shortcutManager.requestPinShortcut(pinShortcutInfo, PendingIntent.getBroadcast(getActivity(), 0, shortcutManager.createShortcutResultIntent(pinShortcutInfo), 0).getIntentSender());
264-
} else {
265-
Log.i(TAG, "RequestPinShortcut is not supported");
266-
}
267-
} else {
268-
Log.e(TAG, ShortcutManager.class.getSimpleName() + " is null");
269-
}
270-
}
271-
272-
return true;
273205
}
274206
return super.onOptionsItemSelected(item);
275207
}
@@ -312,6 +244,7 @@ protected void saveNote(@Nullable ISyncCallback callback) {
312244
} else {
313245
Log.v(TAG, "... not saving, since nothing has changed");
314246
}
247+
if (callback != null) callback.onScheduled();
315248
} else {
316249
// FIXME requires database queries on main thread!
317250
note = repo.updateNoteAndSync(localAccount, note, newContent, null, callback);
@@ -328,32 +261,26 @@ protected void saveNote(@Nullable ISyncCallback callback) {
328261
/**
329262
* Opens a dialog in order to chose a category
330263
*/
331-
private void showCategorySelector() {
332-
final String fragmentId = "fragment_category";
333-
FragmentManager manager = requireActivity().getSupportFragmentManager();
334-
Fragment frag = manager.findFragmentByTag(fragmentId);
335-
if (frag != null) {
336-
manager.beginTransaction().remove(frag).commit();
337-
}
338-
final DialogFragment categoryFragment = CategoryDialogFragment.newInstance(note.getAccountId(), note.getCategory());
339-
categoryFragment.setTargetFragment(this, 0);
340-
categoryFragment.show(manager, fragmentId);
341-
}
264+
public void showNoteDetailsDialog() {
265+
saveNote(new ISyncCallback() {
266+
@Override
267+
public void onFinish() {
342268

343-
/**
344-
* Opens a dialog in order to chose a category
345-
*/
346-
public void showEditTitleDialog() {
347-
saveNote(null);
348-
final String fragmentId = "fragment_edit_title";
349-
FragmentManager manager = requireActivity().getSupportFragmentManager();
350-
Fragment frag = manager.findFragmentByTag(fragmentId);
351-
if (frag != null) {
352-
manager.beginTransaction().remove(frag).commit();
353-
}
354-
DialogFragment editTitleFragment = EditTitleDialogFragment.newInstance(note.getTitle());
355-
editTitleFragment.setTargetFragment(this, 0);
356-
editTitleFragment.show(manager, fragmentId);
269+
}
270+
271+
@Override
272+
public void onScheduled() {
273+
final String fragmentId = "fragment_note_details";
274+
final FragmentManager manager = requireActivity().getSupportFragmentManager();
275+
Fragment frag = manager.findFragmentByTag(fragmentId);
276+
if (frag != null) {
277+
manager.beginTransaction().remove(frag).commit();
278+
}
279+
DialogFragment noteDetailsFragment = NoteDetailsDialogFragment.newInstance(localAccount, note.getId());
280+
noteDetailsFragment.setTargetFragment(BaseNoteFragment.this, 0);
281+
noteDetailsFragment.show(manager, fragmentId);
282+
}
283+
});
357284
}
358285

359286
@Override

app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ protected void onCreate(final Bundle savedInstanceState) {
8484
}
8585

8686
setSupportActionBar(binding.toolbar);
87-
binding.toolbar.setOnClickListener((v) -> fragment.showEditTitleDialog());
87+
binding.toolbar.setOnClickListener((v) -> fragment.showNoteDetailsDialog());
8888
}
8989

9090
@Override

app/src/main/java/it/niedermann/owncloud/notes/edit/NoteReadonlyFragment.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,11 @@ public class NoteReadonlyFragment extends NotePreviewFragment {
1717
@Override
1818
public void onPrepareOptionsMenu(@NonNull Menu menu) {
1919
super.onPrepareOptionsMenu(menu);
20-
menu.findItem(R.id.menu_favorite).setVisible(false);
2120
menu.findItem(R.id.menu_edit).setVisible(false);
2221
menu.findItem(R.id.menu_preview).setVisible(false);
2322
menu.findItem(R.id.menu_cancel).setVisible(false);
2423
menu.findItem(R.id.menu_delete).setVisible(false);
25-
menu.findItem(R.id.menu_share).setVisible(false);
2624
menu.findItem(R.id.menu_move).setVisible(false);
27-
menu.findItem(R.id.menu_category).setVisible(false);
28-
menu.findItem(R.id.menu_title).setVisible(false);
29-
if (menu.findItem(MENU_ID_PIN) != null)
30-
menu.findItem(MENU_ID_PIN).setVisible(false);
3125
}
3226

3327
@Nullable
@@ -44,11 +38,6 @@ protected void registerInternalNoteLinkHandler() {
4438
// Do nothing
4539
}
4640

47-
@Override
48-
public void showEditTitleDialog() {
49-
// Do nothing
50-
}
51-
5241
@Override
5342
public void onCloseNote() {
5443
// Do nothing
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package it.niedermann.owncloud.notes.edit.details;
2+
3+
import android.app.AlertDialog;
4+
import android.app.Dialog;
5+
import android.app.PendingIntent;
6+
import android.content.Context;
7+
import android.content.Intent;
8+
import android.content.pm.ShortcutInfo;
9+
import android.content.pm.ShortcutManager;
10+
import android.graphics.drawable.Icon;
11+
import android.os.Build;
12+
import android.os.Bundle;
13+
import android.text.format.DateUtils;
14+
import android.util.Log;
15+
import android.view.View;
16+
17+
import androidx.annotation.NonNull;
18+
import androidx.annotation.Nullable;
19+
import androidx.fragment.app.DialogFragment;
20+
import androidx.lifecycle.ViewModelProvider;
21+
22+
import it.niedermann.owncloud.notes.R;
23+
import it.niedermann.owncloud.notes.databinding.DialogNoteDetailsBinding;
24+
import it.niedermann.owncloud.notes.edit.EditNoteActivity;
25+
import it.niedermann.owncloud.notes.persistence.entity.Account;
26+
import it.niedermann.owncloud.notes.shared.model.ApiVersion;
27+
import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil;
28+
import it.niedermann.owncloud.notes.shared.util.ShareUtil;
29+
30+
import static androidx.core.content.pm.ShortcutManagerCompat.isRequestPinShortcutSupported;
31+
import static it.niedermann.owncloud.notes.edit.EditNoteActivity.ACTION_SHORTCUT;
32+
import static java.lang.Boolean.TRUE;
33+
34+
public class NoteDetailsDialogFragment extends DialogFragment {
35+
36+
private static final String TAG = NoteDetailsDialogFragment.class.getSimpleName();
37+
static final String PARAM_ACCOUNT = "account";
38+
static final String PARAM_NOTE_ID = "noteId";
39+
private DialogNoteDetailsBinding binding;
40+
41+
42+
private Account account;
43+
private long noteId;
44+
private NoteDetailsViewModel viewModel;
45+
46+
@Override
47+
public void onAttach(@NonNull Context context) {
48+
super.onAttach(context);
49+
final Bundle args = requireArguments();
50+
account = (Account) args.getSerializable(PARAM_ACCOUNT);
51+
noteId = args.getLong(PARAM_NOTE_ID);
52+
viewModel = new ViewModelProvider(requireActivity()).get(NoteDetailsViewModel.class);
53+
}
54+
55+
@NonNull
56+
@Override
57+
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
58+
binding = DialogNoteDetailsBinding.inflate(getLayoutInflater(), null, false);
59+
60+
final Dialog dialog = new AlertDialog.Builder(getActivity())
61+
.setView(binding.getRoot())
62+
.setCancelable(true)
63+
.setNegativeButton(R.string.simple_close, null)
64+
.create();
65+
dialog.setOnShowListener((d) -> {
66+
if (!(isRequestPinShortcutSupported(requireActivity()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)) {
67+
binding.pin.setVisibility(View.GONE);
68+
}
69+
final ApiVersion preferredApiVersion = ApiVersionUtil.getPreferredApiVersion(account.getApiVersion());
70+
final boolean supportsTitle = preferredApiVersion != null && preferredApiVersion.compareTo(ApiVersion.API_VERSION_1_0) >= 0;
71+
if (!supportsTitle) {
72+
binding.titleWrapper.setVisibility(View.GONE);
73+
}
74+
75+
viewModel.getNote$(noteId).observe(this, (note) -> {
76+
binding.favorite.setImageResource(note.getFavorite() ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp);
77+
if (supportsTitle) {
78+
binding.title.setText(note.getTitle());
79+
}
80+
binding.category.setText(note.getCategory());
81+
binding.modified.setText(DateUtils.getRelativeDateTimeString(
82+
getContext(),
83+
note.getModified().getTimeInMillis(),
84+
DateUtils.SECOND_IN_MILLIS,
85+
DateUtils.WEEK_IN_MILLIS,
86+
0
87+
));
88+
89+
binding.pin.setOnClickListener((v) -> {
90+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
91+
final ShortcutManager shortcutManager = requireActivity().getSystemService(ShortcutManager.class);
92+
if (shortcutManager != null) {
93+
if (shortcutManager.isRequestPinShortcutSupported()) {
94+
final ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(getActivity(), String.valueOf(note.getId()))
95+
.setShortLabel(note.getTitle())
96+
.setIcon(Icon.createWithResource(requireActivity().getApplicationContext(), TRUE.equals(note.getFavorite()) ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp))
97+
.setIntent(new Intent(getActivity(), EditNoteActivity.class).putExtra(EditNoteActivity.PARAM_NOTE_ID, note.getId()).setAction(ACTION_SHORTCUT))
98+
.build();
99+
100+
shortcutManager.requestPinShortcut(pinShortcutInfo, PendingIntent.getBroadcast(getActivity(), 0, shortcutManager.createShortcutResultIntent(pinShortcutInfo), 0).getIntentSender());
101+
} else {
102+
Log.i(TAG, "RequestPinShortcut is not supported");
103+
}
104+
} else {
105+
Log.e(TAG, ShortcutManager.class.getSimpleName() + " is null");
106+
}
107+
}
108+
});
109+
binding.share.setOnClickListener((v) -> ShareUtil.openShareDialog(requireContext(), note.getTitle(), note.getContent()));
110+
binding.favorite.setOnClickListener((v) -> viewModel.toggleFavorite(noteId));
111+
});
112+
});
113+
return dialog;
114+
}
115+
116+
public static DialogFragment newInstance(@NonNull Account account, long noteId) {
117+
final DialogFragment fragment = new NoteDetailsDialogFragment();
118+
final Bundle args = new Bundle();
119+
args.putSerializable(PARAM_ACCOUNT, account);
120+
args.putLong(PARAM_NOTE_ID, noteId);
121+
fragment.setArguments(args);
122+
return fragment;
123+
}
124+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package it.niedermann.owncloud.notes.edit.details;
2+
3+
import android.app.Application;
4+
5+
import androidx.annotation.AnyThread;
6+
import androidx.annotation.NonNull;
7+
import androidx.lifecycle.AndroidViewModel;
8+
import androidx.lifecycle.LiveData;
9+
import androidx.lifecycle.SavedStateHandle;
10+
11+
import java.util.concurrent.ExecutorService;
12+
import java.util.concurrent.Executors;
13+
14+
import it.niedermann.owncloud.notes.persistence.NotesRepository;
15+
import it.niedermann.owncloud.notes.persistence.entity.Account;
16+
import it.niedermann.owncloud.notes.persistence.entity.Note;
17+
18+
public class NoteDetailsViewModel extends AndroidViewModel {
19+
20+
private static final String TAG = NoteDetailsViewModel.class.getSimpleName();
21+
22+
private final ExecutorService executor = Executors.newCachedThreadPool();
23+
24+
private final SavedStateHandle state;
25+
26+
@NonNull
27+
private final NotesRepository repo;
28+
29+
30+
public NoteDetailsViewModel(@NonNull Application application, @NonNull SavedStateHandle savedStateHandle) {
31+
super(application);
32+
this.repo = NotesRepository.getInstance(application);
33+
this.state = savedStateHandle;
34+
}
35+
36+
public LiveData<Note> getNote$(long noteId) {
37+
return repo.getNoteById$(noteId);
38+
}
39+
40+
@AnyThread
41+
public void toggleFavorite(long noteId) {
42+
repo.toggleFavorite(noteId);
43+
}
44+
}

0 commit comments

Comments
 (0)