parent
							
								
									0d2ad63531
								
							
						
					
					
						commit
						378d2e56d1
					
				| @ -1,4 +1,3 @@ | ||||
| * 1、新增第三方书源发现支持 | ||||
| * 2、发现内容界面优化 | ||||
| * 3、优化搜索 | ||||
| * 4、修复已知bug | ||||
| * 1、修复发现分类bug | ||||
| * 2、新增章节内容智能分段 | ||||
| * 3、备份/恢复路径支持自定义 | ||||
| @ -1,246 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.adapter; | ||||
| 
 | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.util.ArrayList; | ||||
| 
 | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.widget.filepicker.entity.FileItem; | ||||
| import xyz.fycz.myreader.widget.filepicker.icons.FilePickerIcon; | ||||
| import xyz.fycz.myreader.widget.filepicker.util.ConvertUtils; | ||||
| import xyz.fycz.myreader.widget.filepicker.util.FileUtils; | ||||
| 
 | ||||
| 
 | ||||
| public class FileAdapter extends RecyclerView.Adapter<FileAdapter.MyViewHolder> { | ||||
|     public static final String DIR_ROOT = "."; | ||||
|     public static final String DIR_PARENT = ".."; | ||||
|     private ArrayList<FileItem> data = new ArrayList<>(); | ||||
|     private String rootPath = null; | ||||
|     private String currentPath = null; | ||||
|     private String[] allowExtensions = null;//允许的扩展名
 | ||||
|     private boolean onlyListDir = false;//是否仅仅读取目录
 | ||||
|     private boolean showHomeDir = false;//是否显示返回主目录
 | ||||
|     private boolean showUpDir = true;//是否显示返回上一级
 | ||||
|     private boolean showHideDir = true;//是否显示隐藏的目录(以“.”开头)
 | ||||
|     private int itemHeight = 40;// dp
 | ||||
|     private Drawable homeIcon = null; | ||||
|     private Drawable upIcon = null; | ||||
|     private Drawable folderIcon = null; | ||||
|     private Drawable fileIcon = null; | ||||
|     private CallBack callBack; | ||||
| 
 | ||||
|     public void setCallBack(CallBack callBack) { | ||||
|         this.callBack = callBack; | ||||
|     } | ||||
| 
 | ||||
|     public FileItem getItem(int pos) { | ||||
|         return data.get(pos); | ||||
|     } | ||||
| 
 | ||||
|     public String getCurrentPath() { | ||||
|         return currentPath; | ||||
|     } | ||||
| 
 | ||||
|     public void setFileIcon(Drawable fileIcon) { | ||||
|         this.fileIcon = fileIcon; | ||||
|     } | ||||
| 
 | ||||
|     public void setFolderIcon(Drawable folderIcon) { | ||||
|         this.folderIcon = folderIcon; | ||||
|     } | ||||
| 
 | ||||
|     public void setHomeIcon(Drawable homeIcon) { | ||||
|         this.homeIcon = homeIcon; | ||||
|     } | ||||
| 
 | ||||
|     public void setUpIcon(Drawable upIcon) { | ||||
|         this.upIcon = upIcon; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 允许的扩展名 | ||||
|      */ | ||||
|     public void setAllowExtensions(String[] allowExtensions) { | ||||
|         this.allowExtensions = allowExtensions; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 是否仅仅读取目录 | ||||
|      */ | ||||
|     public void setOnlyListDir(boolean onlyListDir) { | ||||
|         this.onlyListDir = onlyListDir; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isOnlyListDir() { | ||||
|         return onlyListDir; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 是否显示返回主目录 | ||||
|      */ | ||||
|     public void setShowHomeDir(boolean showHomeDir) { | ||||
|         this.showHomeDir = showHomeDir; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isShowHomeDir() { | ||||
|         return showHomeDir; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 是否显示返回上一级 | ||||
|      */ | ||||
|     public void setShowUpDir(boolean showUpDir) { | ||||
|         this.showUpDir = showUpDir; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isShowUpDir() { | ||||
|         return showUpDir; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 是否显示隐藏的目录(以“.”开头) | ||||
|      */ | ||||
|     public void setShowHideDir(boolean showHideDir) { | ||||
|         this.showHideDir = showHideDir; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isShowHideDir() { | ||||
|         return showHideDir; | ||||
|     } | ||||
| 
 | ||||
|     public void setItemHeight(int itemHeight) { | ||||
|         this.itemHeight = itemHeight; | ||||
|     } | ||||
| 
 | ||||
|     public void loadData(String path) { | ||||
|         if (path == null) { | ||||
|             return; | ||||
|         } | ||||
|         if (homeIcon == null) { | ||||
|             homeIcon = ConvertUtils.toDrawable(FilePickerIcon.getHOME()); | ||||
|         } | ||||
|         if (upIcon == null) { | ||||
|             upIcon = ConvertUtils.toDrawable(FilePickerIcon.getUPDIR()); | ||||
|         } | ||||
|         if (folderIcon == null) { | ||||
|             folderIcon = ConvertUtils.toDrawable(FilePickerIcon.getFOLDER()); | ||||
|         } | ||||
|         if (fileIcon == null) { | ||||
|             fileIcon = ConvertUtils.toDrawable(FilePickerIcon.getFILE()); | ||||
|         } | ||||
|         ArrayList<FileItem> datas = new ArrayList<FileItem>(); | ||||
|         if (rootPath == null) { | ||||
|             rootPath = path; | ||||
|         } | ||||
|         currentPath = path; | ||||
|         if (showHomeDir) { | ||||
|             //添加“返回主目录”
 | ||||
|             FileItem fileRoot = new FileItem(); | ||||
|             fileRoot.setDirectory(true); | ||||
|             fileRoot.setIcon(homeIcon); | ||||
|             fileRoot.setName(DIR_ROOT); | ||||
|             fileRoot.setSize(0); | ||||
|             fileRoot.setPath(rootPath); | ||||
|             datas.add(fileRoot); | ||||
|         } | ||||
|         if (showUpDir && !path.equals("/")) { | ||||
|             //添加“返回上一级目录”
 | ||||
|             FileItem fileParent = new FileItem(); | ||||
|             fileParent.setDirectory(true); | ||||
|             fileParent.setIcon(upIcon); | ||||
|             fileParent.setName(DIR_PARENT); | ||||
|             fileParent.setSize(0); | ||||
|             fileParent.setPath(new File(path).getParent()); | ||||
|             datas.add(fileParent); | ||||
|         } | ||||
|         File[] files; | ||||
|         if (allowExtensions == null) { | ||||
|             if (onlyListDir) { | ||||
|                 files = FileUtils.listDirs(currentPath); | ||||
|             } else { | ||||
|                 files = FileUtils.listDirsAndFiles(currentPath); | ||||
|             } | ||||
|         } else { | ||||
|             if (onlyListDir) { | ||||
|                 files = FileUtils.listDirs(currentPath, allowExtensions); | ||||
|             } else { | ||||
|                 files = FileUtils.listDirsAndFiles(currentPath, allowExtensions); | ||||
|             } | ||||
|         } | ||||
|         if (files != null) { | ||||
|             for (File file : files) { | ||||
|                 if (!showHideDir && file.getName().startsWith(".")) { | ||||
|                     continue; | ||||
|                 } | ||||
|                 FileItem fileItem = new FileItem(); | ||||
|                 boolean isDirectory = file.isDirectory(); | ||||
|                 fileItem.setDirectory(isDirectory); | ||||
|                 if (isDirectory) { | ||||
|                     fileItem.setIcon(folderIcon); | ||||
|                     fileItem.setSize(0); | ||||
|                 } else { | ||||
|                     fileItem.setIcon(fileIcon); | ||||
|                     fileItem.setSize(file.length()); | ||||
|                 } | ||||
|                 fileItem.setName(file.getName()); | ||||
|                 fileItem.setPath(file.getAbsolutePath()); | ||||
|                 datas.add(fileItem); | ||||
|             } | ||||
|         } | ||||
|         data.clear(); | ||||
|         data.addAll(datas); | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||
|         return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_file_filepicker, parent, false)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) { | ||||
|         FileItem fileItem = data.get(position); | ||||
|         holder.imageView.setImageDrawable(fileItem.getIcon()); | ||||
|         holder.textView.setText(fileItem.getName()); | ||||
|         holder.itemView.setOnClickListener(new View.OnClickListener() { | ||||
|             @Override | ||||
|             public void onClick(View v) { | ||||
|                 if (callBack != null) { | ||||
|                     callBack.onFileClick(position); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return data.size(); | ||||
|     } | ||||
| 
 | ||||
|     class MyViewHolder extends RecyclerView.ViewHolder { | ||||
|         ImageView imageView; | ||||
|         TextView textView; | ||||
| 
 | ||||
|         MyViewHolder(@NonNull View itemView) { | ||||
|             super(itemView); | ||||
|             imageView = itemView.findViewById(R.id.image_view); | ||||
|             textView = itemView.findViewById(R.id.text_view); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public interface CallBack { | ||||
|         void onFileClick(int position); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| @ -1,103 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.adapter; | ||||
| 
 | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.os.Environment; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.ImageView; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| 
 | ||||
| import java.util.Collections; | ||||
| import java.util.LinkedList; | ||||
| 
 | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.widget.filepicker.icons.FilePickerIcon; | ||||
| import xyz.fycz.myreader.widget.filepicker.util.ConvertUtils; | ||||
| 
 | ||||
| 
 | ||||
| public class PathAdapter extends RecyclerView.Adapter<PathAdapter.MyViewHolder> { | ||||
|     private static final String ROOT_HINT = "SD"; | ||||
|     private LinkedList<String> paths = new LinkedList<>(); | ||||
|     private Drawable arrowIcon = null; | ||||
|     private String sdCardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath(); | ||||
|     private CallBack callBack; | ||||
| 
 | ||||
|     public void setCallBack(CallBack callBack) { | ||||
|         this.callBack = callBack; | ||||
|     } | ||||
| 
 | ||||
|     public String getItem(int position) { | ||||
|         StringBuilder tmp = new StringBuilder(sdCardDirectory + "/"); | ||||
|         //忽略根目录
 | ||||
|         if (position == 0) { | ||||
|             return tmp.toString(); | ||||
|         } | ||||
|         for (int i = 1; i <= position; i++) { | ||||
|             tmp.append(paths.get(i)).append("/"); | ||||
|         } | ||||
|         return tmp.toString(); | ||||
|     } | ||||
| 
 | ||||
|     public void setArrowIcon(Drawable arrowIcon) { | ||||
|         this.arrowIcon = arrowIcon; | ||||
|     } | ||||
| 
 | ||||
|     public void updatePath(String path) { | ||||
|         path = path.replace(sdCardDirectory, ""); | ||||
|         if (arrowIcon == null) { | ||||
|             arrowIcon = ConvertUtils.toDrawable(FilePickerIcon.getARROW()); | ||||
|         } | ||||
|         paths.clear(); | ||||
|         if (!path.equals("/") && !path.equals("")) { | ||||
|             String[] tmps = path.substring(path.indexOf("/") + 1).split("/"); | ||||
|             Collections.addAll(paths, tmps); | ||||
|         } | ||||
|         paths.addFirst(ROOT_HINT); | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     @Override | ||||
|     public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { | ||||
|         return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.item_path_filepicker, parent, false)); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) { | ||||
|         holder.textView.setText(paths.get(position)); | ||||
|         holder.imageView.setImageDrawable(arrowIcon); | ||||
|         holder.itemView.setOnClickListener(new View.OnClickListener() { | ||||
|             @Override | ||||
|             public void onClick(View v) { | ||||
|                 if (callBack != null) { | ||||
|                     callBack.onPathClick(position); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return paths.size(); | ||||
|     } | ||||
| 
 | ||||
|     class MyViewHolder extends RecyclerView.ViewHolder { | ||||
|         ImageView imageView; | ||||
|         TextView textView; | ||||
| 
 | ||||
|         MyViewHolder(@NonNull View itemView) { | ||||
|             super(itemView); | ||||
|             imageView = itemView.findViewById(R.id.image_view); | ||||
|             textView = itemView.findViewById(R.id.text_view); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public interface CallBack { | ||||
|         void onPathClick(int position); | ||||
|     } | ||||
| } | ||||
| @ -1,30 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.drawable; | ||||
| 
 | ||||
| import android.graphics.Color; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.graphics.drawable.StateListDrawable; | ||||
| 
 | ||||
| /** | ||||
|  * 按下状态与普通状态下显示不同的图片或颜色 | ||||
|  * <br /> | ||||
|  * Author:李玉江[QQ:1032694760] | ||||
|  * DateTime:2017/01/01 05:30 | ||||
|  * Builder:Android Studio | ||||
|  */ | ||||
| public abstract class StateBaseDrawable extends StateListDrawable { | ||||
| 
 | ||||
|     protected void addState(Drawable pressed) { | ||||
|         addState(new ColorDrawable(Color.TRANSPARENT), pressed); | ||||
|     } | ||||
| 
 | ||||
|     protected void addState(Drawable normal, Drawable pressed) { | ||||
|         addState(new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}, pressed); | ||||
|         addState(new int[]{android.R.attr.state_enabled, android.R.attr.state_focused}, pressed); | ||||
|         addState(new int[]{android.R.attr.state_enabled}, normal); | ||||
|         addState(new int[]{android.R.attr.state_focused}, pressed); | ||||
|         addState(new int[]{android.R.attr.state_window_focused}, normal); | ||||
|         addState(new int[]{}, normal); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,25 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.drawable; | ||||
| 
 | ||||
| import android.graphics.Color; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| 
 | ||||
| import androidx.annotation.ColorInt; | ||||
| 
 | ||||
| /** | ||||
|  * 按下状态与普通状态下显示不同的颜色 | ||||
|  * <br /> | ||||
|  * Author:李玉江[QQ:1032694760] | ||||
|  * DateTime:2017/01/01 05:30 | ||||
|  * Builder:Android Studio | ||||
|  */ | ||||
| public class StateColorDrawable extends StateBaseDrawable { | ||||
| 
 | ||||
|     public StateColorDrawable(@ColorInt int pressedColor) { | ||||
|         this(Color.TRANSPARENT, pressedColor); | ||||
|     } | ||||
| 
 | ||||
|     public StateColorDrawable(@ColorInt int normalColor, @ColorInt int pressedColor) { | ||||
|         addState(new ColorDrawable(normalColor), new ColorDrawable(pressedColor)); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,58 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.entity; | ||||
| 
 | ||||
| import android.graphics.drawable.Drawable; | ||||
| 
 | ||||
| /** | ||||
|  * 文件项信息 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1032694760] | ||||
|  * @since 2014-05-23 18:02 | ||||
|  */ | ||||
| public class FileItem extends JavaBean { | ||||
|     private Drawable icon; | ||||
|     private String name; | ||||
|     private String path = "/"; | ||||
|     private long size = 0; | ||||
|     private boolean isDirectory = false; | ||||
| 
 | ||||
|     public void setIcon(Drawable icon) { | ||||
|         this.icon = icon; | ||||
|     } | ||||
| 
 | ||||
|     public Drawable getIcon() { | ||||
|         return icon; | ||||
|     } | ||||
| 
 | ||||
|     public String getName() { | ||||
|         return name; | ||||
|     } | ||||
| 
 | ||||
|     public void setName(String name) { | ||||
|         this.name = name; | ||||
|     } | ||||
| 
 | ||||
|     public String getPath() { | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     public void setPath(String path) { | ||||
|         this.path = path; | ||||
|     } | ||||
| 
 | ||||
|     public long getSize() { | ||||
|         return size; | ||||
|     } | ||||
| 
 | ||||
|     public void setSize(long size) { | ||||
|         this.size = size; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isDirectory() { | ||||
|         return isDirectory; | ||||
|     } | ||||
| 
 | ||||
|     public void setDirectory(boolean isDirectory) { | ||||
|         this.isDirectory = isDirectory; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,52 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.entity; | ||||
| 
 | ||||
| import java.io.Serializable; | ||||
| import java.lang.reflect.Field; | ||||
| import java.lang.reflect.Modifier; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Arrays; | ||||
| 
 | ||||
| /** | ||||
|  * JavaBean类 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1032694760] | ||||
|  * @since 2014-04-23 16:14 | ||||
|  */ | ||||
| public class JavaBean implements Serializable { | ||||
|     private static final long serialVersionUID = -6111323241670458039L; | ||||
| 
 | ||||
|     /** | ||||
|      * 反射出所有字段值 | ||||
|      */ | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         ArrayList<Field> list = new ArrayList<>(); | ||||
|         Class<?> clazz = getClass(); | ||||
|         list.addAll(Arrays.asList(clazz.getDeclaredFields()));//得到自身的所有字段
 | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         while (clazz != Object.class) { | ||||
|             clazz = clazz.getSuperclass();//得到继承自父类的字段
 | ||||
|             Field[] fields = clazz.getDeclaredFields(); | ||||
|             for (Field field : fields) { | ||||
|                 int modifier = field.getModifiers(); | ||||
|                 if (Modifier.isPublic(modifier) || Modifier.isProtected(modifier)) { | ||||
|                     list.add(field); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         Field[] fields = list.toArray(new Field[0]); | ||||
|         for (Field field : fields) { | ||||
|             String fieldName = field.getName(); | ||||
|             try { | ||||
|                 Object obj = field.get(this); | ||||
|                 sb.append(fieldName); | ||||
|                 sb.append("="); | ||||
|                 sb.append(obj); | ||||
|                 sb.append("\n"); | ||||
|             } catch (IllegalAccessException ignored) { | ||||
|             } | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,283 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.icons; | ||||
| 
 | ||||
| /** | ||||
|  * Generated by https://github.com/gzu-liyujiang/Image2ByteVar
 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1023694760] | ||||
|  * @since 2017/01/04 06:03 | ||||
|  */ | ||||
| public class FilePickerIcon { | ||||
| 
 | ||||
|     public static byte[] getFILE() { | ||||
|         return FILE; | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] getFOLDER() { | ||||
|         return FOLDER; | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] getHOME() { | ||||
|         return HOME; | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] getUPDIR() { | ||||
|         return UPDIR; | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] getARROW() { | ||||
|         return ARROW; | ||||
|     } | ||||
| 
 | ||||
|     // fixed: 17-1-7 "static final" arrays should be "private"
 | ||||
|     private static final byte[] FILE = { | ||||
|             -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 42, | ||||
|             0, 0, 0, 40, 8, 6, 0, 0, 0, -120, 11, 104, 80, 0, 0, 0, 6, 98, 75, 71, | ||||
|             68, 0, -1, 0, -1, 0, -1, -96, -67, -89, -109, 0, 0, 0, 9, 112, 72, 89, 115, 0, | ||||
|             0, 14, -60, 0, 0, 14, -60, 1, -107, 43, 14, 27, 0, 0, 1, -73, 73, 68, 65, 84, | ||||
|             88, -123, -19, -106, 63, 75, 3, 49, 24, -121, 127, -74, 69, -37, 110, -30, -94, -109, -120, -126, | ||||
|             -125, -101, 56, 72, 63, -125, -97, -64, -63, 77, 28, 69, 20, 81, 68, 113, 83, 113, -12, 91, | ||||
|             -120, -96, -117, -120, -85, 31, 65, 29, 28, -100, -124, -94, -101, 46, -83, -105, 92, 114, 113, -24, | ||||
|             31, -38, -110, 59, -34, -9, 114, 87, 69, -14, 64, 41, -92, 73, -34, -89, -55, -17, 114, 1, | ||||
|             60, 30, -113, -25, 79, 50, 66, -19, 120, -7, 16, 26, 0, -112, 82, -61, 24, 3, 41, 35, | ||||
|             0, -128, 20, 10, 74, 69, -48, 58, -126, 82, -90, -37, -90, -75, -127, 82, 81, 119, 124, 16, | ||||
|             40, -100, 109, 79, -109, -21, 13, 82, -94, 118, -108, 82, 99, -91, 54, -58, 25, 2, 0, 120, | ||||
|             -85, 7, -72, -71, 127, -57, -18, -58, 12, -102, -51, 87, 115, 113, 56, -105, 74, -74, 64, -19, | ||||
|             104, -116, 73, 51, 63, 0, -96, 88, 104, -107, 57, -34, -102, -59, -6, -63, 75, -86, -119, -56, | ||||
|             -94, -99, -83, -26, -96, 123, -122, 20, -37, -107, 78, -9, -25, -79, -74, -13, -52, -106, 37, -117, | ||||
|             114, -23, 72, 42, 109, -96, -93, 8, 66, 0, -97, 95, -83, -49, -55, -34, 2, 86, 55, 31, | ||||
|             89, -78, -12, -116, 10, -59, 18, -20, 48, 90, -86, -96, -47, -48, -72, -66, -5, 64, -40, -98, | ||||
|             -94, 90, -27, -81, 15, 89, -76, -9, 9, -114, 99, 80, 18, 0, -90, 38, -127, -38, -46, 4, | ||||
|             -76, 78, -97, 113, -128, 33, 42, -124, 78, -4, -35, 38, -87, -62, -42, -9, -14, -30, 120, 127, | ||||
|             -69, 6, -82, 110, -21, -44, -46, 0, -72, 103, 77, 12, 73, -110, 125, 109, -55, -1, 53, 17, | ||||
|             86, 70, 109, 66, 113, -72, 72, -39, 32, -89, -38, 53, 99, -82, 100, -14, 48, -39, -74, 57, | ||||
|             107, -100, -49, -47, -84, -77, 24, 7, 121, 69, -125, -64, 126, -114, 82, -91, -66, 3, 106, 37, | ||||
|             59, -12, 21, 85, -46, -87, 80, -91, -20, 52, -100, 46, -38, -108, -87, 111, 104, -103, -64, 58, | ||||
|             71, -121, -15, -48, -60, -63, -54, -24, -80, -14, 104, 35, -73, -37, 83, -42, -112, 69, 5, -15, | ||||
|             -10, -108, 23, -12, 3, 63, -92, -65, 63, 43, 101, -5, -10, 7, 14, -111, 112, -66, -108, -28, | ||||
|             -111, 71, 27, -1, 47, -93, -65, 77, 38, -9, 81, 27, 46, 121, -76, -63, 18, 29, 86, 30, | ||||
|             109, -80, 68, -113, -50, -97, -14, -14, -16, 120, 60, -98, 1, 126, 0, -110, 81, -78, -5, 36, | ||||
|             19, -64, 3, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126}; | ||||
|     private static final byte[] FOLDER = { | ||||
|             -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 42, | ||||
|             0, 0, 0, 40, 8, 6, 0, 0, 0, -120, 11, 104, 80, 0, 0, 0, 6, 98, 75, 71, | ||||
|             68, 0, -1, 0, -1, 0, -1, -96, -67, -89, -109, 0, 0, 0, 9, 112, 72, 89, 115, 0, | ||||
|             0, 14, -60, 0, 0, 14, -60, 1, -107, 43, 14, 27, 0, 0, 2, -102, 73, 68, 65, 84, | ||||
|             88, -123, -19, -105, 61, -113, 19, 49, 16, -122, 95, 111, -110, 75, -124, -124, -60, -49, 65, 20, | ||||
|             -48, 34, 81, 80, 32, 81, 83, 80, -94, 52, 72, 8, 78, 66, -94, 64, 20, -108, 124, 20, | ||||
|             39, -47, 64, -51, -11, -7, 87, -96, 11, -38, -75, 61, 99, 15, -59, 110, 54, 118, -42, -5, | ||||
|             113, -71, 77, 117, -5, 54, -55, -50, -38, -42, -77, -81, 61, 99, 27, -104, 52, 105, -46, -92, | ||||
|             73, -73, 66, 106, 104, -61, -51, 57, -92, -21, -3, -29, 79, -61, -57, 58, 70, -13, 33, -115, | ||||
|             54, -25, -112, 71, -17, 127, 0, 0, -106, -38, -105, 65, 93, 64, -56, 0, 108, 33, 76, -72, | ||||
|             -28, -113, -14, -20, -77, 59, 25, 108, 54, 4, -14, -63, -6, 59, -112, 123, -84, -4, -84, -114, | ||||
|             -117, 39, 96, -74, -17, -2, -12, -59, 91, 92, -66, -103, 117, -70, 126, 19, 117, 58, -80, 57, | ||||
|             -121, 60, 92, 127, 5, 0, -84, -106, -53, -3, 11, 93, -108, -96, 0, 96, 52, -124, 9, 96, | ||||
|             6, 116, -127, -33, -65, -66, -44, -51, 56, -117, -121, -73, 62, 3, -7, 56, -74, 123, 126, -11, | ||||
|             -83, -24, 100, -23, -99, -6, -43, -67, -5, -119, -96, -119, -66, 80, 1, -128, 49, 0, -128, -25, | ||||
|             31, -98, -108, 65, 103, -93, 46, -62, -36, 24, -58, -27, -37, -6, -65, -39, -66, -108, -41, 63, | ||||
|             -13, 86, -40, 65, 107, 84, -7, 43, 64, -103, 70, 92, 108, 17, -45, 82, -94, -115, -47, 77, | ||||
|             -40, -22, 35, -108, 53, 32, 34, 56, 34, 112, -49, -14, 30, 4, 90, 66, -2, -119, 99, -34, | ||||
|             2, -69, -23, -33, -119, -10, -32, 18, -66, -37, -63, 114, 16, 99, -122, 2, -64, 87, 127, 97, | ||||
|             -56, -61, -53, 24, -96, -121, -14, -107, 35, 103, 11, -120, -91, 116, 27, -25, -45, -15, 96, 9, | ||||
|             80, -95, 97, -56, -61, 114, 127, 14, -10, 102, 125, 27, 36, -128, 86, -56, -70, 34, -52, 50, | ||||
|             -128, 109, -78, 77, 40, 118, -82, -73, 77, -65, -93, 98, 26, -128, -111, -62, 41, 62, -101, 67, | ||||
|             116, -111, 110, -41, 34, -53, 2, -26, 22, -9, 3, 29, 53, -11, -111, -109, -39, -94, -4, -83, | ||||
|             0, 85, -74, -120, -41, -25, 72, -22, 4, -27, -86, -58, -119, 45, -102, -119, 3, 52, -36, -124, | ||||
|             61, 40, 65, 81, -58, 55, -5, -117, 99, -80, 115, -89, 115, 52, 9, 93, 65, -90, -36, 76, | ||||
|             65, 94, 87, -67, -96, 74, -52, -2, 52, -46, 54, -91, -95, -109, -119, 108, 87, -13, -59, 126, | ||||
|             -9, 74, 40, -109, 27, 58, 106, 124, 6, -79, 40, -117, -7, 33, 100, 0, 23, -71, -72, -37, | ||||
|             -1, -85, 105, 31, -61, 77, 96, -24, -44, -109, 1, 40, -19, 70, 50, 113, -126, -75, -39, -22, | ||||
|             -26, 53, -85, -61, 113, 89, 127, 8, 23, 78, 119, 80, 55, -5, -36, -12, 117, 34, -11, 23, | ||||
|             -4, 78, 80, -14, 10, 112, 22, -30, 92, -5, -6, 28, 2, 25, -70, -103, 112, -46, -75, -19, | ||||
|             98, 67, 65, 57, 60, -110, -11, 13, 118, 4, -92, -9, 2, 79, 4, -94, 17, 118, 38, 97, | ||||
|             6, -104, 64, -108, -34, -103, -124, -35, -63, 115, -20, -68, -46, 58, 124, 2, 0, 56, 91, -18, | ||||
|             118, -123, -74, -48, 122, 88, -78, 117, -126, 90, 95, 102, -80, 49, 5, -88, 26, 80, -101, -46, | ||||
|             33, 83, -24, -42, 126, 53, 116, 42, 97, -104, -22, 2, -97, 111, 115, 108, -13, 17, 64, 1, | ||||
|             -64, 85, 103, 71, 50, 84, 1, -106, 110, 88, 106, 95, 10, 93, -5, -67, -81, 62, -44, 22, | ||||
|             26, 84, 1, -33, -67, -77, -24, 5, -19, -67, -116, 93, -84, 87, 2, 32, -70, 66, -104, -32, | ||||
|             -112, -53, 94, -63, -113, 112, 1, 125, 119, -15, -17, -92, -73, -40, 73, -109, 38, 77, -70, -19, | ||||
|             -6, 15, -2, -54, -98, -96, -19, -118, -95, -10, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, | ||||
|             96, -126}; | ||||
|     private static final byte[] HOME = { | ||||
|             -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 42, | ||||
|             0, 0, 0, 40, 8, 4, 0, 0, 0, 34, 2, -96, -37, 0, 0, 0, 1, 115, 82, 71, | ||||
|             66, 0, -82, -50, 28, -23, 0, 0, 0, 2, 98, 75, 71, 68, 0, -1, -121, -113, -52, -65, | ||||
|             0, 0, 0, 9, 112, 72, 89, 115, 0, 0, 46, 35, 0, 0, 46, 35, 1, 120, -91, 63, | ||||
|             118, 0, 0, 0, 7, 116, 73, 77, 69, 7, -37, 8, 4, 10, 36, 16, -22, -9, -18, -50, | ||||
|             0, 0, 2, -84, 73, 68, 65, 84, 72, -57, -19, -106, 91, 72, 20, 97, 20, -57, 127, -77, | ||||
|             -18, -106, -41, 54, -14, -106, -23, -102, 4, 21, 97, 5, 5, 61, 70, 74, -76, -122, -94, -11, | ||||
|             18, -108, -92, 121, 41, 16, -124, 96, -95, 48, -118, -108, -94, 18, -70, 96, 33, 68, -81, -127, | ||||
|             15, 25, 68, 15, 21, 89, 80, 42, 25, 42, -91, 97, -106, -103, -122, 107, 41, -19, -86, -37, | ||||
|             -22, 122, -39, 77, -73, -103, -81, 7, -105, 84, -36, -85, -26, -125, -44, -127, -31, 59, -52, -103, | ||||
|             -7, 113, -50, -103, -17, -4, -65, -127, -1, -74, 44, 76, -102, 113, -29, 22, -119, 50, -3, -15, | ||||
|             84, 75, -111, -87, -38, -81, -89, 84, 24, -120, 1, -96, -106, -102, -65, 83, -66, -118, 59, -119, | ||||
|             39, 54, 97, 69, -31, -109, 115, -14, 8, 15, 124, -107, -17, 27, 42, 113, 123, 125, 81, 46, | ||||
|             102, 28, 8, -84, -68, 116, 78, -26, 80, 77, 5, -79, 104, -48, -48, 70, -39, 124, -88, -38, | ||||
|             103, 37, -107, -70, -94, 28, -6, 105, 7, 34, 89, 67, -86, -90, -74, 106, 82, -51, 65, 125, | ||||
|             -110, 13, 27, -99, 43, 2, -17, -87, -60, -51, -124, -30, 99, -104, -88, -63, -12, 20, -93, -90, | ||||
|             96, 111, -80, -106, 20, 117, -3, -35, -97, -65, 54, -13, 29, 21, 8, -9, -3, -14, -122, -68, | ||||
|             17, 127, 50, 15, 51, -49, 49, 85, -109, 73, -79, 51, -81, 94, -103, 96, 21, 123, -126, 66, | ||||
|             86, 10, 64, 4, 12, -107, -72, -70, -50, -112, -57, 0, 47, -24, 123, 66, 46, 50, 80, -19, | ||||
|             40, 121, -59, 20, -31, -20, 102, 0, 121, 1, -48, -14, -72, 83, -7, 12, 81, -121, -79, -106, | ||||
|             67, 76, -71, -18, 94, -73, 85, 54, 34, 19, -122, 115, -102, 23, 16, -12, 114, 92, 73, 1, | ||||
|             22, 26, -24, 110, -26, 0, -114, 89, 17, -61, -32, -61, 22, 4, 2, -127, -30, -31, 125, -9, | ||||
|             -48, -117, -79, 103, -13, -79, -48, 68, -57, 123, -46, 25, -101, 19, -109, 57, -38, -41, -40, -127, | ||||
|             64, 16, -127, 70, -113, -34, 63, 104, 105, -52, -7, 2, -84, -76, -48, -42, 69, 26, -42, 121, | ||||
|             113, 59, 89, 93, -35, -67, 8, -126, -39, -87, 81, -35, 103, -69, 111, -24, -71, -24, 11, -123, | ||||
|             12, -45, -58, -37, -81, -20, -61, -20, -74, 18, 11, -23, -19, -125, 102, 20, -76, 36, 107, 121, | ||||
|             76, -68, 119, -24, -103, -88, 75, -123, -116, -16, -111, 38, 51, 122, -66, 121, -4, -116, 95, 68, | ||||
|             -42, 59, -5, 8, -126, 24, 54, -24, 120, 68, -124, 103, -24, -23, -88, -14, -29, -40, -24, -28, | ||||
|             -75, 85, -92, -47, -27, 117, 48, -102, -27, -20, 86, 121, 28, 5, 29, 107, 119, 112, 111, -10, | ||||
|             24, 5, -51, -72, 17, -122, -32, 107, -39, -110, -99, 30, -22, -58, -108, -3, -76, -6, 20, -93, | ||||
|             -49, -78, -59, -102, 17, -50, 40, -126, -47, -115, 66, 59, 94, -29, 78, 80, -86, -40, 74, -108, | ||||
|             20, -119, 34, 50, -88, -13, 83, 58, -81, -112, 73, 47, 70, -116, 52, -104, -34, 120, 86, 41, | ||||
|             -119, 4, 10, 1, 24, -26, -106, 71, 88, 10, 41, 0, 60, -93, -47, 31, -107, 18, -124, -123, | ||||
|             -106, -19, -30, 7, 31, 122, -68, 64, 83, 19, 75, -75, -12, 51, 108, -101, -127, -6, -40, -4, | ||||
|             97, -92, -110, -20, 67, 18, -109, -40, -58, 106, -113, -86, -66, 96, 83, -36, 15, -2, 34, -96, | ||||
|             -110, 88, 8, 84, -8, 60, -37, 60, 67, -43, -18, -127, 2, 1, 26, -74, 120, -124, 70, 11, | ||||
|             20, -108, 64, -113, 104, -119, 88, -99, -24, 112, -105, -71, 112, 117, -44, 22, 88, -90, 32, 8, | ||||
|             -27, 48, 33, 76, 119, 78, -52, 89, 101, 20, -100, -12, 49, 21, 24, 84, 97, 12, 59, 19, | ||||
|             46, -44, -36, 75, 65, 70, 70, 118, -83, -2, 67, 101, -21, 80, -123, -65, -69, -64, -79, -68, | ||||
|             127, -48, -106, 4, -6, -113, -37, 111, 38, -57, 11, 112, 71, 102, 113, -50, 0, 0, 0, 0, | ||||
|             73, 69, 78, 68, -82, 66, 96, -126}; | ||||
|     private static final byte[] UPDIR = { | ||||
|             -119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 42, | ||||
|             0, 0, 0, 40, 8, 6, 0, 0, 0, -120, 11, 104, 80, 0, 0, 0, 6, 98, 75, 71, | ||||
|             68, 0, -1, 0, -1, 0, -1, -96, -67, -89, -109, 0, 0, 0, 9, 112, 72, 89, 115, 0, | ||||
|             0, 14, -60, 0, 0, 14, -60, 1, -107, 43, 14, 27, 0, 0, 2, -111, 73, 68, 65, 84, | ||||
|             88, -123, -19, -106, -51, 74, -21, 64, 20, -57, -1, -87, -47, 7, -15, 41, 92, 118, -47, 82, | ||||
|             10, -59, 110, 20, -95, 32, 77, -101, 44, -92, -37, -66, 80, -23, 3, 8, -126, -76, -48, -115, | ||||
|             -120, 43, 117, -19, -109, -44, -113, -50, -57, -103, 115, 87, 103, 76, 106, -117, 77, 19, -17, -107, | ||||
|             75, -2, 48, -52, -112, 100, 38, -65, 57, -25, -52, 57, 3, 84, -86, 84, -87, -46, -1, -83, | ||||
|             36, 73, 56, 73, 18, -2, -87, -11, -61, 50, 22, -119, -29, -104, 47, 47, 47, 97, -116, -127, | ||||
|             -75, -106, 39, -109, 73, 80, -58, -70, 105, 21, 94, 48, -114, 99, 78, -110, 4, 68, 4, -91, | ||||
|             20, -116, 49, 120, 121, 121, -63, 120, 60, 46, 21, -74, 86, 100, -14, 112, 56, -28, -85, -85, | ||||
|             43, 0, -128, -75, 22, -50, 57, 48, 51, -114, -113, -113, -47, -21, -11, 74, 13, -125, -67, 65, | ||||
|             -121, -61, 33, -113, 70, 35, 4, 65, 0, 99, -116, 111, -42, 90, 16, 17, 58, -99, 14, 46, | ||||
|             46, 46, 74, -125, -35, 11, 84, 44, -23, -100, -61, -57, -57, 7, 86, -85, 21, -116, 49, 32, | ||||
|             34, 111, 89, 107, 45, 90, -83, 22, -50, -50, -50, 74, -127, -51, 125, -104, 6, -125, 1, -57, | ||||
|             113, -20, -83, -89, -108, -126, -75, 22, 0, -32, -100, -13, 45, 8, 2, 48, 51, -102, -51, 38, | ||||
|             -100, 115, 124, 125, 125, 93, 40, 102, 115, -127, 14, 6, 3, -114, -94, -56, -69, 87, 107, 13, | ||||
|             34, 2, 0, -1, 44, 8, -78, 60, 68, -124, 70, -93, 1, 34, -30, -101, -101, -101, -67, 97, | ||||
|             119, 6, -115, -94, -120, 123, -67, -98, -121, 19, 43, 10, -88, -12, -58, 24, 56, -25, -4, 55, | ||||
|             -78, -127, 122, -67, 14, 34, -30, -37, -37, -37, -67, 96, 119, -102, 20, 69, 17, 119, -69, 93, | ||||
|             15, 98, -83, -59, -63, -63, 1, 0, 32, 12, -61, 12, -88, -124, -61, -37, -37, 27, -34, -33, | ||||
|             -33, -3, -122, 68, 15, 15, 15, -104, -49, -25, -71, 97, -65, -99, -48, -17, -9, -71, -35, 110, | ||||
|             -5, 83, 45, 58, 58, 58, -14, -112, 34, -79, -30, -21, -21, 43, -106, -53, 37, -76, -42, 0, | ||||
|             0, -26, -49, -13, 20, -122, 33, -18, -17, -17, -79, 88, 44, 114, -63, 126, -21, 122, 102, -58, | ||||
|             108, 54, -13, 22, 19, 32, 0, 56, 61, 61, -3, -14, 76, 107, -115, -43, 106, 5, 34, -62, | ||||
|             -45, -45, 83, -26, -35, -6, -72, 84, -48, -23, 116, -70, 113, -25, -25, -25, -25, -20, -100, -53, | ||||
|             -4, 60, 29, -109, 114, -6, 103, -77, 89, 41, 21, 106, -17, 90, 47, -112, 2, 8, -64, 3, | ||||
|             -118, -85, -45, -33, 20, -43, -34, -96, -52, -100, 57, -35, -64, 103, -116, -82, 3, -1, 83, 80, | ||||
|             -87, 62, 2, -72, -98, 79, 5, -74, 44, -107, 2, 42, 112, 0, 50, -15, -7, 43, 64, -103, | ||||
|             121, 35, -24, -81, 118, -67, -28, -41, -76, -53, -91, -43, -21, 117, -106, 119, -23, 94, -58, -113, | ||||
|             -113, -113, 59, 101, -123, -62, -96, -101, -54, -87, 88, -14, -28, -28, 4, -121, -121, -121, 25, 48, | ||||
|             -71, 35, 40, -91, -16, -4, -4, -68, -13, -1, 10, -71, 62, 125, -75, 91, 7, -83, -43, 106, | ||||
|             30, 74, 42, -104, -28, 89, -83, 53, -76, -42, -71, 98, -72, -112, 69, -91, 68, 110, -69, -96, | ||||
|             -92, 123, -7, 70, 41, 5, -91, 84, -18, 10, 85, 10, 104, 58, 70, -45, 125, -6, -80, 73, | ||||
|             47, 22, -51, -85, 66, -82, 87, 74, 1, -128, -17, 55, -127, 109, 2, -1, -85, -96, 98, -47, | ||||
|             -76, 91, -73, 1, -82, -113, 1, -8, 107, -30, -113, -125, -34, -35, -35, 5, 68, -28, 19, -27, | ||||
|             -74, -12, 83, 102, -46, -81, 84, -87, 82, -91, 95, -88, 63, 49, -122, -88, 68, 127, -55, -90, | ||||
|             73, 0, 0, 0, 0, 73, 69, 78, 68, -82, 66, 96, -126}; | ||||
|     private static final byte[] ARROW = {-119, 80, 78, 71, 13, 10, 26, 10, 0, 0, 0, 13, 73, 72, 68, 82, 0, 0, 0, 48, | ||||
|             0, 0, 0, 117, 8, 3, 0, 0, 0, 63, 73, -110, 106, 0, 0, 2, -9, 80, 76, 84, | ||||
|             69, -46, -46, -46, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -65, -65, -65, 0, | ||||
|             0, 0, -52, -52, -52, -49, -49, -49, -47, -47, -47, -47, -47, -47, -48, -48, -48, -54, -54, -54, | ||||
|             -48, -48, -48, -48, -48, -48, -47, -47, -47, -47, -47, -47, -49, -49, -49, -86, -86, -86, -48, -48, | ||||
|             -48, -48, -48, -48, -47, -47, -47, -52, -52, -52, -49, -49, -49, -48, -48, -48, -48, -48, -48, -1, | ||||
|             -1, -1, -49, -49, -49, -48, -48, -48, -48, -48, -48, -51, -51, -51, -50, -50, -50, -48, -48, -48, | ||||
|             -48, -48, -48, -50, -50, -50, -48, -48, -48, -48, -48, -48, -48, -48, -48, -52, -52, -52, -48, -48, | ||||
|             -48, -48, -48, -48, -48, -48, -48, -46, -46, -46, -47, -47, -47, -52, -52, -52, -48, -48, -48, -48, | ||||
|             -48, -48, -1, -1, -1, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, | ||||
|             -48, -48, -48, -41, -41, -41, -48, -48, -48, -49, -49, -49, -43, -43, -43, -47, -47, -47, -49, -49, | ||||
|             -49, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -49, -49, -49, -47, | ||||
|             -47, -47, -49, -49, -49, -47, -47, -47, -48, -48, -48, -48, -48, -48, -48, -48, -48, -49, -49, -49, | ||||
|             -47, -47, -47, -44, -44, -44, -48, -48, -48, -48, -48, -48, -1, -1, -1, -46, -46, -46, -48, -48, | ||||
|             -48, -49, -49, -49, -47, -47, -47, -49, -49, -49, -35, -35, -35, -49, -49, -49, -49, -49, -49, -49, | ||||
|             -49, -49, -47, -47, -47, -40, -40, -40, -49, -49, -49, -48, -48, -48, -48, -48, -48, -47, -47, -47, | ||||
|             -47, -47, -47, -47, -47, -47, -48, -48, -48, -60, -60, -60, -53, -53, -53, -48, -48, -48, -46, -46, | ||||
|             -46, -65, -65, -65, -48, -48, -48, -54, -54, -54, -45, -45, -45, -47, -47, -47, -49, -49, -49, -48, | ||||
|             -48, -48, -49, -49, -49, -51, -51, -51, -48, -48, -48, -48, -48, -48, -46, -46, -46, -47, -47, -47, | ||||
|             -47, -47, -47, -37, -37, -37, -47, -47, -47, -49, -49, -49, -50, -50, -50, -48, -48, -48, -128, -128, | ||||
|             -128, -48, -48, -48, -48, -48, -48, -50, -50, -50, -48, -48, -48, -48, -48, -48, -43, -43, -43, -47, | ||||
|             -47, -47, -48, -48, -48, -48, -48, -48, -48, -48, -48, -43, -43, -43, -47, -47, -47, -48, -48, -48, | ||||
|             -50, -50, -50, -49, -49, -49, -48, -48, -48, -48, -48, -48, -33, -33, -33, -48, -48, -48, -52, -52, | ||||
|             -52, -51, -51, -51, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -52, | ||||
|             -52, -52, -48, -48, -48, -46, -46, -46, -48, -48, -48, -37, -37, -37, -29, -29, -29, -48, -48, -48, | ||||
|             -48, -48, -48, -47, -47, -47, -48, -48, -48, -49, -49, -49, -46, -46, -46, -48, -48, -48, -49, -49, | ||||
|             -49, -47, -47, -47, -58, -58, -58, -49, -49, -49, -47, -47, -47, -48, -48, -48, -50, -50, -50, -47, | ||||
|             -47, -47, -50, -50, -50, -48, -48, -48, -48, -48, -48, -50, -50, -50, -48, -48, -48, -48, -48, -48, | ||||
|             -48, -48, -48, -55, -55, -55, -45, -45, -45, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, | ||||
|             -48, -46, -46, -46, -47, -47, -47, -48, -48, -48, -47, -47, -47, -51, -51, -51, -47, -47, -47, -51, | ||||
|             -51, -51, -48, -48, -48, -47, -47, -47, -48, -48, -48, -65, -65, -65, -48, -48, -48, -50, -50, -50, | ||||
|             -48, -48, -48, -47, -47, -47, -49, -49, -49, -47, -47, -47, -47, -47, -47, -48, -48, -48, -48, -48, | ||||
|             -48, -50, -50, -50, -47, -47, -47, -49, -49, -49, -49, -49, -49, -47, -47, -47, -48, -48, -48, -47, | ||||
|             -47, -47, -49, -49, -49, -39, -39, -39, -50, -50, -50, -47, -47, -47, -48, -48, -48, -42, -42, -42, | ||||
|             -47, -47, -47, -46, -46, -46, -47, -47, -47, -47, -47, -47, -48, -48, -48, -49, -49, -49, -49, -49, | ||||
|             -49, -47, -47, -47, -48, -48, -48, -47, -47, -47, -48, -48, -48, -50, -50, -50, -47, -47, -47, -48, | ||||
|             -48, -48, -47, -47, -47, -49, -49, -49, -48, -48, -48, -49, -49, -49, -50, -50, -50, -47, -47, -47, | ||||
|             -56, -56, -56, -48, -48, -48, -48, -48, -48, -40, -40, -40, -45, -45, -45, -47, -47, -47, -47, -47, | ||||
|             -47, -49, -49, -49, -48, -48, -48, -43, -43, -43, -52, -52, -52, -49, -49, -49, -47, -47, -47, -47, | ||||
|             -47, -47, -50, -50, -50, -49, -49, -49, -47, -47, -47, -49, -49, -49, -48, -48, -48, -49, -49, -49, | ||||
|             -115, 52, -27, 40, 0, 0, 0, -3, 116, 82, 78, 83, 34, -37, -1, -7, 120, 4, 0, 5, | ||||
|             118, -9, -41, 38, 24, -46, -2, -100, 78, 69, 3, -98, -54, 28, 40, -37, -8, 115, 3, 122, | ||||
|             -6, -43, 36, 31, -49, -109, 78, 70, -93, -50, 20, 43, -38, -10, 113, 123, 30, -45, -115, 2, | ||||
|             86, -5, -9, 65, -94, -55, 19, -29, 111, 6, 127, 32, -39, -3, -114, 92, -4, 58, -86, -63, | ||||
|             22, -32, 109, -126, -5, -51, 36, -44, -121, 1, 90, -11, 59, -79, -59, 15, 48, -11, 106, -123, | ||||
|             26, 37, -40, 98, -3, -14, -80, -61, 13, 44, -25, 103, 8, -120, 29, 35, -35, -4, -127, 101, | ||||
|             46, -76, -71, 17, -24, 99, 7, -118, -58, 42, 124, 2, 103, -13, 47, -67, -65, 12, 55, -27, | ||||
|             -116, -57, 24, 44, -35, 119, 112, -21, 49, 8, -70, 10, 51, -19, -14, 93, -111, -62, 25, -30, | ||||
|             119, -78, 14, 9, -108, 113, 117, -18, -53, 63, -23, -15, 89, 9, -106, -2, -66, 21, 50, -125, | ||||
|             -33, -28, 57, 97, -97, -73, 19, 69, -12, -17, 81, -87, 57, 94, -99, -73, 72, -18, 82, -88, | ||||
|             -20, 27, 12, -100, 67, -16, 83, 16, -91, -122, 54, -26, 104, -101, 64, 85, 11, -82, 100, -101, | ||||
|             20, 84, -47, 125, 31, -102, 62, -57, -88, -125, 107, -102, -69, -15, -53, -77, 52, -31, -105, 66, | ||||
|             -21, 87, 121, 110, -67, 23, -60, -84, 13, 46, 111, 88, -75, 119, 42, 50, -32, 106, -107, 63, | ||||
|             91, -78, 117, 114, -108, 41, -51, -28, -65, 0, 0, 3, -107, 73, 68, 65, 84, 88, -61, -107, | ||||
|             -40, 105, 84, -108, 85, 24, 7, 112, -4, -113, -13, -112, -37, -101, -111, -96, 78, 67, -94, 38, | ||||
|             -18, -66, 14, 46, 52, -38, -28, -96, 34, 90, -67, -31, -106, 75, -114, 70, 74, 42, 90, 86, | ||||
|             -109, 4, 38, -88, -111, -90, 50, -126, -72, -46, -54, -102, 38, -102, -53, 104, -101, 123, -88, -71, | ||||
|             78, -18, -91, -90, 88, 82, 46, 89, 90, -71, -107, -27, 7, 95, 62, 120, -114, -100, -93, -121, | ||||
|             -5, 127, 63, -65, -65, 15, -9, -36, 123, -97, -5, 127, -98, -96, -96, 106, -80, 84, -73, -118, | ||||
|             -14, 23, 20, -4, 64, 13, -44, -84, 69, 0, -87, 93, 7, -38, -125, 12, -112, -70, 22, -32, | ||||
|             33, 6, -124, 60, 12, -44, 11, 37, -128, -124, -43, 71, -125, -122, 33, 4, -80, 61, 98, 71, | ||||
|             -8, -93, 4, -112, 70, 17, -48, 26, 51, 64, -102, 0, 53, -102, 50, 64, 30, -45, -48, 44, | ||||
|             -110, 1, -51, 91, -96, 101, 43, 43, 1, -84, -83, -19, -88, -39, -122, 0, 18, -38, 22, 104, | ||||
|             -89, 19, 64, -38, 59, 16, -43, -127, 1, -42, -114, 64, -89, -50, 4, -112, -80, 104, 68, 61, | ||||
|             -82, 19, -64, -39, -59, -126, -120, -82, 4, -112, -48, 39, -32, 122, -110, 1, -46, -51, 1, 119, | ||||
|             12, 3, -84, -35, -127, 30, 61, 9, 32, -51, 99, 17, -43, 75, 39, 64, 112, 92, 111, -12, | ||||
|             105, 68, 0, 121, -22, 105, 104, -49, 48, -64, 120, 22, -120, -17, 75, 0, -111, 126, 64, -1, | ||||
|             1, 12, 24, 24, -117, -25, 6, -39, 8, -32, 28, -20, 64, -77, 33, 4, -112, -95, -49, 3, | ||||
|             113, 6, 1, 100, -104, 7, -61, 99, 24, -32, 28, 1, -68, -112, 64, 0, 121, 113, 36, -30, | ||||
|             71, -23, 4, 72, 124, -55, -114, 78, -93, 9, 32, 99, -58, 34, 105, 28, 3, 100, -68, 27, | ||||
|             13, 94, 102, -128, -13, 21, 96, -62, -85, 4, -112, -127, -81, 33, -2, 117, -125, 0, -34, 55, | ||||
|             -110, 48, 49, -108, 0, -110, -36, 2, -82, 55, 25, -112, -110, 10, 76, 122, -117, 0, 34, -109, | ||||
|             -127, -76, 116, 6, 76, -103, -118, 73, -61, 116, 2, 120, -89, -71, -15, 118, 6, 1, -28, -99, | ||||
|             -23, -64, 12, -125, 0, -58, -69, -64, -52, 89, 4, -112, -39, -26, -70, 51, 125, 4, -112, 57, | ||||
|             89, -56, -98, -101, 66, 0, 95, -114, 3, -13, -26, 19, 64, -110, 23, -64, -79, -112, 1, 82, | ||||
|             -35, -123, -8, -95, 12, -16, -103, -21, 94, -76, -104, 0, 50, 101, 38, -122, 119, 51, 8, -112, | ||||
|             -5, -98, 11, 105, -75, 9, 80, 81, 58, -19, -17, 51, 64, -1, 0, -8, 112, 12, 1, -60, | ||||
|             -6, -111, -71, -18, -39, 4, -112, -113, -13, -112, 95, -112, 66, -128, -62, 34, -83, -8, -109, 37, | ||||
|             4, -112, -91, -79, -16, -92, 50, -64, -8, 20, 88, -58, 0, -55, 1, 74, 24, -80, 124, 36, | ||||
|             44, 43, 8, -112, -16, -103, -85, 120, -27, 42, 2, -84, 94, 3, -1, 90, 67, 29, -92, -41, | ||||
|             1, -42, 89, -43, 55, -50, 54, 24, -120, 14, 34, -114, -58, -25, 37, 112, 127, 65, 28, 62, | ||||
|             -33, -105, -59, -38, 87, -99, 9, -16, -11, 122, -8, 55, 16, 23, -56, 23, 14, 108, -12, -86, | ||||
|             95, 81, 91, 28, -80, 105, 51, 81, 4, -52, 10, 110, 73, 37, -54, -52, -106, -83, 46, -84, | ||||
|             -116, 36, -64, 55, 107, 80, -70, -115, -88, -83, -37, -21, 1, 59, -104, 98, -4, -83, -122, -84, | ||||
|             -47, 68, -71, -33, -71, 11, -10, -35, -60, 11, -108, -66, -57, -115, -52, 72, 2, -20, -51, -122, | ||||
|             127, -97, -95, 14, 2, 17, -64, 119, 78, -11, 103, 87, -17, 98, -34, -29, 90, -60, -61, -66, | ||||
|             60, 26, -98, -3, 68, 116, -16, 29, -48, -76, -52, -125, 4, 88, -67, 9, -2, 67, 68, -4, | ||||
|             -15, 30, 6, -70, 39, -86, 7, 44, -37, 17, 32, -21, 40, 17, -31, 118, -106, -64, 50, -120, | ||||
|             8, -119, -127, -17, 93, -104, -80, -124, 0, 63, 100, 35, -65, 61, -111, -116, -73, 31, 3, -114, | ||||
|             7, 8, 112, -62, 60, -43, 109, -120, -80, -66, 116, 42, -20, 63, 18, -3, 67, -32, -92, 27, | ||||
|             -89, 14, 18, -96, 111, -39, -67, 79, -11, -3, -128, -17, 52, -16, -109, 83, -67, 105, -46, -51, | ||||
|             61, -34, 21, 70, -76, 101, 63, -97, -127, 103, 60, -47, -8, 21, -106, 87, 122, -110, -85, 6, | ||||
|             -65, -4, -118, -46, -77, -122, 58, -16, -98, -82, 28, 43, -86, 2, 33, -25, -52, -32, 114, -108, | ||||
|             104, -64, -25, -100, -127, -3, 60, -47, -30, -5, -54, 93, -72, -16, 27, 1, 98, -4, -56, 46, | ||||
|             32, -26, 26, 9, 23, -127, -33, -1, 32, -64, 17, 13, 101, 42, 73, -27, -50, 63, -105, 74, | ||||
|             -48, -5, 50, 49, -3, 9, 20, 37, -95, -86, 61, -82, 4, 98, 74, -111, -1, -89, -95, 14, | ||||
|             114, -51, 123, -4, 87, -94, -6, -56, -53, -8, 27, -56, -69, 66, 12, -43, -82, 94, -125, -25, | ||||
|             58, 49, -74, 43, -68, -95, 21, 87, 57, -109, -71, 27, -4, -109, -121, -78, 127, 83, -44, -127, | ||||
|             -43, 124, -113, 111, 22, -118, 50, -48, -1, 3, -4, -86, -109, -54, 10, 80, 17, -8, -1, 23, | ||||
|             117, -112, 123, -53, 108, 41, 50, -44, -63, 109, -80, -19, 79, -78, 17, 39, 44, -102, 0, 0, | ||||
|             0, 0, 73, 69, 78, 68, -82, 66, 96, -126}; | ||||
| 
 | ||||
| } | ||||
| @ -1,238 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.picker; | ||||
| 
 | ||||
| import android.annotation.SuppressLint; | ||||
| import android.app.Activity; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.IntDef; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.recyclerview.widget.DividerItemDecoration; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| 
 | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| 
 | ||||
| import xyz.fycz.myreader.R; | ||||
| import xyz.fycz.myreader.widget.filepicker.adapter.FileAdapter; | ||||
| import xyz.fycz.myreader.widget.filepicker.adapter.PathAdapter; | ||||
| import xyz.fycz.myreader.widget.filepicker.entity.FileItem; | ||||
| import xyz.fycz.myreader.widget.filepicker.popup.ConfirmPopup; | ||||
| import xyz.fycz.myreader.widget.filepicker.util.StorageUtils; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * 文件目录选择器 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1032694760] | ||||
|  * @since 2015/9/29, 2017/01/01, 2017/01/08 | ||||
|  */ | ||||
| public class FilePicker extends ConfirmPopup<LinearLayout> implements FileAdapter.CallBack, PathAdapter.CallBack { | ||||
|     public static final int DIRECTORY = 0; | ||||
|     public static final int FILE = 1; | ||||
| 
 | ||||
|     private String initPath; | ||||
|     private FileAdapter adapter = new FileAdapter(); | ||||
|     private PathAdapter pathAdapter = new PathAdapter(); | ||||
|     private TextView emptyView; | ||||
|     private OnFilePickListener onFilePickListener; | ||||
|     private int mode; | ||||
|     private CharSequence emptyHint = java.util.Locale.getDefault().getDisplayLanguage().contains("中文") ? "<空>" : "<Empty>"; | ||||
| 
 | ||||
|     @IntDef(value = {DIRECTORY, FILE}) | ||||
|     @Retention(RetentionPolicy.SOURCE) | ||||
|     public @interface Mode { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @see #FILE | ||||
|      * @see #DIRECTORY | ||||
|      */ | ||||
|     public FilePicker(Activity activity, @Mode int mode) { | ||||
|         super(activity); | ||||
|         setHalfScreen(true); | ||||
|         try { | ||||
|             this.initPath = StorageUtils.getDownloadPath(); | ||||
|         } catch (RuntimeException e) { | ||||
|             this.initPath = StorageUtils.getInternalRootPath(activity); | ||||
|         } | ||||
|         this.mode = mode; | ||||
|         adapter.setOnlyListDir(mode == DIRECTORY); | ||||
|         adapter.setShowHideDir(false); | ||||
|         adapter.setShowHomeDir(false); | ||||
|         adapter.setShowUpDir(false); | ||||
|         adapter.setCallBack(this); | ||||
|         pathAdapter.setCallBack(this); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     @NonNull | ||||
|     protected LinearLayout makeCenterView() { | ||||
|         @SuppressLint("InflateParams") LinearLayout rootLayout = (LinearLayout) LayoutInflater.from(activity).inflate(R.layout.view_file_picker, null); | ||||
| 
 | ||||
|         RecyclerView recyclerView = rootLayout.findViewById(R.id.rv_file); | ||||
|         recyclerView.addItemDecoration(new DividerItemDecoration(activity, LinearLayout.VERTICAL)); | ||||
|         recyclerView.setLayoutManager(new LinearLayoutManager(activity)); | ||||
|         recyclerView.setAdapter(adapter); | ||||
| 
 | ||||
|         emptyView = rootLayout.findViewById(R.id.tv_empty); | ||||
| 
 | ||||
|         RecyclerView pathView = rootLayout.findViewById(R.id.rv_path); | ||||
|         pathView.setLayoutManager(new LinearLayoutManager(activity, RecyclerView.HORIZONTAL, false)); | ||||
|         pathView.setAdapter(pathAdapter); | ||||
| 
 | ||||
|         return rootLayout; | ||||
|     } | ||||
| 
 | ||||
|     public void setRootPath(String initPath) { | ||||
|         this.initPath = initPath; | ||||
|     } | ||||
| 
 | ||||
|     public void setAllowExtensions(String[] allowExtensions) { | ||||
|         adapter.setAllowExtensions(allowExtensions); | ||||
|     } | ||||
| 
 | ||||
|     public void setShowUpDir(boolean showUpDir) { | ||||
|         adapter.setShowUpDir(showUpDir); | ||||
|     } | ||||
| 
 | ||||
|     public void setShowHomeDir(boolean showHomeDir) { | ||||
|         adapter.setShowHomeDir(showHomeDir); | ||||
|     } | ||||
| 
 | ||||
|     public void setShowHideDir(boolean showHideDir) { | ||||
|         adapter.setShowHideDir(showHideDir); | ||||
|     } | ||||
| 
 | ||||
|     public void setFileIcon(Drawable fileIcon) { | ||||
|         adapter.setFileIcon(fileIcon); | ||||
|     } | ||||
| 
 | ||||
|     public void setFolderIcon(Drawable folderIcon) { | ||||
|         adapter.setFolderIcon(folderIcon); | ||||
|     } | ||||
| 
 | ||||
|     public void setHomeIcon(Drawable homeIcon) { | ||||
|         adapter.setHomeIcon(homeIcon); | ||||
|     } | ||||
| 
 | ||||
|     public void setUpIcon(Drawable upIcon) { | ||||
|         adapter.setUpIcon(upIcon); | ||||
|     } | ||||
| 
 | ||||
|     public void setArrowIcon(Drawable arrowIcon) { | ||||
|         pathAdapter.setArrowIcon(arrowIcon); | ||||
|     } | ||||
| 
 | ||||
|     public void setItemHeight(int itemHeight) { | ||||
|         adapter.setItemHeight(itemHeight); | ||||
|     } | ||||
| 
 | ||||
|     public void setEmptyHint(CharSequence emptyHint) { | ||||
|         this.emptyHint = emptyHint; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void setContentViewBefore() { | ||||
|         boolean isPickFile = mode == FILE; | ||||
|         setCancelVisible(!isPickFile); | ||||
|         if (isPickFile) { | ||||
|             setSubmitText(activity.getString(android.R.string.cancel)); | ||||
|         } else { | ||||
|             setSubmitText(activity.getString(android.R.string.ok)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void setContentViewAfter(View contentView) { | ||||
|         refreshCurrentDirPath(initPath); | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     protected void onSubmit() { | ||||
|         if (mode != FILE) { | ||||
|             String currentPath = adapter.getCurrentPath(); | ||||
|             if (onFilePickListener != null) { | ||||
|                 onFilePickListener.onFilePicked(currentPath); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void dismiss() { | ||||
|         super.dismiss(); | ||||
|     } | ||||
| 
 | ||||
|     public FileAdapter getAdapter() { | ||||
|         return adapter; | ||||
|     } | ||||
| 
 | ||||
|     public PathAdapter getPathAdapter() { | ||||
|         return pathAdapter; | ||||
|     } | ||||
| 
 | ||||
|     public String getCurrentPath() { | ||||
|         return adapter.getCurrentPath(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 响应选择器的列表项点击事件 | ||||
|      */ | ||||
|     @Override | ||||
|     public void onFileClick(int position) { | ||||
|         FileItem fileItem = adapter.getItem(position); | ||||
|         if (fileItem.isDirectory()) { | ||||
|             refreshCurrentDirPath(fileItem.getPath()); | ||||
|         } else { | ||||
|             String clickPath = fileItem.getPath(); | ||||
|             if (mode != DIRECTORY) { | ||||
|                 dismiss(); | ||||
|                 if (onFilePickListener != null) { | ||||
|                     onFilePickListener.onFilePicked(clickPath); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onPathClick(int position) { | ||||
|         refreshCurrentDirPath(pathAdapter.getItem(position)); | ||||
|     } | ||||
| 
 | ||||
|     private void refreshCurrentDirPath(String currentPath) { | ||||
|         if (currentPath.equals("/")) { | ||||
|             pathAdapter.updatePath("/"); | ||||
|         } else { | ||||
|             pathAdapter.updatePath(currentPath); | ||||
|         } | ||||
|         adapter.loadData(currentPath); | ||||
|         int adapterCount = adapter.getItemCount(); | ||||
|         if (adapter.isShowHomeDir()) { | ||||
|             adapterCount--; | ||||
|         } | ||||
|         if (adapter.isShowUpDir()) { | ||||
|             adapterCount--; | ||||
|         } | ||||
|         if (adapterCount < 1) { | ||||
|             emptyView.setVisibility(View.VISIBLE); | ||||
|             emptyView.setText(emptyHint); | ||||
|         } else { | ||||
|             emptyView.setVisibility(View.GONE); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void setOnFilePickListener(OnFilePickListener listener) { | ||||
|         this.onFilePickListener = listener; | ||||
|     } | ||||
| 
 | ||||
|     public interface OnFilePickListener { | ||||
| 
 | ||||
|         void onFilePicked(String currentPath); | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,308 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.popup; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.app.Dialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.view.Gravity; | ||||
| import android.view.KeyEvent; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.view.Window; | ||||
| import android.widget.FrameLayout; | ||||
| 
 | ||||
| import androidx.annotation.StyleRes; | ||||
| 
 | ||||
| import xyz.fycz.myreader.widget.filepicker.util.ScreenUtils; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * 弹窗基类 | ||||
|  * | ||||
|  * @param <V> 弹窗的内容视图类型 | ||||
|  * @author 李玉江[QQ:1023694760] | ||||
|  * @since 2015/7/19 | ||||
|  */ | ||||
| public abstract class BasicPopup<V extends View> implements DialogInterface.OnKeyListener, | ||||
|         DialogInterface.OnDismissListener { | ||||
|     public static final int MATCH_PARENT = ViewGroup.LayoutParams.MATCH_PARENT; | ||||
|     public static final int WRAP_CONTENT = ViewGroup.LayoutParams.WRAP_CONTENT; | ||||
|     protected Activity activity; | ||||
|     protected int screenWidthPixels; | ||||
|     protected int screenHeightPixels; | ||||
|     private Dialog dialog; | ||||
|     private FrameLayout contentLayout; | ||||
|     private boolean isPrepared = false; | ||||
| 
 | ||||
|     public BasicPopup(Activity activity) { | ||||
|         this.activity = activity; | ||||
|         DisplayMetrics metrics = ScreenUtils.displayMetrics(activity); | ||||
|         screenWidthPixels = metrics.widthPixels; | ||||
|         screenHeightPixels = metrics.heightPixels; | ||||
|         initDialog(); | ||||
|     } | ||||
| 
 | ||||
|     private void initDialog() { | ||||
|         contentLayout = new FrameLayout(activity); | ||||
|         contentLayout.setLayoutParams(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); | ||||
|         contentLayout.setFocusable(true); | ||||
|         contentLayout.setFocusableInTouchMode(true); | ||||
|         dialog = new Dialog(activity); | ||||
|         dialog.setCanceledOnTouchOutside(true);//触摸屏幕取消窗体
 | ||||
|         dialog.setCancelable(true);//按返回键取消窗体
 | ||||
|         dialog.setOnKeyListener(this); | ||||
|         dialog.setOnDismissListener(this); | ||||
|         Window window = dialog.getWindow(); | ||||
|         if (window != null) { | ||||
|             window.setGravity(Gravity.BOTTOM); | ||||
|             window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); | ||||
|             //AndroidRuntimeException: requestFeature() must be called before adding content
 | ||||
|             window.requestFeature(Window.FEATURE_NO_TITLE); | ||||
|             window.setContentView(contentLayout); | ||||
|         } | ||||
|         setSize(screenWidthPixels, WRAP_CONTENT); | ||||
|     } | ||||
| 
 | ||||
|     public int getScreenWidthPixels() { | ||||
|         return screenWidthPixels; | ||||
|     } | ||||
| 
 | ||||
|     public int getScreenHeightPixels() { | ||||
|         return screenHeightPixels; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 创建弹窗的内容视图 | ||||
|      * | ||||
|      * @return the view | ||||
|      */ | ||||
|     protected abstract V makeContentView(); | ||||
| 
 | ||||
|     /** | ||||
|      * 固定高度为屏幕的高 | ||||
|      * | ||||
|      * @param fillScreen true为全屏 | ||||
|      */ | ||||
|     public void setFillScreen(boolean fillScreen) { | ||||
|         if (fillScreen) { | ||||
|             setSize(screenWidthPixels, (int) (screenHeightPixels * 0.85f)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 固定高度为屏幕的一半 | ||||
|      * | ||||
|      * @param halfScreen true为半屏 | ||||
|      */ | ||||
|     public void setHalfScreen(boolean halfScreen) { | ||||
|         if (halfScreen) { | ||||
|             setSize(screenWidthPixels, screenHeightPixels / 2); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 位于屏幕何处 | ||||
|      * | ||||
|      * @see Gravity | ||||
|      */ | ||||
|     public void setGravity(int gravity) { | ||||
|         Window window = dialog.getWindow(); | ||||
|         if (window != null) { | ||||
|             window.setGravity(gravity); | ||||
|         } | ||||
|         if (gravity == Gravity.CENTER) { | ||||
|             //居于屏幕正中间时,宽度不允许填充屏幕
 | ||||
|             setWidth((int) (screenWidthPixels * 0.7f)); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置弹窗的内容视图之前执行 | ||||
|      */ | ||||
|     protected void setContentViewBefore() { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置弹窗的内容视图之后执行 | ||||
|      * | ||||
|      * @param contentView 弹窗的内容视图 | ||||
|      */ | ||||
|     protected void setContentViewAfter(V contentView) { | ||||
|     } | ||||
| 
 | ||||
|     public void setContentView(View view) { | ||||
|         contentLayout.removeAllViews(); | ||||
|         contentLayout.addView(view); | ||||
|     } | ||||
| 
 | ||||
|     public void setFitsSystemWindows(boolean flag) { | ||||
|         contentLayout.setFitsSystemWindows(flag); | ||||
|     } | ||||
| 
 | ||||
|     public void setAnimationStyle(@StyleRes int animRes) { | ||||
|         Window window = dialog.getWindow(); | ||||
|         if (window != null) { | ||||
|             window.setWindowAnimations(animRes); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public void setCanceledOnTouchOutside(boolean flag) { | ||||
|         dialog.setCanceledOnTouchOutside(flag); | ||||
|     } | ||||
| 
 | ||||
|     public void setCancelable(boolean flag) { | ||||
|         dialog.setCancelable(flag); | ||||
|     } | ||||
| 
 | ||||
|     public void setOnDismissListener(final DialogInterface.OnDismissListener onDismissListener) { | ||||
|         dialog.setOnDismissListener(new DialogInterface.OnDismissListener() { | ||||
|             @Override | ||||
|             public void onDismiss(DialogInterface dialog) { | ||||
|                 BasicPopup.this.onDismiss(dialog); | ||||
|                 onDismissListener.onDismiss(dialog); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     public void setOnKeyListener(final DialogInterface.OnKeyListener onKeyListener) { | ||||
|         dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { | ||||
|             @Override | ||||
|             public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { | ||||
|                 BasicPopup.this.onKey(dialog, keyCode, event); | ||||
|                 return onKeyListener.onKey(dialog, keyCode, event); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置弹窗的宽和高 | ||||
|      * | ||||
|      * @param width  宽 | ||||
|      * @param height 高 | ||||
|      */ | ||||
|     public void setSize(int width, int height) { | ||||
|         if (width == MATCH_PARENT) { | ||||
|             //360奇酷等手机对话框MATCH_PARENT时两边还会有边距,故强制填充屏幕宽
 | ||||
|             width = screenWidthPixels; | ||||
|         } | ||||
|         if (width == 0 && height == 0) { | ||||
|             width = screenWidthPixels; | ||||
|             height = WRAP_CONTENT; | ||||
|         } else if (width == 0) { | ||||
|             width = screenWidthPixels; | ||||
|         } else if (height == 0) { | ||||
|             height = WRAP_CONTENT; | ||||
|         } | ||||
|         ViewGroup.LayoutParams params = contentLayout.getLayoutParams(); | ||||
|         if (params == null) { | ||||
|             params = new ViewGroup.LayoutParams(width, height); | ||||
|         } else { | ||||
|             params.width = width; | ||||
|             params.height = height; | ||||
|         } | ||||
|         contentLayout.setLayoutParams(params); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置弹窗的宽 | ||||
|      * | ||||
|      * @param width 宽 | ||||
|      * @see #setSize(int, int) | ||||
|      */ | ||||
|     public void setWidth(int width) { | ||||
|         setSize(width, 0); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置弹窗的高 | ||||
|      * | ||||
|      * @param height 高 | ||||
|      * @see #setSize(int, int) | ||||
|      */ | ||||
|     public void setHeight(int height) { | ||||
|         setSize(0, height); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置是否需要重新初始化视图,可用于数据刷新 | ||||
|      */ | ||||
|     public void setPrepared(boolean prepared) { | ||||
|         isPrepared = prepared; | ||||
|     } | ||||
| 
 | ||||
|     public boolean isShowing() { | ||||
|         return dialog.isShowing(); | ||||
|     } | ||||
| 
 | ||||
|     public final void show() { | ||||
|         if (isPrepared) { | ||||
|             dialog.show(); | ||||
|             showAfter(); | ||||
|             return; | ||||
|         } | ||||
|         setContentViewBefore(); | ||||
|         V view = makeContentView(); | ||||
|         setContentView(view);// 设置弹出窗体的布局
 | ||||
|         setContentViewAfter(view); | ||||
|         isPrepared = true; | ||||
|         dialog.show(); | ||||
|         showAfter(); | ||||
|     } | ||||
| 
 | ||||
|     protected void showAfter() { | ||||
|     } | ||||
| 
 | ||||
|     public void dismiss() { | ||||
|         dismissImmediately(); | ||||
|     } | ||||
| 
 | ||||
|     protected final void dismissImmediately() { | ||||
|         dialog.dismiss(); | ||||
|     } | ||||
| 
 | ||||
|     public boolean onBackPress() { | ||||
|         dismiss(); | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public final boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { | ||||
|         if (event.getAction() == KeyEvent.ACTION_DOWN && keyCode == KeyEvent.KEYCODE_BACK) { | ||||
|             onBackPress(); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     @Override | ||||
|     public void onDismiss(DialogInterface dialog) { | ||||
|         dismiss(); | ||||
|     } | ||||
| 
 | ||||
|     public Context getContext() { | ||||
|         return dialog.getContext(); | ||||
|     } | ||||
| 
 | ||||
|     public Window getWindow() { | ||||
|         return dialog.getWindow(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 弹框的内容视图 | ||||
|      */ | ||||
|     public View getContentView() { | ||||
|         // IllegalStateException: The specified child already has a parent.
 | ||||
|         // You must call removeView() on the child's parent first.
 | ||||
|         return contentLayout.getChildAt(0); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 弹框的根视图 | ||||
|      */ | ||||
|     public ViewGroup getRootView() { | ||||
|         return contentLayout; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,407 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.popup; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.graphics.Color; | ||||
| import android.text.TextUtils; | ||||
| import android.view.Gravity; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.RelativeLayout; | ||||
| import android.widget.TextView; | ||||
| 
 | ||||
| import androidx.annotation.ColorInt; | ||||
| import androidx.annotation.IntRange; | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.annotation.StringRes; | ||||
| 
 | ||||
| import xyz.fycz.myreader.widget.filepicker.util.ConvertUtils; | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * 带确定及取消按钮的弹窗 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1032694760] | ||||
|  * @since 2015/10/21 | ||||
|  */ | ||||
| @SuppressWarnings("WeakerAccess") | ||||
| public abstract class ConfirmPopup<V extends View> extends BasicPopup<View> { | ||||
|     protected boolean topLineVisible = true; | ||||
|     protected int topLineColor = 0xFF33B5E5; | ||||
|     protected int topLineHeightPixels = 1;//px
 | ||||
|     protected int topBackgroundColor = Color.WHITE; | ||||
|     protected int topHeight = 40;//dp
 | ||||
|     protected int topPadding = 15;//dp
 | ||||
|     protected int contentLeftAndRightPadding = 0;//dp
 | ||||
|     protected int contentTopAndBottomPadding = 0;//dp
 | ||||
|     protected boolean cancelVisible = true; | ||||
|     protected CharSequence cancelText = ""; | ||||
|     protected CharSequence submitText = ""; | ||||
|     protected CharSequence titleText = ""; | ||||
|     protected int cancelTextColor = 0xFF33B5E5; | ||||
|     protected int submitTextColor = 0xFF33B5E5; | ||||
|     protected int titleTextColor = Color.BLACK; | ||||
|     protected int pressedTextColor = 0XFF0288CE; | ||||
|     protected int cancelTextSize = 0; | ||||
|     protected int submitTextSize = 0; | ||||
|     protected int titleTextSize = 0; | ||||
|     protected int backgroundColor = Color.WHITE; | ||||
|     protected TextView cancelButton, submitButton; | ||||
|     protected View titleView; | ||||
|     protected View headerView, centerView, footerView; | ||||
| 
 | ||||
|     public ConfirmPopup(Activity activity) { | ||||
|         super(activity); | ||||
|         cancelText = activity.getString(android.R.string.cancel); | ||||
|         submitText = activity.getString(android.R.string.ok); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏下划线颜色 | ||||
|      */ | ||||
|     public void setTopLineColor(@ColorInt int topLineColor) { | ||||
|         this.topLineColor = topLineColor; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏下划线高度,单位为px | ||||
|      */ | ||||
|     public void setTopLineHeight(int topLineHeightPixels) { | ||||
|         this.topLineHeightPixels = topLineHeightPixels; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏背景颜色 | ||||
|      */ | ||||
|     public void setTopBackgroundColor(@ColorInt int topBackgroundColor) { | ||||
|         this.topBackgroundColor = topBackgroundColor; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏高度(单位为dp) | ||||
|      */ | ||||
|     public void setTopHeight(@IntRange(from = 10, to = 80) int topHeight) { | ||||
|         this.topHeight = topHeight; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部按钮左边及右边边距(单位为dp) | ||||
|      */ | ||||
|     public void setTopPadding(int topPadding) { | ||||
|         this.topPadding = topPadding; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏下划线是否显示 | ||||
|      */ | ||||
|     public void setTopLineVisible(boolean topLineVisible) { | ||||
|         this.topLineVisible = topLineVisible; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置内容上下左右边距(单位为dp) | ||||
|      */ | ||||
|     public void setContentPadding(int leftAndRight, int topAndBottom) { | ||||
|         this.contentLeftAndRightPadding = leftAndRight; | ||||
|         this.contentTopAndBottomPadding = topAndBottom; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏取消按钮是否显示 | ||||
|      */ | ||||
|     public void setCancelVisible(boolean cancelVisible) { | ||||
|         if (null != cancelButton) { | ||||
|             cancelButton.setVisibility(cancelVisible ? View.VISIBLE : View.GONE); | ||||
|         } else { | ||||
|             this.cancelVisible = cancelVisible; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏取消按钮文字 | ||||
|      */ | ||||
|     public void setCancelText(CharSequence cancelText) { | ||||
|         if (null != cancelButton) { | ||||
|             cancelButton.setText(cancelText); | ||||
|         } else { | ||||
|             this.cancelText = cancelText; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏取消按钮文字 | ||||
|      */ | ||||
|     public void setCancelText(@StringRes int textRes) { | ||||
|         setCancelText(activity.getString(textRes)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏确定按钮文字 | ||||
|      */ | ||||
|     public void setSubmitText(CharSequence submitText) { | ||||
|         if (null != submitButton) { | ||||
|             submitButton.setText(submitText); | ||||
|         } else { | ||||
|             this.submitText = submitText; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏确定按钮文字 | ||||
|      */ | ||||
|     public void setSubmitText(@StringRes int textRes) { | ||||
|         setSubmitText(activity.getString(textRes)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏标题文字 | ||||
|      */ | ||||
|     public void setTitleText(CharSequence titleText) { | ||||
|         if (titleView != null && titleView instanceof TextView) { | ||||
|             ((TextView) titleView).setText(titleText); | ||||
|         } else { | ||||
|             this.titleText = titleText; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏标题文字 | ||||
|      */ | ||||
|     public void setTitleText(@StringRes int textRes) { | ||||
|         setTitleText(activity.getString(textRes)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏取消按钮文字颜色 | ||||
|      */ | ||||
|     public void setCancelTextColor(@ColorInt int cancelTextColor) { | ||||
|         if (null != cancelButton) { | ||||
|             cancelButton.setTextColor(cancelTextColor); | ||||
|         } else { | ||||
|             this.cancelTextColor = cancelTextColor; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏确定按钮文字颜色 | ||||
|      */ | ||||
|     public void setSubmitTextColor(@ColorInt int submitTextColor) { | ||||
|         if (null != submitButton) { | ||||
|             submitButton.setTextColor(submitTextColor); | ||||
|         } else { | ||||
|             this.submitTextColor = submitTextColor; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏标题文字颜色 | ||||
|      */ | ||||
|     public void setTitleTextColor(@ColorInt int titleTextColor) { | ||||
|         if (null != titleView && titleView instanceof TextView) { | ||||
|             ((TextView) titleView).setTextColor(titleTextColor); | ||||
|         } else { | ||||
|             this.titleTextColor = titleTextColor; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置按下时的文字颜色 | ||||
|      */ | ||||
|     public void setPressedTextColor(int pressedTextColor) { | ||||
|         this.pressedTextColor = pressedTextColor; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏取消按钮文字大小(单位为sp) | ||||
|      */ | ||||
|     public void setCancelTextSize(@IntRange(from = 10, to = 40) int cancelTextSize) { | ||||
|         this.cancelTextSize = cancelTextSize; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏确定按钮文字大小(单位为sp) | ||||
|      */ | ||||
|     public void setSubmitTextSize(@IntRange(from = 10, to = 40) int submitTextSize) { | ||||
|         this.submitTextSize = submitTextSize; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置顶部标题栏标题文字大小(单位为sp) | ||||
|      */ | ||||
|     public void setTitleTextSize(@IntRange(from = 10, to = 40) int titleTextSize) { | ||||
|         this.titleTextSize = titleTextSize; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 设置选择器主体背景颜色 | ||||
|      */ | ||||
|     public void setBackgroundColor(@ColorInt int backgroundColor) { | ||||
|         this.backgroundColor = backgroundColor; | ||||
|     } | ||||
| 
 | ||||
|     public TextView getCancelButton() { | ||||
|         if (null == cancelButton) { | ||||
|             throw new NullPointerException("please call show at first"); | ||||
|         } | ||||
|         return cancelButton; | ||||
|     } | ||||
| 
 | ||||
|     public TextView getSubmitButton() { | ||||
|         if (null == submitButton) { | ||||
|             throw new NullPointerException("please call show at first"); | ||||
|         } | ||||
|         return submitButton; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * @see #makeHeaderView() | ||||
|      * @see #makeCenterView() | ||||
|      * @see #makeFooterView() | ||||
|      */ | ||||
|     @Override | ||||
|     protected final View makeContentView() { | ||||
|         LinearLayout rootLayout = new LinearLayout(activity); | ||||
|         rootLayout.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)); | ||||
|         rootLayout.setBackgroundColor(backgroundColor); | ||||
|         rootLayout.setOrientation(LinearLayout.VERTICAL); | ||||
|         rootLayout.setGravity(Gravity.CENTER); | ||||
|         rootLayout.setPadding(0, 0, 0, 0); | ||||
|         rootLayout.setClipToPadding(false); | ||||
|         View headerView = makeHeaderView(); | ||||
|         if (headerView != null) { | ||||
|             rootLayout.addView(headerView); | ||||
|         } | ||||
|         if (topLineVisible) { | ||||
|             View lineView = new View(activity); | ||||
|             lineView.setLayoutParams(new LinearLayout.LayoutParams(MATCH_PARENT, topLineHeightPixels)); | ||||
|             lineView.setBackgroundColor(topLineColor); | ||||
|             rootLayout.addView(lineView); | ||||
|         } | ||||
|         if (centerView == null) { | ||||
|             centerView = makeCenterView(); | ||||
|         } | ||||
|         int lr = 0; | ||||
|         int tb = 0; | ||||
|         if (contentLeftAndRightPadding > 0) { | ||||
|             lr = ConvertUtils.toPx(activity, contentLeftAndRightPadding); | ||||
|         } | ||||
|         if (contentTopAndBottomPadding > 0) { | ||||
|             tb = ConvertUtils.toPx(activity, contentTopAndBottomPadding); | ||||
|         } | ||||
|         centerView.setPadding(lr, tb, lr, tb); | ||||
|         ViewGroup vg = (ViewGroup) centerView.getParent(); | ||||
|         if (vg != null) { | ||||
|             //IllegalStateException: The specified child already has a parent
 | ||||
|             vg.removeView(centerView); | ||||
|         } | ||||
|         rootLayout.addView(centerView, new LinearLayout.LayoutParams(MATCH_PARENT, 0, 1.0f)); | ||||
|         View footerView = makeFooterView(); | ||||
|         if (footerView != null) { | ||||
|             rootLayout.addView(footerView); | ||||
|         } | ||||
|         return rootLayout; | ||||
|     } | ||||
| 
 | ||||
|     @Nullable | ||||
|     protected View makeHeaderView() { | ||||
|         if (null != headerView) { | ||||
|             return headerView; | ||||
|         } | ||||
|         RelativeLayout topButtonLayout = new RelativeLayout(activity); | ||||
|         int height = ConvertUtils.toPx(activity, topHeight); | ||||
|         topButtonLayout.setLayoutParams(new RelativeLayout.LayoutParams(MATCH_PARENT, height)); | ||||
|         topButtonLayout.setBackgroundColor(topBackgroundColor); | ||||
|         topButtonLayout.setGravity(Gravity.CENTER_VERTICAL); | ||||
| 
 | ||||
|         cancelButton = new TextView(activity); | ||||
|         cancelButton.setVisibility(cancelVisible ? View.VISIBLE : View.GONE); | ||||
|         RelativeLayout.LayoutParams cancelParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, MATCH_PARENT); | ||||
|         cancelParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE); | ||||
|         cancelParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE); | ||||
|         cancelButton.setLayoutParams(cancelParams); | ||||
|         cancelButton.setBackgroundColor(Color.TRANSPARENT); | ||||
|         cancelButton.setGravity(Gravity.CENTER); | ||||
|         int padding = ConvertUtils.toPx(activity, topPadding); | ||||
|         cancelButton.setPadding(padding, 0, padding, 0); | ||||
|         if (!TextUtils.isEmpty(cancelText)) { | ||||
|             cancelButton.setText(cancelText); | ||||
|         } | ||||
|         cancelButton.setTextColor(ConvertUtils.toColorStateList(cancelTextColor, pressedTextColor)); | ||||
|         if (cancelTextSize != 0) { | ||||
|             cancelButton.setTextSize(cancelTextSize); | ||||
|         } | ||||
|         cancelButton.setOnClickListener(new View.OnClickListener() { | ||||
|             @Override | ||||
|             public void onClick(View v) { | ||||
|                 dismiss(); | ||||
|                 onCancel(); | ||||
|             } | ||||
|         }); | ||||
|         topButtonLayout.addView(cancelButton); | ||||
| 
 | ||||
|         if (null == titleView) { | ||||
|             TextView textView = new TextView(activity); | ||||
|             RelativeLayout.LayoutParams titleParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT); | ||||
|             int margin = ConvertUtils.toPx(activity, topPadding); | ||||
|             titleParams.leftMargin = margin; | ||||
|             titleParams.rightMargin = margin; | ||||
|             titleParams.addRule(RelativeLayout.CENTER_HORIZONTAL, RelativeLayout.TRUE); | ||||
|             titleParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE); | ||||
|             textView.setLayoutParams(titleParams); | ||||
|             textView.setGravity(Gravity.CENTER); | ||||
|             if (!TextUtils.isEmpty(titleText)) { | ||||
|                 textView.setText(titleText); | ||||
|             } | ||||
|             textView.setTextColor(titleTextColor); | ||||
|             if (titleTextSize != 0) { | ||||
|                 textView.setTextSize(titleTextSize); | ||||
|             } | ||||
|             titleView = textView; | ||||
|         } | ||||
|         topButtonLayout.addView(titleView); | ||||
| 
 | ||||
|         submitButton = new TextView(activity); | ||||
|         RelativeLayout.LayoutParams submitParams = new RelativeLayout.LayoutParams(WRAP_CONTENT, MATCH_PARENT); | ||||
|         submitParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, RelativeLayout.TRUE); | ||||
|         submitParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE); | ||||
|         submitButton.setLayoutParams(submitParams); | ||||
|         submitButton.setBackgroundColor(Color.TRANSPARENT); | ||||
|         submitButton.setGravity(Gravity.CENTER); | ||||
|         submitButton.setPadding(padding, 0, padding, 0); | ||||
|         if (!TextUtils.isEmpty(submitText)) { | ||||
|             submitButton.setText(submitText); | ||||
|         } | ||||
|         submitButton.setTextColor(ConvertUtils.toColorStateList(submitTextColor, pressedTextColor)); | ||||
|         if (submitTextSize != 0) { | ||||
|             submitButton.setTextSize(submitTextSize); | ||||
|         } | ||||
|         submitButton.setOnClickListener(v -> { | ||||
|             dismiss(); | ||||
|             onSubmit(); | ||||
|         }); | ||||
|         topButtonLayout.addView(submitButton); | ||||
| 
 | ||||
|         return topButtonLayout; | ||||
|     } | ||||
| 
 | ||||
|     @NonNull | ||||
|     protected abstract V makeCenterView(); | ||||
| 
 | ||||
|     @Nullable | ||||
|     protected View makeFooterView() { | ||||
|         if (null != footerView) { | ||||
|             return footerView; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     protected void onSubmit() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     protected void onCancel() { | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,617 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.util; | ||||
| 
 | ||||
| import android.annotation.TargetApi; | ||||
| import android.content.ContentUris; | ||||
| import android.content.Context; | ||||
| import android.content.res.ColorStateList; | ||||
| import android.content.res.Resources; | ||||
| import android.database.Cursor; | ||||
| import android.graphics.Bitmap; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Canvas; | ||||
| import android.graphics.Color; | ||||
| import android.graphics.drawable.BitmapDrawable; | ||||
| import android.graphics.drawable.ColorDrawable; | ||||
| import android.graphics.drawable.Drawable; | ||||
| import android.graphics.drawable.NinePatchDrawable; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.os.Environment; | ||||
| import android.provider.DocumentsContract; | ||||
| import android.provider.MediaStore; | ||||
| import android.text.TextUtils; | ||||
| import android.view.View; | ||||
| import android.widget.ListView; | ||||
| import android.widget.ScrollView; | ||||
| 
 | ||||
| import androidx.annotation.ColorInt; | ||||
| import androidx.annotation.FloatRange; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.nio.ByteBuffer; | ||||
| import java.text.DecimalFormat; | ||||
| import java.util.Arrays; | ||||
| import java.util.List; | ||||
| 
 | ||||
| /** | ||||
|  * 数据类型转换、单位转换 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1023694760] | ||||
|  * @since 2014-4-18 | ||||
|  */ | ||||
| public class ConvertUtils { | ||||
|     public static final long GB = 1073741824; | ||||
|     public static final long MB = 1048576; | ||||
|     public static final long KB = 1024; | ||||
| 
 | ||||
|     public static int toInt(Object obj) { | ||||
|         try { | ||||
|             return Integer.parseInt(obj.toString()); | ||||
|         } catch (NumberFormatException e) { | ||||
|             return -1; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static int toInt(byte[] bytes) { | ||||
|         int result = 0; | ||||
|         byte abyte; | ||||
|         for (int i = 0; i < bytes.length; i++) { | ||||
|             abyte = bytes[i]; | ||||
|             result += (abyte & 0xFF) << (8 * i); | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     public static int toShort(byte first, byte second) { | ||||
|         return (first << 8) + (second & 0xFF); | ||||
|     } | ||||
| 
 | ||||
|     public static long toLong(Object obj) { | ||||
|         try { | ||||
|             return Long.parseLong(obj.toString()); | ||||
|         } catch (NumberFormatException e) { | ||||
|             return -1L; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static float toFloat(Object obj) { | ||||
|         try { | ||||
|             return Float.parseFloat(obj.toString()); | ||||
|         } catch (NumberFormatException e) { | ||||
|             return -1f; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * int占4字节 | ||||
|      * | ||||
|      * @param i the | ||||
|      * @return byte [ ] | ||||
|      */ | ||||
|     public static byte[] toByteArray(int i) { | ||||
|         // byte[] bytes = new byte[4];
 | ||||
|         // bytes[0] = (byte) (0xff & i);
 | ||||
|         // bytes[1] = (byte) ((0xff00 & i) >> 8);
 | ||||
|         // bytes[2] = (byte) ((0xff0000 & i) >> 16);
 | ||||
|         // bytes[3] = (byte) ((0xff000000 & i) >> 24);
 | ||||
|         // return bytes;
 | ||||
|         return ByteBuffer.allocate(4).putInt(i).array(); | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] toByteArray(String hexData, boolean isHex) { | ||||
|         if (hexData == null || hexData.equals("")) { | ||||
|             return null; | ||||
|         } | ||||
|         if (!isHex) { | ||||
|             return hexData.getBytes(); | ||||
|         } | ||||
|         hexData = hexData.replaceAll("\\s+", ""); | ||||
|         String hexDigits = "0123456789ABCDEF"; | ||||
|         ByteArrayOutputStream baos = new ByteArrayOutputStream( | ||||
|                 hexData.length() / 2); | ||||
|         // 将每2位16进制整数组装成一个字节
 | ||||
|         for (int i = 0; i < hexData.length(); i += 2) { | ||||
|             baos.write((hexDigits.indexOf(hexData.charAt(i)) << 4 | hexDigits | ||||
|                     .indexOf(hexData.charAt(i + 1)))); | ||||
|         } | ||||
|         byte[] bytes = baos.toByteArray(); | ||||
|         try { | ||||
|             baos.close(); | ||||
|         } catch (IOException e) { | ||||
|         } | ||||
|         return bytes; | ||||
|     } | ||||
| 
 | ||||
|     public static String toHexString(String str) { | ||||
|         if (TextUtils.isEmpty(str)) | ||||
|             return ""; | ||||
|         StringBuilder builder = new StringBuilder(); | ||||
|         byte[] bytes = str.getBytes(); | ||||
|         for (byte aByte : bytes) { | ||||
|             builder.append(Integer.toHexString(0xFF & aByte)); | ||||
|             builder.append(" "); | ||||
|         } | ||||
|         return builder.toString(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To hex string string. | ||||
|      * | ||||
|      * @param bytes the bytes | ||||
|      * @return the string | ||||
|      */ | ||||
|     public static String toHexString(byte... bytes) { | ||||
|         char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', | ||||
|                 '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; | ||||
|         // 参见:http://www.oschina.net/code/snippet_116768_9019
 | ||||
|         char[] buffer = new char[bytes.length * 2]; | ||||
|         for (int i = 0, j = 0; i < bytes.length; ++i) { | ||||
|             int u = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];//转无符号整型
 | ||||
|             buffer[j++] = DIGITS[u >>> 4]; | ||||
|             buffer[j++] = DIGITS[u & 0xf]; | ||||
|         } | ||||
|         return new String(buffer); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To hex string string. | ||||
|      * | ||||
|      * @param num the num | ||||
|      * @return the string | ||||
|      */ | ||||
|     public static String toHexString(int num) { | ||||
|         String hexString = Integer.toHexString(num); | ||||
|         return hexString; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To binary string string. | ||||
|      * | ||||
|      * @param bytes the bytes | ||||
|      * @return the string | ||||
|      */ | ||||
|     public static String toBinaryString(byte... bytes) { | ||||
|         char[] DIGITS = {'0', '1', '2', '3', '4', '5', '6', | ||||
|                 '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; | ||||
|         // 参见:http://www.oschina.net/code/snippet_116768_9019
 | ||||
|         char[] buffer = new char[bytes.length * 8]; | ||||
|         for (int i = 0, j = 0; i < bytes.length; ++i) { | ||||
|             int u = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];//转无符号整型
 | ||||
|             buffer[j++] = DIGITS[(u >>> 7) & 0x1]; | ||||
|             buffer[j++] = DIGITS[(u >>> 6) & 0x1]; | ||||
|             buffer[j++] = DIGITS[(u >>> 5) & 0x1]; | ||||
|             buffer[j++] = DIGITS[(u >>> 4) & 0x1]; | ||||
|             buffer[j++] = DIGITS[(u >>> 3) & 0x1]; | ||||
|             buffer[j++] = DIGITS[(u >>> 2) & 0x1]; | ||||
|             buffer[j++] = DIGITS[(u >>> 1) & 0x1]; | ||||
|             buffer[j++] = DIGITS[u & 0x1]; | ||||
|         } | ||||
|         return new String(buffer); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * To binary string string. | ||||
|      * | ||||
|      * @param num the num | ||||
|      * @return the string | ||||
|      */ | ||||
|     public static String toBinaryString(int num) { | ||||
|         String binaryString = Integer.toBinaryString(num); | ||||
|         return binaryString; | ||||
|     } | ||||
| 
 | ||||
|     public static String toSlashString(String str) { | ||||
|         String result = ""; | ||||
|         char[] chars = str.toCharArray(); | ||||
|         for (char chr : chars) { | ||||
|             if (chr == '"' || chr == '\'' || chr == '\\') { | ||||
|                 result += "\\";//符合“"”“'”“\”这三个符号的前面加一个“\”
 | ||||
|             } | ||||
|             result += chr; | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     public static <T> T[] toArray(List<T> list) { | ||||
|         //noinspection unchecked
 | ||||
|         return (T[]) list.toArray(); | ||||
|     } | ||||
| 
 | ||||
|     public static <T> List<T> toList(T[] array) { | ||||
|         return Arrays.asList(array); | ||||
|     } | ||||
| 
 | ||||
|     public static String toString(Object[] objects) { | ||||
|         return Arrays.deepToString(objects); | ||||
|     } | ||||
| 
 | ||||
|     public static String toString(Object[] objects, String tag) { | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         for (Object object : objects) { | ||||
|             sb.append(object); | ||||
|             sb.append(tag); | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] toByteArray(InputStream is) { | ||||
|         if (is == null) { | ||||
|             return null; | ||||
|         } | ||||
|         try { | ||||
|             ByteArrayOutputStream os = new ByteArrayOutputStream(); | ||||
|             byte[] buff = new byte[100]; | ||||
|             while (true) { | ||||
|                 int len = is.read(buff, 0, 100); | ||||
|                 if (len == -1) { | ||||
|                     break; | ||||
|                 } else { | ||||
|                     os.write(buff, 0, len); | ||||
|                 } | ||||
|             } | ||||
|             byte[] bytes = os.toByteArray(); | ||||
|             os.close(); | ||||
|             is.close(); | ||||
|             return bytes; | ||||
|         } catch (IOException e) { | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] toByteArray(Bitmap bitmap) { | ||||
|         if (bitmap == null) { | ||||
|             return null; | ||||
|         } | ||||
|         ByteArrayOutputStream os = new ByteArrayOutputStream(); | ||||
|         // 将Bitmap压缩成PNG编码,质量为100%存储,除了PNG还有很多常见格式,如jpeg等。
 | ||||
|         bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); | ||||
|         byte[] bytes = os.toByteArray(); | ||||
|         try { | ||||
|             os.close(); | ||||
|         } catch (IOException e) { | ||||
|         } | ||||
|         return bytes; | ||||
|     } | ||||
| 
 | ||||
|     public static Bitmap toBitmap(byte[] bytes, int width, int height) { | ||||
|         Bitmap bitmap = null; | ||||
|         if (bytes.length != 0) { | ||||
|             try { | ||||
|                 BitmapFactory.Options options = new BitmapFactory.Options(); | ||||
|                 // 不进行图片抖动处理
 | ||||
|                 options.inDither = false; | ||||
|                 // 设置让解码器以最佳方式解码
 | ||||
|                 options.inPreferredConfig = null; | ||||
|                 if (width > 0 && height > 0) { | ||||
|                     options.outWidth = width; | ||||
|                     options.outHeight = height; | ||||
|                 } | ||||
|                 bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); | ||||
|                 bitmap.setDensity(96);// 96 dpi
 | ||||
|             } catch (Exception e) { | ||||
|             } | ||||
|         } | ||||
|         return bitmap; | ||||
|     } | ||||
| 
 | ||||
|     public static Bitmap toBitmap(byte[] bytes) { | ||||
|         return toBitmap(bytes, -1, -1); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将Drawable转换为Bitmap | ||||
|      * 参考:http://kylines.iteye.com/blog/1660184
 | ||||
|      */ | ||||
|     public static Bitmap toBitmap(Drawable drawable) { | ||||
|         if (drawable instanceof BitmapDrawable) { | ||||
|             return ((BitmapDrawable) drawable).getBitmap(); | ||||
|         } else if (drawable instanceof ColorDrawable) { | ||||
|             //color
 | ||||
|             Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888); | ||||
|             Canvas canvas = new Canvas(bitmap); | ||||
|             canvas.drawColor(((ColorDrawable) drawable).getColor()); | ||||
|             return bitmap; | ||||
|         } else if (drawable instanceof NinePatchDrawable) { | ||||
|             //.9.png
 | ||||
|             Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), | ||||
|                     drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); | ||||
|             Canvas canvas = new Canvas(bitmap); | ||||
|             drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); | ||||
|             drawable.draw(canvas); | ||||
|             return bitmap; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 从第三方文件选择器获取路径。 | ||||
|      * 参见:http://blog.csdn.net/zbjdsbj/article/details/42387551
 | ||||
|      */ | ||||
|     @TargetApi(Build.VERSION_CODES.KITKAT) | ||||
|     public static String toPath(Context context, Uri uri) { | ||||
|         if (uri == null) { | ||||
|             return ""; | ||||
|         } | ||||
|         String path = uri.getPath(); | ||||
|         String scheme = uri.getScheme(); | ||||
|         String authority = uri.getAuthority(); | ||||
|         //是否是4.4及以上版本
 | ||||
|         boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; | ||||
|         // DocumentProvider
 | ||||
|         if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { | ||||
|             String docId = DocumentsContract.getDocumentId(uri); | ||||
|             String[] split = docId.split(":"); | ||||
|             String type = split[0]; | ||||
|             Uri contentUri = null; | ||||
|             switch (authority) { | ||||
|                 // ExternalStorageProvider
 | ||||
|                 case "com.android.externalstorage.documents": | ||||
|                     if ("primary".equalsIgnoreCase(type)) { | ||||
|                         return Environment.getExternalStorageDirectory() + "/" + split[1]; | ||||
|                     } | ||||
|                     break; | ||||
|                 // DownloadsProvider
 | ||||
|                 case "com.android.providers.downloads.documents": | ||||
|                     contentUri = ContentUris.withAppendedId( | ||||
|                             Uri.parse("content://downloads/public_downloads"), Long.valueOf(docId)); | ||||
|                     return _queryPathFromMediaStore(context, contentUri, null, null); | ||||
|                 // MediaProvider
 | ||||
|                 case "com.android.providers.media.documents": | ||||
|                     if ("image".equals(type)) { | ||||
|                         contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; | ||||
|                     } else if ("video".equals(type)) { | ||||
|                         contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; | ||||
|                     } else if ("audio".equals(type)) { | ||||
|                         contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; | ||||
|                     } | ||||
|                     String selection = "_id=?"; | ||||
|                     String[] selectionArgs = new String[]{split[1]}; | ||||
|                     return _queryPathFromMediaStore(context, contentUri, selection, selectionArgs); | ||||
|             } | ||||
|         } | ||||
|         // MediaStore (and general)
 | ||||
|         else { | ||||
|             if ("content".equalsIgnoreCase(scheme)) { | ||||
|                 // Return the remote address
 | ||||
|                 if (authority.equals("com.google.android.apps.photos.content")) { | ||||
|                     return uri.getLastPathSegment(); | ||||
|                 } | ||||
|                 return _queryPathFromMediaStore(context, uri, null, null); | ||||
|             } | ||||
|             // File
 | ||||
|             else if ("file".equalsIgnoreCase(scheme)) { | ||||
|                 return uri.getPath(); | ||||
|             } | ||||
|         } | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     private static String _queryPathFromMediaStore(Context context, Uri uri, String selection, String[] selectionArgs) { | ||||
|         String filePath = null; | ||||
|         try { | ||||
|             String[] projection = {MediaStore.Images.Media.DATA}; | ||||
|             Cursor cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null); | ||||
|             if (cursor != null) { | ||||
|                 int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); | ||||
|                 cursor.moveToFirst(); | ||||
|                 filePath = cursor.getString(column_index); | ||||
|                 cursor.close(); | ||||
|             } | ||||
|         } catch (IllegalArgumentException e) { | ||||
|         } | ||||
|         return filePath; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 把view转化为bitmap(截图) | ||||
|      * 参见:http://www.cnblogs.com/lee0oo0/p/3355468.html
 | ||||
|      */ | ||||
|     public static Bitmap toBitmap(View view) { | ||||
|         int width = view.getWidth(); | ||||
|         int height = view.getHeight(); | ||||
|         if (view instanceof ListView) { | ||||
|             height = 0; | ||||
|             // 获取listView实际高度
 | ||||
|             ListView listView = (ListView) view; | ||||
|             for (int i = 0; i < listView.getChildCount(); i++) { | ||||
|                 height += listView.getChildAt(i).getHeight(); | ||||
|             } | ||||
|         } else if (view instanceof ScrollView) { | ||||
|             height = 0; | ||||
|             // 获取scrollView实际高度
 | ||||
|             ScrollView scrollView = (ScrollView) view; | ||||
|             for (int i = 0; i < scrollView.getChildCount(); i++) { | ||||
|                 height += scrollView.getChildAt(i).getHeight(); | ||||
|             } | ||||
|         } | ||||
|         view.setDrawingCacheEnabled(true); | ||||
|         view.clearFocus(); | ||||
|         view.setPressed(false); | ||||
|         boolean willNotCache = view.willNotCacheDrawing(); | ||||
|         view.setWillNotCacheDrawing(false); | ||||
|         // Reset the drawing cache background color to fully transparent for the duration of this operation
 | ||||
|         int color = view.getDrawingCacheBackgroundColor(); | ||||
|         view.setDrawingCacheBackgroundColor(Color.WHITE);//截图去黑色背景(透明像素)
 | ||||
|         if (color != Color.WHITE) { | ||||
|             view.destroyDrawingCache(); | ||||
|         } | ||||
|         view.buildDrawingCache(); | ||||
|         Bitmap cacheBitmap = view.getDrawingCache(); | ||||
|         if (cacheBitmap == null) { | ||||
|             return null; | ||||
|         } | ||||
|         Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); | ||||
|         Canvas canvas = new Canvas(bitmap); | ||||
|         canvas.drawBitmap(cacheBitmap, 0, 0, null); | ||||
|         canvas.save(); | ||||
|         canvas.restore(); | ||||
|         if (!bitmap.isRecycled()) { | ||||
|             bitmap.recycle(); | ||||
|         } | ||||
|         // Restore the view
 | ||||
|         view.destroyDrawingCache(); | ||||
|         view.setWillNotCacheDrawing(willNotCache); | ||||
|         view.setDrawingCacheBackgroundColor(color); | ||||
|         return bitmap; | ||||
|     } | ||||
| 
 | ||||
|     public static Drawable toDrawable(Bitmap bitmap) { | ||||
|         return bitmap == null ? null : new BitmapDrawable(Resources.getSystem(), bitmap); | ||||
|     } | ||||
| 
 | ||||
|     public static byte[] toByteArray(Drawable drawable) { | ||||
|         return toByteArray(toBitmap(drawable)); | ||||
|     } | ||||
| 
 | ||||
|     public static Drawable toDrawable(byte[] bytes) { | ||||
|         return toDrawable(toBitmap(bytes)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * dp转换为px | ||||
|      */ | ||||
|     public static int toPx(Context context, float dpValue) { | ||||
|         final float scale = context.getResources().getDisplayMetrics().density; | ||||
|         int pxValue = (int) (dpValue * scale + 0.5f); | ||||
|         return pxValue; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * px转换为dp | ||||
|      */ | ||||
|     public static int toDp(Context context, float pxValue) { | ||||
|         final float scale = context.getResources().getDisplayMetrics().density; | ||||
|         int dpValue = (int) (pxValue / scale + 0.5f); | ||||
|         return dpValue; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * px转换为sp | ||||
|      */ | ||||
|     public static int toSp(Context context, float pxValue) { | ||||
|         final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; | ||||
|         int spValue = (int) (pxValue / fontScale + 0.5f); | ||||
|         return spValue; | ||||
|     } | ||||
| 
 | ||||
|     public static String toGbk(String str) { | ||||
|         try { | ||||
|             return new String(str.getBytes("utf-8"), "gbk"); | ||||
|         } catch (UnsupportedEncodingException e) { | ||||
|             return str; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     public static String toFileSizeString(long fileSize) { | ||||
|         DecimalFormat df = new DecimalFormat("0.00"); | ||||
|         String fileSizeString; | ||||
|         if (fileSize < KB) { | ||||
|             fileSizeString = fileSize + "B"; | ||||
|         } else if (fileSize < MB) { | ||||
|             fileSizeString = df.format((double) fileSize / KB) + "K"; | ||||
|         } else if (fileSize < GB) { | ||||
|             fileSizeString = df.format((double) fileSize / MB) + "M"; | ||||
|         } else { | ||||
|             fileSizeString = df.format((double) fileSize / GB) + "G"; | ||||
|         } | ||||
|         return fileSizeString; | ||||
|     } | ||||
| 
 | ||||
|     public static String toString(InputStream is, String charset) { | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         try { | ||||
|             BufferedReader reader = new BufferedReader(new InputStreamReader(is, charset)); | ||||
|             while (true) { | ||||
|                 String line = reader.readLine(); | ||||
|                 if (line == null) { | ||||
|                     break; | ||||
|                 } else { | ||||
|                     sb.append(line).append("\n"); | ||||
|                 } | ||||
|             } | ||||
|             reader.close(); | ||||
|             is.close(); | ||||
|         } catch (IOException e) { | ||||
|         } | ||||
|         return sb.toString(); | ||||
|     } | ||||
| 
 | ||||
|     public static String toString(InputStream is) { | ||||
|         return toString(is, "utf-8"); | ||||
|     } | ||||
| 
 | ||||
|     public static int toDarkenColor(@ColorInt int color) { | ||||
|         return toDarkenColor(color, 0.8f); | ||||
|     } | ||||
| 
 | ||||
|     public static int toDarkenColor(@ColorInt int color, @FloatRange(from = 0f, to = 1f) float value) { | ||||
|         float[] hsv = new float[3]; | ||||
|         Color.colorToHSV(color, hsv); | ||||
|         hsv[2] *= value;//HSV指Hue、Saturation、Value,即色调、饱和度和亮度,此处表示修改亮度
 | ||||
|         return Color.HSVToColor(hsv); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 转换为6位十六进制颜色代码,不含“#” | ||||
|      */ | ||||
|     public static String toColorString(@ColorInt int color) { | ||||
|         return toColorString(color, false); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 转换为6位十六进制颜色代码,不含“#” | ||||
|      */ | ||||
|     public static String toColorString(@ColorInt int color, boolean includeAlpha) { | ||||
|         String alpha = Integer.toHexString(Color.alpha(color)); | ||||
|         String red = Integer.toHexString(Color.red(color)); | ||||
|         String green = Integer.toHexString(Color.green(color)); | ||||
|         String blue = Integer.toHexString(Color.blue(color)); | ||||
|         if (alpha.length() == 1) { | ||||
|             alpha = "0" + alpha; | ||||
|         } | ||||
|         if (red.length() == 1) { | ||||
|             red = "0" + red; | ||||
|         } | ||||
|         if (green.length() == 1) { | ||||
|             green = "0" + green; | ||||
|         } | ||||
|         if (blue.length() == 1) { | ||||
|             blue = "0" + blue; | ||||
|         } | ||||
|         String colorString; | ||||
|         if (includeAlpha) { | ||||
|             colorString = alpha + red + green + blue; | ||||
|         } else { | ||||
|             colorString = red + green + blue; | ||||
|         } | ||||
|         return colorString; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 对TextView、Button等设置不同状态时其文字颜色。 | ||||
|      * 参见:http://blog.csdn.net/sodino/article/details/6797821
 | ||||
|      * Modified by liyujiang at 2015.08.13 | ||||
|      */ | ||||
|     public static ColorStateList toColorStateList(@ColorInt int normalColor, @ColorInt int pressedColor, | ||||
|                                                   @ColorInt int focusedColor, @ColorInt int unableColor) { | ||||
|         int[] colors = new int[]{pressedColor, focusedColor, normalColor, focusedColor, unableColor, normalColor}; | ||||
|         int[][] states = new int[6][]; | ||||
|         states[0] = new int[]{android.R.attr.state_pressed, android.R.attr.state_enabled}; | ||||
|         states[1] = new int[]{android.R.attr.state_enabled, android.R.attr.state_focused}; | ||||
|         states[2] = new int[]{android.R.attr.state_enabled}; | ||||
|         states[3] = new int[]{android.R.attr.state_focused}; | ||||
|         states[4] = new int[]{android.R.attr.state_window_focused}; | ||||
|         states[5] = new int[]{}; | ||||
|         return new ColorStateList(states, colors); | ||||
|     } | ||||
| 
 | ||||
|     public static ColorStateList toColorStateList(@ColorInt int normalColor, @ColorInt int pressedColor) { | ||||
|         return toColorStateList(normalColor, pressedColor, pressedColor, normalColor); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,226 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.util; | ||||
| 
 | ||||
| import androidx.annotation.IntDef; | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.text.ParseException; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Arrays; | ||||
| import java.util.Calendar; | ||||
| import java.util.Date; | ||||
| import java.util.List; | ||||
| import java.util.Locale; | ||||
| 
 | ||||
| /** | ||||
|  * 日期时间工具类 | ||||
|  * | ||||
|  * @author 李玉江[QQ:1023694760] | ||||
|  * @since 2015/8/5 | ||||
|  */ | ||||
| public class DateUtils extends android.text.format.DateUtils { | ||||
|     public static final int Second = 0; | ||||
|     public static final int Minute = 1; | ||||
|     public static final int Hour = 2; | ||||
|     public static final int Day = 3; | ||||
| 
 | ||||
|     @IntDef(value = {Second, Minute, Hour, Day}) | ||||
|     @Retention(RetentionPolicy.SOURCE) | ||||
|     public @interface DifferenceMode { | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentSecond(Date startDate, Date endDate) { | ||||
|         return calculateDifference(startDate, endDate, Second); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentMinute(Date startDate, Date endDate) { | ||||
|         return calculateDifference(startDate, endDate, Minute); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentHour(Date startDate, Date endDate) { | ||||
|         return calculateDifference(startDate, endDate, Hour); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentDay(Date startDate, Date endDate) { | ||||
|         return calculateDifference(startDate, endDate, Day); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentSecond(long startTimeMillis, long endTimeMillis) { | ||||
|         return calculateDifference(startTimeMillis, endTimeMillis, Second); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentMinute(long startTimeMillis, long endTimeMillis) { | ||||
|         return calculateDifference(startTimeMillis, endTimeMillis, Minute); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentHour(long startTimeMillis, long endTimeMillis) { | ||||
|         return calculateDifference(startTimeMillis, endTimeMillis, Hour); | ||||
|     } | ||||
| 
 | ||||
|     public static long calculateDifferentDay(long startTimeMillis, long endTimeMillis) { | ||||
|         return calculateDifference(startTimeMillis, endTimeMillis, Day); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 计算两个时间戳之间相差的时间戳数 | ||||
|      */ | ||||
|     public static long calculateDifference(long startTimeMillis, long endTimeMillis, @DifferenceMode int mode) { | ||||
|         return calculateDifference(new Date(startTimeMillis), new Date(endTimeMillis), mode); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 计算两个日期之间相差的时间戳数 | ||||
|      */ | ||||
|     public static long calculateDifference(Date startDate, Date endDate, @DifferenceMode int mode) { | ||||
|         long[] different = calculateDifference(startDate, endDate); | ||||
|         if (mode == Minute) { | ||||
|             return different[2]; | ||||
|         } else if (mode == Hour) { | ||||
|             return different[1]; | ||||
|         } else if (mode == Day) { | ||||
|             return different[0]; | ||||
|         } else { | ||||
|             return different[3]; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private static long[] calculateDifference(Date startDate, Date endDate) { | ||||
|         return calculateDifference(endDate.getTime() - startDate.getTime()); | ||||
|     } | ||||
| 
 | ||||
|     private static long[] calculateDifference(long differentMilliSeconds) { | ||||
|         long secondsInMilli = 1000;//1s==1000ms
 | ||||
|         long minutesInMilli = secondsInMilli * 60; | ||||
|         long hoursInMilli = minutesInMilli * 60; | ||||
|         long daysInMilli = hoursInMilli * 24; | ||||
|         long elapsedDays = differentMilliSeconds / daysInMilli; | ||||
|         differentMilliSeconds = differentMilliSeconds % daysInMilli; | ||||
|         long elapsedHours = differentMilliSeconds / hoursInMilli; | ||||
|         differentMilliSeconds = differentMilliSeconds % hoursInMilli; | ||||
|         long elapsedMinutes = differentMilliSeconds / minutesInMilli; | ||||
|         differentMilliSeconds = differentMilliSeconds % minutesInMilli; | ||||
|         long elapsedSeconds = differentMilliSeconds / secondsInMilli; | ||||
|         return new long[]{elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds}; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 计算每月的天数 | ||||
|      */ | ||||
|     public static int calculateDaysInMonth(int month) { | ||||
|         return calculateDaysInMonth(0, month); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 根据年份及月份计算每月的天数 | ||||
|      */ | ||||
|     public static int calculateDaysInMonth(int year, int month) { | ||||
|         // 添加大小月月份并将其转换为list,方便之后的判断
 | ||||
|         String[] bigMonths = {"1", "3", "5", "7", "8", "10", "12"}; | ||||
|         String[] littleMonths = {"4", "6", "9", "11"}; | ||||
|         List<String> bigList = Arrays.asList(bigMonths); | ||||
|         List<String> littleList = Arrays.asList(littleMonths); | ||||
|         // 判断大小月及是否闰年,用来确定"日"的数据
 | ||||
|         if (bigList.contains(String.valueOf(month))) { | ||||
|             return 31; | ||||
|         } else if (littleList.contains(String.valueOf(month))) { | ||||
|             return 30; | ||||
|         } else { | ||||
|             if (year <= 0) { | ||||
|                 return 29; | ||||
|             } | ||||
|             // 是否闰年
 | ||||
|             if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { | ||||
|                 return 29; | ||||
|             } else { | ||||
|                 return 28; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 月日时分秒,0-9前补0 | ||||
|      */ | ||||
|     @NonNull | ||||
|     public static String fillZero(int number) { | ||||
|         return number < 10 ? "0" + number : "" + number; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 截取掉前缀0以便转换为整数 | ||||
|      * | ||||
|      * @see #fillZero(int) | ||||
|      */ | ||||
|     public static int trimZero(@NonNull String text) { | ||||
|         try { | ||||
|             if (text.startsWith("0")) { | ||||
|                 text = text.substring(1); | ||||
|             } | ||||
|             return Integer.parseInt(text); | ||||
|         } catch (NumberFormatException e) { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 功能:判断日期是否和当前date对象在同一天。 | ||||
|      * 参见:http://www.cnblogs.com/myzhijie/p/3330970.html
 | ||||
|      * | ||||
|      * @param date 比较的日期 | ||||
|      * @return boolean 如果在返回true,否则返回false。 | ||||
|      */ | ||||
|     public static boolean isSameDay(Date date) { | ||||
|         if (date == null) { | ||||
|             throw new IllegalArgumentException("date is null"); | ||||
|         } | ||||
|         Calendar nowCalendar = Calendar.getInstance(); | ||||
|         Calendar newCalendar = Calendar.getInstance(); | ||||
|         newCalendar.setTime(date); | ||||
|         return (nowCalendar.get(Calendar.ERA) == newCalendar.get(Calendar.ERA) && | ||||
|                 nowCalendar.get(Calendar.YEAR) == newCalendar.get(Calendar.YEAR) && | ||||
|                 nowCalendar.get(Calendar.DAY_OF_YEAR) == newCalendar.get(Calendar.DAY_OF_YEAR)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将yyyy-MM-dd HH:mm:ss字符串转换成日期<br/> | ||||
|      * | ||||
|      * @param dateStr    时间字符串 | ||||
|      * @param dataFormat 当前时间字符串的格式。 | ||||
|      * @return Date 日期 ,转换异常时返回null。 | ||||
|      */ | ||||
|     public static Date parseDate(String dateStr, String dataFormat) { | ||||
|         try { | ||||
|             SimpleDateFormat dateFormat = new SimpleDateFormat(dataFormat, Locale.PRC); | ||||
|             Date date = dateFormat.parse(dateStr); | ||||
|             return new Date(date.getTime()); | ||||
|         } catch (ParseException e) { | ||||
|             return null; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将yyyy-MM-dd HH:mm:ss字符串转换成日期<br/> | ||||
|      * | ||||
|      * @param dateStr yyyy-MM-dd HH:mm:ss字符串 | ||||
|      * @return Date 日期 ,转换异常时返回null。 | ||||
|      */ | ||||
|     public static Date parseDate(String dateStr) { | ||||
|         return parseDate(dateStr, "yyyy-MM-dd HH:mm:ss"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将指定的日期转换为一定格式的字符串 | ||||
|      */ | ||||
|     public static String formatDate(Date date, String format) { | ||||
|         SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.PRC); | ||||
|         return sdf.format(date); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将当前日期转换为一定格式的字符串 | ||||
|      */ | ||||
|     public static String formatDate(String format) { | ||||
|         return formatDate(Calendar.getInstance(Locale.CHINA).getTime(), format); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,783 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.util; | ||||
| 
 | ||||
| import android.webkit.MimeTypeMap; | ||||
| 
 | ||||
| import androidx.annotation.IntDef; | ||||
| 
 | ||||
| import java.io.BufferedInputStream; | ||||
| import java.io.BufferedOutputStream; | ||||
| import java.io.ByteArrayOutputStream; | ||||
| import java.io.Closeable; | ||||
| import java.io.File; | ||||
| import java.io.FileFilter; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.FileWriter; | ||||
| import java.io.FilenameFilter; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
| import java.io.UnsupportedEncodingException; | ||||
| import java.lang.annotation.Retention; | ||||
| import java.lang.annotation.RetentionPolicy; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Calendar; | ||||
| import java.util.Collections; | ||||
| import java.util.Comparator; | ||||
| import java.util.regex.Pattern; | ||||
| 
 | ||||
| /** | ||||
|  * 文件处理 | ||||
|  * <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||||
|  * <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||||
|  * | ||||
|  * @author 李玉江[QQ:1023694760] | ||||
|  * @since 2014-4-18 | ||||
|  */ | ||||
| public final class FileUtils { | ||||
|     public static final int BY_NAME_ASC = 0; | ||||
|     public static final int BY_NAME_DESC = 1; | ||||
|     public static final int BY_TIME_ASC = 2; | ||||
|     public static final int BY_TIME_DESC = 3; | ||||
|     public static final int BY_SIZE_ASC = 4; | ||||
|     public static final int BY_SIZE_DESC = 5; | ||||
|     public static final int BY_EXTENSION_ASC = 6; | ||||
|     public static final int BY_EXTENSION_DESC = 7; | ||||
| 
 | ||||
|     @IntDef(value = { | ||||
|             BY_NAME_ASC, | ||||
|             BY_NAME_DESC, | ||||
|             BY_TIME_ASC, | ||||
|             BY_TIME_DESC, | ||||
|             BY_SIZE_ASC, | ||||
|             BY_SIZE_DESC, | ||||
|             BY_EXTENSION_ASC, | ||||
|             BY_EXTENSION_DESC | ||||
|     }) | ||||
|     @Retention(RetentionPolicy.SOURCE) | ||||
|     public @interface SortType { | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 将目录分隔符统一为平台默认的分隔符,并为目录结尾添加分隔符 | ||||
|      */ | ||||
|     public static String separator(String path) { | ||||
|         String separator = File.separator; | ||||
|         path = path.replace("\\", separator); | ||||
|         if (!path.endsWith(separator)) { | ||||
|             path += separator; | ||||
|         } | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     public static void closeSilently(Closeable c) { | ||||
|         if (c == null) { | ||||
|             return; | ||||
|         } | ||||
|         try { | ||||
|             c.close(); | ||||
|         } catch (IOException ignored) { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有子目录 | ||||
|      */ | ||||
|     public static File[] listDirs(String startDirPath, String[] excludeDirs, @SortType int sortType) { | ||||
|         ArrayList<File> dirList = new ArrayList<File>(); | ||||
|         File startDir = new File(startDirPath); | ||||
|         if (!startDir.isDirectory()) { | ||||
|             return new File[0]; | ||||
|         } | ||||
|         File[] dirs = startDir.listFiles(new FileFilter() { | ||||
|             public boolean accept(File f) { | ||||
|                 if (f == null) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 //noinspection RedundantIfStatement
 | ||||
|                 if (f.isDirectory()) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 return false; | ||||
|             } | ||||
|         }); | ||||
|         if (dirs == null) { | ||||
|             return new File[0]; | ||||
|         } | ||||
|         if (excludeDirs == null) { | ||||
|             excludeDirs = new String[0]; | ||||
|         } | ||||
|         for (File dir : dirs) { | ||||
|             File file = dir.getAbsoluteFile(); | ||||
|             if (!ConvertUtils.toString(excludeDirs).contains(file.getName())) { | ||||
|                 dirList.add(file); | ||||
|             } | ||||
|         } | ||||
|         if (sortType == BY_NAME_ASC) { | ||||
|             Collections.sort(dirList, new SortByName()); | ||||
|         } else if (sortType == BY_NAME_DESC) { | ||||
|             Collections.sort(dirList, new SortByName()); | ||||
|             Collections.reverse(dirList); | ||||
|         } else if (sortType == BY_TIME_ASC) { | ||||
|             Collections.sort(dirList, new SortByTime()); | ||||
|         } else if (sortType == BY_TIME_DESC) { | ||||
|             Collections.sort(dirList, new SortByTime()); | ||||
|             Collections.reverse(dirList); | ||||
|         } else if (sortType == BY_SIZE_ASC) { | ||||
|             Collections.sort(dirList, new SortBySize()); | ||||
|         } else if (sortType == BY_SIZE_DESC) { | ||||
|             Collections.sort(dirList, new SortBySize()); | ||||
|             Collections.reverse(dirList); | ||||
|         } else if (sortType == BY_EXTENSION_ASC) { | ||||
|             Collections.sort(dirList, new SortByExtension()); | ||||
|         } else if (sortType == BY_EXTENSION_DESC) { | ||||
|             Collections.sort(dirList, new SortByExtension()); | ||||
|             Collections.reverse(dirList); | ||||
|         } | ||||
|         return dirList.toArray(new File[dirList.size()]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有子目录 | ||||
|      */ | ||||
|     public static File[] listDirs(String startDirPath, String[] excludeDirs) { | ||||
|         return listDirs(startDirPath, excludeDirs, BY_NAME_ASC); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有子目录 | ||||
|      */ | ||||
|     public static File[] listDirs(String startDirPath) { | ||||
|         return listDirs(startDirPath, null, BY_NAME_ASC); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有子目录及所有文件 | ||||
|      */ | ||||
|     public static File[] listDirsAndFiles(String startDirPath, String[] allowExtensions) { | ||||
|         File[] dirs, files, dirsAndFiles; | ||||
|         dirs = listDirs(startDirPath); | ||||
|         if (allowExtensions == null) { | ||||
|             files = listFiles(startDirPath); | ||||
|         } else { | ||||
|             files = listFiles(startDirPath, allowExtensions); | ||||
|         } | ||||
|         if (dirs == null || files == null) { | ||||
|             return null; | ||||
|         } | ||||
|         dirsAndFiles = new File[dirs.length + files.length]; | ||||
|         System.arraycopy(dirs, 0, dirsAndFiles, 0, dirs.length); | ||||
|         System.arraycopy(files, 0, dirsAndFiles, dirs.length, files.length); | ||||
|         return dirsAndFiles; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有子目录及所有文件 | ||||
|      */ | ||||
|     public static File[] listDirsAndFiles(String startDirPath) { | ||||
|         return listDirsAndFiles(startDirPath, null); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有文件 | ||||
|      */ | ||||
|     public static File[] listFiles(String startDirPath, final Pattern filterPattern, @SortType int sortType) { | ||||
|         ArrayList<File> fileList = new ArrayList<File>(); | ||||
|         File f = new File(startDirPath); | ||||
|         if (!f.isDirectory()) { | ||||
|             return new File[0]; | ||||
|         } | ||||
|         File[] files = f.listFiles(new FileFilter() { | ||||
|             public boolean accept(File f) { | ||||
|                 if (f == null) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 if (f.isDirectory()) { | ||||
|                     return false; | ||||
|                 } | ||||
|                 //noinspection SimplifiableIfStatement
 | ||||
|                 if (filterPattern == null) { | ||||
|                     return true; | ||||
|                 } | ||||
|                 return filterPattern.matcher(f.getName()).find(); | ||||
|             } | ||||
|         }); | ||||
|         if (files == null) { | ||||
|             return new File[0]; | ||||
|         } | ||||
|         for (File file : files) { | ||||
|             fileList.add(file.getAbsoluteFile()); | ||||
|         } | ||||
|         if (sortType == BY_NAME_ASC) { | ||||
|             Collections.sort(fileList, new SortByName()); | ||||
|         } else if (sortType == BY_NAME_DESC) { | ||||
|             Collections.sort(fileList, new SortByName()); | ||||
|             Collections.reverse(fileList); | ||||
|         } else if (sortType == BY_TIME_ASC) { | ||||
|             Collections.sort(fileList, new SortByTime()); | ||||
|         } else if (sortType == BY_TIME_DESC) { | ||||
|             Collections.sort(fileList, new SortByTime()); | ||||
|             Collections.reverse(fileList); | ||||
|         } else if (sortType == BY_SIZE_ASC) { | ||||
|             Collections.sort(fileList, new SortBySize()); | ||||
|         } else if (sortType == BY_SIZE_DESC) { | ||||
|             Collections.sort(fileList, new SortBySize()); | ||||
|             Collections.reverse(fileList); | ||||
|         } else if (sortType == BY_EXTENSION_ASC) { | ||||
|             Collections.sort(fileList, new SortByExtension()); | ||||
|         } else if (sortType == BY_EXTENSION_DESC) { | ||||
|             Collections.sort(fileList, new SortByExtension()); | ||||
|             Collections.reverse(fileList); | ||||
|         } | ||||
|         return fileList.toArray(new File[fileList.size()]); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有文件 | ||||
|      */ | ||||
|     public static File[] listFiles(String startDirPath, Pattern filterPattern) { | ||||
|         return listFiles(startDirPath, filterPattern, BY_NAME_ASC); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有文件 | ||||
|      */ | ||||
|     public static File[] listFiles(String startDirPath) { | ||||
|         return listFiles(startDirPath, null, BY_NAME_ASC); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有文件 | ||||
|      */ | ||||
|     public static File[] listFiles(String startDirPath, final String[] allowExtensions) { | ||||
|         File file = new File(startDirPath); | ||||
|         return file.listFiles(new FilenameFilter() { | ||||
| 
 | ||||
|             @Override | ||||
|             public boolean accept(File dir, String name) { | ||||
|                 //返回当前目录所有以某些扩展名结尾的文件
 | ||||
|                 String extension = FileUtils.getExtension(name); | ||||
|                 return ConvertUtils.toString(allowExtensions).contains(extension); | ||||
|             } | ||||
| 
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 列出指定目录下的所有文件 | ||||
|      */ | ||||
|     public static File[] listFiles(String startDirPath, String allowExtension) { | ||||
|         return listFiles(startDirPath, new String[]{allowExtension}); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 判断文件或目录是否存在 | ||||
|      */ | ||||
|     public static boolean exist(String path) { | ||||
|         File file = new File(path); | ||||
|         return file.exists(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 删除文件或目录 | ||||
|      */ | ||||
|     public static boolean delete(File file, boolean deleteRootDir) { | ||||
|         boolean result = false; | ||||
|         if (file.isFile()) { | ||||
|             //是文件
 | ||||
|             result = deleteResolveEBUSY(file); | ||||
|         } else { | ||||
|             //是目录
 | ||||
|             File[] files = file.listFiles(); | ||||
|             if (files == null) { | ||||
|                 return false; | ||||
|             } | ||||
|             if (files.length == 0) { | ||||
|                 result = deleteRootDir && deleteResolveEBUSY(file); | ||||
|             } else { | ||||
|                 for (File f : files) { | ||||
|                     delete(f, deleteRootDir); | ||||
|                     result = deleteResolveEBUSY(f); | ||||
|                 } | ||||
|             } | ||||
|             if (deleteRootDir) { | ||||
|                 result = deleteResolveEBUSY(file); | ||||
|             } | ||||
|         } | ||||
|         return result; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * bug: open failed: EBUSY (Device or resource busy) | ||||
|      * fix: http://stackoverflow.com/questions/11539657/open-failed-ebusy-device-or-resource-busy
 | ||||
|      */ | ||||
|     private static boolean deleteResolveEBUSY(File file) { | ||||
|         // Before you delete a Directory or File: rename it!
 | ||||
|         final File to = new File(file.getAbsolutePath() + System.currentTimeMillis()); | ||||
|         //noinspection ResultOfMethodCallIgnored
 | ||||
|         file.renameTo(to); | ||||
|         return to.delete(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 删除文件或目录 | ||||
|      */ | ||||
|     public static boolean delete(String path, boolean deleteRootDir) { | ||||
|         File file = new File(path); | ||||
|         //noinspection SimplifiableIfStatement
 | ||||
|         if (file.exists()) { | ||||
|             return delete(file, deleteRootDir); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 删除文件或目录, 不删除最顶层目录 | ||||
|      */ | ||||
|     public static boolean delete(String path) { | ||||
|         return delete(path, false); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 删除文件或目录, 不删除最顶层目录 | ||||
|      */ | ||||
|     public static boolean delete(File file) { | ||||
|         return delete(file, false); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 复制文件为另一个文件,或复制某目录下的所有文件及目录到另一个目录下 | ||||
|      */ | ||||
|     public static boolean copy(String src, String tar) { | ||||
|         File srcFile = new File(src); | ||||
|         return srcFile.exists() && copy(srcFile, new File(tar)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 复制文件或目录 | ||||
|      */ | ||||
|     public static boolean copy(File src, File tar) { | ||||
|         try { | ||||
|             if (src.isFile()) { | ||||
|                 InputStream is = new FileInputStream(src); | ||||
|                 OutputStream op = new FileOutputStream(tar); | ||||
|                 BufferedInputStream bis = new BufferedInputStream(is); | ||||
|                 BufferedOutputStream bos = new BufferedOutputStream(op); | ||||
|                 byte[] bt = new byte[1024 * 8]; | ||||
|                 while (true) { | ||||
|                     int len = bis.read(bt); | ||||
|                     if (len == -1) { | ||||
|                         break; | ||||
|                     } else { | ||||
|                         bos.write(bt, 0, len); | ||||
|                     } | ||||
|                 } | ||||
|                 bis.close(); | ||||
|                 bos.close(); | ||||
|             } else if (src.isDirectory()) { | ||||
|                 File[] files = src.listFiles(); | ||||
|                 //noinspection ResultOfMethodCallIgnored
 | ||||
|                 tar.mkdirs(); | ||||
|                 for (File file : files) { | ||||
|                     copy(file.getAbsoluteFile(), new File(tar.getAbsoluteFile(), file.getName())); | ||||
|                 } | ||||
|             } | ||||
|             return true; | ||||
|         } catch (Exception e) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 移动文件或目录 | ||||
|      */ | ||||
|     public static boolean move(String src, String tar) { | ||||
|         return move(new File(src), new File(tar)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 移动文件或目录 | ||||
|      */ | ||||
|     public static boolean move(File src, File tar) { | ||||
|         return rename(src, tar); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 文件重命名 | ||||
|      */ | ||||
|     public static boolean rename(String oldPath, String newPath) { | ||||
|         return rename(new File(oldPath), new File(newPath)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 文件重命名 | ||||
|      */ | ||||
|     public static boolean rename(File src, File tar) { | ||||
|         return src.renameTo(tar); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 读取文本文件, 失败将返回空串 | ||||
|      */ | ||||
|     public static String readText(String filepath, String charset) { | ||||
|         try { | ||||
|             byte[] data = readBytes(filepath); | ||||
|             if (data != null) { | ||||
|                 return new String(data, charset).trim(); | ||||
|             } | ||||
|         } catch (UnsupportedEncodingException ignored) { | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 读取文本文件, 失败将返回空串 | ||||
|      */ | ||||
|     public static String readText(String filepath) { | ||||
|         return readText(filepath, "utf-8"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 读取文件内容, 失败将返回空串 | ||||
|      */ | ||||
|     public static byte[] readBytes(String filepath) { | ||||
|         FileInputStream fis = null; | ||||
|         try { | ||||
|             fis = new FileInputStream(filepath); | ||||
|             ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||||
|             byte[] buffer = new byte[1024]; | ||||
|             while (true) { | ||||
|                 int len = fis.read(buffer, 0, buffer.length); | ||||
|                 if (len == -1) { | ||||
|                     break; | ||||
|                 } else { | ||||
|                     baos.write(buffer, 0, len); | ||||
|                 } | ||||
|             } | ||||
|             byte[] data = baos.toByteArray(); | ||||
|             baos.close(); | ||||
|             return data; | ||||
|         } catch (IOException e) { | ||||
|             return null; | ||||
|         } finally { | ||||
|             closeSilently(fis); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 保存文本内容 | ||||
|      */ | ||||
|     public static boolean writeText(String filepath, String content, String charset) { | ||||
|         try { | ||||
|             writeBytes(filepath, content.getBytes(charset)); | ||||
|             return true; | ||||
|         } catch (UnsupportedEncodingException e) { | ||||
|             return false; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 保存文本内容 | ||||
|      */ | ||||
|     public static boolean writeText(String filepath, String content) { | ||||
|         return writeText(filepath, content, "utf-8"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 保存文件内容 | ||||
|      */ | ||||
|     public static boolean writeBytes(String filepath, byte[] data) { | ||||
|         File file = new File(filepath); | ||||
|         FileOutputStream fos = null; | ||||
|         try { | ||||
|             if (!file.exists()) { | ||||
|                 //noinspection ResultOfMethodCallIgnored
 | ||||
|                 file.getParentFile().mkdirs(); | ||||
|                 //noinspection ResultOfMethodCallIgnored
 | ||||
|                 file.createNewFile(); | ||||
|             } | ||||
|             fos = new FileOutputStream(filepath); | ||||
|             fos.write(data); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             return false; | ||||
|         } finally { | ||||
|             closeSilently(fos); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 追加文本内容 | ||||
|      */ | ||||
|     public static boolean appendText(String path, String content) { | ||||
|         File file = new File(path); | ||||
|         FileWriter writer = null; | ||||
|         try { | ||||
|             if (!file.exists()) { | ||||
|                 //noinspection ResultOfMethodCallIgnored
 | ||||
|                 file.createNewFile(); | ||||
|             } | ||||
|             writer = new FileWriter(file, true); | ||||
|             writer.write(content); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             return false; | ||||
|         } finally { | ||||
|             closeSilently(writer); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取文件大小 | ||||
|      */ | ||||
|     public static long getLength(String path) { | ||||
|         File file = new File(path); | ||||
|         if (!file.isFile() || !file.exists()) { | ||||
|             return 0; | ||||
|         } | ||||
|         return file.length(); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取文件或网址的名称(包括后缀) | ||||
|      */ | ||||
|     public static String getName(String pathOrUrl) { | ||||
|         if (pathOrUrl == null) { | ||||
|             return ""; | ||||
|         } | ||||
|         int pos = pathOrUrl.lastIndexOf('/'); | ||||
|         if (0 <= pos) { | ||||
|             return pathOrUrl.substring(pos + 1); | ||||
|         } else { | ||||
|             return String.valueOf(System.currentTimeMillis()) + "." + getExtension(pathOrUrl); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取文件名(不包括扩展名) | ||||
|      */ | ||||
|     public static String getNameExcludeExtension(String path) { | ||||
|         try { | ||||
|             String fileName = (new File(path)).getName(); | ||||
|             int lastIndexOf = fileName.lastIndexOf("."); | ||||
|             if (lastIndexOf != -1) { | ||||
|                 fileName = fileName.substring(0, lastIndexOf); | ||||
|             } | ||||
|             return fileName; | ||||
|         } catch (Exception e) { | ||||
|             return ""; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取格式化后的文件大小 | ||||
|      */ | ||||
|     public static String getSize(String path) { | ||||
|         long fileSize = getLength(path); | ||||
|         return ConvertUtils.toFileSizeString(fileSize); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取文件后缀,不包括“.” | ||||
|      */ | ||||
|     public static String getExtension(String pathOrUrl) { | ||||
|         int dotPos = pathOrUrl.lastIndexOf('.'); | ||||
|         if (0 <= dotPos) { | ||||
|             return pathOrUrl.substring(dotPos + 1); | ||||
|         } else { | ||||
|             return "ext"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取文件的MIME类型 | ||||
|      */ | ||||
|     public static String getMimeType(String pathOrUrl) { | ||||
|         String ext = getExtension(pathOrUrl); | ||||
|         MimeTypeMap map = MimeTypeMap.getSingleton(); | ||||
|         String mimeType; | ||||
|         if (map.hasExtension(ext)) { | ||||
|             mimeType = map.getMimeTypeFromExtension(ext); | ||||
|         } else { | ||||
|             mimeType = "*/*"; | ||||
|         } | ||||
|         return mimeType; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取格式化后的文件/目录创建或最后修改时间 | ||||
|      */ | ||||
|     public static String getDateTime(String path) { | ||||
|         return getDateTime(path, "yyyy年MM月dd日HH:mm"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取格式化后的文件/目录创建或最后修改时间 | ||||
|      */ | ||||
|     public static String getDateTime(String path, String format) { | ||||
|         File file = new File(path); | ||||
|         return getDateTime(file, format); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 获取格式化后的文件/目录创建或最后修改时间 | ||||
|      */ | ||||
|     public static String getDateTime(File file, String format) { | ||||
|         Calendar cal = Calendar.getInstance(); | ||||
|         cal.setTimeInMillis(file.lastModified()); | ||||
|         return DateUtils.formatDate(cal.getTime(), format); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 比较两个文件的最后修改时间 | ||||
|      */ | ||||
|     public static int compareLastModified(String path1, String path2) { | ||||
|         long stamp1 = (new File(path1)).lastModified(); | ||||
|         long stamp2 = (new File(path2)).lastModified(); | ||||
|         if (stamp1 > stamp2) { | ||||
|             return 1; | ||||
|         } else if (stamp1 < stamp2) { | ||||
|             return -1; | ||||
|         } else { | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 创建多级别的目录 | ||||
|      */ | ||||
|     public static boolean makeDirs(String path) { | ||||
|         return makeDirs(new File(path)); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 创建多级别的目录 | ||||
|      */ | ||||
|     public static boolean makeDirs(File file) { | ||||
|         return file.mkdirs(); | ||||
|     } | ||||
| 
 | ||||
|     public static class SortByExtension implements Comparator<File> { | ||||
| 
 | ||||
|         public SortByExtension() { | ||||
|             super(); | ||||
|         } | ||||
| 
 | ||||
|         public int compare(File f1, File f2) { | ||||
|             if (f1 == null || f2 == null) { | ||||
|                 if (f1 == null) { | ||||
|                     return -1; | ||||
|                 } else { | ||||
|                     return 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (f1.isDirectory() && f2.isFile()) { | ||||
|                     return -1; | ||||
|                 } else if (f1.isFile() && f2.isDirectory()) { | ||||
|                     return 1; | ||||
|                 } else { | ||||
|                     return f1.getName().compareToIgnoreCase(f2.getName()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static class SortByName implements Comparator<File> { | ||||
|         private boolean caseSensitive; | ||||
| 
 | ||||
|         public SortByName(boolean caseSensitive) { | ||||
|             this.caseSensitive = caseSensitive; | ||||
|         } | ||||
| 
 | ||||
|         public SortByName() { | ||||
|             this.caseSensitive = false; | ||||
|         } | ||||
| 
 | ||||
|         public int compare(File f1, File f2) { | ||||
|             if (f1 == null || f2 == null) { | ||||
|                 if (f1 == null) { | ||||
|                     return -1; | ||||
|                 } else { | ||||
|                     return 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (f1.isDirectory() && f2.isFile()) { | ||||
|                     return -1; | ||||
|                 } else if (f1.isFile() && f2.isDirectory()) { | ||||
|                     return 1; | ||||
|                 } else { | ||||
|                     String s1 = f1.getName(); | ||||
|                     String s2 = f2.getName(); | ||||
|                     if (caseSensitive) { | ||||
|                         return s1.compareTo(s2); | ||||
|                     } else { | ||||
|                         return s1.compareToIgnoreCase(s2); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static class SortBySize implements Comparator<File> { | ||||
| 
 | ||||
|         public SortBySize() { | ||||
|             super(); | ||||
|         } | ||||
| 
 | ||||
|         public int compare(File f1, File f2) { | ||||
|             if (f1 == null || f2 == null) { | ||||
|                 if (f1 == null) { | ||||
|                     return -1; | ||||
|                 } else { | ||||
|                     return 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (f1.isDirectory() && f2.isFile()) { | ||||
|                     return -1; | ||||
|                 } else if (f1.isFile() && f2.isDirectory()) { | ||||
|                     return 1; | ||||
|                 } else { | ||||
|                     if (f1.length() < f2.length()) { | ||||
|                         return -1; | ||||
|                     } else { | ||||
|                         return 1; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     public static class SortByTime implements Comparator<File> { | ||||
| 
 | ||||
|         public SortByTime() { | ||||
|             super(); | ||||
|         } | ||||
| 
 | ||||
|         public int compare(File f1, File f2) { | ||||
|             if (f1 == null || f2 == null) { | ||||
|                 if (f1 == null) { | ||||
|                     return -1; | ||||
|                 } else { | ||||
|                     return 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (f1.isDirectory() && f2.isFile()) { | ||||
|                     return -1; | ||||
|                 } else if (f1.isFile() && f2.isDirectory()) { | ||||
|                     return 1; | ||||
|                 } else { | ||||
|                     if (f1.lastModified() > f2.lastModified()) { | ||||
|                         return -1; | ||||
|                     } else { | ||||
|                         return 1; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,71 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.util; | ||||
| 
 | ||||
| import android.app.Activity; | ||||
| import android.content.Context; | ||||
| import android.util.DisplayMetrics; | ||||
| import android.view.Window; | ||||
| import android.view.WindowManager; | ||||
| 
 | ||||
| /** | ||||
|  * 获取屏幕宽高等信息、全屏切换、保持屏幕常亮、截屏等 | ||||
|  * | ||||
|  * @author liyujiang[QQ:1032694760] | ||||
|  * @since 2015/11/26 | ||||
|  */ | ||||
| public final class ScreenUtils { | ||||
|     private static boolean isFullScreen = false; | ||||
|     private static DisplayMetrics dm = null; | ||||
| 
 | ||||
|     public static DisplayMetrics displayMetrics(Context context) { | ||||
|         if (null != dm) { | ||||
|             return dm; | ||||
|         } | ||||
|         DisplayMetrics dm = new DisplayMetrics(); | ||||
|         WindowManager windowManager = (WindowManager) context | ||||
|                 .getSystemService(Context.WINDOW_SERVICE); | ||||
|         windowManager.getDefaultDisplay().getMetrics(dm); | ||||
|         return dm; | ||||
|     } | ||||
| 
 | ||||
|     public static int widthPixels(Context context) { | ||||
|         return displayMetrics(context).widthPixels; | ||||
|     } | ||||
| 
 | ||||
|     public static int heightPixels(Context context) { | ||||
|         return displayMetrics(context).heightPixels; | ||||
|     } | ||||
| 
 | ||||
|     public static float density(Context context) { | ||||
|         return displayMetrics(context).density; | ||||
|     } | ||||
| 
 | ||||
|     public static int densityDpi(Context context) { | ||||
|         return displayMetrics(context).densityDpi; | ||||
|     } | ||||
| 
 | ||||
|     public static boolean isFullScreen() { | ||||
|         return isFullScreen; | ||||
|     } | ||||
| 
 | ||||
|     public static void toggleFullScreen(Activity activity) { | ||||
|         Window window = activity.getWindow(); | ||||
|         int flagFullscreen = WindowManager.LayoutParams.FLAG_FULLSCREEN; | ||||
|         if (isFullScreen) { | ||||
|             window.clearFlags(flagFullscreen); | ||||
|             isFullScreen = false; | ||||
|         } else { | ||||
|             window.setFlags(flagFullscreen, flagFullscreen); | ||||
|             isFullScreen = true; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 保持屏幕常亮 | ||||
|      */ | ||||
|     public static void keepBright(Activity activity) { | ||||
|         //需在setContentView前调用
 | ||||
|         int keepScreenOn = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; | ||||
|         activity.getWindow().setFlags(keepScreenOn, keepScreenOn); | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,161 +0,0 @@ | ||||
| package xyz.fycz.myreader.widget.filepicker.util; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.os.Environment; | ||||
| import android.text.TextUtils; | ||||
| 
 | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| 
 | ||||
| /** | ||||
|  * 存储设备工具类 | ||||
|  * <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | ||||
|  * <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> | ||||
|  * | ||||
|  * @author 李玉江[QQ:1023694760] | ||||
|  * @since 2013-11-2 | ||||
|  */ | ||||
| public final class StorageUtils { | ||||
| 
 | ||||
|     /** | ||||
|      * 判断外置存储是否可用 | ||||
|      * | ||||
|      * @return the boolean | ||||
|      */ | ||||
|     public static boolean externalMounted() { | ||||
|         String state = Environment.getExternalStorageState(); | ||||
|         if (state.equals(Environment.MEDIA_MOUNTED)) { | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 返回以“/”结尾的内部存储根目录 | ||||
|      */ | ||||
|     public static String getInternalRootPath(Context context, String type) { | ||||
|         File file; | ||||
|         if (TextUtils.isEmpty(type)) { | ||||
|             file = context.getFilesDir(); | ||||
|         } else { | ||||
|             file = new File(FileUtils.separator(context.getFilesDir().getAbsolutePath()) + type); | ||||
|             //noinspection ResultOfMethodCallIgnored
 | ||||
|             file.mkdirs(); | ||||
|         } | ||||
|         String path = ""; | ||||
|         if (file != null) { | ||||
|             path = FileUtils.separator(file.getAbsolutePath()); | ||||
|         } | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     public static String getInternalRootPath(Context context) { | ||||
|         return getInternalRootPath(context, null); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 返回以“/”结尾的外部存储根目录,外置卡不可用则返回空字符串 | ||||
|      */ | ||||
|     public static String getExternalRootPath(String type) { | ||||
|         File file = null; | ||||
|         if (externalMounted()) { | ||||
|             file = Environment.getExternalStorageDirectory(); | ||||
|         } | ||||
|         if (file != null && !TextUtils.isEmpty(type)) { | ||||
|             file = new File(file, type); | ||||
|             //noinspection ResultOfMethodCallIgnored
 | ||||
|             file.mkdirs(); | ||||
|         } | ||||
|         String path = ""; | ||||
|         if (file != null) { | ||||
|             path = FileUtils.separator(file.getAbsolutePath()); | ||||
|         } | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     public static String getExternalRootPath() { | ||||
|         return getExternalRootPath(null); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 各种类型的文件的专用的保存路径,以“/”结尾 | ||||
|      * | ||||
|      * @return 诸如:/mnt/sdcard/Android/data/[package]/files/[type]/ | ||||
|      */ | ||||
|     public static String getExternalPrivatePath(Context context, String type) { | ||||
|         File file = null; | ||||
|         if (externalMounted()) { | ||||
|             file = context.getExternalFilesDir(type); | ||||
|         } | ||||
|         //高频触发java.lang.NullPointerException,是SD卡不可用或暂时繁忙么?
 | ||||
|         String path = ""; | ||||
|         if (file != null) { | ||||
|             path = FileUtils.separator(file.getAbsolutePath()); | ||||
|         } | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     public static String getExternalPrivatePath(Context context) { | ||||
|         return getExternalPrivatePath(context, null); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 下载的文件的保存路径,必须为外部存储,以“/”结尾 | ||||
|      * | ||||
|      * @return 诸如 :/mnt/sdcard/Download/ | ||||
|      */ | ||||
|     public static String getDownloadPath() throws RuntimeException { | ||||
|         File file; | ||||
|         if (externalMounted()) { | ||||
|             file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS); | ||||
|         } else { | ||||
|             throw new RuntimeException("外置存储不可用!"); | ||||
|         } | ||||
|         return FileUtils.separator(file.getAbsolutePath()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 各种类型的文件的专用的缓存存储保存路径,优先使用外置存储,以“/”结尾 | ||||
|      */ | ||||
|     public static String getCachePath(Context context, String type) { | ||||
|         File file; | ||||
|         if (externalMounted()) { | ||||
|             file = context.getExternalCacheDir(); | ||||
|         } else { | ||||
|             file = context.getCacheDir(); | ||||
|         } | ||||
|         if (!TextUtils.isEmpty(type)) { | ||||
|             file = new File(file, type); | ||||
|             //noinspection ResultOfMethodCallIgnored
 | ||||
|             file.mkdirs(); | ||||
|         } | ||||
|         String path = ""; | ||||
|         if (file != null) { | ||||
|             path = FileUtils.separator(file.getAbsolutePath()); | ||||
|         } | ||||
|         return path; | ||||
|     } | ||||
| 
 | ||||
|     public static String getCachePath(Context context) { | ||||
|         return getCachePath(context, null); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 返回以“/”结尾的临时存储目录 | ||||
|      */ | ||||
|     public static String getTempDirPath(Context context) { | ||||
|         return getExternalPrivatePath(context, "temporary"); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * 返回临时存储文件路径 | ||||
|      */ | ||||
|     public static String getTempFilePath(Context context) { | ||||
|         try { | ||||
|             return File.createTempFile("lyj_", ".tmp", context.getCacheDir()).getAbsolutePath(); | ||||
|         } catch (IOException e) { | ||||
|             return getTempDirPath(context) + "lyj.tmp"; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| @ -1,22 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:orientation="horizontal" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="wrap_content" | ||||
|     android:gravity="center_vertical" | ||||
|     android:padding="5dp"> | ||||
| 
 | ||||
|     <ImageView | ||||
|         android:id="@+id/image_view" | ||||
|         android:layout_width="24dp" | ||||
|         android:layout_height="24dp" | ||||
|         tools:ignore="ContentDescription" /> | ||||
| 
 | ||||
|     <TextView | ||||
|         android:id="@+id/text_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="match_parent" | ||||
|         android:gravity="center_vertical" /> | ||||
| 
 | ||||
| </LinearLayout> | ||||
| @ -1,22 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" | ||||
|     android:orientation="horizontal" | ||||
|     android:layout_width="wrap_content" | ||||
|     android:layout_height="match_parent" | ||||
|     android:clickable="true" | ||||
|     android:focusable="true"> | ||||
| 
 | ||||
|     <TextView | ||||
|         android:id="@+id/text_view" | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="match_parent" | ||||
|         android:gravity="center_vertical" /> | ||||
| 
 | ||||
|     <ImageView | ||||
|         android:id="@+id/image_view" | ||||
|         android:layout_width="20dp" | ||||
|         android:layout_height="match_parent" | ||||
|         tools:ignore="ContentDescription" /> | ||||
| 
 | ||||
| </LinearLayout> | ||||
| @ -1,35 +0,0 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:orientation="vertical" | ||||
|     android:layout_width="match_parent" | ||||
|     android:layout_height="match_parent"> | ||||
| 
 | ||||
|     <androidx.recyclerview.widget.RecyclerView | ||||
|         android:id="@+id/rv_path" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="30dp" /> | ||||
| 
 | ||||
|     <View | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="0.2dp" | ||||
|         android:background="@color/btn_bg_press_2" /> | ||||
| 
 | ||||
|     <FrameLayout | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent"> | ||||
| 
 | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:id="@+id/rv_file" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" /> | ||||
| 
 | ||||
|         <TextView | ||||
|             android:id="@+id/tv_empty" | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="match_parent" | ||||
|             android:gravity="center" | ||||
|             android:visibility="gone" /> | ||||
| 
 | ||||
|     </FrameLayout> | ||||
| 
 | ||||
| </LinearLayout> | ||||
					Loading…
					
					
				
		Reference in new issue