Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00e1b5d6 authored by Stefan Niedermann's avatar Stefan Niedermann
Browse files

Implement first version of a GridView

parent 3d0a1fdc
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -37,8 +37,8 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
            @NonNull ISyncCallback syncCallBack,
            @NonNull Runnable refreshLists,
            @Nullable SwipeRefreshLayout swipeRefreshLayout,
            @Nullable ViewProvider viewProvider
    ) {
            @Nullable ViewProvider viewProvider,
            boolean gridView) {
        super(new SimpleCallback(0, ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
            private boolean swipeRefreshLayoutEnabled;

@@ -56,7 +56,7 @@ public class NotesListViewItemTouchHelper extends ItemTouchHelper {
             */
            @Override
            public int getSwipeDirs(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
                if (viewHolder instanceof SectionViewHolder) return 0;
                if (gridView || viewHolder instanceof SectionViewHolder) return 0;
                return super.getSwipeDirs(recyclerView, viewHolder);
            }

+16 −4
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
@@ -27,6 +28,7 @@ import androidx.core.view.GravityCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;

import com.bumptech.glide.Glide;
@@ -90,6 +92,8 @@ public class NotesListViewActivity extends LockedActivity implements NoteClickLi

    private static final String TAG = NotesListViewActivity.class.getSimpleName();

    public static final boolean FEATURE_TOGGLE_GRID_VIEW = true;

    public static final String CREATED_NOTE = "it.niedermann.owncloud.notes.created_notes";
    public static final String ADAPTER_KEY_RECENT = "recent";
    public static final String ADAPTER_KEY_STARRED = "starred";
@@ -229,7 +233,8 @@ public class NotesListViewActivity extends LockedActivity implements NoteClickLi
            try {
                BrandingUtil.saveBrandColors(this, localAccount.getColor(), localAccount.getTextColor());
                ssoAccount = SingleAccountHelper.getCurrentSingleSignOnAccount(getApplicationContext());
                new NotesListViewItemTouchHelper(ssoAccount, this, db, adapter, syncCallBack, this::refreshLists, swipeRefreshLayout, this).attachToRecyclerView(listView);
                new NotesListViewItemTouchHelper(ssoAccount, this, db, adapter, syncCallBack, this::refreshLists, swipeRefreshLayout, this, FEATURE_TOGGLE_GRID_VIEW)
                        .attachToRecyclerView(listView);
                synchronize();
            } catch (NextcloudFilesAppAccountNotFoundException | NoCurrentAccountSelectedException e) {
                Log.i(TAG, "Tried to select account, but got an " + e.getClass().getSimpleName() + ". Asking for importing an account...");
@@ -588,10 +593,17 @@ public class NotesListViewActivity extends LockedActivity implements NoteClickLi
        binding.navigationMenu.setAdapter(adapterMenu);
    }

    public void initList() {
        adapter = new ItemAdapter(this);
    private void initList() {
        adapter = new ItemAdapter(this, FEATURE_TOGGLE_GRID_VIEW);
        listView.setAdapter(adapter);
        listView.setLayoutManager(new LinearLayoutManager(this));

        final DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        int spanCount = (int) ((displayMetrics.widthPixels / displayMetrics.density) / getResources().getInteger(R.integer.max_dp_grid_view));
        listView.setLayoutManager(
                FEATURE_TOGGLE_GRID_VIEW
                        ? new StaggeredGridLayoutManager(spanCount, StaggeredGridLayoutManager.VERTICAL)
                        : new LinearLayoutManager(this)
        );
    }

    private void refreshLists() {
+39 −20
Original line number Diff line number Diff line
@@ -8,14 +8,17 @@ import android.view.LayoutInflater;
import android.view.ViewGroup;

import androidx.annotation.ColorInt;
import androidx.annotation.IntRange;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;

import java.util.ArrayList;
import java.util.List;

import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.branding.Branded;
import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridBinding;
import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithExcerptBinding;
import it.niedermann.owncloud.notes.databinding.ItemNotesListSectionItemBinding;

@@ -25,10 +28,12 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i

    private static final String TAG = ItemAdapter.class.getSimpleName();

    private static final int TYPE_SECTION = R.layout.item_notes_list_section_item;
    private static final int TYPE_NOTE_WITH_EXCERPT = R.layout.item_notes_list_note_item_with_excerpt;
    private static final int TYPE_NOTE_WITHOUT_EXCERPT = R.layout.item_notes_list_note_item_without_excerpt;
    public static final int TYPE_SECTION = 0;
    public static final int TYPE_NOTE_WITH_EXCERPT = 1;
    public static final int TYPE_NOTE_WITHOUT_EXCERPT = 2;

    private final NoteClickListener noteClickListener;
    private final boolean gridView;
    private List<Item> itemList = new ArrayList<>();
    private boolean showCategory = true;
    private CharSequence searchQuery;
@@ -38,8 +43,9 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
    @ColorInt
    private int textColor;

    public <T extends Context & NoteClickListener> ItemAdapter(@NonNull T context) {
    public <T extends Context & NoteClickListener> ItemAdapter(@NonNull T context, boolean gridView) {
        this.noteClickListener = context;
        this.gridView = gridView;
        this.mainColor = context.getResources().getColor(R.color.defaultBrand);
        this.textColor = Color.WHITE;
    }
@@ -76,6 +82,20 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        if (gridView) {
            switch (viewType) {
                case TYPE_SECTION: {
                    return new SectionViewHolder(ItemNotesListSectionItemBinding.inflate(LayoutInflater.from(parent.getContext())));
                }
                case TYPE_NOTE_WITH_EXCERPT:
                case TYPE_NOTE_WITHOUT_EXCERPT: {
                    return new NoteViewGridHolder(ItemNotesListNoteItemGridBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false), noteClickListener);
                }
                default: {
                    throw new IllegalArgumentException("Not supported viewType: " + viewType);
                }
            }
        } else {
            switch (viewType) {
                case TYPE_SECTION: {
                    return new SectionViewHolder(ItemNotesListSectionItemBinding.inflate(LayoutInflater.from(parent.getContext())));
@@ -91,6 +111,7 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
                }
            }
        }
    }

    @Override
    public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
@@ -99,12 +120,9 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
                ((SectionViewHolder) holder).bind((SectionItem) itemList.get(position));
                break;
            }
            case TYPE_NOTE_WITH_EXCERPT: {
                ((NoteViewHolderWithExcerpt) holder).bind((DBNote) itemList.get(position), showCategory, mainColor, textColor, searchQuery);
                break;
            }
            case TYPE_NOTE_WITH_EXCERPT:
            case TYPE_NOTE_WITHOUT_EXCERPT: {
                ((NoteViewHolderWithoutExcerpt) holder).bind((DBNote) itemList.get(position), showCategory, mainColor, textColor, searchQuery);
                ((NoteViewHolder) holder).bind((DBNote) itemList.get(position), showCategory, mainColor, textColor, searchQuery);
                break;
            }
        }
@@ -160,6 +178,7 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
        return itemList.size();
    }

    @IntRange(from = 0, to = 2)
    @Override
    public int getItemViewType(int position) {
        Item item = getItem(position);
+39 −0
Original line number Diff line number Diff line
package it.niedermann.owncloud.notes.model;

import android.content.Context;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridBinding;

public class NoteViewGridHolder extends NoteViewHolder {
    @NonNull
    private final ItemNotesListNoteItemGridBinding binding;

    public NoteViewGridHolder(@NonNull ItemNotesListNoteItemGridBinding binding, @NonNull NoteClickListener noteClickListener) {
        super(binding.getRoot(), noteClickListener);
        this.binding = binding;
        itemView.setOnClickListener(this);
        itemView.setOnLongClickListener(this);
    }


    public void showSwipe(boolean left) {

    }

    public void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
        @NonNull final Context context = itemView.getContext();
        bindCategory(context, binding.noteCategory, showCategory, note.getCategory(), mainColor);
        binding.noteStatus.setVisibility(DBStatus.VOID.equals(note.getStatus()) ? View.INVISIBLE : View.VISIBLE);
        bindFavorite(binding.noteFavorite, note.isFavorite());
        bindTitle(context, binding.noteTitle, searchQuery, note, mainColor);
        bindExcerpt(context, binding.noteContent, searchQuery, note, mainColor);
    }

    public View getNoteSwipeable() {
        return null;
    }
}
 No newline at end of file
+24 −14
Original line number Diff line number Diff line
@@ -52,6 +52,8 @@ public abstract class NoteViewHolder extends RecyclerView.ViewHolder implements
        return noteClickListener.onNoteLongClick(getAdapterPosition(), v);
    }

    public abstract void bind(@NonNull DBNote note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery);

    protected void bindCategory(@NonNull Context context, @NonNull TextView noteCategory, boolean showCategory, @NonNull String category, int mainColor) {
        final boolean isDarkThemeActive = Notes.isDarkThemeActive(context);
        noteCategory.setVisibility(showCategory && !category.isEmpty() ? View.VISIBLE : View.GONE);
@@ -97,8 +99,10 @@ public abstract class NoteViewHolder extends RecyclerView.ViewHolder implements
        noteFavorite.setOnClickListener(view -> noteClickListener.onNoteFavoriteClick(getAdapterPosition(), view));
    }

    protected void bindTitleAndExcerpt(@NonNull Context context, @NonNull TextView noteTitle, @Nullable TextView noteExcerpt, @Nullable CharSequence searchQuery, @NonNull DBNote note, int mainColor) {
        if (!TextUtils.isEmpty(searchQuery)) {
    protected void bindTitle(@NonNull Context context, @NonNull TextView noteTitle, @Nullable CharSequence searchQuery, @NonNull DBNote note, int mainColor) {
        if (TextUtils.isEmpty(searchQuery)) {
            noteTitle.setText(note.getTitle());
        } else {
            @ColorInt final int searchBackground = context.getResources().getColor(R.color.bg_highlighted);
            @ColorInt final int searchForeground = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, mainColor);

@@ -108,29 +112,35 @@ public abstract class NoteViewHolder extends RecyclerView.ViewHolder implements
            final Pattern pattern = Pattern.compile("(" + Pattern.quote(searchQuery.toString()) + ")", Pattern.CASE_INSENSITIVE);
            SpannableString spannableString = new SpannableString(note.getTitle());
            Matcher matcher = pattern.matcher(spannableString);

            while (matcher.find()) {
                spannableString.setSpan(new ForegroundColorSpan(searchForeground), matcher.start(), matcher.end(), 0);
                spannableString.setSpan(new BackgroundColorSpan(searchBackground), matcher.start(), matcher.end(), 0);
            }

            noteTitle.setText(spannableString);
        }
    }

    protected void bindExcerpt(@NonNull Context context, @NonNull TextView noteExcerpt, @Nullable CharSequence searchQuery, @NonNull DBNote note, int mainColor) {
        if (TextUtils.isEmpty(searchQuery)) {
            noteExcerpt.setText(note.getExcerpt());
        } else {
            @ColorInt final int searchBackground = context.getResources().getColor(R.color.bg_highlighted);
            @ColorInt final int searchForeground = BrandingUtil.getSecondaryForegroundColorDependingOnTheme(context, mainColor);

            // The Pattern.quote method will add \Q to the very beginning of the string and \E to the end of the string
            // It implies that the string between \Q and \E is a literal string and thus the reserved keyword in such string will be ignored.
            // See https://stackoverflow.com/questions/15409296/what-is-the-use-of-pattern-quote-method
            final Pattern pattern = Pattern.compile("(" + Pattern.quote(searchQuery.toString()) + ")", Pattern.CASE_INSENSITIVE);
            SpannableString spannableString = new SpannableString(note.getExcerpt());
            Matcher matcher = pattern.matcher(spannableString);

            spannableString = new SpannableString(note.getExcerpt());
            matcher = pattern.matcher(spannableString);
            while (matcher.find()) {
                spannableString.setSpan(new ForegroundColorSpan(searchForeground), matcher.start(), matcher.end(), 0);
                spannableString.setSpan(new BackgroundColorSpan(searchBackground), matcher.start(), matcher.end(), 0);
            }

            if (noteExcerpt != null) {
            noteExcerpt.setText(spannableString);
        }
        } else {
            noteTitle.setText(note.getTitle());
            if (noteExcerpt != null) {
                noteExcerpt.setText(note.getExcerpt());
            }
        }
    }

    public abstract void showSwipe(boolean left);
Loading