1 /*
2  * Copyright 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.example.androidx.widget.selection.fancy;
17 
18 import android.content.Context;
19 import android.graphics.Rect;
20 import android.net.Uri;
21 import android.util.Log;
22 import android.view.MotionEvent;
23 import android.view.View;
24 import android.view.ViewGroup;
25 import android.widget.LinearLayout;
26 import android.widget.TextView;
27 
28 import androidx.annotation.Dimension;
29 import androidx.recyclerview.selection.ItemDetailsLookup.ItemDetails;
30 
31 import com.example.androidx.R;
32 
33 import org.jspecify.annotations.NonNull;
34 import org.jspecify.annotations.Nullable;
35 
36 final class DemoItemHolder extends DemoHolder {
37 
38     private static final String TAG = "SelectionDemos";
39     private final LinearLayout mContainer;
40     private final TextView mSelector;
41     private final TextView mLabel;
42     private final ItemDetails<Uri> mDetails;
43 
44     private @Nullable Uri mKey;
45 
DemoItemHolder(@onNull Context context, @NonNull ViewGroup parent)46     DemoItemHolder(@NonNull Context context, @NonNull ViewGroup parent) {
47         this(inflateLayout(context, parent, R.layout.selection_demo_list_item));
48     }
49 
DemoItemHolder(LinearLayout layout)50     private DemoItemHolder(LinearLayout layout) {
51         super(layout);
52 
53         mContainer = layout.findViewById(R.id.container);
54         mSelector = layout.findViewById(R.id.selector);
55         mLabel = layout.findViewById(R.id.label);
56         mDetails = new ItemDetails<Uri>() {
57             @Override
58             public int getPosition() {
59                 return DemoItemHolder.this.getAbsoluteAdapterPosition();
60             }
61 
62             @Override
63             public Uri getSelectionKey() {
64                 return DemoItemHolder.this.mKey;
65             }
66 
67             @Override
68             public boolean inDragRegion(@NonNull MotionEvent e) {
69                 return DemoItemHolder.this.inDragRegion(e);
70             }
71 
72             @Override
73             public boolean inSelectionHotspot(@NonNull MotionEvent e) {
74                 return DemoItemHolder.this.inSelectRegion(e);
75             }
76 
77             @Override
78             public @NonNull String toString() {
79                 return DemoItemHolder.this.toString();
80             }
81         };
82 
83         mLabel.setOnClickListener(new View.OnClickListener() {
84             @Override
85             public void onClick(View view) {
86                 view.setBackgroundColor(0xAA000000);
87                 Log.d(TAG, "Unexpected click received on item: " + mDetails.getSelectionKey());
88             }
89         });
90     }
91 
92     @Override
update(@onNull Uri uri)93     void update(@NonNull Uri uri) {
94         mKey = uri;
95         mLabel.setText(Uris.getCheese(uri));
96     }
97 
setSmallLayoutMode(boolean small)98     void setSmallLayoutMode(boolean small) {
99         mSelector.setVisibility(small ? View.GONE : View.VISIBLE);
100         mLabel.setTextSize(Dimension.SP, small ? 14f : 20f);
101     }
102 
setSelected(boolean selected)103     void setSelected(boolean selected) {
104         mContainer.setActivated(selected);
105         mSelector.setActivated(selected);
106     }
107 
inDragRegion(MotionEvent event)108     boolean inDragRegion(MotionEvent event) {
109         // If itemView is activated = selected, then whole region is interactive
110         if (itemView.isActivated()) {
111             return true;
112         }
113 
114         // Do everything in global coordinates - it makes things simpler.
115         int[] coords = new int[2];
116         mSelector.getLocationOnScreen(coords);
117 
118         Rect textBounds = new Rect();
119         mLabel.getPaint().getTextBounds(
120                 mLabel.getText().toString(), 0, mLabel.getText().length(), textBounds);
121 
122         Rect rect = new Rect(
123                 coords[0],
124                 coords[1],
125                 coords[0] + mSelector.getWidth() + textBounds.width(),
126                 coords[1] + Math.max(mSelector.getHeight(), textBounds.height()));
127 
128         // If the tap occurred inside icon or the text, these are interactive spots.
129         return rect.contains((int) event.getRawX(), (int) event.getRawY());
130     }
131 
inSelectRegion(MotionEvent e)132     boolean inSelectRegion(MotionEvent e) {
133         Rect iconRect = new Rect();
134         return mSelector.getGlobalVisibleRect(iconRect)
135                 && iconRect.contains((int) e.getRawX(), (int) e.getRawY());
136     }
137 
getItemDetails()138     ItemDetails<Uri> getItemDetails() {
139         return mDetails;
140     }
141 
142     @Override
toString()143     public String toString() {
144         return "Item{name:" + mLabel.getText() + ", url:" + mKey + "}";
145     }
146 }
147