diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceFragment.java index 56f5249..b77347b 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceFragment.java @@ -24,6 +24,7 @@ import de.sebse.fuplanner.services.kvv.types.Resource; import de.sebse.fuplanner.tools.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.ui.treeview.DirectoryNodeBinder; +import de.sebse.fuplanner.tools.ui.treeview.DocumentNodeBinder; import de.sebse.fuplanner.tools.ui.treeview.FileNodeBinder; import de.sebse.fuplanner.tools.ui.treeview.TreeNode; import de.sebse.fuplanner.tools.ui.treeview.TreeViewAdapter; @@ -81,7 +82,7 @@ public class ModDetailResourceFragment extends Fragment { RecyclerView recyclerView = view.findViewById(R.id.list); recyclerView.setLayoutManager(new LinearLayoutManager(context)); - adapter = new ModDetailResourceAdapter(Arrays.asList(new FileNodeBinder(), new DirectoryNodeBinder())); + adapter = new ModDetailResourceAdapter(Arrays.asList(new FileNodeBinder(), new DirectoryNodeBinder(), new DocumentNodeBinder())); adapter.setOnTreeNodeListener(new TreeViewAdapter.OnTreeNodeListener() { @Override public boolean onClick(TreeNode node, RecyclerView.ViewHolder holder) { diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java index 990622f..a672b9b 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java @@ -14,6 +14,7 @@ import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.concurrent.CountDownLatch; import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.services.kvv.types.Resource; @@ -126,9 +127,82 @@ public class ModulesResources extends PartModules> { @Override protected void upgradeBB(String ID, NetworkCallback> callback, NetworkErrorCallback errorCallback) { - callback.onResponse(new ArrayList<>()); + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) { + errorCallback.onError(new NetworkError(101614, 500, "Currently running in offline mode!")); + return; + } + getRescourceFolder(String.format("https://lms.fu-berlin.de/learn/api/public/v1/courses/%s/contents/", ID), ID, false, callback, errorCallback); + //callback.onResponse(new ArrayList<>()); } + private void getRescourceFolder(String url, String ID, boolean subRequest, NetworkCallback> callback, NetworkErrorCallback errorCallback) { + if (mLogin.getLoginTokenBB() == null) { + errorCallback.onError(new NetworkError(101610, 500, "Cannot get resources!")); + return; + } + get(url, mLogin.getLoginTokenBB().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(101611, 403, "No resources retrieved!")); + return; + } + ArrayList resources = new ArrayList<>(); + JSONArray sites; + try { + JSONObject json = new JSONObject(body); + sites = json.getJSONArray("results"); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101612, 400, "Cannot parse resources!")); + return; + } + + final int[] latch = {sites.length()}; + for (int i = 0; i < sites.length(); i++) { + try { + JSONObject resource = sites.getJSONObject(i); + String resid = resource.getString("id"); + String title = resource.getString("title"); + String created = resource.getString("created"); + String content = resource.getJSONObject("contentHandler").getString("id"); + long createdDate = UtilsDate.stringToMillis(created, "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); + if (content.equals("resource/x-bb-folder")) { + Resource.Folder folder = new Resource.Folder("", title, createdDate, "", true, ""); + resources.add(folder); + getRescourceFolder(String.format("https://lms.fu-berlin.de/learn/api/public/v1/courses/%s/contents/%s/children", ID, resid), ID, true, response1 -> { + for (Resource resource1 : response1) { + folder.add(resource1); + } + if (--latch[0] == 0) callback.onResponse(resources); + }, errorCallback); + } else { + String bodyText = resource.optString("body", ""); + bodyText = String.valueOf(PartModules.fromHtml(bodyText)); + resources.add(new Resource.Document("", title, createdDate, true, "", bodyText)); + if (--latch[0] == 0) callback.onResponse(resources); + } + } catch (JSONException e) { + log.e(new NetworkError(101615, 400, "Cannot parse resources!")); + e.printStackTrace(); + log.e("ID:", i, "JSON:", sites); + return; + } + } + }, error -> { + if (!subRequest || error.networkResponse.statusCode != 403) { + errorCallback.onError(new NetworkError(101613, error.networkResponse.statusCode, "Cannot get resources!")); + } else { + callback.onResponse(new ArrayList<>()); + } + }); + } + + + + + + + diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Resource.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Resource.java index 829e53f..5de841c 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Resource.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Resource.java @@ -62,6 +62,61 @@ public abstract class Resource implements Serializable { return Objects.hashCode(getAuthor(), getContainer(), getModifiedDate(), getTitle(), getUrl()); } + public static class Document extends Resource implements LayoutItemType { + private final ArrayList urls; + private final String body; + + public Document(String author, String title, long modifiedDate, boolean visible, String container, String body) { + super(author, title, modifiedDate, "", visible, container); + this.body = body; + this.urls = new ArrayList<>(); + } + + @NonNull + @Override + public String toString() { + return "Resource{" + + "author='" + author + '\'' + + ", modifiedDate=" + modifiedDate + + ", title='" + title + '\'' + + ", urls='" + urls.size() + '\'' + + ", body='" + body + '\'' + + ", urls='" + body + '\'' + + '}'; + } + + public String getBody() { + return body; + } + + public void addUrl(String res){ + urls.add(res); + } + + public String getUrl(int id){ + return urls.get(id); + } + + public int size(){ + return urls.size(); + } + + @Override + public TreeNode getTreeNode() { + return new TreeNode<>(this); + } + + @Override + public @LayoutRes int getLayoutId() { + return R.layout.list_announcement_items; + } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), this.getClass().getSimpleName()); + } + } + public static class File extends Resource implements LayoutItemType { private final String type; @@ -91,6 +146,11 @@ public abstract class Resource implements Serializable { public @LayoutRes int getLayoutId() { return R.layout.item_file; } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), this.getClass().getSimpleName()); + } } public static class Folder extends Resource implements LayoutItemType { @@ -138,6 +198,11 @@ public abstract class Resource implements Serializable { public @LayoutRes int getLayoutId() { return R.layout.item_dir; } + + @Override + public int hashCode() { + return Objects.hashCode(super.hashCode(), this.getClass().getSimpleName()); + } } } diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/cardview/ExpandableCardView.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/cardview/ExpandableCardView.java index c2080c3..a3594d4 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/ui/cardview/ExpandableCardView.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/cardview/ExpandableCardView.java @@ -64,12 +64,12 @@ public class ExpandableCardView extends CardView { private int expandedHeight = 0; private OnExpandedListener listener; + private final Logger log = new Logger(this); private final OnClickListener defaultClickListener = v -> { if(isExpanded()) collapse(); else expand(); }; - private final Logger log = new Logger(this); public ExpandableCardView(Context context) { super(context); diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DocumentNodeBinder.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DocumentNodeBinder.java new file mode 100644 index 0000000..b23a474 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DocumentNodeBinder.java @@ -0,0 +1,67 @@ +package de.sebse.fuplanner.tools.ui.treeview; + +import android.view.View; +import android.widget.TextView; + +import com.cunoraz.tagview.Tag; +import com.cunoraz.tagview.TagView; + +import androidx.core.content.ContextCompat; +import de.sebse.fuplanner.R; +import de.sebse.fuplanner.services.kvv.types.Resource; +import de.sebse.fuplanner.tools.logging.Logger; +import de.sebse.fuplanner.tools.ui.cardview.ExpandableCardView; + +/** + * Created by tlh on 2016/10/1 :) + */ + +public class DocumentNodeBinder extends TreeViewBinder { + @Override + public ViewHolder provideViewHolder(View itemView) { + return new ViewHolder(itemView); + } + + @Override + public void bindView(ViewHolder holder, int position, TreeNode node) { + Resource.Document fileNode = (Resource.Document) node.getContent(); + holder.title.setText(fileNode.getTitle()); + holder.notes.setText(fileNode.getBody()); + + /*for (int i = 0, notesSize = fileNode.size(); i < notesSize; i++) { + String name = urlToName(fileNode.getUrl(i), i, holder.itemView.getResources()); + Tag tag = new Tag(name); + tag.id = i; + tag.layoutColor = ContextCompat.getColor(holder.itemView.getContext(), R.color.colorFUBlue); + holder.mTagGroup.addTag(tag); + } + holder.mTagGroup.setOnTagClickListener((tag, i) -> { + String s = fileNode.getUrl(i); + if (s != null) { + String name = urlToName(s, i, holder.itemView.getResources()); + requestInterface.request(name, s); + } + });*/ + } + + @Override + public int getLayoutId() { + return R.layout.list_announcement_items; + } + + public class ViewHolder extends TreeViewBinder.ViewHolder { + final TextView title; + final TextView notes; + final ExpandableCardView card_view; + final TagView mTagGroup; + + ViewHolder(View rootView) { + super(rootView); + this.card_view = rootView.findViewById(R.id.card_view); + this.title = this.card_view.getOuterView().findViewById(R.id.title); + this.notes = this.card_view.getInnerView().findViewById(R.id.notes); + this.mTagGroup = this.card_view.getInnerView().findViewById(R.id.tag_group); + } + + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/TreeViewAdapter.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/TreeViewAdapter.java index b2de9ed..d3cc94a 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/TreeViewAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/TreeViewAdapter.java @@ -13,6 +13,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.recyclerview.widget.DiffUtil; import androidx.recyclerview.widget.RecyclerView; +import de.sebse.fuplanner.tools.logging.Logger; /** * Created by tlh on 2016/10/1 :) @@ -88,32 +89,34 @@ public class TreeViewAdapter extends RecyclerView.Adapter { - 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) { + if (!holder.itemView.hasOnClickListeners()) { + holder.itemView.setOnClickListener(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()); - } - 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)); - } - }); + 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()) //noinspection unchecked diff --git a/app/src/main/res/layout/list_announcement_items.xml b/app/src/main/res/layout/list_announcement_items.xml index 2d6a290..a769558 100644 --- a/app/src/main/res/layout/list_announcement_items.xml +++ b/app/src/main/res/layout/list_announcement_items.xml @@ -2,6 +2,7 @@