Browse Source

Work in progress: profile activity tabs

pull/24/head
Apostolos Fanakis 8 years ago
parent
commit
eeb0db0a9f
  1. 34
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java
  2. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java
  3. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java
  4. 8
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java
  5. 235
      app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java
  6. 2
      app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java
  7. 25
      app/src/main/res/layout-v21/activity_profile.xml
  8. 28
      app/src/main/res/layout/activity_profile.xml
  9. 7
      app/src/main/res/layout/profile_fragment_latest_posts.xml
  10. 7
      app/src/main/res/layout/profile_fragment_stats.xml
  11. 36
      app/src/main/res/layout/profile_fragment_summary.xml

34
app/src/main/java/gr/thmmy/mthmmy/activities/profile/ProfileActivity.java

@ -8,6 +8,7 @@ import android.os.Build;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.res.ResourcesCompat;
import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.text.Html;
@ -53,9 +54,9 @@ public class ProfileActivity extends BaseActivity {
private ImageView userThumbnail;
private TextView userName;
private TextView personalText;
private LinearLayout mainContent;
private MaterialProgressBar progressBar;
private FloatingActionButton replyFAB;
private ViewPager viewPager;
//Other variables
/**
@ -97,9 +98,8 @@ public class ProfileActivity extends BaseActivity {
progressBar = (MaterialProgressBar) findViewById(R.id.progressBar);
userThumbnail = (ImageView) findViewById(R.id.user_thumbnail);
userName = (TextView) findViewById(R.id.profile_act_username);
userName = (TextView) findViewById(R.id.profile_activity_username);
personalText = (TextView) findViewById(R.id.profile_activity_personal_text);
mainContent = (LinearLayout) findViewById(R.id.profile_activity_content);
replyFAB = (FloatingActionButton) findViewById(R.id.profile_fab); //TODO hide fab while logged out
replyFAB.setEnabled(false);
@ -149,7 +149,7 @@ public class ProfileActivity extends BaseActivity {
* data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link #populateLayout()}
* to build graphics.
* <p>
* <p>Calling ProfileTask's {@link AsyncTask#execute execute} method needs to have profile's url
* <p>Calling ProfileSummaryTask's {@link AsyncTask#execute execute} method needs to have profile's url
* as String parameter!</p>
*/
public class ProfileTask extends AsyncTask<String, Void, Boolean> {
@ -225,31 +225,5 @@ public class ProfileActivity extends BaseActivity {
} else {
personalText.setVisibility(View.GONE);
}
for (int i = PERSONAL_TEXT_INDEX + 1; i < parsedProfileData.size(); ++i) {
if (parsedProfileData.get(i).contains("Signature")
|| parsedProfileData.get(i).contains("Υπογραφή")) {
WebView signatureEntry = new WebView(this);
signatureEntry.loadDataWithBaseURL("file:///android_asset/", parsedProfileData.get(i), "text/html", "UTF-8", null);
}
TextView entry = new TextView(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
entry.setTextColor(getResources().getColor(R.color.primary_text, null));
} else {
//noinspection deprecation
entry.setTextColor(getResources().getColor(R.color.primary_text));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
entry.setText(Html.fromHtml(parsedProfileData.get(i), Html.FROM_HTML_MODE_LEGACY));
} else {
//noinspection deprecation
entry.setText(Html.fromHtml(parsedProfileData.get(i)));
}
mainContent.addView(entry);
Log.d(TAG, "new: " + parsedProfileData.get(i));
}
}
}

8
app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsAdapter.java

@ -0,0 +1,8 @@
package gr.thmmy.mthmmy.activities.profile.latestPosts;
/**
* Created by apostolof on 1/1/17.
*/
public class LatestPostsAdapter {
}

8
app/src/main/java/gr/thmmy/mthmmy/activities/profile/latestPosts/LatestPostsFragment.java

@ -0,0 +1,8 @@
package gr.thmmy.mthmmy.activities.profile.latestPosts;
/**
* Created by apostolof on 1/1/17.
*/
public class LatestPostsFragment {
}

8
app/src/main/java/gr/thmmy/mthmmy/activities/profile/stats/StatsFragment.java

@ -0,0 +1,8 @@
package gr.thmmy.mthmmy.activities.profile.stats;
/**
* Created by apostolof on 1/1/17.
*/
public class StatsFragment {
}

235
app/src/main/java/gr/thmmy/mthmmy/activities/profile/summary/SummaryFragment.java

