Resource 1st version... Visible
This commit is contained in:
2
.idea/misc.xml
generated
2
.idea/misc.xml
generated
@@ -25,5 +25,5 @@
|
|||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" project-jdk-name="1.8 (2)" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
||||||
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@@ -2,7 +2,7 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="ProjectModuleManager">
|
<component name="ProjectModuleManager">
|
||||||
<modules>
|
<modules>
|
||||||
<module fileurl="file://$PROJECT_DIR$/.idea/FUPlanner.iml" filepath="$PROJECT_DIR$/.idea/FUPlanner.iml" />
|
<module fileurl="file://$PROJECT_DIR$/FUPlanner.iml" filepath="$PROJECT_DIR$/FUPlanner.iml" />
|
||||||
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
<module fileurl="file://$PROJECT_DIR$/app/app.iml" filepath="$PROJECT_DIR$/app/app.iml" />
|
||||||
</modules>
|
</modules>
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
||||||
@@ -38,6 +38,8 @@ class ModDetailAdapter extends FragmentStatePagerAdapter {
|
|||||||
return ModDetailEventFragment.newInstance(mItemPos);
|
return ModDetailEventFragment.newInstance(mItemPos);
|
||||||
case ModulePart.GRADEBOOK:
|
case ModulePart.GRADEBOOK:
|
||||||
return ModDetailGradebookFragment.newInstance(mItemPos);
|
return ModDetailGradebookFragment.newInstance(mItemPos);
|
||||||
|
case ModulePart.RESOURCES:
|
||||||
|
return ModDetailResourceFragment.newInstance(mItemPos);
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -57,6 +59,8 @@ class ModDetailAdapter extends FragmentStatePagerAdapter {
|
|||||||
return this.mContext.getResources().getString(R.string.events);
|
return this.mContext.getResources().getString(R.string.events);
|
||||||
case ModulePart.GRADEBOOK:
|
case ModulePart.GRADEBOOK:
|
||||||
return this.mContext.getResources().getString(R.string.gradebook);
|
return this.mContext.getResources().getString(R.string.gradebook);
|
||||||
|
case ModulePart.RESOURCES:
|
||||||
|
return this.mContext.getResources().getString(R.string.resourcen);
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package de.sebse.fuplanner.fragments.moddetails;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.services.KVV.types.Modules;
|
||||||
|
import de.sebse.fuplanner.services.KVV.types.Resource;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeNode;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeViewAdapter;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeViewBinder;
|
||||||
|
|
||||||
|
class ModDetailResourceAdapter extends TreeViewAdapter {
|
||||||
|
private Modules.Module mValue;
|
||||||
|
public ModDetailResourceAdapter(List<? extends TreeViewBinder> viewBinders) {
|
||||||
|
super(viewBinders);
|
||||||
|
mValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModule(Modules.Module module) {
|
||||||
|
mValue = module;
|
||||||
|
this.setModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModule() {
|
||||||
|
if (mValue == null || mValue.resources == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<TreeNode> nodes = new ArrayList<>();
|
||||||
|
for (Resource res: mValue.resources) {
|
||||||
|
nodes.add(res.getTreeNode());
|
||||||
|
}
|
||||||
|
refresh(nodes);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
package de.sebse.fuplanner.fragments.moddetails;
|
||||||
|
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.v4.app.Fragment;
|
||||||
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.MainActivity;
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
import de.sebse.fuplanner.services.KVV.KVV;
|
||||||
|
import de.sebse.fuplanner.services.KVV.types.Modules;
|
||||||
|
import de.sebse.fuplanner.tools.logging.Logger;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.DirectoryNodeBinder;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.FileNodeBinder;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeNode;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeViewAdapter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A simple {@link Fragment} subclass.
|
||||||
|
* Use the {@link ModDetailResourceFragment#newInstance} factory method to
|
||||||
|
* create an instance of this fragment.
|
||||||
|
*/
|
||||||
|
public class ModDetailResourceFragment extends Fragment {
|
||||||
|
private static final String ARG_POSITION = "itemPosition";
|
||||||
|
|
||||||
|
private String mItemPos;
|
||||||
|
private final Logger log = new Logger(this);
|
||||||
|
private ModDetailResourceAdapter adapter;
|
||||||
|
private SwipeRefreshLayout swipeLayout;
|
||||||
|
|
||||||
|
|
||||||
|
public ModDetailResourceFragment() {
|
||||||
|
// Required empty public constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this factory method to create a new instance of
|
||||||
|
* this fragment using the provided parameters.
|
||||||
|
*
|
||||||
|
* @param itemPosition Item position in module list.
|
||||||
|
* @return A new instance of fragment ModDetailAnnounceFragment.
|
||||||
|
*/
|
||||||
|
public static ModDetailResourceFragment newInstance(String itemPosition) {
|
||||||
|
ModDetailResourceFragment fragment = new ModDetailResourceFragment();
|
||||||
|
Bundle args = new Bundle();
|
||||||
|
args.putString(ARG_POSITION, itemPosition);
|
||||||
|
fragment.setArguments(args);
|
||||||
|
return fragment;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
if (getArguments() != null) {
|
||||||
|
mItemPos = getArguments().getString(ARG_POSITION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
|
||||||
|
Bundle savedInstanceState) {
|
||||||
|
// Inflate the layout for this fragment
|
||||||
|
View view = inflater.inflate(R.layout.fragment_recycler_view, container, false);
|
||||||
|
// Set the adapter
|
||||||
|
Context context = view.getContext();
|
||||||
|
RecyclerView recyclerView = view.findViewById(R.id.list);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(context));
|
||||||
|
|
||||||
|
adapter = new ModDetailResourceAdapter(Arrays.asList(new FileNodeBinder(), new DirectoryNodeBinder()));
|
||||||
|
adapter.setOnTreeNodeListener(new TreeViewAdapter.OnTreeNodeListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onClick(TreeNode node, RecyclerView.ViewHolder holder) {
|
||||||
|
if (!node.isLeaf()) {
|
||||||
|
//Update and toggle the node.
|
||||||
|
onToggle(!node.isExpand(), holder);
|
||||||
|
// if (!node.isExpand())
|
||||||
|
// adapter.collapseBrotherNode(node);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onToggle(boolean isExpand, RecyclerView.ViewHolder holder) {
|
||||||
|
DirectoryNodeBinder.ViewHolder dirViewHolder = (DirectoryNodeBinder.ViewHolder) holder;
|
||||||
|
final ImageView ivArrow = dirViewHolder.getIvArrow();
|
||||||
|
int rotateDegree = isExpand ? 90 : -90;
|
||||||
|
ivArrow.animate().rotationBy(rotateDegree)
|
||||||
|
.start();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
recyclerView.setAdapter(adapter);
|
||||||
|
|
||||||
|
// Getting SwipeContainerLayout
|
||||||
|
swipeLayout = view.findViewById(R.id.swipe_container);
|
||||||
|
// Adding Listener
|
||||||
|
swipeLayout.setOnRefreshListener(() -> refresh(true));
|
||||||
|
refresh(false);
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void refresh(boolean forceRefresh) {
|
||||||
|
if (getActivity() != null) {
|
||||||
|
KVV kvv = ((MainActivity) getActivity()).getKVV();
|
||||||
|
kvv.getModule(mItemPos, (Modules.Module module) -> {
|
||||||
|
adapter.setModule(module);
|
||||||
|
kvv.getModuleResources(module, success1 -> {
|
||||||
|
adapter.setModule();
|
||||||
|
swipeLayout.setRefreshing(false);
|
||||||
|
}, error -> {
|
||||||
|
swipeLayout.setRefreshing(false);
|
||||||
|
log.e(error);
|
||||||
|
}, forceRefresh);
|
||||||
|
}, error -> {
|
||||||
|
swipeLayout.setRefreshing(false);
|
||||||
|
log.e(error);
|
||||||
|
}, forceRefresh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,7 +7,8 @@ class ModulePart {
|
|||||||
static final int ASSIGNMENT = 3;
|
static final int ASSIGNMENT = 3;
|
||||||
static final int EVENT = 4;
|
static final int EVENT = 4;
|
||||||
static final int GRADEBOOK = 5;
|
static final int GRADEBOOK = 5;
|
||||||
private static final int[] pages = new int[]{OVERVIEW, ANNOUNCEMENT, ASSIGNMENT, EVENT, GRADEBOOK};
|
static final int RESOURCES = 6;
|
||||||
|
private static final int[] pages = new int[]{OVERVIEW, ANNOUNCEMENT, ASSIGNMENT, EVENT, GRADEBOOK, RESOURCES};
|
||||||
|
|
||||||
static int getPageCount() {
|
static int getPageCount() {
|
||||||
return pages.length;
|
return pages.length;
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ package de.sebse.fuplanner.services.KVV.types;
|
|||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.Dir;
|
||||||
|
import de.sebse.fuplanner.tools.ui.treeview.TreeNode;
|
||||||
|
|
||||||
|
|
||||||
public abstract class Resource implements Serializable {
|
public abstract class Resource implements Serializable {
|
||||||
|
|
||||||
@@ -47,9 +50,9 @@ public abstract class Resource implements Serializable {
|
|||||||
return visible;
|
return visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract TreeNode getTreeNode();
|
||||||
|
|
||||||
public static class File extends Resource {
|
public static class File extends Resource {
|
||||||
|
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
public File(String author, String title, long modifiedDate, String url, boolean visible, String container, String type) {
|
public File(String author, String title, long modifiedDate, String url, boolean visible, String container, String type) {
|
||||||
@@ -67,6 +70,11 @@ public abstract class Resource implements Serializable {
|
|||||||
", type='" + type + '\'' +
|
", type='" + type + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TreeNode getTreeNode() {
|
||||||
|
return new TreeNode<>(new de.sebse.fuplanner.tools.ui.treeview.File(title));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Folder extends Resource{
|
public static class Folder extends Resource{
|
||||||
@@ -99,6 +107,15 @@ public abstract class Resource implements Serializable {
|
|||||||
", childs='" + childs + '\'' +
|
", childs='" + childs + '\'' +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TreeNode getTreeNode() {
|
||||||
|
TreeNode<Dir> dir = new TreeNode<>(new Dir(title));
|
||||||
|
for (Resource res: childs) {
|
||||||
|
dir.addChild(res.getTreeNode());
|
||||||
|
}
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Dir implements LayoutItemType {
|
||||||
|
public String dirName;
|
||||||
|
|
||||||
|
public Dir(String dirName) {
|
||||||
|
this.dirName = dirName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutId() {
|
||||||
|
return R.layout.item_dir;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class DirectoryNodeBinder extends TreeViewBinder<DirectoryNodeBinder.ViewHolder> {
|
||||||
|
@Override
|
||||||
|
public ViewHolder provideViewHolder(View itemView) {
|
||||||
|
return new ViewHolder(itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindView(ViewHolder holder, int position, TreeNode node) {
|
||||||
|
holder.ivArrow.setRotation(0);
|
||||||
|
holder.ivArrow.setImageResource(R.drawable.ic_keyboard_arrow_right_black_18dp);
|
||||||
|
int rotateDegree = node.isExpand() ? 90 : 0;
|
||||||
|
holder.ivArrow.setRotation(rotateDegree);
|
||||||
|
Dir dirNode = (Dir) node.getContent();
|
||||||
|
holder.tvName.setText(dirNode.dirName);
|
||||||
|
if (node.isLeaf())
|
||||||
|
holder.ivArrow.setVisibility(View.INVISIBLE);
|
||||||
|
else holder.ivArrow.setVisibility(View.VISIBLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutId() {
|
||||||
|
return R.layout.item_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ViewHolder extends TreeViewBinder.ViewHolder {
|
||||||
|
private ImageView ivArrow;
|
||||||
|
private TextView tvName;
|
||||||
|
|
||||||
|
public ViewHolder(View rootView) {
|
||||||
|
super(rootView);
|
||||||
|
this.ivArrow = (ImageView) rootView.findViewById(R.id.iv_arrow);
|
||||||
|
this.tvName = (TextView) rootView.findViewById(R.id.tv_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageView getIvArrow() {
|
||||||
|
return ivArrow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TextView getTvName() {
|
||||||
|
return tvName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class File implements LayoutItemType {
|
||||||
|
public String fileName;
|
||||||
|
|
||||||
|
public File(String fileName) {
|
||||||
|
this.fileName = fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutId() {
|
||||||
|
return R.layout.item_file;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import de.sebse.fuplanner.R;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class FileNodeBinder extends TreeViewBinder<FileNodeBinder.ViewHolder> {
|
||||||
|
@Override
|
||||||
|
public ViewHolder provideViewHolder(View itemView) {
|
||||||
|
return new ViewHolder(itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void bindView(ViewHolder holder, int position, TreeNode node) {
|
||||||
|
File fileNode = (File) node.getContent();
|
||||||
|
holder.tvName.setText(fileNode.fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLayoutId() {
|
||||||
|
return R.layout.item_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ViewHolder extends TreeViewBinder.ViewHolder {
|
||||||
|
public TextView tvName;
|
||||||
|
|
||||||
|
public ViewHolder(View rootView) {
|
||||||
|
super(rootView);
|
||||||
|
this.tvName = (TextView) rootView.findViewById(R.id.tv_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public interface LayoutItemType {
|
||||||
|
int getLayoutId();
|
||||||
|
}
|
||||||
@@ -0,0 +1,149 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class TreeNode<T extends LayoutItemType> implements Cloneable {
|
||||||
|
private T content;
|
||||||
|
private TreeNode parent;
|
||||||
|
private List<TreeNode> childList;
|
||||||
|
private boolean isExpand;
|
||||||
|
private boolean isLocked;
|
||||||
|
//the tree high
|
||||||
|
private int height = UNDEFINE;
|
||||||
|
|
||||||
|
private static final int UNDEFINE = -1;
|
||||||
|
|
||||||
|
public TreeNode(@NonNull T content) {
|
||||||
|
this.content = content;
|
||||||
|
this.childList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getHeight() {
|
||||||
|
if (isRoot())
|
||||||
|
height = 0;
|
||||||
|
else if (height == UNDEFINE)
|
||||||
|
height = parent.getHeight() + 1;
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRoot() {
|
||||||
|
return parent == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLeaf() {
|
||||||
|
return childList == null || childList.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContent(T content) {
|
||||||
|
this.content = content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T getContent() {
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<TreeNode> getChildList() {
|
||||||
|
return childList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setChildList(List<TreeNode> childList) {
|
||||||
|
this.childList.clear();
|
||||||
|
for (TreeNode treeNode : childList) {
|
||||||
|
addChild(treeNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeNode addChild(TreeNode node) {
|
||||||
|
if (childList == null)
|
||||||
|
childList = new ArrayList<>();
|
||||||
|
childList.add(node);
|
||||||
|
node.parent = this;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean toggle() {
|
||||||
|
isExpand = !isExpand;
|
||||||
|
return isExpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collapse() {
|
||||||
|
if (isExpand) {
|
||||||
|
isExpand = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collapseAll() {
|
||||||
|
if (childList == null || childList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (TreeNode child : this.childList) {
|
||||||
|
child.collapseAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expand() {
|
||||||
|
if (!isExpand) {
|
||||||
|
isExpand = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expandAll() {
|
||||||
|
expand();
|
||||||
|
if (childList == null || childList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (TreeNode child : this.childList) {
|
||||||
|
child.expandAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isExpand() {
|
||||||
|
return isExpand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setParent(TreeNode parent) {
|
||||||
|
this.parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeNode getParent() {
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeNode<T> lock() {
|
||||||
|
isLocked = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeNode<T> unlock() {
|
||||||
|
isLocked = false;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLocked() {
|
||||||
|
return isLocked;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "TreeNode{" +
|
||||||
|
"content=" + this.content +
|
||||||
|
", parent=" + (parent == null ? "null" : parent.getContent().toString()) +
|
||||||
|
", childList=" + (childList == null ? "null" : childList.toString()) +
|
||||||
|
", isExpand=" + isExpand +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected TreeNode<T> clone() throws CloneNotSupportedException {
|
||||||
|
TreeNode<T> clone = new TreeNode<>(this.content);
|
||||||
|
clone.isExpand = this.isExpand;
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,320 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
import android.support.v7.util.DiffUtil;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by tlh on 2016/10/1 :)
|
||||||
|
*/
|
||||||
|
public class TreeViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
private static final String KEY_IS_EXPAND = "IS_EXPAND";
|
||||||
|
private final List<? extends TreeViewBinder> viewBinders;
|
||||||
|
private List<TreeNode> displayNodes;
|
||||||
|
private int padding = 30;
|
||||||
|
private OnTreeNodeListener onTreeNodeListener;
|
||||||
|
private boolean toCollapseChild;
|
||||||
|
|
||||||
|
public TreeViewAdapter(List<? extends TreeViewBinder> viewBinders) {
|
||||||
|
this(null, viewBinders);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TreeViewAdapter(List<TreeNode> nodes, List<? extends TreeViewBinder> viewBinders) {
|
||||||
|
displayNodes = new ArrayList<>();
|
||||||
|
if (nodes != null)
|
||||||
|
findDisplayNodes(nodes);
|
||||||
|
this.viewBinders = viewBinders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从nodes的结点中寻找展开了的非叶结点,添加到displayNodes中。
|
||||||
|
*
|
||||||
|
* @param nodes 基准点
|
||||||
|
*/
|
||||||
|
private void findDisplayNodes(List<TreeNode> nodes) {
|
||||||
|
for (TreeNode node : nodes) {
|
||||||
|
displayNodes.add(node);
|
||||||
|
if (!node.isLeaf() && node.isExpand())
|
||||||
|
findDisplayNodes(node.getChildList());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return displayNodes.get(position).getContent().getLayoutId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||||
|
View v = LayoutInflater.from(parent.getContext())
|
||||||
|
.inflate(viewType, parent, false);
|
||||||
|
if (viewBinders.size() == 1)
|
||||||
|
return viewBinders.get(0).provideViewHolder(v);
|
||||||
|
for (TreeViewBinder viewBinder : viewBinders) {
|
||||||
|
if (viewBinder.getLayoutId() == viewType)
|
||||||
|
return viewBinder.provideViewHolder(v);
|
||||||
|
}
|
||||||
|
return viewBinders.get(0).provideViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position, List<Object> payloads) {
|
||||||
|
if (payloads != null && !payloads.isEmpty()) {
|
||||||
|
Bundle b = (Bundle) payloads.get(0);
|
||||||
|
for (String key : b.keySet()) {
|
||||||
|
switch (key) {
|
||||||
|
case KEY_IS_EXPAND:
|
||||||
|
if (onTreeNodeListener != null)
|
||||||
|
onTreeNodeListener.onToggle(b.getBoolean(key), holder);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onBindViewHolder(holder, position, payloads);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
|
||||||
|
holder.itemView.setPadding(displayNodes.get(position).getHeight() * padding, 3, 3, 3);
|
||||||
|
holder.itemView.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
TreeNode selectedNode = displayNodes.get(holder.getLayoutPosition());
|
||||||
|
// Prevent multi-click during the short interval.
|
||||||
|
try {
|
||||||
|
long lastClickTime = (long) holder.itemView.getTag();
|
||||||
|
if (System.currentTimeMillis() - lastClickTime < 500)
|
||||||
|
return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
holder.itemView.setTag(System.currentTimeMillis());
|
||||||
|
}
|
||||||
|
holder.itemView.setTag(System.currentTimeMillis());
|
||||||
|
|
||||||
|
if (onTreeNodeListener != null && onTreeNodeListener.onClick(selectedNode, holder))
|
||||||
|
return;
|
||||||
|
if (selectedNode.isLeaf())
|
||||||
|
return;
|
||||||
|
// This TreeNode was locked to click.
|
||||||
|
if (selectedNode.isLocked()) return;
|
||||||
|
boolean isExpand = selectedNode.isExpand();
|
||||||
|
int positionStart = displayNodes.indexOf(selectedNode) + 1;
|
||||||
|
if (!isExpand) {
|
||||||
|
notifyItemRangeInserted(positionStart, addChildNodes(selectedNode, positionStart));
|
||||||
|
} else {
|
||||||
|
notifyItemRangeRemoved(positionStart, removeChildNodes(selectedNode, true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for (TreeViewBinder viewBinder : viewBinders) {
|
||||||
|
if (viewBinder.getLayoutId() == displayNodes.get(position).getContent().getLayoutId())
|
||||||
|
viewBinder.bindView(holder, position, displayNodes.get(position));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addChildNodes(TreeNode pNode, int startIndex) {
|
||||||
|
List<TreeNode> childList = pNode.getChildList();
|
||||||
|
int addChildCount = 0;
|
||||||
|
for (TreeNode treeNode : childList) {
|
||||||
|
displayNodes.add(startIndex + addChildCount++, treeNode);
|
||||||
|
if (treeNode.isExpand()) {
|
||||||
|
addChildCount += addChildNodes(treeNode, startIndex + addChildCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!pNode.isExpand())
|
||||||
|
pNode.toggle();
|
||||||
|
return addChildCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int removeChildNodes(TreeNode pNode) {
|
||||||
|
return removeChildNodes(pNode, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int removeChildNodes(TreeNode pNode, boolean shouldToggle) {
|
||||||
|
if (pNode.isLeaf())
|
||||||
|
return 0;
|
||||||
|
List<TreeNode> childList = pNode.getChildList();
|
||||||
|
int removeChildCount = childList.size();
|
||||||
|
displayNodes.removeAll(childList);
|
||||||
|
for (TreeNode child : childList) {
|
||||||
|
if (child.isExpand()) {
|
||||||
|
if (toCollapseChild)
|
||||||
|
child.toggle();
|
||||||
|
removeChildCount += removeChildNodes(child, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shouldToggle)
|
||||||
|
pNode.toggle();
|
||||||
|
return removeChildCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return displayNodes == null ? 0 : displayNodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPadding(int padding) {
|
||||||
|
this.padding = padding;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ifCollapseChildWhileCollapseParent(boolean toCollapseChild) {
|
||||||
|
this.toCollapseChild = toCollapseChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOnTreeNodeListener(OnTreeNodeListener onTreeNodeListener) {
|
||||||
|
this.onTreeNodeListener = onTreeNodeListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface OnTreeNodeListener {
|
||||||
|
/**
|
||||||
|
* called when TreeNodes were clicked.
|
||||||
|
* @return weather consume the click event.
|
||||||
|
*/
|
||||||
|
boolean onClick(TreeNode node, RecyclerView.ViewHolder holder);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* called when TreeNodes were toggle.
|
||||||
|
* @param isExpand the status of TreeNodes after being toggled.
|
||||||
|
*/
|
||||||
|
void onToggle(boolean isExpand, RecyclerView.ViewHolder holder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void refresh(List<TreeNode> treeNodes) {
|
||||||
|
displayNodes.clear();
|
||||||
|
findDisplayNodes(treeNodes);
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Iterator<TreeNode> getDisplayNodesIterator() {
|
||||||
|
return displayNodes.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void notifyDiff(final List<TreeNode> temp) {
|
||||||
|
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtil.Callback() {
|
||||||
|
@Override
|
||||||
|
public int getOldListSize() {
|
||||||
|
return temp.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNewListSize() {
|
||||||
|
return displayNodes.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
// judge if the same items
|
||||||
|
@Override
|
||||||
|
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return TreeViewAdapter.this.areItemsTheSame(temp.get(oldItemPosition), displayNodes.get(newItemPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if they are the same items, whether the contents has bean changed.
|
||||||
|
@Override
|
||||||
|
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||||
|
return TreeViewAdapter.this.areContentsTheSame(temp.get(oldItemPosition), displayNodes.get(newItemPosition));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public Object getChangePayload(int oldItemPosition, int newItemPosition) {
|
||||||
|
return TreeViewAdapter.this.getChangePayload(temp.get(oldItemPosition), displayNodes.get(newItemPosition));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
diffResult.dispatchUpdatesTo(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getChangePayload(TreeNode oldNode, TreeNode newNode) {
|
||||||
|
Bundle diffBundle = new Bundle();
|
||||||
|
if (newNode.isExpand() != oldNode.isExpand()) {
|
||||||
|
diffBundle.putBoolean(KEY_IS_EXPAND, newNode.isExpand());
|
||||||
|
}
|
||||||
|
if (diffBundle.size() == 0)
|
||||||
|
return null;
|
||||||
|
return diffBundle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For DiffUtil, if they are the same items, whether the contents has bean changed.
|
||||||
|
private boolean areContentsTheSame(TreeNode oldNode, TreeNode newNode) {
|
||||||
|
return oldNode.getContent() != null && oldNode.getContent().equals(newNode.getContent())
|
||||||
|
&& oldNode.isExpand() == newNode.isExpand();
|
||||||
|
}
|
||||||
|
|
||||||
|
// judge if the same item for DiffUtil
|
||||||
|
private boolean areItemsTheSame(TreeNode oldNode, TreeNode newNode) {
|
||||||
|
return oldNode.getContent() != null && oldNode.getContent().equals(newNode.getContent());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* collapse all root nodes.
|
||||||
|
*/
|
||||||
|
public void collapseAll() {
|
||||||
|
// Back up the nodes are displaying.
|
||||||
|
List<TreeNode> temp = backupDisplayNodes();
|
||||||
|
//find all root nodes.
|
||||||
|
List<TreeNode> roots = new ArrayList<>();
|
||||||
|
for (TreeNode displayNode : displayNodes) {
|
||||||
|
if (displayNode.isRoot())
|
||||||
|
roots.add(displayNode);
|
||||||
|
}
|
||||||
|
//Close all root nodes.
|
||||||
|
for (TreeNode root : roots) {
|
||||||
|
if (root.isExpand())
|
||||||
|
removeChildNodes(root);
|
||||||
|
}
|
||||||
|
notifyDiff(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private List<TreeNode> backupDisplayNodes() {
|
||||||
|
List<TreeNode> temp = new ArrayList<>();
|
||||||
|
for (TreeNode displayNode : displayNodes) {
|
||||||
|
try {
|
||||||
|
temp.add(displayNode.clone());
|
||||||
|
} catch (CloneNotSupportedException e) {
|
||||||
|
temp.add(displayNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collapseNode(TreeNode pNode) {
|
||||||
|
List<TreeNode> temp = backupDisplayNodes();
|
||||||
|
removeChildNodes(pNode);
|
||||||
|
notifyDiff(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void collapseBrotherNode(TreeNode pNode) {
|
||||||
|
List<TreeNode> temp = backupDisplayNodes();
|
||||||
|
if (pNode.isRoot()) {
|
||||||
|
List<TreeNode> roots = new ArrayList<>();
|
||||||
|
for (TreeNode displayNode : displayNodes) {
|
||||||
|
if (displayNode.isRoot())
|
||||||
|
roots.add(displayNode);
|
||||||
|
}
|
||||||
|
//Close all root nodes.
|
||||||
|
for (TreeNode root : roots) {
|
||||||
|
if (root.isExpand() && !root.equals(pNode))
|
||||||
|
removeChildNodes(root);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
TreeNode parent = pNode.getParent();
|
||||||
|
if (parent == null)
|
||||||
|
return;
|
||||||
|
List<TreeNode> childList = parent.getChildList();
|
||||||
|
for (TreeNode node : childList) {
|
||||||
|
if (node.equals(pNode) || !node.isExpand())
|
||||||
|
continue;
|
||||||
|
removeChildNodes(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
notifyDiff(temp);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package de.sebse.fuplanner.tools.ui.treeview;
|
||||||
|
|
||||||
|
import android.support.annotation.IdRes;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
|
import android.view.View;
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class TreeViewBinder<VH extends RecyclerView.ViewHolder> implements LayoutItemType {
|
||||||
|
public abstract VH provideViewHolder(View itemView);
|
||||||
|
|
||||||
|
public abstract void bindView(VH holder, int position, TreeNode node);
|
||||||
|
|
||||||
|
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
public ViewHolder(View rootView) {
|
||||||
|
super(rootView);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T extends View> T findViewById(@IdRes int id) {
|
||||||
|
return (T) itemView.findViewById(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
24
app/src/main/res/layout/item_dir.xml
Normal file
24
app/src/main/res/layout/item_dir.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/iv_arrow"
|
||||||
|
android:layout_width="18dp"
|
||||||
|
android:layout_height="18dp"
|
||||||
|
android:layout_gravity="center_vertical"
|
||||||
|
android:src="@drawable/ic_keyboard_arrow_right_black_18dp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_name"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginLeft="5dp"
|
||||||
|
android:drawableLeft="@drawable/ic_folder_light_blue_700_24dp"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
tools:text="@string/app_name"
|
||||||
|
android:textSize="18sp" />
|
||||||
|
</LinearLayout>
|
||||||
16
app/src/main/res/layout/item_file.xml
Normal file
16
app/src/main/res/layout/item_file.xml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/tv_name"
|
||||||
|
android:layout_marginLeft="23dp"
|
||||||
|
android:drawableLeft="@drawable/ic_insert_drive_file_light_blue_700_24dp"
|
||||||
|
android:drawablePadding="10dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
tools:text="@string/app_name"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</LinearLayout>
|
||||||
Reference in New Issue
Block a user