Blackboard Resources (no links)
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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<ArrayList<Resource>> {
|
||||
|
||||
@Override
|
||||
protected void upgradeBB(String ID, NetworkCallback<ArrayList<Resource>> 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<ArrayList<Resource>> 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<Resource> 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<>());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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<String> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<DocumentNodeBinder.ViewHolder> {
|
||||
@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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<RecyclerView.ViewHolde
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
|
||||
holder.itemView.setPadding(displayNodes.get(position).getHeight() * padding, 3, 3, 3);
|
||||
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) {
|
||||
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
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<de.sebse.fuplanner.tools.ui.cardview.ExpandableCardView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:card_view="http://schemas.android.com/tools"
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="@dimen/cardview_margin"
|
||||
|
||||
Reference in New Issue
Block a user