@ -0,0 +1,235 @@
package gr.thmmy.mthmmy.activities.profile.summary;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.ArrayList;
import java.util.Objects;
import gr.thmmy.mthmmy.R;
import gr.thmmy.mthmmy.activities.base.BaseFragment;
import gr.thmmy.mthmmy.activities.profile.ProfileActivity;
import me.zhanghai.android.materialprogressbar.MaterialProgressBar;
import mthmmy.utils.Report;
/**
* A {@link BaseFragment} subclass.
* Use the {@link SummaryFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class SummaryFragment extends BaseFragment {
static final String PROFILE_DOCUMENT = "PROFILE_DOCUMENT";
private static final String TAG = "SummaryFragment";
/**
* {@link ArrayList} of Strings used to hold profile's information. Data are added in {@link ProfileActivity.ProfileTask}.
*/
private Document profileSummaryDocument;
private ProfileSummaryTask profileSummaryTask;
private ArrayList<String> parsedProfileSummaryData;
private LinearLayout mainContent;
private MaterialProgressBar progressBar;
public SummaryFragment() {
// Required empty public constructor
this.profileSummaryDocument = Jsoup.parse(getArguments().getString(PROFILE_DOCUMENT));
}
/**
* Use ONLY this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @return A new instance of fragment Summary.
*/
public static SummaryFragment newInstance(int sectionNumber, Document profileSummaryDocument) {
SummaryFragment fragment = new SummaryFragment();
Bundle args = new Bundle();
args.putString(ARG_TAG, TAG);
args.putInt(ARG_SECTION_NUMBER, sectionNumber);
args.putString(PROFILE_DOCUMENT, profileSummaryDocument.toString());
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
parsedProfileSummaryData = new ArrayList<>();
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (parsedProfileSummaryData.isEmpty()) {
profileSummaryTask = new ProfileSummaryTask();
profileSummaryTask.execute(profileSummaryDocument);
}
Report.d(TAG, "onActivityCreated");
}
@Override
public void onDestroy() {
super.onDestroy();
if (profileSummaryTask != null && profileSummaryTask.getStatus() != AsyncTask.Status.RUNNING)
profileSummaryTask.cancel(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.profile_fragment_summary, container, false);
progressBar = (MaterialProgressBar) rootView.findViewById(R.id.progressBar);
mainContent = (LinearLayout) rootView.findViewById(R.id.profile_activity_content);
populateLayout();
return rootView;
}
/**
* An {@link AsyncTask} that handles asynchronous fetching of a profile page and parsing it's
* data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link #populateLayout()}
* to build graphics.
* <p>
* <p>Calling ProfileSummaryTask's {@link AsyncTask#execute execute} method needs to have profile's url
* as String parameter!</p>
*/
public class ProfileSummaryTask extends AsyncTask<Document, Void, Void> {
//Class variables
/**
* Debug Tag for logging debug output to LogCat
*/
private static final String TAG = "TopicTask"; //Separate tag for AsyncTask
protected void onPreExecute() {
progressBar.setVisibility(MaterialProgressBar.VISIBLE);
}
protected Void doInBackground(Document... profileSummaryPage) {
parsedProfileSummaryData = parseProfileSummary(profileSummaryPage[0]);
return null;
}
protected void onPostExecute(Void result) {
progressBar.setVisibility(MaterialProgressBar.INVISIBLE);
populateLayout();
}
/**
* Returns an {@link ArrayList} of {@link String}s. This method is used to parse all available
* information in a user profile.
* <p>
* User's thumbnail image url, username and personal text are placed at Array's indexes defined
* by public constants THUMBNAIL_URL_INDEX, USERNAME_INDEX and PERSONAL_TEXT_INDEX respectively.
*
* @param profile {@link Document} object containing this profile's source code
* @return ArrayList containing this profile's parsed information
* @see org.jsoup.Jsoup Jsoup
*/
ArrayList<String> parseProfileSummary(Document profile) {
//Method's variables
ArrayList<String> parsedInformation = new ArrayList<>();
//Contains all summary's rows
Elements summaryRows = profile.select(".bordercolor > tbody:nth-child(1) > tr:nth-child(2) tr");
for (Element row : summaryRows) {
String rowText = row.text(), pHtml = "";
//Horizontal rule rows
if (row.select("td").size() == 1)
pHtml = "";
else if (rowText.contains("Signature") || rowText.contains("Υπογραφή")) {
//This needs special handling since it may have css
{ //Fix embedded videos
Elements noembedTag = row.select("noembed");
ArrayList<String> embededVideosUrls = new ArrayList<>();
for (Element _noembed : noembedTag) {
embededVideosUrls.add(_noembed.text().substring(_noembed.text()
.indexOf("href=\"https://www.youtube.com/watch?") + 38
, _noembed.text().indexOf("target") - 2));
}
pHtml = row.html();
int tmp_counter = 0;
while (pHtml.contains("<embed")) {
if (tmp_counter > embededVideosUrls.size())
break;
pHtml = pHtml.replace(
pHtml.substring(pHtml.indexOf("<embed"), pHtml.indexOf("/noembed>") + 9)
, "<div class=\"embedded-video\">"
+ "<a href=\"https://www.youtube.com/"
+ embededVideosUrls.get(tmp_counter) + "\" target=\"_blank\">"
+ "<img src=\"https://img.youtube.com/vi/"
+ embededVideosUrls.get(tmp_counter) + "/default.jpg\" alt=\"\" border=\"0\">"
+ "</a>"
//+ "<img class=\"embedded-video-play\" src=\"http://www.youtube.com/yt/brand/media/image/YouTube_light_color_icon.png\">"
+ "</div>");
}
}
//Add stuff to make it work in WebView
//style.css
pHtml = ("<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />" + pHtml);
} else if (!rowText.contains("Name") && !rowText.contains("Όνομα")) { //Don't add username twice
if (Objects.equals(row.select("td").get(1).text(), ""))
continue;
//Style parsed information with html
pHtml = "<b>" + row.select("td").first().text() + "</b> "
+ row.select("td").get(1).text();
}
parsedInformation.add(pHtml);
}
return parsedInformation;
}
}
/**
* Simple method that builds the UI of a {@link ProfileActivity}.
* <p>Use this method <b>only after</b> parsing profile's data with
* {@link gr.thmmy.mthmmy.activities.profile.ProfileActivity.ProfileTask} as it reads from
* {@link #parsedProfileSummaryData}</p>
*/
private void populateLayout() {
for (String profileSummaryRow : parsedProfileSummaryData) {
if (profileSummaryRow.contains("Signature")
|| profileSummaryRow.contains("Υπογραφή")) {
WebView signatureEntry = new WebView(this.getContext());
signatureEntry.loadDataWithBaseURL("file:///android_asset/", profileSummaryRow, "text/html", "UTF-8", null);
}
TextView entry = new TextView(this.getContext());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
entry.setTextColor(getResources().getColor(R.color.primary_text, null));
} else {
//noinspection deprecation
entry.setTextColor(getResources().getColor(R.color.primary_text));
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
entry.setText(Html.fromHtml(profileSummaryRow, Html.FROM_HTML_MODE_LEGACY));
} else {
//noinspection deprecation
entry.setText(Html.fromHtml(profileSummaryRow));
}
mainContent.addView(entry);
Log.d(TAG, "new: " + profileSummaryRow);
}
}
}

