From af9d2fed0e5980ae75de2cb1d2b4c15713970209 Mon Sep 17 00:00:00 2001 From: Caesar2011 Date: Fri, 9 Nov 2018 20:11:40 +0100 Subject: [PATCH] Bug fixing, Implemented Rescource, Event and Gradebook --- .../fuplanner/fragments/ScheduleFragment.java | 71 +++-- .../moddetails/ModDetailAnnounceAdapter.java | 2 +- .../moddetails/ModDetailAnnounceFragment.java | 2 +- .../ModDetailAssignmentAdapter.java | 2 +- .../ModDetailAssignmentFragment.java | 3 +- .../moddetails/ModDetailEventAdapter.java | 8 +- .../ModDetailEventAdapterInner.java | 9 +- .../moddetails/ModDetailEventFragment.java | 47 ++-- .../moddetails/ModDetailFragment.java | 4 +- .../moddetails/ModDetailGradebookAdapter.java | 14 +- .../ModDetailGradebookFragment.java | 47 ++-- .../moddetails/ModDetailOverviewFragment.java | 3 - .../moddetails/ModDetailResourceAdapter.java | 4 +- .../moddetails/ModDetailResourceFragment.java | 52 ++-- .../fuplanner/services/NewKVV/Download.java | 265 ++++++++++++++++++ .../fuplanner/services/NewKVV/KVVLogin.java | 3 - .../fuplanner/services/NewKVV/KVVModules.java | 19 +- .../NewKVV/KVVModulesAnnouncements.java | 1 + .../NewKVV/KVVModulesAssignments.java | 3 +- .../services/NewKVV/KVVModulesEvents.java | 83 ++++++ .../services/NewKVV/KVVModulesGradebook.java | 76 +++++ .../services/NewKVV/KVVModulesList.java | 2 + .../services/NewKVV/KVVModulesResources.java | 220 +++++++++++++++ .../sebse/fuplanner/services/NewKVV/Part.java | 6 +- .../types/{Gradebook.java => Grade.java} | 11 +- .../services/NewKVV/types/Modules.java | 4 +- .../ui/treeview/DirectoryNodeBinder.java | 2 +- .../tools/ui/treeview/FileNodeBinder.java | 2 +- 28 files changed, 818 insertions(+), 147 deletions(-) create mode 100644 app/src/main/java/de/sebse/fuplanner/services/NewKVV/Download.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesEvents.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesGradebook.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesResources.java rename app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/{Gradebook.java => Grade.java} (69%) diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java index eaafe4a..c6439ca 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/ScheduleFragment.java @@ -16,9 +16,9 @@ import java.util.List; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.KVV; -import de.sebse.fuplanner.services.KVV.types.Event; -import de.sebse.fuplanner.services.KVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.KVV; +import de.sebse.fuplanner.services.NewKVV.types.Event; +import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.UtilsDate; import de.sebse.fuplanner.tools.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; @@ -59,24 +59,22 @@ public class ScheduleFragment extends Fragment implements MonthLoader.MonthChang } public void invalidate(boolean forceRefresh) { - if (mListener != null) { - KVV kvv = mListener.getKVV(); - kvv.getModuleList((Modules success) -> { - mModules = success; - final int[] i = {0}; - for (Modules.Module module: mModules) { - kvv.getModuleEvents(module, success1 -> { - i[0]++; - if (i[0] >= mModules.size()) { - if (mWeekView != null) { - mWeekView.invalidate(); - mWeekView.notifyDatasetChanged(); - } + if (mListener == null) return; + mListener.getNewKVV().modules().list().recv(modules -> { + mModules = modules; + final int[] i = {0}; + for (Modules.Module module: mModules) { + mListener.getNewKVV().modules().events().recv(module, success1 -> { + i[0]++; + if (i[0] >= mModules.size()) { + if (mWeekView != null) { + mWeekView.invalidate(); + mWeekView.notifyDatasetChanged(); } - }, log::e, forceRefresh); - } - }, log::e, forceRefresh); - } + } + }, log::e, forceRefresh); + } + }, log::e, forceRefresh); } @Override @@ -183,24 +181,21 @@ public class ScheduleFragment extends Fragment implements MonthLoader.MonthChang String moduleId = idParts[0]; AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getContext()); - if (mListener != null) { - KVV kvv = mListener.getKVV(); - kvv.getModuleList((Modules success) -> { - Modules.Module module = success.get(moduleId); - String moduleName = module.title; - alertDialogBuilder - .setTitle(event.getName()) - .setMessage( - getResources().getString(R.string.module_name, moduleName) + "\n" + - getResources().getString(R.string.location_name, event.getLocation()) + "\n" + - getResources().getString(R.string.date_scale, UtilsDate.getModifiedTime(getContext(), event.getStartTime().getTimeInMillis()), UtilsDate.getModifiedTime(getContext(), event.getEndTime().getTimeInMillis()+1)) - ) - .setCancelable(true) - .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel()); + if (mListener == null) return; + mListener.getNewKVV().modules().list().find(moduleId, module -> { + String moduleName = module.title; + alertDialogBuilder + .setTitle(event.getName()) + .setMessage( + getResources().getString(R.string.module_name, moduleName) + "\n" + + getResources().getString(R.string.location_name, event.getLocation()) + "\n" + + getResources().getString(R.string.date_scale, UtilsDate.getModifiedTime(getContext(), event.getStartTime().getTimeInMillis()), UtilsDate.getModifiedTime(getContext(), event.getEndTime().getTimeInMillis()+1)) + ) + .setCancelable(true) + .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel()); - AlertDialog alertDialog = alertDialogBuilder.create(); - alertDialog.show(); - }, log::e); - } + AlertDialog alertDialog = alertDialogBuilder.create(); + alertDialog.show(); + }, log::e); } } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java index 6e1c49b..2c09880 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceAdapter.java @@ -16,7 +16,7 @@ import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.Download; +import de.sebse.fuplanner.services.NewKVV.Download; import de.sebse.fuplanner.services.NewKVV.types.Announcement; import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.Regex; diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java index 4b4d34a..3c7dc6b 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAnnounceFragment.java @@ -14,7 +14,7 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import de.sebse.fuplanner.MainActivity; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.Download; +import de.sebse.fuplanner.services.NewKVV.Download; import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java index fb33aa8..32f6379 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentAdapter.java @@ -16,7 +16,7 @@ import androidx.annotation.Nullable; import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.RecyclerView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.Download; +import de.sebse.fuplanner.services.NewKVV.Download; import de.sebse.fuplanner.services.NewKVV.types.Assignment; import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.Regex; diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentFragment.java index 5396532..8a9dbb3 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailAssignmentFragment.java @@ -14,7 +14,7 @@ import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import de.sebse.fuplanner.MainActivity; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.Download; +import de.sebse.fuplanner.services.NewKVV.Download; import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; @@ -95,6 +95,7 @@ public class ModDetailAssignmentFragment extends Fragment implements Download.On @Override public void request(String title, String url) { + log.d(title, url, mListener); if (mListener == null) return; mListener.getNewKVV().modules().list().find(mItemPos, (Modules.Module module) -> { diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java index a3ef881..c3b80d3 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapter.java @@ -14,10 +14,10 @@ import androidx.annotation.NonNull; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.types.Event; -import de.sebse.fuplanner.services.KVV.types.EventList; -import de.sebse.fuplanner.services.KVV.types.GroupedEvents; -import de.sebse.fuplanner.services.KVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.types.Event; +import de.sebse.fuplanner.services.NewKVV.types.EventList; +import de.sebse.fuplanner.services.NewKVV.types.GroupedEvents; +import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.Triplet; import de.sebse.fuplanner.tools.UtilsDate; import de.sebse.fuplanner.tools.logging.Logger; diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapterInner.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapterInner.java index b4e5551..9ab60d7 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapterInner.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventAdapterInner.java @@ -10,14 +10,11 @@ import java.util.ArrayList; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.types.Event; -import de.sebse.fuplanner.services.KVV.types.EventList; -import de.sebse.fuplanner.services.KVV.types.GroupedEvents; -import de.sebse.fuplanner.tools.Triplet; +import de.sebse.fuplanner.services.NewKVV.types.Event; +import de.sebse.fuplanner.services.NewKVV.types.EventList; +import de.sebse.fuplanner.services.NewKVV.types.GroupedEvents; import de.sebse.fuplanner.tools.UtilsDate; -import de.sebse.fuplanner.tools.ui.CustomViewHolder; import de.sebse.fuplanner.tools.ui.ItemViewHolder; -import de.sebse.fuplanner.tools.ui.ListViewHolder; class ModDetailEventAdapterInner extends RecyclerView.Adapter { private final ArrayList mPositionalData; diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventFragment.java index 04fb784..759a27c 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailEventFragment.java @@ -8,14 +8,13 @@ import android.view.View; import android.view.ViewGroup; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -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.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; /** @@ -30,6 +29,7 @@ public class ModDetailEventFragment extends Fragment { private final Logger log = new Logger(this); private ModDetailEventAdapter adapter; private SwipeRefreshLayout swipeLayout; + @Nullable private MainActivityListener mListener; public ModDetailEventFragment() { @@ -81,22 +81,31 @@ public class ModDetailEventFragment extends Fragment { } private void refresh(boolean forceRefresh) { - if (getActivity() != null) { - KVV kvv = ((MainActivity) getActivity()).getKVV(); - kvv.getModule(mItemPos, (Modules.Module module) -> { - adapter.setModule(module); - kvv.getModuleEvents(module, success1 -> { - adapter.setModule(); - swipeLayout.setRefreshing(false); - }, error -> { - swipeLayout.setRefreshing(false); - log.e(error); - }, forceRefresh); - }, error -> { - swipeLayout.setRefreshing(false); - log.e(error); - }, forceRefresh); - } + if (mListener == null) + return; + mListener.getNewKVV().modules().events().recv(mItemPos, success -> { + adapter.setModule(success); + swipeLayout.setRefreshing(false); + }, error -> { + swipeLayout.setRefreshing(false); + log.e(error); + }, forceRefresh); } + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof MainActivityListener) { + this.mListener = ((MainActivityListener) context); + } else + throw new RuntimeException(context.toString() + " must implement MainActivityListener"); + } + + @Override + public void onDetach() { + super.onDetach(); + if (this.mListener != null) { + this.mListener = null; + } + } } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java index d1c2591..1502fac 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailFragment.java @@ -10,7 +10,7 @@ import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; import androidx.viewpager.widget.ViewPager; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; @@ -72,7 +72,7 @@ public class ModDetailFragment extends Fragment implements ModDetailListener { } if (mListener != null) { mListener.onTitleTextChange(R.string.courses); - mListener.getKVV().getModuleList(success -> { + mListener.getNewKVV().modules().list().recv(success -> { Modules.Module module = success.get(mItemPos); if (mListener != null && module != null) mListener.onTitleTextChange(module.title); diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailGradebookAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailGradebookAdapter.java index 62a779d..3201f0d 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailGradebookAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailGradebookAdapter.java @@ -12,8 +12,8 @@ import java.util.ArrayList; import androidx.annotation.NonNull; import androidx.recyclerview.widget.RecyclerView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.types.Gradebook; -import de.sebse.fuplanner.services.KVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.types.Grade; +import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.tools.ui.StringViewHolder; class ModDetailGradebookAdapter extends RecyclerView.Adapter { @@ -62,7 +62,7 @@ class ModDetailGradebookAdapter extends RecyclerView.Adapter { - adapter.setModule(module); - kvv.getModuleGradebook(module, success1 -> { - adapter.setModule(); - swipeLayout.setRefreshing(false); - }, error -> { - swipeLayout.setRefreshing(false); - log.e(error); - }, forceRefresh); - }, error -> { - swipeLayout.setRefreshing(false); - log.e(error); - }, forceRefresh); - } + if (mListener == null) + return; + mListener.getNewKVV().modules().gradebook().recv(mItemPos, success -> { + adapter.setModule(success); + swipeLayout.setRefreshing(false); + }, error -> { + swipeLayout.setRefreshing(false); + log.e(error); + }, forceRefresh); } + @Override + public void onAttach(Context context) { + super.onAttach(context); + if (context instanceof MainActivityListener) { + this.mListener = ((MainActivityListener) context); + } else + throw new RuntimeException(context.toString() + " must implement MainActivityListener"); + } + + @Override + public void onDetach() { + super.onDetach(); + if (this.mListener != null) { + this.mListener = null; + } + } } diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java index df03414..9bce5b8 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailOverviewFragment.java @@ -13,10 +13,7 @@ import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; -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.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceAdapter.java b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceAdapter.java index 8b5e570..c63e94d 100644 --- a/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceAdapter.java +++ b/app/src/main/java/de/sebse/fuplanner/fragments/moddetails/ModDetailResourceAdapter.java @@ -3,8 +3,8 @@ 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.services.NewKVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.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; 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 665ba28..b245d79 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 @@ -11,16 +11,16 @@ import android.widget.ImageView; import java.util.Arrays; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import de.sebse.fuplanner.MainActivity; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.Download; -import de.sebse.fuplanner.services.KVV.KVV; -import de.sebse.fuplanner.services.KVV.types.Modules; -import de.sebse.fuplanner.services.KVV.types.Resource; +import de.sebse.fuplanner.services.NewKVV.Download; +import de.sebse.fuplanner.services.NewKVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.types.Resource; import de.sebse.fuplanner.tools.MainActivityListener; import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.ui.treeview.DirectoryNodeBinder; @@ -40,8 +40,8 @@ public class ModDetailResourceFragment extends Fragment { private final Logger log = new Logger(this); private ModDetailResourceAdapter adapter; private SwipeRefreshLayout swipeLayout; - private MainActivityListener context; private Download download; + @Nullable private MainActivityListener mListener; public ModDetailResourceFragment() { @@ -88,10 +88,8 @@ public class ModDetailResourceFragment extends Fragment { if (!node.isLeaf()) { // Update and toggle the node. onToggle(!node.isExpand(), holder); - } else if(node.getContent() instanceof Resource.File) { // if leaf is file - KVV kvv = ModDetailResourceFragment.this.context.getKVV(); - kvv.getModule(mItemPos, (Modules.Module module) -> { - + } else if (node.getContent() instanceof Resource.File && ModDetailResourceFragment.this.mListener != null) { // if leaf is file + ModDetailResourceFragment.this.mListener.getNewKVV().modules().resources().recv(mItemPos, (Modules.Module module) -> { String folderName = "FU-"+module.title.replaceAll("[:*<>|/\"\\\\]", "-"); Resource.File file = (Resource.File) node.getContent(); getDownload().openDownloadDialog(file, folderName); @@ -120,14 +118,12 @@ public class ModDetailResourceFragment extends Fragment { return view; } - - @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof MainActivityListener) { - this.context = ((MainActivityListener) context); - this.context.addRequestPermissionsResultListener(getDownload().getRequestPermissionsResultListener(), "ModDetailResourceFragment"); + this.mListener = ((MainActivityListener) context); + this.mListener.addRequestPermissionsResultListener(getDownload().getRequestPermissionsResultListener(), "ModDetailResourceFragment"); } else throw new RuntimeException(context.toString() + " must implement MainActivityListener"); } @@ -135,26 +131,22 @@ public class ModDetailResourceFragment extends Fragment { @Override public void onDetach() { super.onDetach(); - this.context.removeRequestPermissionsResultListener("ModDetailResourceFragment"); + if (this.mListener != null) { + this.mListener.removeRequestPermissionsResultListener("ModDetailResourceFragment"); + this.mListener = null; + } } 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); - } + if (mListener == null) + return; + mListener.getNewKVV().modules().assignments().recv(mItemPos, success -> { + adapter.setModule(success); + swipeLayout.setRefreshing(false); + }, error -> { + swipeLayout.setRefreshing(false); + log.e(error); + }, forceRefresh); } Download getDownload() { diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Download.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Download.java new file mode 100644 index 0000000..9ba73e2 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Download.java @@ -0,0 +1,265 @@ +package de.sebse.fuplanner.services.NewKVV; + +import android.Manifest; +import android.app.AlertDialog; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.net.Uri; +import android.os.Environment; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; + +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.content.FileProvider; +import de.sebse.fuplanner.MainActivity; +import de.sebse.fuplanner.R; +import de.sebse.fuplanner.services.NewKVV.KVV; +import de.sebse.fuplanner.services.NewKVV.types.Resource; +import de.sebse.fuplanner.tools.Regex; +import de.sebse.fuplanner.tools.RequestPermissionsResultListener; +import de.sebse.fuplanner.tools.UtilsDate; +import de.sebse.fuplanner.tools.logging.Logger; + +import static androidx.core.content.ContextCompat.checkSelfPermission; + +public class Download { + + private final ContextInterface contextInterface; + private final ActivityInterface activityInterface; + private RequestedDownload requestedDownload; + private Logger log = new Logger(this); + + + public Download(ContextInterface contextInterface, ActivityInterface activityInterface) { + this.contextInterface = contextInterface; + this.activityInterface = activityInterface; + } + + public void openDownloadDialog(String title, String url, String folderName) { + openDownloadDialog(new Resource.File("", title, 0, url, true, "", ""), folderName); + } + + public void openDownloadDialog(Resource.File file, String folderName) { + Context context = contextInterface.get(); + if (context == null) + return; + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); + File f = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DOWNLOADS)+"/"+folderName+"/"+file.getTitle()); + Resources resources = context.getResources(); + String message = ""; + if (file.getAuthor() != null && !file.getAuthor().isEmpty()) + message += resources.getString(R.string.creator_name, file.getAuthor()); + if (file.getModifiedDate() != 0) { + if (!message.isEmpty()) + message += "\n"; + message += resources.getString(R.string.last_modified_on, UtilsDate.getModifiedDateTime(context, file.getModifiedDate())); + } + + alertDialogBuilder + .setTitle(file.getTitle()) + .setMessage(message) + .setCancelable(true) + .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel()); + // if already downloaded, show open button + if (f.exists()) { + alertDialogBuilder + .setPositiveButton(R.string.download_again, (dialog, id) -> download(file, folderName, true)) + .setNegativeButton(R.string.openFile, (dialog, id) -> download(file, folderName, false)); + } else { + alertDialogBuilder + .setPositiveButton(R.string.download, (dialog, id) -> download(file, folderName, true)); + } + AlertDialog alertDialog = alertDialogBuilder.create(); + alertDialog.show(); + } + + private void download(Resource.File file, String folderName, boolean downloadNew){ + MainActivity activity = activityInterface.get(); + if (activity == null) { + showDownloadError(); + return; + } + if (checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) { + // Access granted + downloadOrOpen(file, folderName, downloadNew); + } else { + this.requestedDownload = new RequestedDownload(file, folderName, downloadNew); + ActivityCompat.requestPermissions(activity, + new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, + 1); + } + } + + private void downloadOrOpen(Resource.File file, String folderName, boolean downloadNew) { + if (!isExternalStorageWritable()) { + return; + } + MainActivity activity = activityInterface.get(); + if (activity == null) { + showDownloadError(); + return; + } + activity.getNewKVV().modules().resources().file(file.getTitle(), file.getUrl(), folderName, success -> { + Context context = contextInterface.get(); + if (success.equals("")) { + showDownloadError(); + } else { + if (Regex.has("^http", success)){ + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(success)); + context.startActivity(intent); + } + else { + fileOpen(new File(success)); + } + + } + }, log::e, downloadNew); + } + + private void showDownloadError() { + Context context = contextInterface.get(); + if (context == null) + return; + AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); + alertDialogBuilder + .setTitle(R.string.ErrorFileDownload) + .setMessage( + R.string.ErrorFileDownloadText + ) + .setCancelable(true) + .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel()); + AlertDialog alertDialog = alertDialogBuilder.create(); + alertDialog.show(); + } + + public RequestPermissionsResultListener getRequestPermissionsResultListener() { + return (requestCode, permissions, grantResults) -> { + if (requestedDownload == null) { + log.d("No request"); + return; + } + if (activityInterface.get() == null) { + showDownloadError(); + return; + } + ArrayList intList = new ArrayList<>(); + for (int i : grantResults) + { + intList.add(i); + } + log.d(requestCode, Arrays.asList(permissions), intList); + int pos = Arrays.asList(permissions).indexOf("android.permission.WRITE_EXTERNAL_STORAGE"); + if (pos != -1) { + if (grantResults[pos] != -1) { + downloadOrOpen(requestedDownload.file, requestedDownload.folderName, requestedDownload.downloadNew); + } else { + log.d(requestedDownload, pos, grantResults[pos]); + showDownloadError(); + } + requestedDownload = null; + } + }; + } + + private class RequestedDownload { + Resource.File file; + String folderName; + boolean downloadNew; + + RequestedDownload(Resource.File file, String folderName, boolean downloadNew) { + this.file = file; + this.folderName = folderName; + this.downloadNew = downloadNew; + } + } + + /* Checks if external storage is available for read and write */ + private boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + log.e("File system: Writing not possible"); + return false; + } + + private void fileOpen(File url){ + Uri uri = FileProvider.getUriForFile(contextInterface.get(), contextInterface.get().getApplicationContext().getPackageName() + ".my.provider", url); + + Intent intent; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { + intent = new Intent(Intent.ACTION_VIEW); + } else { + intent = new Intent(); + } + intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION); + // Check what kind of file you are trying to open, by comparing the url with extensions. + // When the if condition is matched, plugin sets the correct intent (mime) type, + // so Android knew what application to use to open the file + if (url.toString().contains(".doc") || url.toString().contains(".docx")) { + // Word document + intent.setDataAndType(uri, "application/msword"); + } else if(url.toString().contains(".pdf")) { + // PDF file + intent.setDataAndType(uri, "application/pdf"); + } else if(url.toString().contains(".ppt") || url.toString().contains(".pptx")) { + // Powerpoint file + intent.setDataAndType(uri, "application/vnd.ms-powerpoint"); + } else if(url.toString().contains(".xls") || url.toString().contains(".xlsx")) { + // Excel file + intent.setDataAndType(uri, "application/vnd.ms-excel"); + } else if(url.toString().contains(".zip") || url.toString().contains(".rar")) { + // ZIP file + intent.setDataAndType(uri, "application/zip"); + } else if(url.toString().contains(".rtf")) { + // RTF file + intent.setDataAndType(uri, "application/rtf"); + } else if(url.toString().contains(".wav") || url.toString().contains(".mp3")) { + // WAV audio file + intent.setDataAndType(uri, "audio/x-wav"); + } else if(url.toString().contains(".gif")) { + // GIF file + intent.setDataAndType(uri, "image/gif"); + } else if(url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) { + // JPG file + intent.setDataAndType(uri, "image/jpeg"); + } else if(url.toString().contains(".txt")) { + // Text file + intent.setDataAndType(uri, "text/plain"); + } else if(url.toString().contains(".3gp") || url.toString().contains(".mpg") || url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) { + // Video files + intent.setDataAndType(uri, "video/*"); + } else { + //if you want you can also define the intent type for any other file + + //additionally use else clause below, to manage other unknown extensions + //in this case, Android will show all applications installed on the device + //so you can choose which application to use + intent.setDataAndType(uri, "*/*"); + } + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + contextInterface.get().startActivity(intent); + + } + + @FunctionalInterface + public interface ContextInterface { + @Nullable Context get(); + } + + @FunctionalInterface + public interface ActivityInterface { + @Nullable MainActivity get(); + } + + public interface OnDownloadRequestInterface { + void request(String title, String url); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVLogin.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVLogin.java index 3d89e7d..96b13e1 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVLogin.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVLogin.java @@ -35,9 +35,6 @@ public class KVVLogin extends HTTPService { if (mLoginPending) { errorCallback.onError(new NetworkError(100160, -1, "Login already pending!")); } - if (mToken != null) { - errorCallback.onError(new NetworkError(100161, -1, "Already logged in!")); - } mLoginPending = true; doLogin(username, password, token -> { testLoginToken(token, token2 -> { diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModules.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModules.java index ecc6aad..7adbe0b 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModules.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModules.java @@ -12,7 +12,7 @@ public class KVVModules { private final KVVLogin mLogin; private final Context context; - public KVVModules(KVVLogin login, Context context) { + KVVModules(KVVLogin login, Context context) { this.mLogin = login; this.context = context; } @@ -20,7 +20,7 @@ public class KVVModules { @NotNull public KVVModulesDetails details() { return (KVVModulesDetails) addAndGet("details", () -> { - ModulesPart[] parts = {announcements(), assignments()}; + ModulesPart[] parts = {announcements(), assignments(), events(), gradebook(), resources()}; return new KVVModulesDetails(mLogin, list(), context, parts); }); } @@ -35,6 +35,21 @@ public class KVVModules { return (KVVModulesAssignments) addAndGet("assignments", () -> new KVVModulesAssignments(mLogin, list(), context)); } + @NotNull + public KVVModulesEvents events() { + return (KVVModulesEvents) addAndGet("events", () -> new KVVModulesEvents(mLogin, list(), context)); + } + + @NotNull + public KVVModulesGradebook gradebook() { + return (KVVModulesGradebook) addAndGet("gradebook", () -> new KVVModulesGradebook(mLogin, list(), context)); + } + + @NotNull + public KVVModulesResources resources() { + return (KVVModulesResources) addAndGet("resources", () -> new KVVModulesResources(mLogin, list(), context)); + } + @NotNull public KVVModulesList list() { if (mList == null) { diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAnnouncements.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAnnouncements.java index a719484..af57532 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAnnouncements.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAnnouncements.java @@ -75,6 +75,7 @@ public class KVVModulesAnnouncements extends ModulesPart announcements.add(new Announcement(id, title, text, createdBy, createdOn, urls)); } catch (JSONException e) { log.e(new NetworkError(101205, 403, "Cannot parse announcements!")); + log.e("ID:", i, "JSON:", sites); e.printStackTrace(); return; } diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAssignments.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAssignments.java index 29a70b2..0863e32 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAssignments.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesAssignments.java @@ -75,6 +75,7 @@ public class KVVModulesAssignments extends ModulesPart { } catch (JSONException e) { log.e(new NetworkError(101305, 403, "Cannot parse assignments!")); e.printStackTrace(); + log.e("ID:", i, "JSON:", sites); return; } } @@ -84,6 +85,6 @@ public class KVVModulesAssignments extends ModulesPart { mLogin.testLoginToken(token -> callback.onResponse(assignments), errorCallback); else callback.onResponse(assignments); - }, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get announcements!"))); + }, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get assignments!"))); } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesEvents.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesEvents.java new file mode 100644 index 0000000..4673090 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesEvents.java @@ -0,0 +1,83 @@ +package de.sebse.fuplanner.services.NewKVV; + +import android.content.Context; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import de.sebse.fuplanner.services.NewKVV.types.Event; +import de.sebse.fuplanner.services.NewKVV.types.EventList; +import de.sebse.fuplanner.services.NewKVV.types.Modules; +import de.sebse.fuplanner.tools.network.NetworkCallback; +import de.sebse.fuplanner.tools.network.NetworkError; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; + +public class KVVModulesEvents extends ModulesPart { + + KVVModulesEvents(KVVLogin login, KVVModulesList list, Context context) { + super(login, list, context); + } + + @Override + protected EventList getPart(Modules.Module module) { + return module.events; + } + + @Override + protected boolean setPart(Modules.Module module, EventList part) { + boolean changed = module.events == null || module.events.hashCode() != part.hashCode(); + module.events = part; + return changed; + } + + @Override + protected void upgrade(final String ID, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + errorCallback.onError(new NetworkError(101404, 500, "Currently running in offline mode!")); + return; + } + get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true", ID), mLogin.getLoginToken().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(101401, 403, "No events retrieved!")); + return; + } + EventList events = new EventList(); + JSONArray sites; + try { + JSONObject json = new JSONObject(body); + sites = json.getJSONArray("calendar_collection"); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101402, 403, "Cannot parse events!")); + return; + } + + for (int i = 0; i < sites.length(); i++) { + try { + JSONObject site = sites.getJSONObject(i); + String id = site.getString("eventId"); + String type = site.getString("type"); + String title = site.getString("title"); + String siteId = site.getString("siteId"); + long duration = site.getLong("duration"); + long firstTime = site.getJSONObject("firstTime").getLong("time"); + String location = site.getString("location"); + events.add(new Event(id, type, title, duration, firstTime, siteId, location)); + } catch (JSONException e) { + log.e(new NetworkError(101405, 403, "Cannot parse events!")); + e.printStackTrace(); + log.e("ID:", i, "JSON:", sites); + return; + } + } + + // Empty events *may be* because token is invalid -> check + if (events.size() == 0) + mLogin.testLoginToken(token -> callback.onResponse(events), errorCallback); + else + callback.onResponse(events); + }, error -> errorCallback.onError(new NetworkError(101403, error.networkResponse.statusCode, "Cannot get events!"))); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesGradebook.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesGradebook.java new file mode 100644 index 0000000..08d461e --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesGradebook.java @@ -0,0 +1,76 @@ +package de.sebse.fuplanner.services.NewKVV; + +import android.content.Context; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; + +import de.sebse.fuplanner.services.NewKVV.types.Grade; +import de.sebse.fuplanner.services.NewKVV.types.Modules; +import de.sebse.fuplanner.tools.network.NetworkCallback; +import de.sebse.fuplanner.tools.network.NetworkError; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; + +public class KVVModulesGradebook extends ModulesPart> { + + KVVModulesGradebook(KVVLogin login, KVVModulesList list, Context context) { + super(login, list, context); + } + + @Override + protected ArrayList getPart(Modules.Module module) { + return module.gradebook; + } + + @Override + protected boolean setPart(Modules.Module module, ArrayList part) { + boolean changed = module.gradebook == null || module.gradebook.hashCode() != part.hashCode(); + module.gradebook = part; + return changed; + } + + @Override + protected void upgrade(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + errorCallback.onError(new NetworkError(101504, 500, "Currently running in offline mode!")); + return; + } + super.get(String.format("https://kvv.imp.fu-berlin.de/direct/gradebook/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(101501, 403, "No gradebook retrieved!")); + return; + } + ArrayList gradebook = new ArrayList<>(); + JSONArray sites; + try { + JSONObject json = new JSONObject(body); + sites = json.getJSONArray("assignments"); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101502, 403, "Cannot parse gradebook!")); + return; + } + + for (int i = 0; i < sites.length(); i++) { + try { + JSONObject site = sites.getJSONObject(i); + double grade = site.optDouble("grade", 0); + String itemName = site.optString("itemName", null); + double maxPoints = site.optDouble("points", -1); + + gradebook.add(0, new Grade(itemName, grade, maxPoints)); + } catch (JSONException e) { + log.e(new NetworkError(101505, 403, "Cannot parse gradebook!")); + log.e("ID:", i, "JSON:", sites); + e.printStackTrace(); + return; + } + } + callback.onResponse(gradebook); + }, error -> errorCallback.onError(new NetworkError(101503, error.networkResponse.statusCode, "Cannot get gradebook!"))); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesList.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesList.java index 810d5c4..dbb52ff 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesList.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesList.java @@ -179,9 +179,11 @@ public class KVVModulesList extends HTTPService { modules.addModule(semester, lvNumbers, title, lecturers, type, description, id); } catch (JSONException e) { log.e(new NetworkError(101103, 403, "Cannot parse module list!")); + log.e("ID:", i, "JSON:", sites); e.printStackTrace(); } catch (NoSuchFieldException e) { log.e(new NetworkError(101106, 403, "Cannot parse module list!")); + log.e("ID:", i, "JSON:", sites); e.printStackTrace(); } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesResources.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesResources.java new file mode 100644 index 0000000..1598a5b --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/KVVModulesResources.java @@ -0,0 +1,220 @@ +package de.sebse.fuplanner.services.NewKVV; + +import android.content.Context; +import android.os.Environment; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; + +import de.sebse.fuplanner.services.NewKVV.types.Modules; +import de.sebse.fuplanner.services.NewKVV.types.Resource; +import de.sebse.fuplanner.tools.Regex; +import de.sebse.fuplanner.tools.network.NetworkCallback; +import de.sebse.fuplanner.tools.network.NetworkError; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; + +public class KVVModulesResources extends ModulesPart> { + + KVVModulesResources(KVVLogin login, KVVModulesList list, Context context) { + super(login, list, context); + } + + @Override + protected ArrayList getPart(Modules.Module module) { + return module.resources; + } + + @Override + protected boolean setPart(Modules.Module module, ArrayList part) { + boolean changed = module.assignments == null || module.assignments.hashCode() != part.hashCode(); + module.resources = part; + return changed; + } + + @Override + protected void upgrade(final String ID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!")); + return; + } + get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(101601, 403, "No resources retrieved!")); + return; + } + ArrayList resources = new ArrayList<>(); + JSONArray sites; + try { + JSONObject json = new JSONObject(body); + sites = json.getJSONArray("content_collection"); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(101602, 403, "Cannot parse resources!")); + return; + } + + for (int i = 0; i < sites.length(); i++) { + try { + JSONObject site = sites.getJSONObject(i); + String author = site.getString("author"); + String title = site.getString("title"); + long modifiedDate = site.getLong("modifiedDate"); + String url = site.getString("url"); + boolean visible = site.getBoolean("visible"); + String type = site.getString("type"); + String container = site.getString("container"); + if (type.equals("collection")){ + resources.add(new Resource.Folder(author, title, modifiedDate, url, visible, container)); + } + else { + resources.add(new Resource.File(author, title, modifiedDate, url, visible, container, type)); + } + } catch (JSONException e) { + log.e(new NetworkError(101605, 403, "Cannot parse resources!")); + e.printStackTrace(); + log.e("ID:", i, "JSON:", sites); + return; + } + } + + ArrayList root = new ArrayList<>(); + // Generate folder structure + for (Resource res: resources) { + if (!res.getContainer().equals("/content/group/")) { + if (res.getContainer().equals("/content/group/"+ID+"/")){ + // if file in root folder + root.add(res); + } else { + // in sub folder + for (Resource res2: resources) { + if (res2.getUrl().endsWith(res.getContainer()) && res2 instanceof Resource.Folder) { + // Append File/Folder to list + ((Resource.Folder) res2).add(res); + } + } + } + } + } + + // Empty assignments *may be* because token is invalid -> check + if (root.size() == 0) + mLogin.testLoginToken(token -> callback.onResponse(root), errorCallback); + else + callback.onResponse(root); + }, error -> errorCallback.onError(new NetworkError(101603, error.networkResponse.statusCode, "Cannot get resources!"))); + } + + + + + + + + + + + + public void file(final String filename, final String url, final String modulename, final NetworkCallback callback, final NetworkErrorCallback errorCallback, boolean forceRefresh) { + file(filename, url, modulename, callback, errorCallback, forceRefresh, RETRY_COUNT); + } + + public void file(final String filename, final String url, final String modulename, final NetworkCallback callback, final NetworkErrorCallback errorCallback, boolean forceRefresh, int retries) { + if (isExternalStorageReadable()){ + File f = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DOWNLOADS)+"/"+modulename+"/"+filename); + // check if file already downloaded -> do not download again + if (f.exists() && !forceRefresh) { + callback.onResponse(f.getPath()); + return; + } + } + fileUpgrade(filename, url , modulename, callback, error -> { + if (retries >= 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) { + mLogin.refreshLogin(success -> { + file(filename, url, modulename, callback, errorCallback, forceRefresh, retries-1); + }, errorCallback); + return; + } + errorCallback.onError(error); + }); + } + + private void fileUpgrade(String filename, String url, String modulename, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) { + errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!")); + return; + } + get(url, mLogin.getLoginToken().getCookies(), response -> { + if (Regex.has("\\.[Uu][Rr][Ll]$", url)){ + // Return redirected URL + String path = response.getHeaders().get("Location"); + if (path == null){ + path = ""; + } + callback.onResponse(path); + } else if (response.getBytes() == null) { + errorCallback.onError(new NetworkError(101705, 403, "Cannot get file!")); + } else if (isExternalStorageWritable()) { + String path = saveFileInDownloads(filename, response.getBytes(), modulename); + callback.onResponse(path); + } else { + errorCallback.onError(new NetworkError(101704, 403, "External storage not writable!")); + } + }, error -> errorCallback.onError(new NetworkError(101702, error.networkResponse.statusCode, "Cannot get file!"))); + + + } + + + + + + + + /* Checks if external storage is available for read and write */ + private boolean isExternalStorageWritable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state)) { + return true; + } + log.w("File system: Writing not possible!"); + return false; + } + + /* Checks if external storage is available to at least read */ + private boolean isExternalStorageReadable() { + String state = Environment.getExternalStorageState(); + if (Environment.MEDIA_MOUNTED.equals(state) || + Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) { + return true; + } + log.w("File system: Reading not possible!"); + return false; + } + private String saveFileInDownloads(String filename, byte[] data, String moduleName) { + // Saves file in folder: DOWNLOADS/moduleName + File folder = new File(Environment.getExternalStoragePublicDirectory( + Environment.DIRECTORY_DOWNLOADS), moduleName); + if (!folder.mkdir()) { + log.w( "Directory not created"); + } + String path = ""; + try { + // TODO check if enough storage space is available + FileOutputStream out = new FileOutputStream(folder.getPath()+"/"+filename); + out.write(data); + out.close(); + path = folder.getPath()+"/"+filename; + } catch (Exception e) { + log.w("File not saved!"); + e.printStackTrace(); + } + return path; + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Part.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Part.java index 294636c..0521a9f 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Part.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/Part.java @@ -23,7 +23,11 @@ public abstract class Part extends HTTPService { } public void recv(final String moduleID, final NetworkCallback callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh) { - mList.find(moduleID, success -> recv(success, callback, errorCallback, forceRefresh, RETRY_COUNT), errorCallback); + mList.find(moduleID, success -> recv(success, callback, errorCallback, forceRefresh), errorCallback); + } + + public void recv(final Modules.Module module, final NetworkCallback callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh) { + recv(module, callback, errorCallback, forceRefresh, RETRY_COUNT); } abstract protected void recv(final Modules.Module module, final NetworkCallback callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh, final int retries); diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Gradebook.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Grade.java similarity index 69% rename from app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Gradebook.java rename to app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Grade.java index d97e368..d102d84 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Gradebook.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Grade.java @@ -1,13 +1,15 @@ package de.sebse.fuplanner.services.NewKVV.types; +import com.google.android.gms.common.internal.Objects; + import java.io.Serializable; -public class Gradebook implements Serializable { +public class Grade implements Serializable { private final String itemName; private final double grade; private final double maxPoints; - public Gradebook(String itemName, double points, double maxPoints) { + public Grade(String itemName, double points, double maxPoints) { this.itemName = itemName; this.grade = points; this.maxPoints = maxPoints; @@ -31,4 +33,9 @@ public class Gradebook implements Serializable { "\nPoints: "+ getPoints()+ "\nMax points: "+getMaxPoints(); } + + @Override + public int hashCode() { + return Objects.hashCode(getItemName(), getPoints(), getMaxPoints()); + } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Modules.java b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Modules.java index 8994948..a746e45 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Modules.java +++ b/app/src/main/java/de/sebse/fuplanner/services/NewKVV/types/Modules.java @@ -116,14 +116,14 @@ public class Modules implements Iterable, Serializable { @Nullable public ArrayList announcements; @Nullable public AssignmentList assignments; @Nullable public EventList events; - @Nullable public ArrayList gradebook; + @Nullable public ArrayList gradebook; @Nullable public ArrayList resources; public float getGradebookPercent(){ float maxPoint = 0; float userPoint = 0; if (gradebook != null) { - for (Gradebook g : gradebook){ + for (Grade g : gradebook){ maxPoint += g.getMaxPoints(); userPoint += g.getPoints(); } diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DirectoryNodeBinder.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DirectoryNodeBinder.java index 9a2ac9c..9cae51b 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DirectoryNodeBinder.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/DirectoryNodeBinder.java @@ -5,7 +5,7 @@ import android.widget.ImageView; import android.widget.TextView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.types.Resource; +import de.sebse.fuplanner.services.NewKVV.types.Resource; /** * Created by tlh on 2016/10/1 :) diff --git a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/FileNodeBinder.java b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/FileNodeBinder.java index f337b37..a89af39 100644 --- a/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/FileNodeBinder.java +++ b/app/src/main/java/de/sebse/fuplanner/tools/ui/treeview/FileNodeBinder.java @@ -4,7 +4,7 @@ import android.view.View; import android.widget.TextView; import de.sebse.fuplanner.R; -import de.sebse.fuplanner.services.KVV.types.Resource; +import de.sebse.fuplanner.services.NewKVV.types.Resource; /** * Created by tlh on 2016/10/1 :)