22
33import android .content .Context ;
44import android .os .Build ;
5- import android .util .Log ;
65import android .view .LayoutInflater ;
76import android .view .View ;
87import android .view .ViewGroup ;
1918import com .developer .filepicker .model .FileListItem ;
2019import com .developer .filepicker .model .MarkedItemList ;
2120import com .developer .filepicker .widget .MaterialCheckbox ;
22- import com .developer .filepicker .widget .OnCheckedChangeListener ;
2321
2422import java .text .DateFormat ;
2523import java .util .ArrayList ;
2624import java .util .Date ;
2725
2826/**
29- * @author akshay sunil masram
27+ * Adapter that renders files/folders and keeps checkbox state stable during row recycling.
3028 */
3129public class FileListAdapter extends BaseAdapter {
3230
33- private static final String TAG = FileListAdapter .class .getSimpleName ();
34-
35- private ArrayList <FileListItem > listItem ;
36- private Context context ;
37- private DialogProperties properties ;
31+ private final ArrayList <FileListItem > listItem ;
32+ private final Context context ;
33+ private final DialogProperties properties ;
3834 private NotifyItemChecked notifyItemChecked ;
3935
40- public FileListAdapter (ArrayList <FileListItem > listItem , Context context ,
41- DialogProperties properties ) {
42- this .listItem = listItem ;
36+ public FileListAdapter (ArrayList <FileListItem > listItem , Context context , DialogProperties properties ) {
37+ this .listItem = listItem == null ? new ArrayList <>() : listItem ;
4338 this .context = context ;
44- this .properties = properties ;
39+ this .properties = properties == null ? new DialogProperties () : properties ;
4540 }
4641
4742 @ Override
@@ -50,120 +45,129 @@ public int getCount() {
5045 }
5146
5247 @ Override
53- public FileListItem getItem (int i ) {
54- return listItem .get (i );
48+ public FileListItem getItem (int position ) {
49+ return listItem .get (position );
5550 }
5651
5752 @ Override
58- public long getItemId (int i ) {
59- return i ;
53+ public long getItemId (int position ) {
54+ return position ;
6055 }
6156
6257 @ Override
63- public View getView (final int i , View view , ViewGroup viewGroup ) {
58+ public View getView (final int position , View convertView , ViewGroup parent ) {
6459 final ViewHolder holder ;
65- if (view == null ) {
66- view = LayoutInflater .from (context ).inflate (R .layout .dialog_file_list_item ,
67- viewGroup , false );
68- holder = new ViewHolder (view );
69- view .setTag (holder );
60+ if (convertView == null ) {
61+ convertView = LayoutInflater .from (context ).inflate (R .layout .dialog_file_list_item , parent , false );
62+ holder = new ViewHolder (convertView );
63+ convertView .setTag (holder );
7064 } else {
71- holder = (ViewHolder ) view .getTag ();
65+ holder = (ViewHolder ) convertView .getTag ();
7266 }
73- final FileListItem item = listItem .get (i );
74- if (MarkedItemList .hasItem (item .getLocation ())) {
75- Animation animation = AnimationUtils .loadAnimation (context ,
76- R .anim .marked_item_animation );
77- view .setAnimation (animation );
78- } else {
79- Animation animation = AnimationUtils .loadAnimation (context ,
80- R .anim .unmarked_item_animation );
81- view .setAnimation (animation );
67+
68+ final FileListItem item = listItem .get (position );
69+ final boolean isParentRow = isParentRow (position , item );
70+ final boolean isSelectable = isSelectable (item , isParentRow );
71+
72+ applySelectionAnimation (convertView , item );
73+ bindIcon (holder , item );
74+ bindTexts (holder , item , isParentRow );
75+
76+ holder .checkbox .setOnCheckedChangedListener (null );
77+ holder .checkbox .setVisibility (isSelectable ? View .VISIBLE : View .INVISIBLE );
78+ holder .checkbox .setChecked (MarkedItemList .hasItem (item .getLocation ()));
79+ holder .checkbox .setEnabled (isSelectable );
80+
81+ if (isSelectable ) {
82+ holder .checkbox .setOnCheckedChangedListener ((checkbox , isChecked ) -> {
83+ item .setMarked (isChecked );
84+ if (isChecked ) {
85+ if (properties .selection_mode == DialogConfigs .MULTI_MODE ) {
86+ MarkedItemList .addSelectedItem (item );
87+ } else {
88+ MarkedItemList .addSingleFile (item );
89+ }
90+ } else {
91+ MarkedItemList .removeSelectedItem (item .getLocation ());
92+ }
93+ if (notifyItemChecked != null ) {
94+ notifyItemChecked .notifyCheckBoxIsClicked ();
95+ }
96+ });
8297 }
98+
99+ return convertView ;
100+ }
101+
102+ private void applySelectionAnimation (View view , FileListItem item ) {
103+ int animationRes = MarkedItemList .hasItem (item .getLocation ())
104+ ? R .anim .marked_item_animation
105+ : R .anim .unmarked_item_animation ;
106+ Animation animation = AnimationUtils .loadAnimation (context , animationRes );
107+ view .startAnimation (animation );
108+ }
109+
110+ private void bindIcon (ViewHolder holder , FileListItem item ) {
83111 if (item .isDirectory ()) {
84- holder .type_icon .setImageResource (R .mipmap .ic_type_folder );
85- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
86- holder .type_icon .setColorFilter (context .getResources ()
87- .getColor (R .color .colorPrimary , context .getTheme ()));
88- } else {
89- holder .type_icon .setColorFilter (context .getResources ()
90- .getColor (R .color .colorPrimary ));
91- }
92- if (properties .selection_type == DialogConfigs .FILE_SELECT ) {
93- holder .checkbox .setVisibility (View .INVISIBLE );
94- } else {
95- holder .checkbox .setVisibility (View .VISIBLE );
96- }
112+ holder .typeIcon .setImageResource (R .mipmap .ic_type_folder );
113+ holder .typeIcon .setColorFilter (getColorCompat (R .color .colorPrimary ));
97114 } else {
98- holder .type_icon .setImageResource (R .mipmap .ic_type_file );
99- if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
100- holder .type_icon .setColorFilter (context .getResources ()
101- .getColor (R .color .colorAccent , context .getTheme ()));
102- } else {
103- holder .type_icon .setColorFilter (context .getResources ()
104- .getColor (R .color .colorAccent ));
105- }
106- if (properties .selection_type == DialogConfigs .DIR_SELECT ) {
107- holder .checkbox .setVisibility (View .INVISIBLE );
108- } else {
109- holder .checkbox .setVisibility (View .VISIBLE );
110- }
115+ holder .typeIcon .setImageResource (R .mipmap .ic_type_file );
116+ holder .typeIcon .setColorFilter (getColorCompat (R .color .colorAccent ));
111117 }
112- holder .type_icon .setContentDescription (item .getFilename ());
118+ holder .typeIcon .setContentDescription (item .getFilename ());
119+ }
120+
121+ private void bindTexts (ViewHolder holder , FileListItem item , boolean isParentRow ) {
113122 holder .name .setText (item .getFilename ());
114- DateFormat dateFormatter = android .text .format .DateFormat .getMediumDateFormat (context );
115- DateFormat timeFormatter = android .text .format .DateFormat .getTimeFormat (context );
116- Date date = new Date (item .getTime ());
117- if (i == 0 && item .getFilename ().startsWith (context .getString (R .string .label_parent_dir ))) {
123+ if (isParentRow ) {
118124 holder .type .setText (R .string .label_parent_directory );
119125 } else {
126+ Date date = new Date (item .getTime ());
127+ DateFormat dateFormatter = android .text .format .DateFormat .getMediumDateFormat (context );
128+ DateFormat timeFormatter = android .text .format .DateFormat .getTimeFormat (context );
120129 holder .type .setText (String .format (context .getString (R .string .last_edit ),
121130 dateFormatter .format (date ), timeFormatter .format (date )));
122131 }
123- if (holder .checkbox .getVisibility () == View .VISIBLE ) {
124- if (i == 0 && item .getFilename ().startsWith (context .getString (R .string .label_parent_dir ))) {
125- holder .checkbox .setVisibility (View .INVISIBLE );
126- }
127- if (MarkedItemList .hasItem (item .getLocation ())) {
128- holder .checkbox .setChecked (true );
129- } else {
130- holder .checkbox .setChecked (false );
131- }
132+ }
133+
134+ private boolean isSelectable (FileListItem item , boolean isParentRow ) {
135+ if (item == null || isParentRow ) {
136+ return false ;
137+ }
138+ if (item .isDirectory ()) {
139+ return properties .selection_type != DialogConfigs .FILE_SELECT ;
132140 }
141+ return properties .selection_type != DialogConfigs .DIR_SELECT ;
142+ }
133143
134- holder .checkbox .setOnCheckedChangedListener (new OnCheckedChangeListener () {
135- @ Override
136- public void onCheckedChanged (MaterialCheckbox checkbox , boolean isChecked ) {
137- item .setMarked (isChecked );
138- if (item .isMarked ()) {
139- if (properties .selection_mode == DialogConfigs .MULTI_MODE ) {
140- MarkedItemList .addSelectedItem (item );
141- } else {
142- MarkedItemList .addSingleFile (item );
143- }
144- } else {
145- MarkedItemList .removeSelectedItem (item .getLocation ());
146- }
147- notifyItemChecked .notifyCheckBoxIsClicked ();
148- }
149- });
150- return view ;
144+ private boolean isParentRow (int position , FileListItem item ) {
145+ return position == 0 && item != null
146+ && item .getFilename ().startsWith (context .getString (R .string .label_parent_dir ));
147+ }
148+
149+ private int getColorCompat (int colorRes ) {
150+ if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .M ) {
151+ return context .getResources ().getColor (colorRes , context .getTheme ());
152+ }
153+ return context .getResources ().getColor (colorRes );
154+ }
155+
156+ public void setNotifyItemCheckedListener (NotifyItemChecked notifyItemChecked ) {
157+ this .notifyItemChecked = notifyItemChecked ;
151158 }
152159
153- private class ViewHolder {
154- ImageView type_icon ;
155- TextView name , type ;
156- MaterialCheckbox checkbox ;
160+ private static class ViewHolder {
161+ final ImageView typeIcon ;
162+ final TextView name ;
163+ final TextView type ;
164+ final MaterialCheckbox checkbox ;
157165
158166 ViewHolder (View itemView ) {
159167 name = itemView .findViewById (R .id .fname );
160168 type = itemView .findViewById (R .id .ftype );
161- type_icon = itemView .findViewById (R .id .image_type );
169+ typeIcon = itemView .findViewById (R .id .image_type );
162170 checkbox = itemView .findViewById (R .id .file_mark );
163171 }
164172 }
165-
166- public void setNotifyItemCheckedListener (NotifyItemChecked notifyItemChecked ) {
167- this .notifyItemChecked = notifyItemChecked ;
168- }
169173}
0 commit comments