2
app/src/main/java/gr/thmmy/mthmmy/activities/topic/TopicActivity.java

@ -309,7 +309,7 @@ public class TopicActivity extends BaseActivity {
* data. {@link AsyncTask#onPostExecute(Object) OnPostExecute} method calls {@link RecyclerView#swapAdapter}
* to build graphics.
* <p>
* <p>Calling ProfileTask's {@link AsyncTask#execute execute} method needs to have profile's url
* <p>Calling TopicTask's {@link AsyncTask#execute execute} method needs to have profile's url
* as String parameter!</p>
*/
class TopicTask extends AsyncTask<String, Void, Integer> {

25
app/src/main/res/layout-v21/activity_profile.xml

@ -64,36 +64,29 @@
app:popupTheme="@style/ToolbarTheme">
<TextView
android:id="@+id/profile_act_username"
android:id="@+id/profile_activity_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/accent"
android:textSize="25sp"/>
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/profile_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll"
<android.support.v4.view.ViewPager
android:id="@+id/profile_tab_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|start"
android:background="@color/background"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:scrollbars="none"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/profile_activity_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar"

28
app/src/main/res/layout/activity_profile.xml

@ -63,36 +63,32 @@
app:popupTheme="@style/ToolbarTheme">
<TextView
android:id="@+id/profile_act_username"
android:id="@+id/profile_activity_username"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textColor="@color/accent"
android:textSize="25sp"/>
</android.support.v7.widget.Toolbar>
<android.support.design.widget.TabLayout
android:id="@+id/profile_tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:tabMode="fixed"
app:tabGravity="fill"
android:gravity="center"/>
</android.support.design.widget.AppBarLayout>
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll"
<android.support.v4.view.ViewPager
android:id="@+id/profile_tab_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="top|start"
android:background="@color/background"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:scrollbars="none"
app:layout_anchor="@id/appbar"
app:layout_anchorGravity="bottom|center"
app:layout_behavior="@string/appbar_scrolling_view_behavior">
<LinearLayout
android:id="@+id/profile_activity_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
app:layout_behavior="@string/appbar_scrolling_view_behavior"/>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar"

7
app/src/main/res/layout/profile_fragment_latest_posts.xml

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

7
app/src/main/res/layout/profile_fragment_stats.xml

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>

36
app/src/main/res/layout/profile_fragment_summary.xml

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.widget.NestedScrollView
android:id="@+id/nested_scroll"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/background"
android:paddingEnd="16dp"
android:paddingStart="16dp"
android:scrollbars="none">
<LinearLayout
android:id="@+id/profile_activity_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical">
</LinearLayout>
</android.support.v4.widget.NestedScrollView>
<me.zhanghai.android.materialprogressbar.MaterialProgressBar
android:id="@+id/progressBar"
style="@style/Widget.MaterialProgressBar.ProgressBar.Horizontal.NoPadding"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:indeterminate="true"
android:visibility="invisible"
app:mpb_indeterminateTint="@color/accent"
app:mpb_progressStyle="horizontal"/>
</RelativeLayout>
Loading…
Cancel
Save