diff --git a/app/build.gradle b/app/build.gradle index 23d4ad5a..95cc0dd5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -43,6 +43,8 @@ dependencies { } compile 'com.mikepenz:fontawesome-typeface:4.7.0.0@aar' compile 'pl.droidsonroids.gif:android-gif-drawable:1.2.3' + compile 'com.google.code.gson:gson:2.8.0' + compile 'com.bignerdranch.android:expandablerecyclerview:3.0.0-RC1' } apply plugin: 'com.google.gms.google-services' diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java index ac2e95e9..e6842165 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumAdapter.java @@ -1,16 +1,24 @@ package gr.thmmy.mthmmy.activities.main.forum; import android.content.Context; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; +import com.bignerdranch.expandablerecyclerview.ChildViewHolder; +import com.bignerdranch.expandablerecyclerview.ExpandableRecyclerAdapter; +import com.bignerdranch.expandablerecyclerview.ParentViewHolder; + import java.util.List; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.base.BaseFragment; +import gr.thmmy.mthmmy.data.Board; +import gr.thmmy.mthmmy.data.Category; import gr.thmmy.mthmmy.data.TopicSummary; @@ -18,68 +26,90 @@ import gr.thmmy.mthmmy.data.TopicSummary; * {@link RecyclerView.Adapter} that can display a {@link TopicSummary} and makes a call to the * specified {@link ForumFragment.ForumFragmentInteractionListener}. */ -class ForumAdapter extends RecyclerView.Adapter { +class ForumAdapter extends ExpandableRecyclerAdapter { private final Context context; - private final List recentList; + private final LayoutInflater layoutInflater; + + private final List categories; private final ForumFragment.ForumFragmentInteractionListener mListener; - ForumAdapter(Context context, List topicSummaryList, BaseFragment.FragmentInteractionListener listener) { + ForumAdapter(Context context, @NonNull List categories, BaseFragment.FragmentInteractionListener listener) { + super(categories); this.context = context; - this.recentList = topicSummaryList; + this.categories = categories; mListener = (ForumFragment.ForumFragmentInteractionListener)listener; + layoutInflater = LayoutInflater.from(context); } + @NonNull + @Override + public CategoryViewHolder onCreateParentViewHolder(@NonNull ViewGroup parentViewGroup, int viewType) { + View categoryView = layoutInflater.inflate(R.layout.fragment_forum_category_row, parentViewGroup, false); + return new CategoryViewHolder(categoryView); + } + @NonNull @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.fragment_recent_row, parent, false); - return new ViewHolder(view); + public BoardViewHolder onCreateChildViewHolder(@NonNull ViewGroup childViewGroup, int viewType) { + View boardView = layoutInflater.inflate(R.layout.fragment_forum_board_row, childViewGroup, false); + return new BoardViewHolder(boardView); } + @Override + public void onBindParentViewHolder(@NonNull CategoryViewHolder parentViewHolder, int parentPosition, @NonNull Category parent) { + parentViewHolder.bind(parent); + } @Override - public void onBindViewHolder(final ViewHolder holder, final int position) { + public void onBindChildViewHolder(@NonNull BoardViewHolder childViewHolder, int parentPosition, int childPosition, @NonNull Board child) { + childViewHolder.bind(child); + } - holder.mTitleView.setText(recentList.get(position).getTitle()); - holder.mDateTimeView.setText(recentList.get(position).getDateTimeModified()); - holder.mUserView.setText(context.getString(R.string.byUser, recentList.get(position).getLastUser())); - holder.topic = recentList.get(position); + class CategoryViewHolder extends ParentViewHolder { - holder.mView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { + private TextView categoryTextview; + private ImageView arrowImageView; - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - mListener.onFragmentInteraction(holder.topic); //? + CategoryViewHolder(View itemView) { + super(itemView); + categoryTextview = (TextView) itemView.findViewById(R.id.category); + arrowImageView = (ImageView) itemView.findViewById(R.id.arrow); //todo animated arrow up/down + arrowImageView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (isExpanded()) { + collapseView(); + } else { + expandView(); + } } + }); + } - } - }); - } + void bind(Category category) { + categoryTextview.setText(category.getName()); + } + + @Override + public boolean shouldItemViewClickToggleExpansion() { + return false; + } - @Override - public int getItemCount() { - return recentList.size(); } - class ViewHolder extends RecyclerView.ViewHolder { - final View mView; - final TextView mTitleView; - final TextView mUserView; - final TextView mDateTimeView; - public TopicSummary topic; - - ViewHolder(View view) { - super(view); - mView = view; - mTitleView = (TextView) view.findViewById(R.id.title); - mUserView = (TextView) view.findViewById(R.id.lastUser); - mDateTimeView = (TextView) view.findViewById(R.id.dateTime); + class BoardViewHolder extends ChildViewHolder { + + private TextView boardTextView; + + BoardViewHolder(View itemView) { + super(itemView); + boardTextView = (TextView) itemView.findViewById(R.id.board); + } + + void bind(Board board) { + boardTextView.setText(board.getName()); } } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java index 85244dbc..3a9ab1b6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/forum/ForumFragment.java @@ -2,8 +2,8 @@ package gr.thmmy.mthmmy.activities.main.forum; import android.os.AsyncTask; import android.os.Bundle; -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; @@ -11,21 +11,23 @@ import android.widget.ProgressBar; import android.widget.RelativeLayout; import android.widget.Toast; +import com.bignerdranch.expandablerecyclerview.ExpandableRecyclerAdapter; + import org.jsoup.Jsoup; import org.jsoup.nodes.Document; +import org.jsoup.nodes.Element; import org.jsoup.select.Elements; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import gr.thmmy.mthmmy.R; import gr.thmmy.mthmmy.activities.base.BaseFragment; +import gr.thmmy.mthmmy.data.Board; +import gr.thmmy.mthmmy.data.Category; import gr.thmmy.mthmmy.data.TopicSummary; import gr.thmmy.mthmmy.session.SessionManager; -import gr.thmmy.mthmmy.utils.CustomRecyclerView; import mthmmy.utils.Report; import okhttp3.HttpUrl; import okhttp3.Request; @@ -45,10 +47,9 @@ public class ForumFragment extends BaseFragment // Fragment initialization parameters, e.g. ARG_SECTION_NUMBER private ProgressBar progressBar; - private SwipeRefreshLayout swipeRefreshLayout; private ForumAdapter forumAdapter; - private List topicSummaries; + private List categories; private ForumTask forumTask; @@ -72,13 +73,13 @@ public class ForumFragment extends BaseFragment @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - topicSummaries = new ArrayList<>(); + categories = new ArrayList<>(); } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); - if (topicSummaries.isEmpty()) + if (categories.isEmpty()) { forumTask =new ForumTask(); forumTask.execute(); @@ -91,30 +92,36 @@ public class ForumFragment extends BaseFragment public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment - final View rootView = inflater.inflate(R.layout.fragment_recent, container, false); + final View rootView = inflater.inflate(R.layout.fragment_forum, container, false); // Set the adapter if (rootView instanceof RelativeLayout) { progressBar = (ProgressBar) rootView.findViewById(R.id.progressBar); - forumAdapter = new ForumAdapter(getActivity(), topicSummaries, fragmentInteractionListener); + forumAdapter = new ForumAdapter(getContext(), categories, fragmentInteractionListener); + forumAdapter.setExpandCollapseListener(new ExpandableRecyclerAdapter.ExpandCollapseListener() { + @Override + public void onParentExpanded(int parentPosition) { + if(forumTask.getStatus()== AsyncTask.Status.RUNNING) + forumTask.cancel(true); + forumTask =new ForumTask(); + forumTask.setUrl(categories.get(parentPosition).getCategoryURL()); + forumTask.execute(); + } + + @Override + public void onParentCollapsed(int parentPosition) { + if(forumTask.getStatus()== AsyncTask.Status.RUNNING) + forumTask.cancel(true); + forumTask =new ForumTask(); + forumTask.setUrl(categories.get(parentPosition).getCategoryURL()); + forumTask.execute(); + } + }); - CustomRecyclerView recyclerView = (CustomRecyclerView) rootView.findViewById(R.id.list); + RecyclerView recyclerView = (RecyclerView) rootView.findViewById(R.id.list); recyclerView.setLayoutManager(new LinearLayoutManager(rootView.findViewById(R.id.list).getContext())); recyclerView.setAdapter(forumAdapter); - swipeRefreshLayout = (SwipeRefreshLayout) rootView.findViewById(R.id.swiperefresh); - swipeRefreshLayout.setOnRefreshListener( - new SwipeRefreshLayout.OnRefreshListener() { - @Override - public void onRefresh() { - if (forumTask != null && forumTask.getStatus() != AsyncTask.Status.RUNNING) { - forumTask = new ForumTask(); - forumTask.execute(); - } - } - - } - ); } return rootView; } @@ -134,25 +141,30 @@ public class ForumFragment extends BaseFragment public class ForumTask extends AsyncTask { private static final String TAG = "ForumTask"; - private final HttpUrl thmmyUrl = SessionManager.indexUrl; - + private HttpUrl forumUrl = SessionManager.forumUrl; //may change upon collapse/expand private Document document; + private List fetchedCategories; - protected void onPreExecute() { + ForumTask() { + fetchedCategories = new ArrayList<>(); + } + protected void onPreExecute() { progressBar.setVisibility(ProgressBar.VISIBLE); } protected Integer doInBackground(Void... voids) { - Request request = new Request.Builder() - .url(thmmyUrl) + .url(forumUrl) .build(); try { Response response = client.newCall(request).execute(); document = Jsoup.parse(response.body().string()); parse(document); + categories.clear(); + categories.addAll(fetchedCategories); + fetchedCategories.clear(); return 0; } catch (IOException e) { Report.d(TAG, "Network Error", e); @@ -168,51 +180,46 @@ public class ForumFragment extends BaseFragment protected void onPostExecute(Integer result) { if (result == 0) - forumAdapter.notifyDataSetChanged(); + forumAdapter.notifyParentDataSetChanged(false); else if (result == 1) Toast.makeText(getActivity(), "Network error", Toast.LENGTH_SHORT).show(); progressBar.setVisibility(ProgressBar.INVISIBLE); - swipeRefreshLayout.setRefreshing(false); } - private void parse(Document document) { - Elements recent = document.select("#block8 :first-child div"); - if (recent.size() == 30) { - topicSummaries.clear(); - - for (int i = 0; i < recent.size(); i += 3) { - String link = recent.get(i).child(0).attr("href"); - String title = recent.get(i).child(0).attr("title"); - - String lastUser = recent.get(i + 1).text(); - Pattern pattern = Pattern.compile("\\b (.*)"); - Matcher matcher = pattern.matcher(lastUser); - if (matcher.find()) - lastUser = matcher.group(1); - else { - Report.e(TAG, "Parsing failed (lastUser)!"); - return; - } - - String dateTime = recent.get(i + 2).text(); - pattern = Pattern.compile("\\[(.*)\\]"); - matcher = pattern.matcher(dateTime); - if (matcher.find()) - dateTime = matcher.group(1); - else { - Report.e(TAG, "Parsing failed (dateTime)!"); - return; + private void parse(Document document) + { + Elements categoryBlocks = document.select(".tborder:not([style])>table[cellpadding=5]"); + if (categoryBlocks.size() != 0) { + for(Element categoryBlock: categoryBlocks) + { + Element categoryElement = categoryBlock.select("td[colspan=2]>[name]").first(); + String categoryUrl = categoryElement.attr("href"); + Category category = new Category(categoryElement.text(), categoryUrl); + + category.setExpanded(categoryUrl.contains("sa=collapse")); + if(categoryUrl.contains("sa=collapse")) + { + category.setExpanded(true); + Elements boardsElements = categoryBlock.select("b [name]"); + for(Element boardElement: boardsElements) { + Board board = new Board(boardElement.text(), boardElement.attr("href")); + category.getBoards().add(board); + } } + else + category.setExpanded(false); - - topicSummaries.add(new TopicSummary(link, title, lastUser, dateTime)); + fetchedCategories.add(category); } - - return; } - Report.e(TAG, "Parsing failed!"); + else + Report.e(TAG, "Parsing failed!"); } - } + public void setUrl(String string) + { + forumUrl = HttpUrl.parse(string); + } + } } diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java index a81b0cdd..c2eb8d37 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentAdapter.java @@ -1,6 +1,7 @@ package gr.thmmy.mthmmy.activities.main.recent; import android.content.Context; +import android.support.annotation.NonNull; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; @@ -23,7 +24,7 @@ class RecentAdapter extends RecyclerView.Adapter { private final List recentList; private final RecentFragment.RecentFragmentInteractionListener mListener; - RecentAdapter(Context context, List topicSummaryList, BaseFragment.FragmentInteractionListener listener) { + RecentAdapter(Context context, @NonNull List topicSummaryList, BaseFragment.FragmentInteractionListener listener) { this.context = context; this.recentList = topicSummaryList; mListener = (RecentFragment.RecentFragmentInteractionListener) listener; diff --git a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java index dac762de..bb3c6180 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java +++ b/app/src/main/java/gr/thmmy/mthmmy/activities/main/recent/RecentFragment.java @@ -135,12 +135,10 @@ public class RecentFragment extends BaseFragment { //---------------------------------------ASYNC TASK----------------------------------- public class RecentTask extends AsyncTask { - private static final String TAG = "ForumTask"; + private static final String TAG = "RecentTask"; private final HttpUrl thmmyUrl = SessionManager.indexUrl; - private Document document; - protected void onPreExecute() { progressBar.setVisibility(ProgressBar.VISIBLE); diff --git a/app/src/main/java/gr/thmmy/mthmmy/data/Board.java b/app/src/main/java/gr/thmmy/mthmmy/data/Board.java new file mode 100644 index 00000000..2ed0c1e2 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/data/Board.java @@ -0,0 +1,34 @@ +package gr.thmmy.mthmmy.data; + +import java.util.ArrayList; + +public class Board { + private final String name; + private final String boardURL; + + private ArrayList subBoards; + private ArrayList topicSummaries; + + public Board(String name, String boardURL) { + this.name = name; + this.boardURL = boardURL; + subBoards = new ArrayList<>(); + topicSummaries = new ArrayList<>(); + } + + public String getName() { + return name; + } + + public String getBoardURL() { + return boardURL; + } + + public ArrayList getSubBoards() { + return subBoards; + } + + public ArrayList getTopicSummaries() { + return topicSummaries; + } +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/data/Category.java b/app/src/main/java/gr/thmmy/mthmmy/data/Category.java new file mode 100644 index 00000000..9f0e22a6 --- /dev/null +++ b/app/src/main/java/gr/thmmy/mthmmy/data/Category.java @@ -0,0 +1,58 @@ +package gr.thmmy.mthmmy.data; + +import com.bignerdranch.expandablerecyclerview.model.Parent; + +import java.util.ArrayList; +import java.util.List; + +import static android.R.attr.id; + +public class Category implements Parent +{ + private final String name; + private final String categoryURL; + private boolean expanded = false; + private List boards; + + public Category(String name, String categoryURL) { + this.name = name; + this.categoryURL = categoryURL; + boards = new ArrayList<>(); + } + + public int getId() { + return id; + } + + public String getName() { + return name; + } + + public String getCategoryURL() { + return categoryURL; + } + + public boolean isExpanded() { + return expanded; + } + + public List getBoards() { + return boards; + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } + + @Override + public List getChildList() { + return getBoards(); + } + + @Override + public boolean isInitiallyExpanded() { + return expanded; + } + + +} diff --git a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java index 92acba97..7e16f0a6 100644 --- a/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java +++ b/app/src/main/java/gr/thmmy/mthmmy/session/SessionManager.java @@ -36,6 +36,7 @@ public class SessionManager //Generic constants public static final HttpUrl indexUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php"); + public static final HttpUrl forumUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=forum"); private static final HttpUrl loginUrl = HttpUrl.parse("https://www.thmmy.gr/smf/index.php?action=login2"); private static final String guestName = "Guest"; diff --git a/app/src/main/res/layout/fragment_forum.xml b/app/src/main/res/layout/fragment_forum.xml new file mode 100644 index 00000000..b2229cd3 --- /dev/null +++ b/app/src/main/res/layout/fragment_forum.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_forum_board_row.xml b/app/src/main/res/layout/fragment_forum_board_row.xml new file mode 100644 index 00000000..b87fd1c4 --- /dev/null +++ b/app/src/main/res/layout/fragment_forum_board_row.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_forum_category_row.xml b/app/src/main/res/layout/fragment_forum_category_row.xml new file mode 100644 index 00000000..fb2e7fe1 --- /dev/null +++ b/app/src/main/res/layout/fragment_forum_category_row.xml @@ -0,0 +1,27 @@ + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_recent.xml b/app/src/main/res/layout/fragment_recent.xml index 68a56f3f..911412c2 100644 --- a/app/src/main/res/layout/fragment_recent.xml +++ b/app/src/main/res/layout/fragment_recent.xml @@ -11,10 +11,9 @@ android:layout_width="match_parent" android:layout_height="match_parent"> -